Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat(agent/agentcontainers): fall back to workspace folder name#18466

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Draft
DanielleMaywood wants to merge4 commits intomain
base:main
Choose a base branch
Loading
fromdm-devcontainer-folder-name
Draft
Show file tree
Hide file tree
Changes from1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
NextNext commit
feat(agent/agentcontainers): fall back to workspace folder name
This PR changes the logic for how we decide on an agent name.Previously it followed these steps:1. Use a name from `customizations.coder.name`2. Use a name from the terraform resource `coder_devcontainer`3. Use the dev container's friendly nameWith this change it now does:1. Use a name from `customizations.coder.name`2. Use a name from the terraform resource `coder_devcontainer`3. Use a name from the workspace folder4. Use the dev container's friendly nameWe now attempt to construct a valid agent name from the workspacefolder. Should we fail to construct a valid agent name from theworkspace folder, we will fall back to the dev container's friendlyname.
  • Loading branch information
@DanielleMaywood
DanielleMaywood committedJun 20, 2025
commit0660cbaa459ca29a39c72d2107dcadba5b9eebcc
68 changes: 41 additions & 27 deletionsagent/agentcontainers/api.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
package agentcontainers

import (
"bytes"
"context"
"errors"
"fmt"
"io"
"net/http"
"os"
"path"
"path/filepath"
"regexp"
"runtime"
"slices"
"strings"
"sync"
"sync/atomic"
"time"
"unicode"

"github.com/fsnotify/fsnotify"
"github.com/go-chi/chi/v5"
Expand DownExpand Up@@ -585,10 +585,10 @@
if dc.Container != nil {
if !api.devcontainerNames[dc.Name] {
// If the devcontainer name wasn't set via terraform, we
//use the containers friendlynameas a fallback which
//will keep changing as the devcontainer is recreated.
//TODO(mafredri): Parse the container label (i.e. devcontainer.json) for customization.
dc.Name =safeFriendlyName(dc.Container.FriendlyName)
//will attempt to create an agentnamebased on the workspace
//folder's name. If that is not possible, we will fall back
//to using the container's friendly name.
dc.Name =safeAgentName(filepath.Base(dc.WorkspaceFolder),dc.Container.FriendlyName)
}
}

Expand DownExpand Up@@ -633,6 +633,39 @@
api.containersErr = nil
}

var consecutiveHyphenRegex = regexp.MustCompile("-+")

// safeAgentName returns an agent name safe version
// of a folder name, falling back to a safe version
// of the container name if unable to create a name.
func safeAgentName(name string, friendlyName string) string {

Check failure on line 641 in agent/agentcontainers/api.go

View workflow job for this annotation

GitHub Actions/ lint

unused-parameter: parameter 'friendlyName' seems to be unused, consider removing or renaming it as _ (revive)
// Keep only letters and digits, replacing everything
// else with a hyphen.
var sb strings.Builder
for _, r := range strings.ToLower(name) {
if unicode.IsLetter(r) || unicode.IsDigit(r) {
sb.WriteRune(r)

Check failure on line 647 in agent/agentcontainers/api.go

View workflow job for this annotation

GitHub Actions/ lint

unhandled-error: Unhandled error in call to function strings.Builder.WriteRune (revive)
} else {
sb.WriteRune('-')

Check failure on line 649 in agent/agentcontainers/api.go

View workflow job for this annotation

GitHub Actions/ lint

unhandled-error: Unhandled error in call to function strings.Builder.WriteRune (revive)
}
}

// Remove any consecutive hyphens, and then trim and leading
// and trailing hyphens.
name = consecutiveHyphenRegex.ReplaceAllString(sb.String(), "-")
name = strings.Trim(name, "-")

name = strings.ToLower(name)
name = strings.ReplaceAll(name, " ", "-")
name = strings.ReplaceAll(name, "_", "-")

if name == "" {
return safeFriendlyName(name)
}

return name
}

// safeFriendlyName returns a API safe version of the container's
// friendly name.
//
Expand DownExpand Up@@ -1114,27 +1147,6 @@
if proc.agent.ID == uuid.Nil || maybeRecreateSubAgent {
subAgentConfig.Architecture = arch

// Detect workspace folder by executing `pwd` in the container.
// NOTE(mafredri): This is a quick and dirty way to detect the
// workspace folder inside the container. In the future we will
// rely more on `devcontainer read-configuration`.
var pwdBuf bytes.Buffer
err = api.dccli.Exec(ctx, dc.WorkspaceFolder, dc.ConfigPath, "pwd", []string{},
WithExecOutput(&pwdBuf, io.Discard),
WithExecContainerID(container.ID),
)
if err != nil {
return xerrors.Errorf("check workspace folder in container: %w", err)
}
directory := strings.TrimSpace(pwdBuf.String())
if directory == "" {
logger.Warn(ctx, "detected workspace folder is empty, using default workspace folder",
slog.F("default_workspace_folder", DevcontainerDefaultContainerWorkspaceFolder),
)
directory = DevcontainerDefaultContainerWorkspaceFolder
}
subAgentConfig.Directory = directory

displayAppsMap := map[codersdk.DisplayApp]bool{
// NOTE(DanielleMaywood):
// We use the same defaults here as set in terraform-provider-coder.
Expand DownExpand Up@@ -1207,6 +1219,8 @@
appsWithPossibleDuplicates = append(appsWithPossibleDuplicates, customization.Apps...)
}

subAgentConfig.Directory = config.Workspace.WorkspaceFolder

return nil
}(); err != nil {
api.logger.Error(ctx, "unable to read devcontainer config", slog.Error(err))
Expand Down
65 changes: 23 additions & 42 deletionsagent/agentcontainers/api_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -897,26 +897,26 @@ func TestAPI(t *testing.T) {
FriendlyName: "project1-container",
Running: true,
Labels: map[string]string{
agentcontainers.DevcontainerLocalFolderLabel: "/workspace/project",
agentcontainers.DevcontainerConfigFileLabel: "/workspace/project/.devcontainer/devcontainer.json",
agentcontainers.DevcontainerLocalFolderLabel: "/workspace/project1",
agentcontainers.DevcontainerConfigFileLabel: "/workspace/project1/.devcontainer/devcontainer.json",
},
},
{
ID: "project2-container",
FriendlyName: "project2-container",
Running: true,
Labels: map[string]string{
agentcontainers.DevcontainerLocalFolderLabel: "/home/user/project",
agentcontainers.DevcontainerConfigFileLabel: "/home/user/project/.devcontainer/devcontainer.json",
agentcontainers.DevcontainerLocalFolderLabel: "/home/user/project2",
agentcontainers.DevcontainerConfigFileLabel: "/home/user/project2/.devcontainer/devcontainer.json",
},
},
{
ID: "project3-container",
FriendlyName: "project3-container",
Running: true,
Labels: map[string]string{
agentcontainers.DevcontainerLocalFolderLabel: "/var/lib/project",
agentcontainers.DevcontainerConfigFileLabel: "/var/lib/project/.devcontainer/devcontainer.json",
agentcontainers.DevcontainerLocalFolderLabel: "/var/lib/project3",
agentcontainers.DevcontainerConfigFileLabel: "/var/lib/project3/.devcontainer/devcontainer.json",
},
},
},
Expand DownExpand Up@@ -1262,7 +1262,12 @@ func TestAPI(t *testing.T) {
deleteErrC: make(chan error, 1),
}
fakeDCCLI = &fakeDevcontainerCLI{
execErrC: make(chan func(cmd string, args ...string) error, 1),
execErrC: make(chan func(cmd string, args ...string) error, 1),
readConfig: agentcontainers.DevcontainerConfig{
Workspace: agentcontainers.DevcontainerWorkspace{
WorkspaceFolder: "/workspaces/coder",
},
},
readConfigErrC: make(chan func(envs []string) error, 1),
}

Expand All@@ -1273,8 +1278,8 @@ func TestAPI(t *testing.T) {
Running: true,
CreatedAt: time.Now(),
Labels: map[string]string{
agentcontainers.DevcontainerLocalFolderLabel: "/workspaces",
agentcontainers.DevcontainerConfigFileLabel: "/workspace/.devcontainer/devcontainer.json",
agentcontainers.DevcontainerLocalFolderLabel: "/workspaces/coder",
agentcontainers.DevcontainerConfigFileLabel: "/workspaces/coder/.devcontainer/devcontainer.json",
},
}
)
Expand DownExpand Up@@ -1320,13 +1325,8 @@ func TestAPI(t *testing.T) {

// Allow initial agent creation and injection to succeed.
testutil.RequireSend(ctx, t, fakeSAC.createErrC, nil)
testutil.RequireSend(ctx, t, fakeDCCLI.execErrC, func(cmd string, args ...string) error {
assert.Equal(t, "pwd", cmd)
assert.Empty(t, args)
return nil
}) // Exec pwd.
testutil.RequireSend(ctx, t, fakeDCCLI.readConfigErrC, func(envs []string) error {
assert.Contains(t, envs, "CODER_WORKSPACE_AGENT_NAME=test-container")
assert.Contains(t, envs, "CODER_WORKSPACE_AGENT_NAME=coder")
assert.Contains(t, envs, "CODER_WORKSPACE_NAME=test-workspace")
assert.Contains(t, envs, "CODER_WORKSPACE_OWNER_NAME=test-user")
assert.Contains(t, envs, "CODER_URL=test-subagent-url")
Expand All@@ -1349,8 +1349,8 @@ func TestAPI(t *testing.T) {

// Verify agent was created.
require.Len(t, fakeSAC.created, 1)
assert.Equal(t, "test-container", fakeSAC.created[0].Name)
assert.Equal(t, "/workspaces", fakeSAC.created[0].Directory)
assert.Equal(t, "coder", fakeSAC.created[0].Name)
assert.Equal(t, "/workspaces/coder", fakeSAC.created[0].Directory)
assert.Len(t, fakeSAC.deleted, 0)

t.Log("Agent injected successfully, now testing reinjection into the same container...")
Expand DownExpand Up@@ -1405,7 +1405,7 @@ func TestAPI(t *testing.T) {
WaitStartLoop:
for {
// Agent reinjection will succeed and we will not re-create the
// agent, nor re-probe pwd.
// agent.
mCCLI.EXPECT().List(gomock.Any()).Return(codersdk.WorkspaceAgentListContainersResponse{
Containers: []codersdk.WorkspaceAgentContainer{testContainer},
}, nil).Times(1) // 1 update.
Expand DownExpand Up@@ -1467,13 +1467,8 @@ func TestAPI(t *testing.T) {
testutil.RequireSend(ctx, t, fakeSAC.deleteErrC, nil)
// Expect the agent to be recreated.
testutil.RequireSend(ctx, t, fakeSAC.createErrC, nil)
testutil.RequireSend(ctx, t, fakeDCCLI.execErrC, func(cmd string, args ...string) error {
assert.Equal(t, "pwd", cmd)
assert.Empty(t, args)
return nil
}) // Exec pwd.
testutil.RequireSend(ctx, t, fakeDCCLI.readConfigErrC, func(envs []string) error {
assert.Contains(t, envs, "CODER_WORKSPACE_AGENT_NAME=test-container")
assert.Contains(t, envs, "CODER_WORKSPACE_AGENT_NAME=coder")
assert.Contains(t, envs, "CODER_WORKSPACE_NAME=test-workspace")
assert.Contains(t, envs, "CODER_WORKSPACE_OWNER_NAME=test-user")
assert.Contains(t, envs, "CODER_URL=test-subagent-url")
Expand DownExpand Up@@ -1814,7 +1809,6 @@ func TestAPI(t *testing.T) {
},
},
},
execErrC: make(chan func(cmd string, args ...string) error, 1),
}

testContainer = codersdk.WorkspaceAgentContainer{
Expand DownExpand Up@@ -1861,15 +1855,9 @@ func TestAPI(t *testing.T) {

// Close before api.Close() defer to avoid deadlock after test.
defer close(fSAC.createErrC)
defer close(fDCCLI.execErrC)

// Given: We allow agent creation and injection to succeed.
testutil.RequireSend(ctx, t, fSAC.createErrC, nil)
testutil.RequireSend(ctx, t, fDCCLI.execErrC, func(cmd string, args ...string) error {
assert.Equal(t, "pwd", cmd)
assert.Empty(t, args)
return nil
})

// Wait until the ticker has been registered.
tickerTrap.MustWait(ctx).MustRelease(ctx)
Expand DownExpand Up@@ -1913,7 +1901,6 @@ func TestAPI(t *testing.T) {
},
},
readConfigErrC: make(chan func(envs []string) error, 2),
execErrC: make(chan func(cmd string, args ...string) error, 1),
}

testContainer = codersdk.WorkspaceAgentContainer{
Expand All@@ -1923,8 +1910,8 @@ func TestAPI(t *testing.T) {
Running: true,
CreatedAt: time.Now(),
Labels: map[string]string{
agentcontainers.DevcontainerLocalFolderLabel: "/workspaces",
agentcontainers.DevcontainerConfigFileLabel: "/workspace/.devcontainer/devcontainer.json",
agentcontainers.DevcontainerLocalFolderLabel: "/workspaces/coder",
agentcontainers.DevcontainerConfigFileLabel: "/workspaces/coder/.devcontainer/devcontainer.json",
},
}
)
Expand DownExpand Up@@ -1960,25 +1947,19 @@ func TestAPI(t *testing.T) {

// Close before api.Close() defer to avoid deadlock after test.
defer close(fSAC.createErrC)
defer close(fDCCLI.execErrC)
defer close(fDCCLI.readConfigErrC)

// Given: We allow agent creation and injection to succeed.
testutil.RequireSend(ctx, t, fSAC.createErrC, nil)
testutil.RequireSend(ctx, t, fDCCLI.execErrC, func(cmd string, args ...string) error {
assert.Equal(t, "pwd", cmd)
assert.Empty(t, args)
return nil
})
testutil.RequireSend(ctx, t, fDCCLI.readConfigErrC, func(env []string) error {
// We expect the wrong workspace agent name passed in first.
assert.Contains(t, env, "CODER_WORKSPACE_AGENT_NAME=test-container")
assert.Contains(t, env, "CODER_WORKSPACE_AGENT_NAME=coder")
return nil
})
testutil.RequireSend(ctx, t, fDCCLI.readConfigErrC, func(env []string) error {
// We then expect the agent name passed here to have been read from the config.
assert.Contains(t, env, "CODER_WORKSPACE_AGENT_NAME=custom-name")
assert.NotContains(t, env, "CODER_WORKSPACE_AGENT_NAME=test-container")
assert.NotContains(t, env, "CODER_WORKSPACE_AGENT_NAME=coder")
return nil
})

Expand Down
2 changes: 0 additions & 2 deletionsagent/agentcontainers/devcontainer.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,8 +18,6 @@ const (
// DevcontainerConfigFileLabel is the label that contains the path to
// the devcontainer.json configuration file.
DevcontainerConfigFileLabel = "devcontainer.config_file"
// The default workspace folder inside the devcontainer.
DevcontainerDefaultContainerWorkspaceFolder = "/workspaces"
)

const devcontainerUpScriptTemplate = `
Expand Down
5 changes: 5 additions & 0 deletionsagent/agentcontainers/devcontainercli.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,6 +22,11 @@ import (
type DevcontainerConfig struct {
MergedConfiguration DevcontainerMergedConfiguration `json:"mergedConfiguration"`
Configuration DevcontainerConfiguration `json:"configuration"`
Workspace DevcontainerWorkspace `json:"workspace"`
}

type DevcontainerWorkspace struct {
WorkspaceFolder string `json:"workspaceFolder"`
}

type DevcontainerMergedConfiguration struct {
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp