mirror of
https://github.com/harness/drone.git
synced 2025-05-20 10:59:56 +08:00
feat: [CDE-473]: Adding support for containerUser and remoteUser. (#3086)
* Adding support for root as remoteUser * Changing logger from gitspace to application in config util. * Changing logger from gitspace to application in config util. * feat: [CDE-473]: Adding support for containerUser and remoteUser.
This commit is contained in:
parent
b7cca56ec7
commit
1086397b3f
@ -124,6 +124,10 @@ func (l *LogStreamInstance) Debug(msg string) {
|
|||||||
l.Write("DEBUG: " + msg) //nolint:errcheck
|
l.Write("DEBUG: " + msg) //nolint:errcheck
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *LogStreamInstance) Warn(msg string) {
|
||||||
|
l.Write("WARN: " + msg) //nolint:errcheck
|
||||||
|
}
|
||||||
|
|
||||||
func (l *LogStreamInstance) Error(msg string, err error) {
|
func (l *LogStreamInstance) Error(msg string, err error) {
|
||||||
l.Write("ERROR: " + msg + ": " + err.Error()) //nolint:errcheck
|
l.Write("ERROR: " + msg + ": " + err.Error()) //nolint:errcheck
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,12 @@ package container
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/ide"
|
"github.com/harness/gitness/app/gitspace/orchestrator/ide"
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/runarg"
|
"github.com/harness/gitness/app/gitspace/orchestrator/runarg"
|
||||||
types2 "github.com/harness/gitness/app/gitspace/types"
|
gitspaceTypes "github.com/harness/gitness/app/gitspace/types"
|
||||||
"github.com/harness/gitness/types"
|
"github.com/harness/gitness/types"
|
||||||
"github.com/harness/gitness/types/enum"
|
"github.com/harness/gitness/types/enum"
|
||||||
|
|
||||||
@ -40,11 +41,11 @@ func ExtractRunArgs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var runArgsMap = make(map[types.RunArg]*types.RunArgValue)
|
var runArgsMap = make(map[types.RunArg]*types.RunArgValue)
|
||||||
primaryLoopCounter := 0
|
argLoopCounter := 0
|
||||||
for primaryLoopCounter < len(runArgsRaw) {
|
for argLoopCounter < len(runArgsRaw) {
|
||||||
currentArg := runArgsRaw[primaryLoopCounter]
|
currentArg := runArgsRaw[argLoopCounter]
|
||||||
if currentArg == "" || !isArg(currentArg) {
|
if currentArg == "" || !isArg(currentArg) {
|
||||||
primaryLoopCounter++
|
argLoopCounter++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,13 +54,13 @@ func ExtractRunArgs(
|
|||||||
|
|
||||||
currentRunArgDefinition, isSupportedArg := supportedRunArgsMap[types.RunArg(argKey)]
|
currentRunArgDefinition, isSupportedArg := supportedRunArgsMap[types.RunArg(argKey)]
|
||||||
if !isSupportedArg {
|
if !isSupportedArg {
|
||||||
primaryLoopCounter++
|
argLoopCounter++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
updatedPrimaryLoopCounter, allowedValues, isAnyValueBlocked := getValues(runArgsRaw, argParts,
|
updatedArgLoopCounter, allowedValues, isAnyValueBlocked := getValues(runArgsRaw, argParts, argLoopCounter,
|
||||||
primaryLoopCounter, currentRunArgDefinition)
|
currentRunArgDefinition)
|
||||||
|
|
||||||
primaryLoopCounter = updatedPrimaryLoopCounter
|
argLoopCounter = updatedArgLoopCounter
|
||||||
|
|
||||||
if isAnyValueBlocked && len(allowedValues) == 0 {
|
if isAnyValueBlocked && len(allowedValues) == 0 {
|
||||||
continue
|
continue
|
||||||
@ -84,45 +85,69 @@ func ExtractRunArgs(
|
|||||||
func getValues(
|
func getValues(
|
||||||
runArgs []string,
|
runArgs []string,
|
||||||
argParts []string,
|
argParts []string,
|
||||||
primaryLoopCounter int,
|
argLoopCounter int,
|
||||||
currentRunArgDefinition types.RunArgDefinition,
|
currentRunArgDefinition types.RunArgDefinition,
|
||||||
) (int, []string, bool) {
|
) (int, []string, bool) {
|
||||||
values := make([]string, 0)
|
values := make([]string, 0)
|
||||||
if len(argParts) > 1 {
|
if len(argParts) > 1 {
|
||||||
values = append(values, argParts[1])
|
values = append(values, strings.TrimSpace(argParts[1]))
|
||||||
primaryLoopCounter++
|
argLoopCounter++
|
||||||
} else {
|
} else {
|
||||||
var secondaryLoopCounter = primaryLoopCounter + 1
|
var valueLoopCounter = argLoopCounter + 1
|
||||||
for secondaryLoopCounter < len(runArgs) {
|
for valueLoopCounter < len(runArgs) {
|
||||||
currentValue := runArgs[secondaryLoopCounter]
|
currentValue := runArgs[valueLoopCounter]
|
||||||
if isArg(currentValue) {
|
if isArg(currentValue) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
values = append(values, currentValue)
|
values = append(values, strings.TrimSpace(currentValue))
|
||||||
secondaryLoopCounter++
|
valueLoopCounter++
|
||||||
}
|
}
|
||||||
primaryLoopCounter = secondaryLoopCounter
|
argLoopCounter = valueLoopCounter
|
||||||
}
|
}
|
||||||
allowedValues, isAnyValueBlocked := filterAllowedValues(values, currentRunArgDefinition)
|
allowedValues, isAnyValueBlocked := filterAllowedValues(values, currentRunArgDefinition)
|
||||||
return primaryLoopCounter, allowedValues, isAnyValueBlocked
|
return argLoopCounter, allowedValues, isAnyValueBlocked
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterAllowedValues(values []string, currentRunArgDefinition types.RunArgDefinition) ([]string, bool) {
|
func filterAllowedValues(
|
||||||
|
values []string,
|
||||||
|
currentRunArgDefinition types.RunArgDefinition,
|
||||||
|
) ([]string, bool) {
|
||||||
isAnyValueBlocked := false
|
isAnyValueBlocked := false
|
||||||
allowedValues := make([]string, 0)
|
allowedValues := make([]string, 0)
|
||||||
for _, v := range values {
|
for _, v := range values {
|
||||||
switch {
|
switch {
|
||||||
case len(currentRunArgDefinition.AllowedValues) > 0:
|
case len(currentRunArgDefinition.AllowedValues) > 0:
|
||||||
if _, ok := currentRunArgDefinition.AllowedValues[v]; ok {
|
for allowedValue := range currentRunArgDefinition.AllowedValues {
|
||||||
allowedValues = append(allowedValues, v)
|
matches, err := regexp.MatchString(allowedValue, v)
|
||||||
} else {
|
if err != nil {
|
||||||
isAnyValueBlocked = true
|
log.Warn().Err(err).Msgf("error checking allowed values for RunArg %s value %s",
|
||||||
|
currentRunArgDefinition.Name, v)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if matches {
|
||||||
|
allowedValues = append(allowedValues, v)
|
||||||
|
} else {
|
||||||
|
log.Warn().Msgf("Value %s for runArg %s not allowed", v, currentRunArgDefinition.Name)
|
||||||
|
isAnyValueBlocked = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case len(currentRunArgDefinition.BlockedValues) > 0:
|
case len(currentRunArgDefinition.BlockedValues) > 0:
|
||||||
if _, ok := currentRunArgDefinition.BlockedValues[v]; !ok {
|
var isValueBlocked = false
|
||||||
|
for blockedValue := range currentRunArgDefinition.BlockedValues {
|
||||||
|
matches, err := regexp.MatchString(blockedValue, v)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn().Err(err).Msgf("error checking blocked values for RunArg %s value %s",
|
||||||
|
currentRunArgDefinition.Name, v)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if matches {
|
||||||
|
log.Warn().Msgf("Value %s for runArg %s not allowed", v, currentRunArgDefinition.Name)
|
||||||
|
isValueBlocked = true
|
||||||
|
isAnyValueBlocked = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !isValueBlocked {
|
||||||
allowedValues = append(allowedValues, v)
|
allowedValues = append(allowedValues, v)
|
||||||
} else {
|
|
||||||
isAnyValueBlocked = true
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
allowedValues = append(allowedValues, v)
|
allowedValues = append(allowedValues, v)
|
||||||
@ -176,7 +201,7 @@ func ExtractIDECustomizations(
|
|||||||
var args = make(map[string]interface{})
|
var args = make(map[string]interface{})
|
||||||
if ideService.Type() == enum.IDETypeVSCodeWeb || ideService.Type() == enum.IDETypeVSCode {
|
if ideService.Type() == enum.IDETypeVSCodeWeb || ideService.Type() == enum.IDETypeVSCode {
|
||||||
if devcontainerConfig.Customizations.ExtractVSCodeSpec() != nil {
|
if devcontainerConfig.Customizations.ExtractVSCodeSpec() != nil {
|
||||||
args[types2.VSCodeCustomization] = *devcontainerConfig.Customizations.ExtractVSCodeSpec()
|
args[gitspaceTypes.VSCodeCustomization] = *devcontainerConfig.Customizations.ExtractVSCodeSpec()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return args
|
return args
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"path/filepath"
|
||||||
goruntime "runtime"
|
goruntime "runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -136,6 +137,8 @@ func CreateContainer(
|
|||||||
portMappings map[int]*types.PortMapping,
|
portMappings map[int]*types.PortMapping,
|
||||||
env []string,
|
env []string,
|
||||||
runArgsMap map[types.RunArg]*types.RunArgValue,
|
runArgsMap map[types.RunArg]*types.RunArgValue,
|
||||||
|
containerUser string,
|
||||||
|
remoteUser string,
|
||||||
) error {
|
) error {
|
||||||
exposedPorts, portBindings := applyPortMappings(portMappings)
|
exposedPorts, portBindings := applyPortMappings(portMappings)
|
||||||
|
|
||||||
@ -161,6 +164,10 @@ func CreateContainer(
|
|||||||
cmd = []string{"-c", "trap 'exit 0' 15; sleep infinity & wait $!"}
|
cmd = []string{"-c", "trap 'exit 0' 15; sleep infinity & wait $!"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
labels := getLabels(runArgsMap)
|
||||||
|
// Setting the following so that it can be read later to form gitspace URL.
|
||||||
|
labels[gitspaceRemoteUserLabel] = remoteUser
|
||||||
|
|
||||||
// Create the container
|
// Create the container
|
||||||
containerConfig := &container.Config{
|
containerConfig := &container.Config{
|
||||||
Hostname: getHostname(runArgsMap),
|
Hostname: getHostname(runArgsMap),
|
||||||
@ -170,12 +177,12 @@ func CreateContainer(
|
|||||||
Entrypoint: entrypoint,
|
Entrypoint: entrypoint,
|
||||||
Cmd: cmd,
|
Cmd: cmd,
|
||||||
ExposedPorts: exposedPorts,
|
ExposedPorts: exposedPorts,
|
||||||
Labels: getLabels(runArgsMap),
|
Labels: labels,
|
||||||
Healthcheck: healthCheckConfig,
|
Healthcheck: healthCheckConfig,
|
||||||
MacAddress: getMACAddress(runArgsMap),
|
MacAddress: getMACAddress(runArgsMap),
|
||||||
StopSignal: getStopSignal(runArgsMap),
|
StopSignal: getStopSignal(runArgsMap),
|
||||||
StopTimeout: stopTimeout,
|
StopTimeout: stopTimeout,
|
||||||
User: getUser(runArgsMap),
|
User: containerUser,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = dockerClient.ContainerCreate(ctx, containerConfig, hostConfig, nil, nil, containerName)
|
_, err = dockerClient.ContainerCreate(ctx, containerConfig, hostConfig, nil, nil, containerName)
|
||||||
@ -278,10 +285,10 @@ func GetContainerInfo(
|
|||||||
containerName string,
|
containerName string,
|
||||||
dockerClient *client.Client,
|
dockerClient *client.Client,
|
||||||
portMappings map[int]*types.PortMapping,
|
portMappings map[int]*types.PortMapping,
|
||||||
) (string, map[int]string, error) {
|
) (string, map[int]string, string, error) {
|
||||||
inspectResp, err := dockerClient.ContainerInspect(ctx, containerName)
|
inspectResp, err := dockerClient.ContainerInspect(ctx, containerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, fmt.Errorf("could not inspect container %s: %w", containerName, err)
|
return "", nil, "", fmt.Errorf("could not inspect container %s: %w", containerName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
usedPorts := make(map[int]string)
|
usedPorts := make(map[int]string)
|
||||||
@ -289,7 +296,7 @@ func GetContainerInfo(
|
|||||||
portRaw := strings.Split(string(portAndProtocol), "/")[0]
|
portRaw := strings.Split(string(portAndProtocol), "/")[0]
|
||||||
port, conversionErr := strconv.Atoi(portRaw)
|
port, conversionErr := strconv.Atoi(portRaw)
|
||||||
if conversionErr != nil {
|
if conversionErr != nil {
|
||||||
return "", nil, fmt.Errorf("could not convert port %s to int: %w", portRaw, conversionErr)
|
return "", nil, "", fmt.Errorf("could not convert port %s to int: %w", portRaw, conversionErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
if portMappings[port] != nil {
|
if portMappings[port] != nil {
|
||||||
@ -297,7 +304,34 @@ func GetContainerInfo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return inspectResp.ID, usedPorts, nil
|
remoteUser := ExtractRemoteUserFromLabels(inspectResp)
|
||||||
|
|
||||||
|
return inspectResp.ID, usedPorts, remoteUser, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExtractMetadataFromImage(
|
||||||
|
ctx context.Context,
|
||||||
|
imageName string,
|
||||||
|
dockerClient *client.Client,
|
||||||
|
) (map[string]any, error) {
|
||||||
|
imageInspect, _, err := dockerClient.ImageInspectWithRaw(ctx, imageName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error while inspecting image: %w", err)
|
||||||
|
}
|
||||||
|
metadataMap := map[string]any{}
|
||||||
|
if metadata, ok := imageInspect.Config.Labels["devcontainer.metadata"]; ok {
|
||||||
|
dst := []map[string]any{}
|
||||||
|
unmarshalErr := json.Unmarshal([]byte(metadata), &dst)
|
||||||
|
if unmarshalErr != nil {
|
||||||
|
return nil, fmt.Errorf("error while unmarshalling metadata: %w", err)
|
||||||
|
}
|
||||||
|
for _, values := range dst {
|
||||||
|
for k, v := range values {
|
||||||
|
metadataMap[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return metadataMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func PullImage(
|
func PullImage(
|
||||||
@ -429,7 +463,6 @@ func ExtractRunArgsWithLogging(
|
|||||||
runArgsRaw []string,
|
runArgsRaw []string,
|
||||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
) (map[types.RunArg]*types.RunArgValue, error) {
|
) (map[types.RunArg]*types.RunArgValue, error) {
|
||||||
gitspaceLogger.Info("Extracting runsArgs")
|
|
||||||
runArgsMap, err := ExtractRunArgs(ctx, spaceID, runArgProvider, runArgsRaw)
|
runArgsMap, err := ExtractRunArgs(ctx, spaceID, runArgProvider, runArgsRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, logStreamWrapError(gitspaceLogger, "Error while extracting runArgs", err)
|
return nil, logStreamWrapError(gitspaceLogger, "Error while extracting runArgs", err)
|
||||||
@ -439,7 +472,9 @@ func ExtractRunArgsWithLogging(
|
|||||||
for key, value := range runArgsMap {
|
for key, value := range runArgsMap {
|
||||||
st = fmt.Sprintf("%s%s: %s\n", st, key, value)
|
st = fmt.Sprintf("%s%s: %s\n", st, key, value)
|
||||||
}
|
}
|
||||||
gitspaceLogger.Info(fmt.Sprintf("Extracted following runArgs\n%v", st))
|
gitspaceLogger.Info(fmt.Sprintf("Using the following runArgs\n%v", st))
|
||||||
|
} else {
|
||||||
|
gitspaceLogger.Info("No runArgs found")
|
||||||
}
|
}
|
||||||
return runArgsMap, nil
|
return runArgsMap, nil
|
||||||
}
|
}
|
||||||
@ -450,20 +485,38 @@ func GetContainerResponse(
|
|||||||
dockerClient *client.Client,
|
dockerClient *client.Client,
|
||||||
containerName string,
|
containerName string,
|
||||||
portMappings map[int]*types.PortMapping,
|
portMappings map[int]*types.PortMapping,
|
||||||
codeRepoDir string,
|
repoName string,
|
||||||
) (*StartResponse, error) {
|
) (*StartResponse, error) {
|
||||||
id, ports, err := GetContainerInfo(ctx, containerName, dockerClient, portMappings)
|
id, ports, remoteUser, err := GetContainerInfo(ctx, containerName, dockerClient, portMappings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
homeDir := GetUserHomeDir(remoteUser)
|
||||||
|
codeRepoDir := filepath.Join(homeDir, repoName)
|
||||||
|
|
||||||
return &StartResponse{
|
return &StartResponse{
|
||||||
ContainerID: id,
|
ContainerID: id,
|
||||||
ContainerName: containerName,
|
ContainerName: containerName,
|
||||||
PublishedPorts: ports,
|
PublishedPorts: ports,
|
||||||
AbsoluteRepoPath: codeRepoDir,
|
AbsoluteRepoPath: codeRepoDir,
|
||||||
|
RemoteUser: remoteUser,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetRemoteUserFromContainerLabel(
|
||||||
|
ctx context.Context,
|
||||||
|
containerName string,
|
||||||
|
dockerClient *client.Client,
|
||||||
|
) (string, error) {
|
||||||
|
inspectResp, err := dockerClient.ContainerInspect(ctx, containerName)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("could not inspect container %s: %w", containerName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExtractRemoteUserFromLabels(inspectResp), nil
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to encode the AuthConfig into a Base64 string.
|
// Helper function to encode the AuthConfig into a Base64 string.
|
||||||
func encodeAuthToBase64(authConfig registry.AuthConfig) (string, error) {
|
func encodeAuthToBase64(authConfig registry.AuthConfig) (string, error) {
|
||||||
authJSON, err := json.Marshal(authConfig)
|
authJSON, err := json.Marshal(authConfig)
|
||||||
|
@ -159,11 +159,8 @@ func (e *EmbeddedDockerOrchestrator) CreateAndStartGitspace(
|
|||||||
return nil, fmt.Errorf("gitspace %s is in a bad state: %s", containerName, state)
|
return nil, fmt.Errorf("gitspace %s is in a bad state: %s", containerName, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
homeDir := GetUserHomeDir(gitspaceConfig.GitspaceUser.Identifier)
|
|
||||||
codeRepoDir := filepath.Join(homeDir, resolvedRepoDetails.RepoName)
|
|
||||||
|
|
||||||
// Step 5: Retrieve container information and return response
|
// Step 5: Retrieve container information and return response
|
||||||
return GetContainerResponse(ctx, dockerClient, containerName, infra.GitspacePortMappings, codeRepoDir)
|
return GetContainerResponse(ctx, dockerClient, containerName, infra.GitspacePortMappings, resolvedRepoDetails.RepoName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// startStoppedGitspace starts the Gitspace container if it was stopped.
|
// startStoppedGitspace starts the Gitspace container if it was stopped.
|
||||||
@ -179,25 +176,33 @@ func (e *EmbeddedDockerOrchestrator) startStoppedGitspace(
|
|||||||
containerName := GetGitspaceContainerName(gitspaceConfig)
|
containerName := GetGitspaceContainerName(gitspaceConfig)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error getting log stream for gitspace ID %d: %w", gitspaceConfig.ID, err)
|
return fmt.Errorf("error getting log stream for gitspace instance %s: %w",
|
||||||
|
gitspaceConfig.GitspaceInstance.Identifier, err)
|
||||||
}
|
}
|
||||||
defer e.flushLogStream(logStreamInstance, gitspaceConfig.ID)
|
defer e.flushLogStream(logStreamInstance, gitspaceConfig.ID)
|
||||||
|
|
||||||
|
remoteUser, err := GetRemoteUserFromContainerLabel(ctx, containerName, dockerClient)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error getting remote user for gitspace instance %s: %w",
|
||||||
|
gitspaceConfig.GitspaceInstance.Identifier, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
homeDir := GetUserHomeDir(remoteUser)
|
||||||
|
|
||||||
startErr := ManageContainer(ctx, ContainerActionStart, containerName, dockerClient, logStreamInstance)
|
startErr := ManageContainer(ctx, ContainerActionStart, containerName, dockerClient, logStreamInstance)
|
||||||
if startErr != nil {
|
if startErr != nil {
|
||||||
return startErr
|
return startErr
|
||||||
}
|
}
|
||||||
|
|
||||||
homeDir := GetUserHomeDir(gitspaceConfig.GitspaceUser.Identifier)
|
|
||||||
codeRepoDir := filepath.Join(homeDir, resolvedRepoDetails.RepoName)
|
codeRepoDir := filepath.Join(homeDir, resolvedRepoDetails.RepoName)
|
||||||
|
|
||||||
exec := &devcontainer.Exec{
|
exec := &devcontainer.Exec{
|
||||||
ContainerName: containerName,
|
ContainerName: containerName,
|
||||||
DockerClient: dockerClient,
|
DockerClient: dockerClient,
|
||||||
HomeDir: homeDir,
|
HomeDir: homeDir,
|
||||||
UserIdentifier: gitspaceConfig.GitspaceUser.Identifier,
|
RemoteUser: remoteUser,
|
||||||
AccessKey: accessKey,
|
AccessKey: accessKey,
|
||||||
AccessType: gitspaceConfig.GitspaceInstance.AccessType,
|
AccessType: gitspaceConfig.GitspaceInstance.AccessType,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up git credentials if needed
|
// Set up git credentials if needed
|
||||||
@ -376,14 +381,10 @@ func (e *EmbeddedDockerOrchestrator) runGitspaceSetupSteps(
|
|||||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
imageAuthMap map[string]gitspaceTypes.DockerRegistryAuth,
|
imageAuthMap map[string]gitspaceTypes.DockerRegistryAuth,
|
||||||
) error {
|
) error {
|
||||||
homeDir := GetUserHomeDir(gitspaceConfig.GitspaceUser.Identifier)
|
|
||||||
containerName := GetGitspaceContainerName(gitspaceConfig)
|
containerName := GetGitspaceContainerName(gitspaceConfig)
|
||||||
|
|
||||||
devcontainerConfig := resolvedRepoDetails.DevcontainerConfig
|
devcontainerConfig := resolvedRepoDetails.DevcontainerConfig
|
||||||
imageName := devcontainerConfig.Image
|
imageName := GetImage(devcontainerConfig, defaultBaseImage)
|
||||||
if imageName == "" {
|
|
||||||
imageName = defaultBaseImage
|
|
||||||
}
|
|
||||||
|
|
||||||
runArgsMap, err := ExtractRunArgsWithLogging(ctx, gitspaceConfig.SpaceID, e.runArgProvider,
|
runArgsMap, err := ExtractRunArgsWithLogging(ctx, gitspaceConfig.SpaceID, e.runArgProvider,
|
||||||
devcontainerConfig.RunArgs, gitspaceLogger)
|
devcontainerConfig.RunArgs, gitspaceLogger)
|
||||||
@ -395,6 +396,12 @@ func (e *EmbeddedDockerOrchestrator) runGitspaceSetupSteps(
|
|||||||
if err := PullImage(ctx, imageName, dockerClient, runArgsMap, gitspaceLogger, imageAuthMap); err != nil {
|
if err := PullImage(ctx, imageName, dockerClient, runArgsMap, gitspaceLogger, imageAuthMap); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
metadataFromImage, err := ExtractMetadataFromImage(ctx, imageName, dockerClient)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
portMappings := infrastructure.GitspacePortMappings
|
portMappings := infrastructure.GitspacePortMappings
|
||||||
forwardPorts := ExtractForwardPorts(devcontainerConfig)
|
forwardPorts := ExtractForwardPorts(devcontainerConfig)
|
||||||
if len(forwardPorts) > 0 {
|
if len(forwardPorts) > 0 {
|
||||||
@ -412,6 +419,15 @@ func (e *EmbeddedDockerOrchestrator) runGitspaceSetupSteps(
|
|||||||
if len(environment) > 0 {
|
if len(environment) > 0 {
|
||||||
gitspaceLogger.Info(fmt.Sprintf("Setting Environment : %v", environment))
|
gitspaceLogger.Info(fmt.Sprintf("Setting Environment : %v", environment))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
containerUser := GetContainerUser(runArgsMap, devcontainerConfig, metadataFromImage)
|
||||||
|
remoteUser := GetRemoteUser(devcontainerConfig, metadataFromImage, containerUser)
|
||||||
|
|
||||||
|
homeDir := GetUserHomeDir(remoteUser)
|
||||||
|
|
||||||
|
gitspaceLogger.Info(fmt.Sprintf("Container user: %s", containerUser))
|
||||||
|
gitspaceLogger.Info(fmt.Sprintf("Remote user: %s", remoteUser))
|
||||||
|
|
||||||
// Create the container
|
// Create the container
|
||||||
err = CreateContainer(
|
err = CreateContainer(
|
||||||
ctx,
|
ctx,
|
||||||
@ -425,6 +441,8 @@ func (e *EmbeddedDockerOrchestrator) runGitspaceSetupSteps(
|
|||||||
portMappings,
|
portMappings,
|
||||||
environment,
|
environment,
|
||||||
runArgsMap,
|
runArgsMap,
|
||||||
|
containerUser,
|
||||||
|
remoteUser,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -437,12 +455,12 @@ func (e *EmbeddedDockerOrchestrator) runGitspaceSetupSteps(
|
|||||||
|
|
||||||
// Setup and run commands
|
// Setup and run commands
|
||||||
exec := &devcontainer.Exec{
|
exec := &devcontainer.Exec{
|
||||||
ContainerName: containerName,
|
ContainerName: containerName,
|
||||||
DockerClient: dockerClient,
|
DockerClient: dockerClient,
|
||||||
HomeDir: homeDir,
|
HomeDir: homeDir,
|
||||||
UserIdentifier: gitspaceConfig.GitspaceUser.Identifier,
|
RemoteUser: remoteUser,
|
||||||
AccessKey: *gitspaceConfig.GitspaceInstance.AccessKey,
|
AccessKey: *gitspaceConfig.GitspaceInstance.AccessKey,
|
||||||
AccessType: gitspaceConfig.GitspaceInstance.AccessType,
|
AccessType: gitspaceConfig.GitspaceInstance.AccessType,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := e.setupGitspaceAndIDE(
|
if err := e.setupGitspaceAndIDE(
|
||||||
|
@ -372,8 +372,8 @@ func getHealthCheckConfig(runArgsMap map[types.RunArg]*types.RunArgValue) (*cont
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getLabels(runArgsMap map[types.RunArg]*types.RunArgValue) map[string]string {
|
func getLabels(runArgsMap map[types.RunArg]*types.RunArgValue) map[string]string {
|
||||||
arg, ok := runArgsMap[types.RunArgLabel]
|
|
||||||
labelsMap := make(map[string]string)
|
labelsMap := make(map[string]string)
|
||||||
|
arg, ok := runArgsMap[types.RunArgLabel]
|
||||||
if ok {
|
if ok {
|
||||||
labels := arg.Values
|
labels := arg.Values
|
||||||
for _, v := range labels {
|
for _, v := range labels {
|
||||||
|
@ -19,6 +19,7 @@ type StartResponse struct {
|
|||||||
ContainerName string
|
ContainerName string
|
||||||
PublishedPorts map[int]string
|
PublishedPorts map[int]string
|
||||||
AbsoluteRepoPath string
|
AbsoluteRepoPath string
|
||||||
|
RemoteUser string
|
||||||
}
|
}
|
||||||
|
|
||||||
type PostAction string
|
type PostAction string
|
||||||
|
@ -18,10 +18,14 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/harness/gitness/types"
|
"github.com/harness/gitness/types"
|
||||||
|
|
||||||
|
types2 "github.com/docker/docker/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
linuxHome = "/home"
|
linuxHome = "/home"
|
||||||
|
deprecatedRemoteUser = "harness"
|
||||||
|
gitspaceRemoteUserLabel = "gitspace.remote.user"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetGitspaceContainerName(config types.GitspaceConfig) string {
|
func GetGitspaceContainerName(config types.GitspaceConfig) string {
|
||||||
@ -29,5 +33,56 @@ func GetGitspaceContainerName(config types.GitspaceConfig) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetUserHomeDir(userIdentifier string) string {
|
func GetUserHomeDir(userIdentifier string) string {
|
||||||
|
if userIdentifier == "root" {
|
||||||
|
return "/root"
|
||||||
|
}
|
||||||
return filepath.Join(linuxHome, userIdentifier)
|
return filepath.Join(linuxHome, userIdentifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetImage(devcontainerConfig types.DevcontainerConfig, defaultBaseImage string) string {
|
||||||
|
imageName := devcontainerConfig.Image
|
||||||
|
if imageName == "" {
|
||||||
|
imageName = defaultBaseImage
|
||||||
|
}
|
||||||
|
return imageName
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetContainerUser(
|
||||||
|
runArgsMap map[types.RunArg]*types.RunArgValue,
|
||||||
|
devcontainerConfig types.DevcontainerConfig,
|
||||||
|
metadataFromImage map[string]any,
|
||||||
|
) string {
|
||||||
|
if containerUser := getUser(runArgsMap); containerUser != "" {
|
||||||
|
return containerUser
|
||||||
|
}
|
||||||
|
if devcontainerConfig.ContainerUser != "" {
|
||||||
|
return devcontainerConfig.ContainerUser
|
||||||
|
}
|
||||||
|
if containerUser, ok := metadataFromImage["containerUser"].(string); ok {
|
||||||
|
return containerUser
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExtractRemoteUserFromLabels(inspectResp types2.ContainerJSON) string {
|
||||||
|
remoteUser := deprecatedRemoteUser
|
||||||
|
|
||||||
|
if remoteUserValue, ok := inspectResp.Config.Labels[gitspaceRemoteUserLabel]; ok {
|
||||||
|
remoteUser = remoteUserValue
|
||||||
|
}
|
||||||
|
return remoteUser
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRemoteUser(
|
||||||
|
devcontainerConfig types.DevcontainerConfig,
|
||||||
|
metadataFromImage map[string]any,
|
||||||
|
containerUser string,
|
||||||
|
) string {
|
||||||
|
if devcontainerConfig.RemoteUser != "" {
|
||||||
|
return devcontainerConfig.RemoteUser
|
||||||
|
}
|
||||||
|
if remoteUser, ok := metadataFromImage["remoteUser"].(string); ok {
|
||||||
|
return remoteUser
|
||||||
|
}
|
||||||
|
return containerUser
|
||||||
|
}
|
||||||
|
@ -34,12 +34,12 @@ const RootUser = "root"
|
|||||||
const ErrMsgTCP = "unable to upgrade to tcp, received 200"
|
const ErrMsgTCP = "unable to upgrade to tcp, received 200"
|
||||||
|
|
||||||
type Exec struct {
|
type Exec struct {
|
||||||
ContainerName string
|
ContainerName string
|
||||||
DockerClient *client.Client
|
DockerClient *client.Client
|
||||||
HomeDir string
|
HomeDir string
|
||||||
UserIdentifier string
|
RemoteUser string
|
||||||
AccessKey string
|
AccessKey string
|
||||||
AccessType enum.GitspaceAccessType
|
AccessType enum.GitspaceAccessType
|
||||||
}
|
}
|
||||||
|
|
||||||
type execResult struct {
|
type execResult struct {
|
||||||
@ -56,7 +56,7 @@ func (e *Exec) ExecuteCommand(
|
|||||||
workingDir string,
|
workingDir string,
|
||||||
outputCh chan []byte, // channel to stream output as []byte
|
outputCh chan []byte, // channel to stream output as []byte
|
||||||
) error {
|
) error {
|
||||||
user := e.UserIdentifier
|
user := e.RemoteUser
|
||||||
if root {
|
if root {
|
||||||
user = RootUser
|
user = RootUser
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ func (v *VSCode) Setup(
|
|||||||
osInfoScript := common.GetOSInfoScript()
|
osInfoScript := common.GetOSInfoScript()
|
||||||
sshServerScript, err := template.GenerateScriptFromTemplate(
|
sshServerScript, err := template.GenerateScriptFromTemplate(
|
||||||
templateSetupSSHServer, &template.SetupSSHServerPayload{
|
templateSetupSSHServer, &template.SetupSSHServerPayload{
|
||||||
Username: exec.UserIdentifier,
|
Username: exec.RemoteUser,
|
||||||
AccessType: exec.AccessType,
|
AccessType: exec.AccessType,
|
||||||
OSInfoScript: osInfoScript,
|
OSInfoScript: osInfoScript,
|
||||||
})
|
})
|
||||||
|
@ -220,7 +220,7 @@ func generateIDEURL(
|
|||||||
Host: "", // Empty since we include the host and port in the path
|
Host: "", // Empty since we include the host and port in the path
|
||||||
Path: fmt.Sprintf(
|
Path: fmt.Sprintf(
|
||||||
"ssh-remote+%s@%s:%s",
|
"ssh-remote+%s@%s:%s",
|
||||||
gitspaceConfig.GitspaceUser.Identifier,
|
startResponse.RemoteUser,
|
||||||
host,
|
host,
|
||||||
filepath.Join(forwardedPort, relativeRepoPath),
|
filepath.Join(forwardedPort, relativeRepoPath),
|
||||||
),
|
),
|
||||||
|
54
app/gitspace/orchestrator/runarg/resolver.go
Normal file
54
app/gitspace/orchestrator/runarg/resolver.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright 2023 Harness, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package runarg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/harness/gitness/types"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
|
||||||
|
_ "embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed runArgs.yaml
|
||||||
|
var supportedRunArgsRaw []byte
|
||||||
|
|
||||||
|
type Resolver struct {
|
||||||
|
supportedRunArgsMap map[types.RunArg]types.RunArgDefinition
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewResolver() (*Resolver, error) {
|
||||||
|
allRunArgs := make([]types.RunArgDefinition, 0)
|
||||||
|
err := yaml.Unmarshal(supportedRunArgsRaw, &allRunArgs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to unmarshal runArgs.yaml: %w", err)
|
||||||
|
}
|
||||||
|
argsMap := make(map[types.RunArg]types.RunArgDefinition)
|
||||||
|
for _, arg := range allRunArgs {
|
||||||
|
if arg.Supported {
|
||||||
|
argsMap[arg.Name] = arg
|
||||||
|
if arg.ShortHand != "" {
|
||||||
|
argsMap[arg.ShortHand] = arg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &Resolver{supportedRunArgsMap: argsMap}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resolver) ResolveSupportedRunArgs() map[types.RunArg]types.RunArgDefinition {
|
||||||
|
return r.supportedRunArgsMap
|
||||||
|
}
|
@ -2,36 +2,36 @@
|
|||||||
- name: --add-host
|
- name: --add-host
|
||||||
short_hand:
|
short_hand:
|
||||||
supported: true
|
supported: true
|
||||||
blocked_values: {}
|
blocked_values: { }
|
||||||
allowed_values: {}
|
allowed_values: { }
|
||||||
allow_multiple_occurrences: true
|
allow_multiple_occurrences: true
|
||||||
|
|
||||||
- name: --annotation
|
- name: --annotation
|
||||||
short_hand:
|
short_hand:
|
||||||
supported: true
|
supported: true
|
||||||
blocked_values: {}
|
blocked_values: { }
|
||||||
allowed_values: {}
|
allowed_values: { }
|
||||||
allow_multiple_occurrences: true
|
allow_multiple_occurrences: true
|
||||||
|
|
||||||
- name: --attach
|
- name: --attach
|
||||||
short_hand: -a
|
short_hand: -a
|
||||||
supported: false
|
supported: false
|
||||||
blocked_values: {}
|
blocked_values: { }
|
||||||
allowed_values: {}
|
allowed_values: { }
|
||||||
allow_multiple_occurrences: true
|
allow_multiple_occurrences: true
|
||||||
|
|
||||||
- name: --blkio-weight
|
- name: --blkio-weight
|
||||||
short_hand:
|
short_hand:
|
||||||
supported: true
|
supported: true
|
||||||
blocked_values: {}
|
blocked_values: { }
|
||||||
allowed_values: {}
|
allowed_values: { }
|
||||||
allow_multiple_occurrences: false
|
allow_multiple_occurrences: false
|
||||||
|
|
||||||
- name: --blkio-weight-device
|
- name: --blkio-weight-device
|
||||||
short_hand:
|
short_hand:
|
||||||
supported: false
|
supported: false
|
||||||
blocked_values: {}
|
blocked_values: { }
|
||||||
allowed_values: {}
|
allowed_values: { }
|
||||||
allow_multiple_occurrences: true
|
allow_multiple_occurrences: true
|
||||||
|
|
||||||
- name: --cap-add
|
- name: --cap-add
|
||||||
@ -394,15 +394,16 @@
|
|||||||
- name: --label
|
- name: --label
|
||||||
short_hand: -l
|
short_hand: -l
|
||||||
supported: true
|
supported: true
|
||||||
blocked_values: { }
|
blocked_values:
|
||||||
|
^gitspace\.remote\.user=: true
|
||||||
allowed_values: { }
|
allowed_values: { }
|
||||||
allow_multiple_occurrences: true
|
allow_multiple_occurrences: true
|
||||||
|
|
||||||
- name: --label-file
|
- name: --label-file
|
||||||
short_hand:
|
short_hand:
|
||||||
supported: false
|
supported: false
|
||||||
blocked_values: {}
|
blocked_values: { }
|
||||||
allowed_values: {}
|
allowed_values: { }
|
||||||
allow_multiple_occurrences: true
|
allow_multiple_occurrences: true
|
||||||
|
|
||||||
- name: --link
|
- name: --link
|
||||||
@ -486,8 +487,8 @@
|
|||||||
short_hand:
|
short_hand:
|
||||||
supported: true
|
supported: true
|
||||||
blocked_values:
|
blocked_values:
|
||||||
host: true
|
^host$: true
|
||||||
none: true
|
^none$: true
|
||||||
allowed_values: { }
|
allowed_values: { }
|
||||||
allow_multiple_occurrences: false
|
allow_multiple_occurrences: false
|
||||||
|
|
||||||
|
@ -16,40 +16,18 @@ package runarg
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/harness/gitness/types"
|
"github.com/harness/gitness/types"
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
|
|
||||||
_ "embed"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Provider = (*StaticProvider)(nil)
|
var _ Provider = (*StaticProvider)(nil)
|
||||||
|
|
||||||
//go:embed runArgs.yaml
|
|
||||||
var supportedRunArgsRaw []byte
|
|
||||||
|
|
||||||
type StaticProvider struct {
|
type StaticProvider struct {
|
||||||
supportedRunArgsMap map[types.RunArg]types.RunArgDefinition
|
supportedRunArgsMap map[types.RunArg]types.RunArgDefinition
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStaticProvider() (Provider, error) {
|
func NewStaticProvider(resolver *Resolver) (Provider, error) {
|
||||||
allRunArgs := make([]types.RunArgDefinition, 0)
|
return &StaticProvider{supportedRunArgsMap: resolver.ResolveSupportedRunArgs()}, nil
|
||||||
err := yaml.Unmarshal(supportedRunArgsRaw, &allRunArgs)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to unmarshal runArgs.yaml: %w", err)
|
|
||||||
}
|
|
||||||
argsMap := make(map[types.RunArg]types.RunArgDefinition)
|
|
||||||
for _, arg := range allRunArgs {
|
|
||||||
if arg.Supported {
|
|
||||||
argsMap[arg.Name] = arg
|
|
||||||
if arg.ShortHand != "" {
|
|
||||||
argsMap[arg.ShortHand] = arg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &StaticProvider{supportedRunArgsMap: argsMap}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProvideSupportedRunArgs provides a static map of supported run args.
|
// ProvideSupportedRunArgs provides a static map of supported run args.
|
||||||
|
@ -20,8 +20,12 @@ import (
|
|||||||
|
|
||||||
var WireSet = wire.NewSet(
|
var WireSet = wire.NewSet(
|
||||||
ProvideStaticProvider,
|
ProvideStaticProvider,
|
||||||
|
ProvideResolver,
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProvideStaticProvider() (Provider, error) {
|
func ProvideStaticProvider(resolver *Resolver) (Provider, error) {
|
||||||
return NewStaticProvider()
|
return NewStaticProvider(resolver)
|
||||||
|
}
|
||||||
|
func ProvideResolver() (*Resolver, error) {
|
||||||
|
return NewResolver()
|
||||||
}
|
}
|
||||||
|
@ -63,11 +63,10 @@ type SetupVSCodeWebPayload struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SetupUserPayload struct {
|
type SetupUserPayload struct {
|
||||||
Username string
|
Username string
|
||||||
AccessKey string
|
AccessKey string
|
||||||
AccessType enum.GitspaceAccessType
|
AccessType enum.GitspaceAccessType
|
||||||
HomeDir string
|
HomeDir string
|
||||||
OSInfoScript string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SetupSSHServerPayload struct {
|
type SetupSSHServerPayload struct {
|
||||||
|
@ -1,65 +1,41 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
username={{ .Username }}
|
username="{{ .Username }}"
|
||||||
accessKey="{{ .AccessKey }}"
|
accessKey="{{ .AccessKey }}"
|
||||||
homeDir={{ .HomeDir }}
|
homeDir="{{ .HomeDir }}"
|
||||||
accessType={{ .AccessType }}
|
accessType={{ .AccessType }}
|
||||||
osInfoScript={{ .OSInfoScript }}
|
|
||||||
|
|
||||||
eval "$osInfoScript"
|
# Check if the user's home directory exists
|
||||||
|
if [ ! -d "$homeDir" ]; then
|
||||||
# Check if the user already exists
|
echo "Directory $homeDir does not exist. Creating it..."
|
||||||
if id "$username" >/dev/null 2>&1; then
|
mkdir -p "$homeDir"
|
||||||
echo "User $username already exists."
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Failed to create directory $homeDir."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
# Create a new user
|
echo "Directory $homeDir already exists."
|
||||||
case "$(distro)" in
|
|
||||||
debian)
|
|
||||||
apt-get update && apt-get install -y adduser && apt-get install -y sudo
|
|
||||||
adduser --disabled-password --home "$homeDir" --gecos "" "$username"
|
|
||||||
usermod -aG sudo "$username"
|
|
||||||
echo "%sudo ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers
|
|
||||||
;;
|
|
||||||
fedora)
|
|
||||||
useradd -m -d "$homeDir" "$username"
|
|
||||||
usermod -aG wheel "$username"
|
|
||||||
dnf install -y sudo
|
|
||||||
echo "%wheel ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers
|
|
||||||
;;
|
|
||||||
opensuse)
|
|
||||||
useradd -m -d "$homeDir" "$username"
|
|
||||||
passwd -l "$username" # Locks the password to prevent login
|
|
||||||
zypper in -y sudo
|
|
||||||
groupadd sudo
|
|
||||||
usermod -aG sudo "$username"
|
|
||||||
echo "%sudo ALL=(ALL:ALL) NOPASSWD: ALL" >> /etc/sudoers
|
|
||||||
chown -R "$username":sudo "$homeDir"
|
|
||||||
;;
|
|
||||||
alpine)
|
|
||||||
adduser -h "$homeDir" -s /bin/ash -D "$username" # Default shell is ash for Alpine
|
|
||||||
;;
|
|
||||||
arch)
|
|
||||||
useradd -m -d "$homeDir" -s /bin/bash "$username"
|
|
||||||
;;
|
|
||||||
freebsd)
|
|
||||||
pw useradd -n "$username" -d "$homeDir" -m
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Unsupported distribution: $distro."
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "Failed to create user $username."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Changing ownership of everything inside user home to the newly created user
|
# Ensure the user has ownership and permissions to the home directory
|
||||||
chown -R $username:$username $homeDir
|
currentOwner=$(stat -c '%U' "$homeDir")
|
||||||
echo "Changing ownership of dir $homeDir to $username."
|
if [ "$currentOwner" != "$username" ]; then
|
||||||
chmod 755 $homeDir
|
echo "Updating ownership of $homeDir to $username..."
|
||||||
|
chown -R "$username:$username" "$homeDir"
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Failed to update ownership of $homeDir."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Ensuring proper permissions for $homeDir..."
|
||||||
|
chmod 755 "$homeDir"
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Failed to set permissions for $homeDir."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Directory setup for $username is complete."
|
||||||
|
|
||||||
if [ "ssh_key" = "$accessType" ] ; then
|
if [ "ssh_key" = "$accessType" ] ; then
|
||||||
echo "Add ssh key in $homeDir/.ssh/authorized_keys"
|
echo "Add ssh key in $homeDir/.ssh/authorized_keys"
|
||||||
@ -68,7 +44,6 @@ if [ "ssh_key" = "$accessType" ] ; then
|
|||||||
echo $accessKey > $homeDir/.ssh/authorized_keys
|
echo $accessKey > $homeDir/.ssh/authorized_keys
|
||||||
chmod 600 $homeDir/.ssh/authorized_keys
|
chmod 600 $homeDir/.ssh/authorized_keys
|
||||||
chown -R $username:$username $homeDir/.ssh
|
chown -R $username:$username $homeDir/.ssh
|
||||||
echo "$username:$username" | chpasswd
|
|
||||||
elif [ "user_credentials" = "$accessType" ] ; then
|
elif [ "user_credentials" = "$accessType" ] ; then
|
||||||
echo "$username:$accessKey" | chpasswd
|
echo "$username:$accessKey" | chpasswd
|
||||||
else
|
else
|
||||||
|
@ -47,8 +47,8 @@ config_file='/etc/ssh/sshd_config'
|
|||||||
|
|
||||||
grep -q "^AllowUsers" $config_file
|
grep -q "^AllowUsers" $config_file
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
# If AllowUsers exists, add the user to it
|
# If AllowUsers exists, overwrite all existing users with new user
|
||||||
sed -i "/^AllowUsers/ s/$/ $username/" $config_file
|
sed -i "s/^AllowUsers.*/AllowUsers $username/" $config_file
|
||||||
else
|
else
|
||||||
# Otherwise, add a new AllowUsers line
|
# Otherwise, add a new AllowUsers line
|
||||||
echo "AllowUsers $username" >> $config_file
|
echo "AllowUsers $username" >> $config_file
|
||||||
@ -67,10 +67,15 @@ echo "AuthorizedKeysFile .ssh/authorized_keys" >> $config_file
|
|||||||
echo "PubkeyAuthentication yes" >> $config_file
|
echo "PubkeyAuthentication yes" >> $config_file
|
||||||
else
|
else
|
||||||
# Ensure password authentication is enabled
|
# Ensure password authentication is enabled
|
||||||
sed -i 's/^PasswordAuthentication no/PasswordAuthentication yes/' $config_file
|
|
||||||
if ! grep -q "^PasswordAuthentication yes" $config_file; then
|
if ! grep -q "^PasswordAuthentication yes" $config_file; then
|
||||||
echo "PasswordAuthentication yes" >> $config_file
|
echo "PasswordAuthentication yes" >> $config_file
|
||||||
fi
|
fi
|
||||||
|
if ! grep -q "^PermitEmptyPasswords yes" $config_file; then
|
||||||
|
echo "PermitEmptyPasswords yes" >> $config_file
|
||||||
|
fi
|
||||||
|
if ! grep -q "^PermitRootLogin yes" $config_file; then
|
||||||
|
echo "PermitRootLogin yes" >> $config_file
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p /var/run/sshd
|
mkdir -p /var/run/sshd
|
@ -40,28 +40,25 @@ func (u *ServiceImpl) Manage(
|
|||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
) error {
|
) error {
|
||||||
osInfoScript := common.GetOSInfoScript()
|
|
||||||
script, err := template.GenerateScriptFromTemplate(
|
script, err := template.GenerateScriptFromTemplate(
|
||||||
templateManagerUser, &template.SetupUserPayload{
|
templateManagerUser, &template.SetupUserPayload{
|
||||||
Username: exec.UserIdentifier,
|
Username: exec.RemoteUser,
|
||||||
AccessKey: exec.AccessKey,
|
AccessKey: exec.AccessKey,
|
||||||
AccessType: exec.AccessType,
|
AccessType: exec.AccessType,
|
||||||
HomeDir: exec.HomeDir,
|
HomeDir: exec.HomeDir,
|
||||||
OSInfoScript: osInfoScript,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"failed to generate scipt to manager user from template %s: %w", templateManagerUser, err)
|
"failed to generate scipt to manager user from template %s: %w", templateManagerUser, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gitspaceLogger.Info("Setting up user inside container")
|
gitspaceLogger.Info("Configuring user directory and credentials inside container")
|
||||||
gitspaceLogger.Info("Managing user output...")
|
|
||||||
err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, script, true, gitspaceLogger)
|
err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, script, true, gitspaceLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to setup user: %w", err)
|
return fmt.Errorf("failed to setup user: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gitspaceLogger.Info("Successfully setup user")
|
gitspaceLogger.Info("Successfully configured the user directory and credentials.")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ const VSCodeProxyURI = "VSCODE_PROXY_URI"
|
|||||||
type GitspaceLogger interface {
|
type GitspaceLogger interface {
|
||||||
Info(msg string)
|
Info(msg string)
|
||||||
Debug(msg string)
|
Debug(msg string)
|
||||||
|
Warn(msg string)
|
||||||
Error(msg string, err error)
|
Error(msg string, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,10 @@ func (z *ZerologAdapter) Debug(msg string) {
|
|||||||
z.logger.Debug().Msg("DEBUG: " + msg)
|
z.logger.Debug().Msg("DEBUG: " + msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (z *ZerologAdapter) Warn(msg string) {
|
||||||
|
z.logger.Warn().Msg("WARN: " + msg)
|
||||||
|
}
|
||||||
|
|
||||||
func (z *ZerologAdapter) Error(msg string, err error) {
|
func (z *ZerologAdapter) Error(msg string, err error) {
|
||||||
z.logger.Err(err).Msg("ERROR: " + msg)
|
z.logger.Err(err).Msg("ERROR: " + msg)
|
||||||
}
|
}
|
||||||
|
@ -319,7 +319,11 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
|||||||
statefulLogger := logutil.ProvideStatefulLogger(logStream)
|
statefulLogger := logutil.ProvideStatefulLogger(logStream)
|
||||||
gitService := git2.ProvideGitServiceImpl()
|
gitService := git2.ProvideGitServiceImpl()
|
||||||
userService := user2.ProvideUserServiceImpl()
|
userService := user2.ProvideUserServiceImpl()
|
||||||
runargProvider, err := runarg.ProvideStaticProvider()
|
runargResolver, err := runarg.ProvideResolver()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
runargProvider, err := runarg.ProvideStaticProvider(runargResolver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,9 @@ type DevcontainerConfig struct {
|
|||||||
ForwardPorts []json.Number `json:"forwardPorts,omitempty"` //nolint:tagliatelle
|
ForwardPorts []json.Number `json:"forwardPorts,omitempty"` //nolint:tagliatelle
|
||||||
ContainerEnv map[string]string `json:"containerEnv,omitempty"` //nolint:tagliatelle
|
ContainerEnv map[string]string `json:"containerEnv,omitempty"` //nolint:tagliatelle
|
||||||
Customizations DevContainerConfigCustomizations `json:"customizations,omitempty"`
|
Customizations DevContainerConfigCustomizations `json:"customizations,omitempty"`
|
||||||
RunArgs []string `json:"runArgs,omitempty"` //nolint:tagliatelle
|
RunArgs []string `json:"runArgs,omitempty"` //nolint:tagliatelle
|
||||||
|
ContainerUser string `json:"containerUser,omitempty"` //nolint:tagliatelle
|
||||||
|
RemoteUser string `json:"remoteUser,omitempty"` //nolint:tagliatelle
|
||||||
}
|
}
|
||||||
|
|
||||||
// LifecycleCommand supports multiple formats for lifecycle commands.
|
// LifecycleCommand supports multiple formats for lifecycle commands.
|
||||||
|
Loading…
Reference in New Issue
Block a user