Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 62b3cf4

Browse files
committed
Merge branch 'main' into agentlogs
2 parents a4be45f + c2b5009 commit 62b3cf4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1294
-461
lines changed

agent/agent.go

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import (
4040

4141
type Options struct {
4242
ReconnectingPTYTimeout time.Duration
43+
EnvironmentVariables map[string]string
4344
Logger slog.Logger
4445
}
4546

@@ -48,6 +49,7 @@ type Metadata struct {
4849
OwnerUsername string `json:"owner_username"`
4950
EnvironmentVariables map[string]string `json:"environment_variables"`
5051
StartupScript string `json:"startup_script"`
52+
Directory string `json:"directory"`
5153
}
5254

5355
type Dialer func(ctx context.Context, logger slog.Logger) (Metadata, *peerbroker.Listener, error)
@@ -66,6 +68,7 @@ func New(dialer Dialer, options *Options) io.Closer {
6668
logger: options.Logger,
6769
closeCancel: cancelFunc,
6870
closed: make(chan struct{}),
71+
envVars: options.EnvironmentVariables,
6972
}
7073
server.init(ctx)
7174
return server
@@ -83,23 +86,21 @@ type agent struct {
8386
closeMutex sync.Mutex
8487
closed chan struct{}
8588

86-
// Environment variables sent by Coder to inject for shell sessions.
87-
// These are atomic because values can change after reconnect.
88-
envVars atomic.Value
89-
ownerEmail atomic.String
90-
ownerUsername atomic.String
89+
envVars map[string]string
90+
// metadata is atomic because values can change after reconnection.
91+
metadata atomic.Value
9192
startupScript atomic.Bool
9293
sshServer *ssh.Server
9394
}
9495

9596
func (a *agent) run(ctx context.Context) {
96-
var options Metadata
97+
var metadata Metadata
9798
var peerListener *peerbroker.Listener
9899
var err error
99100
// An exponential back-off occurs when the connection is failing to dial.
100101
// This is to prevent server spam in case of a coderd outage.
101102
for retrier := retry.New(50*time.Millisecond, 10*time.Second); retrier.Wait(ctx); {
102-
options, peerListener, err = a.dialer(ctx, a.logger)
103+
metadata, peerListener, err = a.dialer(ctx, a.logger)
103104
if err != nil {
104105
if errors.Is(err, context.Canceled) {
105106
return
@@ -118,14 +119,12 @@ func (a *agent) run(ctx context.Context) {
118119
return
119120
default:
120121
}
121-
a.envVars.Store(options.EnvironmentVariables)
122-
a.ownerEmail.Store(options.OwnerEmail)
123-
a.ownerUsername.Store(options.OwnerUsername)
122+
a.metadata.Store(metadata)
124123

125124
if a.startupScript.CAS(false, true) {
126125
// The startup script has not ran yet!
127126
go func() {
128-
err := a.runStartupScript(ctx, options.StartupScript)
127+
err := a.runStartupScript(ctx, metadata.StartupScript)
129128
if errors.Is(err, context.Canceled) {
130129
return
131130
}
@@ -313,6 +312,15 @@ func (a *agent) createCommand(ctx context.Context, rawCommand string, env []stri
313312
return nil, xerrors.Errorf("get user shell: %w", err)
314313
}
315314

315+
rawMetadata := a.metadata.Load()
316+
if rawMetadata == nil {
317+
return nil, xerrors.Errorf("no metadata was provided: %w", err)
318+
}
319+
metadata, valid := rawMetadata.(Metadata)
320+
if !valid {
321+
return nil, xerrors.Errorf("metadata is the wrong type: %T", metadata)
322+
}
323+
316324
// gliderlabs/ssh returns a command slice of zero
317325
// when a shell is requested.
318326
command := rawCommand
@@ -327,6 +335,11 @@ func (a *agent) createCommand(ctx context.Context, rawCommand string, env []stri
327335
caller = "/c"
328336
}
329337
cmd := exec.CommandContext(ctx, shell, caller, command)
338+
cmd.Dir = metadata.Directory
339+
if cmd.Dir == "" {
340+
// Default to $HOME if a directory is not set!
341+
cmd.Dir = os.Getenv("HOME")
342+
}
330343
cmd.Env = append(os.Environ(), env...)
331344
executablePath, err := os.Executable()
332345
if err != nil {
@@ -338,22 +351,23 @@ func (a *agent) createCommand(ctx context.Context, rawCommand string, env []stri
338351
cmd.Env = append(cmd.Env, fmt.Sprintf(`GIT_SSH_COMMAND=%s gitssh --`, executablePath))
339352
// These prevent the user from having to specify _anything_ to successfully commit.
340353
// Both author and committer must be set!
341-
cmd.Env = append(cmd.Env, fmt.Sprintf(`GIT_AUTHOR_EMAIL=%s`, a.ownerEmail.Load()))
342-
cmd.Env = append(cmd.Env, fmt.Sprintf(`GIT_COMMITTER_EMAIL=%s`, a.ownerEmail.Load()))
343-
cmd.Env = append(cmd.Env, fmt.Sprintf(`GIT_AUTHOR_NAME=%s`, a.ownerUsername.Load()))
344-
cmd.Env = append(cmd.Env, fmt.Sprintf(`GIT_COMMITTER_NAME=%s`, a.ownerUsername.Load()))
354+
cmd.Env = append(cmd.Env, fmt.Sprintf(`GIT_AUTHOR_EMAIL=%s`, metadata.OwnerEmail))
355+
cmd.Env = append(cmd.Env, fmt.Sprintf(`GIT_COMMITTER_EMAIL=%s`, metadata.OwnerEmail))
356+
cmd.Env = append(cmd.Env, fmt.Sprintf(`GIT_AUTHOR_NAME=%s`, metadata.OwnerUsername))
357+
cmd.Env = append(cmd.Env, fmt.Sprintf(`GIT_COMMITTER_NAME=%s`, metadata.OwnerUsername))
345358

346359
// Load environment variables passed via the agent.
347360
// These should override all variables we manually specify.
348-
envVars := a.envVars.Load()
349-
if envVars != nil {
350-
envVarMap, ok := envVars.(map[string]string)
351-
if ok {
352-
for key, value := range envVarMap {
353-
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", key, value))
354-
}
355-
}
361+
for key, value := range metadata.EnvironmentVariables {
362+
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", key, value))
363+
}
364+
365+
// Agent-level environment variables should take over all!
366+
// This is used for setting agent-specific variables like "CODER_AGENT_TOKEN".
367+
for key, value := range a.envVars {
368+
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", key, value))
356369
}
370+
357371
return cmd, nil
358372
}
359373

buildinfo/buildinfo.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,17 @@ func Version() string {
3333
revision = "+" + revision[:7]
3434
}
3535
if tag == "" {
36+
// This occurs when the tag hasn't been injected,
37+
// like when using "go run".
3638
version = "v0.0.0-devel" + revision
3739
return
3840
}
39-
if semver.Build(tag) == "" {
40-
tag += revision
41-
}
4241
version = "v" + tag
42+
// The tag must be prefixed with "v" otherwise the
43+
// semver library will return an empty string.
44+
if semver.Build(version) == "" {
45+
version += revision
46+
}
4347
})
4448
return version
4549
}

cli/agent.go

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,16 @@ import (
2323

2424
func workspaceAgent() *cobra.Command {
2525
var (
26-
rawURL string
27-
auth string
28-
token string
26+
auth string
2927
)
3028
cmd := &cobra.Command{
3129
Use: "agent",
3230
// This command isn't useful to manually execute.
3331
Hidden: true,
3432
RunE: func(cmd *cobra.Command, args []string) error {
35-
if rawURL == "" {
36-
return xerrors.New("CODER_URL must be set")
33+
rawURL, err := cmd.Flags().GetString(varAgentURL)
34+
if err != nil {
35+
return xerrors.Errorf("CODER_AGENT_URL must be set: %w", err)
3736
}
3837
coderURL, err := url.Parse(rawURL)
3938
if err != nil {
@@ -56,8 +55,9 @@ func workspaceAgent() *cobra.Command {
5655
var exchangeToken func(context.Context) (codersdk.WorkspaceAgentAuthenticateResponse, error)
5756
switch auth {
5857
case "token":
59-
if token == "" {
60-
return xerrors.Errorf("CODER_TOKEN must be set for token auth")
58+
token, err := cmd.Flags().GetString(varAgentToken)
59+
if err != nil {
60+
return xerrors.Errorf("CODER_AGENT_TOKEN must be set for token auth: %w", err)
6161
}
6262
client.SessionToken = token
6363
case "google-instance-identity":
@@ -125,27 +125,19 @@ func workspaceAgent() *cobra.Command {
125125
}
126126
}
127127

128-
cfg := createConfig(cmd)
129-
err = cfg.AgentSession().Write(client.SessionToken)
130-
if err != nil {
131-
return xerrors.Errorf("writing agent session token to config: %w", err)
132-
}
133-
err = cfg.URL().Write(client.URL.String())
134-
if err != nil {
135-
return xerrors.Errorf("writing agent url to config: %w", err)
136-
}
137-
138128
closer := agent.New(client.ListenWorkspaceAgent, &agent.Options{
139129
Logger: logger,
130+
EnvironmentVariables: map[string]string{
131+
// Override the "CODER_AGENT_TOKEN" variable in all
132+
// shells so "gitssh" works!
133+
"CODER_AGENT_TOKEN": client.SessionToken,
134+
},
140135
})
141136
<-cmd.Context().Done()
142137
return closer.Close()
143138
},
144139
}
145140

146-
cliflag.StringVarP(cmd.Flags(), &auth, "auth", "", "CODER_AUTH", "token", "Specify the authentication type to use for the agent")
147-
cliflag.StringVarP(cmd.Flags(), &rawURL, "url", "", "CODER_URL", "", "Specify the URL to access Coder")
148-
cliflag.StringVarP(cmd.Flags(), &token, "token", "", "CODER_TOKEN", "", "Specifies the authentication token to access Coder")
149-
141+
cliflag.StringVarP(cmd.Flags(), &auth, "auth", "", "CODER_AGENT_AUTH", "token", "Specify the authentication type to use for the agent")
150142
return cmd
151143
}

cli/agent_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func TestWorkspaceAgent(t *testing.T) {
4646
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
4747
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
4848

49-
cmd, _ := clitest.New(t, "agent", "--auth", "azure-instance-identity", "--url", client.URL.String())
49+
cmd, _ := clitest.New(t, "agent", "--auth", "azure-instance-identity", "--agent-url", client.URL.String())
5050
ctx, cancelFunc := context.WithCancel(context.Background())
5151
defer cancelFunc()
5252
go func() {
@@ -100,7 +100,7 @@ func TestWorkspaceAgent(t *testing.T) {
100100
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
101101
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
102102

103-
cmd, _ := clitest.New(t, "agent", "--auth", "aws-instance-identity", "--url", client.URL.String())
103+
cmd, _ := clitest.New(t, "agent", "--auth", "aws-instance-identity", "--agent-url", client.URL.String())
104104
ctx, cancelFunc := context.WithCancel(context.Background())
105105
defer cancelFunc()
106106
go func() {
@@ -154,7 +154,7 @@ func TestWorkspaceAgent(t *testing.T) {
154154
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID)
155155
coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
156156

157-
cmd, _ := clitest.New(t, "agent", "--auth", "google-instance-identity", "--url", client.URL.String())
157+
cmd, _ := clitest.New(t, "agent", "--auth", "google-instance-identity", "--agent-url", client.URL.String())
158158
ctx, cancelFunc := context.WithCancel(context.Background())
159159
defer cancelFunc()
160160
go func() {

cli/workspaceautostart.go renamed to cli/autostart.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,30 @@ When enabling autostart, provide the minute, hour, and day(s) of week.
1616
The default schedule is at 09:00 in your local timezone (TZ env, UTC by default).
1717
`
1818

19-
func workspaceAutostart() *cobra.Command {
19+
func autostart() *cobra.Command {
2020
autostartCmd := &cobra.Command{
2121
Use: "autostart enable <workspace>",
2222
Short: "schedule a workspace to automatically start at a regular time",
2323
Long: autostartDescriptionLong,
24-
Example: "coder workspaces autostart enable my-workspace --minute 30 --hour 9 --days 1-5 --tz Europe/Dublin",
24+
Example: "coder autostart enable my-workspace --minute 30 --hour 9 --days 1-5 --tz Europe/Dublin",
2525
Hidden: true,
2626
}
2727

28-
autostartCmd.AddCommand(workspaceAutostartEnable())
29-
autostartCmd.AddCommand(workspaceAutostartDisable())
28+
autostartCmd.AddCommand(autostartEnable())
29+
autostartCmd.AddCommand(autostartDisable())
3030

3131
return autostartCmd
3232
}
3333

34-
func workspaceAutostartEnable() *cobra.Command {
34+
func autostartEnable() *cobra.Command {
3535
// yes some of these are technically numbers but the cron library will do that work
3636
var autostartMinute string
3737
var autostartHour string
3838
var autostartDayOfWeek string
3939
var autostartTimezone string
4040
cmd := &cobra.Command{
41-
Use: "enable <workspace_name> <schedule>",
42-
ValidArgsFunction: validArgsWorkspaceName,
43-
Args: cobra.ExactArgs(1),
41+
Use: "enable <workspace_name> <schedule>",
42+
Args: cobra.ExactArgs(1),
4443
RunE: func(cmd *cobra.Command, args []string) error {
4544
client, err := createClient(cmd)
4645
if err != nil {
@@ -86,11 +85,10 @@ func workspaceAutostartEnable() *cobra.Command {
8685
return cmd
8786
}
8887

89-
func workspaceAutostartDisable() *cobra.Command {
88+
func autostartDisable() *cobra.Command {
9089
return &cobra.Command{
91-
Use: "disable <workspace_name>",
92-
ValidArgsFunction: validArgsWorkspaceName,
93-
Args: cobra.ExactArgs(1),
90+
Use: "disable <workspace_name>",
91+
Args: cobra.ExactArgs(1),
9492
RunE: func(cmd *cobra.Command, args []string) error {
9593
client, err := createClient(cmd)
9694
if err != nil {

cli/workspaceautostart_test.go renamed to cli/autostart_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
"github.com/coder/coder/coderd/coderdtest"
1414
)
1515

16-
func TestWorkspaceAutostart(t *testing.T) {
16+
func TestAutostart(t *testing.T) {
1717
t.Parallel()
1818

1919
t.Run("EnableDisableOK", func(t *testing.T) {
@@ -29,7 +29,7 @@ func TestWorkspaceAutostart(t *testing.T) {
2929
project = coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID)
3030
workspace = coderdtest.CreateWorkspace(t, client, user.OrganizationID, project.ID)
3131
tz = "Europe/Dublin"
32-
cmdArgs = []string{"workspaces", "autostart", "enable", workspace.Name, "--minute", "30", "--hour", "9", "--days", "1-5", "--tz", tz}
32+
cmdArgs = []string{"autostart", "enable", workspace.Name, "--minute", "30", "--hour", "9", "--days", "1-5", "--tz", tz}
3333
sched = "CRON_TZ=Europe/Dublin 30 9 * * 1-5"
3434
stdoutBuf = &bytes.Buffer{}
3535
)
@@ -48,7 +48,7 @@ func TestWorkspaceAutostart(t *testing.T) {
4848
require.Equal(t, sched, updated.AutostartSchedule, "expected autostart schedule to be set")
4949

5050
// Disable schedule
51-
cmd, root = clitest.New(t, "workspaces", "autostart", "disable", workspace.Name)
51+
cmd, root = clitest.New(t, "autostart", "disable", workspace.Name)
5252
clitest.SetupConfig(t, client, root)
5353
cmd.SetOut(stdoutBuf)
5454

@@ -73,7 +73,7 @@ func TestWorkspaceAutostart(t *testing.T) {
7373
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
7474
)
7575

76-
cmd, root := clitest.New(t, "workspaces", "autostart", "enable", "doesnotexist")
76+
cmd, root := clitest.New(t, "autostart", "enable", "doesnotexist")
7777
clitest.SetupConfig(t, client, root)
7878

7979
err := cmd.Execute()
@@ -91,7 +91,7 @@ func TestWorkspaceAutostart(t *testing.T) {
9191
_ = coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
9292
)
9393

94-
cmd, root := clitest.New(t, "workspaces", "autostart", "disable", "doesnotexist")
94+
cmd, root := clitest.New(t, "autostart", "disable", "doesnotexist")
9595
clitest.SetupConfig(t, client, root)
9696

9797
err := cmd.Execute()
@@ -118,7 +118,7 @@ func TestWorkspaceAutostart(t *testing.T) {
118118
currTz = "UTC"
119119
}
120120
expectedSchedule := fmt.Sprintf("CRON_TZ=%s 0 9 * * 1-5", currTz)
121-
cmd, root := clitest.New(t, "workspaces", "autostart", "enable", workspace.Name)
121+
cmd, root := clitest.New(t, "autostart", "enable", workspace.Name)
122122
clitest.SetupConfig(t, client, root)
123123

124124
err := cmd.Execute()

0 commit comments

Comments
 (0)