Skip to content
Merged
Changes from all commits
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
68 changes: 57 additions & 11 deletions internal/pkg/devcontainers/dockerutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,12 @@ func ExecInDevContainer(containerID string, workDir string, args []string) error
if err != nil {
return err
}
if userName == "" {
userName, err = getUserNameFromRunningContainer(containerID)
if err != nil {
return err
}
}

statusWriter.Printf("Checking for SSH_AUTH_SOCK")
sshAuthSockValue, err := getSshAuthSockValue(containerID)
Expand All @@ -251,10 +257,11 @@ func ExecInDevContainer(containerID string, workDir string, args []string) error

statusWriter.Printf("Getting container PATH")
containerPath, err := getContainerEnvVar(containerID, "PATH")
vscodeServerPath := ""
if err == nil {
// Got the PATH
statusWriter.Printf("Getting code server path")
vscodeServerPath, err := getVscodeServerPath(containerID)
vscodeServerPath, err = getVscodeServerPath(containerID, userName)
if err == nil {
// Got the VS Code server location - add bin subfolder to PATH
containerPath = strings.TrimSpace(containerPath)
Expand All @@ -271,6 +278,13 @@ func ExecInDevContainer(containerID string, workDir string, args []string) error
fmt.Println("Continuing without overriding PATH...")
}

browser := ""
if vscodeServerPath == "" {
fmt.Printf("Warning: VS Code Server location not found. Continuing without setting BROWSER...")
} else {
browser = fmt.Sprintf("%s/helpers/browser.sh", vscodeServerPath)
}

statusWriter.Printf("Getting VSCODE_IPC_HOOK_CLI")
vscodeIpcSock, err := getVscodeIpcSock(containerID)
if err != nil {
Expand Down Expand Up @@ -349,6 +363,9 @@ func ExecInDevContainer(containerID string, workDir string, args []string) error
if vscodeGitIpcSock != "" {
dockerArgs = append(dockerArgs, "--env", "VSCODE_GIT_IPC_HANDLE="+vscodeGitIpcSock)
}
if browser != "" {
dockerArgs = append(dockerArgs, "--env", "BROWSER="+browser)
}
dockerArgs = append(dockerArgs, containerID)
dockerArgs = append(dockerArgs, args...)

Expand Down Expand Up @@ -382,34 +399,38 @@ func getSshAuthSockValue(containerID string) (string, error) {
// Host has SSH_AUTH_SOCK set, so expecting the dev container to have forwarding set up
// Find the latest /tmp/vscode-ssh-auth-<...>.sock

return getLatestFileMatch(containerID, "\"${TMPDIR:-/tmp}\"/vscode-ssh-auth-*")
return getLatestFileMatch(containerID, "", "\"${TMPDIR:-/tmp}\"/vscode-ssh-auth-*")
}

func getVscodeServerPath(containerID string) (string, error) {
path, err := getLatestFileMatch(containerID, "${HOME}/.vscode-server/bin/*")
func getVscodeServerPath(containerID string, userName string) (string, error) {
path, err := getLatestFileMatch(containerID, userName, "${HOME}/.vscode-server/bin/*")
if err == nil {
return path, err
}
path, err = getLatestFileMatch(containerID, "/vscode/vscode-server/bin/linux-x64/*")
path, err = getLatestFileMatch(containerID, "", "/vscode/vscode-server/bin/linux-x64/*")
if err == nil {
return path, err
}
return getLatestFileMatch(containerID, "/vscode/vscode-server/bin/x64/*")
return getLatestFileMatch(containerID, "", "/vscode/vscode-server/bin/x64/*")
}
func getVscodeIpcSock(containerID string) (string, error) {
return getLatestFileMatch(containerID, "\"${TMPDIR:-/tmp}\"/vscode-ipc-*")
return getLatestFileMatch(containerID, "", "\"${TMPDIR:-/tmp}\"/vscode-ipc-*")
}
func getRemoteContainersIpcSock(containerID string) (string, error) {
return getLatestFileMatch(containerID, "\"${TMPDIR:-/tmp}\"/vscode-remote-containers-ipc-*")
return getLatestFileMatch(containerID, "", "\"${TMPDIR:-/tmp}\"/vscode-remote-containers-ipc-*")
}
func getGitIpcSock(containerID string, userID string) (string, error) {
return getLatestFileMatch(containerID, fmt.Sprintf("\"${TMPDIR:-/tmp}\"/user/%s/vscode-git-*", userID))
return getLatestFileMatch(containerID, "", fmt.Sprintf("\"${TMPDIR:-/tmp}\"/user/%s/vscode-git-*", userID))
}

// getLatestFileMatch lists files matching `pattern` in the container and returns the latest filename
func getLatestFileMatch(containerID string, pattern string) (string, error) {
func getLatestFileMatch(containerID string, userName string, pattern string) (string, error) {

dockerArgs := []string{"exec", containerID, "bash", "-c", fmt.Sprintf("ls -t -d -1 %s", pattern)}
dockerArgs := []string{"exec"}
if userName != "" {
dockerArgs = append(dockerArgs, "--user", userName)
}
dockerArgs = append(dockerArgs, containerID, "bash", "-c", fmt.Sprintf("ls -t -d -1 %s", pattern))
dockerCmd := exec.Command("docker", dockerArgs...)
buf, err := dockerCmd.CombinedOutput()
if err != nil {
Expand Down Expand Up @@ -470,3 +491,28 @@ func testContainerPathExists(containerID string, path string) (bool, error) {
response := strings.TrimSpace(string(buf))
return response == "0", nil
}

func getUserNameFromRunningContainer(containerID string) (string, error) {
dockerArgs := []string{"inspect", containerID, "--format", "{{index .Config.Labels \"devcontainer.metadata\" }}"}
dockerCmd := exec.Command("docker", dockerArgs...)
buf, err := dockerCmd.CombinedOutput()
if err != nil {
errMessage := string(buf)
return "", fmt.Errorf("Docker exec error: %s (%s)", err, strings.TrimSpace(errMessage))
}

var metadata []interface{}
err = json.Unmarshal(buf, &metadata)
if err != nil {
return "", nil
}

for _, value := range metadata {
if valueMap, ok := value.(map[string]interface{}); ok {
if userName, ok := valueMap["remoteUser"]; ok {
return userName.(string), nil
}
}
}
return "", nil
}