mirror of
https://github.com/harness/drone.git
synced 2025-05-05 23:42:57 +00:00
feat: [CDE-470]: use stream logger and buffer the results for gitspaces exec (#3008)
* feat: [CDE-470]: set env variable for flavours * feat: [CDE-470]: set env variable for flavours * feat: [CDE-470]: set env variable for flavours * feat: [CDE-470]: set env variable for flavours * feat: [CDE-470]: format code * feat: [CDE-470]: format code * feat: [CDE-470]: format code * feat: [CDE-470]: use stream logger * feat: [CDE-470]: use stream logger * feat: [CDE-470]: use stream logger * feat: [CDE-470]: env variables for VS Code desktop
This commit is contained in:
parent
fa05570220
commit
17dea68b57
@ -17,17 +17,24 @@ package common
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/template"
|
"github.com/harness/gitness/app/gitspace/orchestrator/template"
|
||||||
|
"github.com/harness/gitness/app/gitspace/types"
|
||||||
"github.com/harness/gitness/types/enum"
|
"github.com/harness/gitness/types/enum"
|
||||||
)
|
)
|
||||||
|
|
||||||
const templateSupportedOSDistribution = "supported_os_distribution.sh"
|
const templateSupportedOSDistribution = "supported_os_distribution.sh"
|
||||||
const templateVsCodeWebToolsInstallation = "install_tools_vs_code_web.sh"
|
const templateVsCodeWebToolsInstallation = "install_tools_vs_code_web.sh"
|
||||||
const templateVsCodeToolsInstallation = "install_tools_vs_code.sh"
|
const templateVsCodeToolsInstallation = "install_tools_vs_code.sh"
|
||||||
|
const templateSetEnv = "set_env.sh"
|
||||||
|
|
||||||
func ValidateSupportedOS(ctx context.Context, exec *devcontainer.Exec) ([]byte, error) {
|
func ValidateSupportedOS(
|
||||||
|
ctx context.Context,
|
||||||
|
exec *devcontainer.Exec,
|
||||||
|
gitspaceLogger types.GitspaceLogger,
|
||||||
|
) error {
|
||||||
// TODO: Currently not supporting arch, freebsd and alpine.
|
// TODO: Currently not supporting arch, freebsd and alpine.
|
||||||
// For alpine wee need to install multiple things from
|
// For alpine wee need to install multiple things from
|
||||||
// https://github.com/microsoft/vscode/wiki/How-to-Contribute#prerequisites
|
// https://github.com/microsoft/vscode/wiki/How-to-Contribute#prerequisites
|
||||||
@ -36,79 +43,127 @@ func ValidateSupportedOS(ctx context.Context, exec *devcontainer.Exec) ([]byte,
|
|||||||
OSInfoScript: osDetectScript,
|
OSInfoScript: osDetectScript,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to generate scipt to validate supported os distribution from template %s: %w",
|
return fmt.Errorf("failed to generate scipt to validate supported os distribution from template %s: %w",
|
||||||
templateSupportedOSDistribution, err)
|
templateSupportedOSDistribution, err)
|
||||||
}
|
}
|
||||||
|
gitspaceLogger.Info("Validate supported OSes...")
|
||||||
output, err := exec.ExecuteCommandInHomeDirectory(ctx, script, true, false)
|
err = ExecuteCommandInHomeDirAndLog(ctx, exec, script, true, gitspaceLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error while detecting os distribution: %w", err)
|
return fmt.Errorf("error while detecting os distribution: %w", err)
|
||||||
}
|
}
|
||||||
return output, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func InstallTools(ctx context.Context, exec *devcontainer.Exec, ideType enum.IDEType) ([]byte, error) {
|
func InstallTools(
|
||||||
|
ctx context.Context,
|
||||||
|
exec *devcontainer.Exec,
|
||||||
|
ideType enum.IDEType,
|
||||||
|
gitspaceLogger types.GitspaceLogger,
|
||||||
|
) error {
|
||||||
switch ideType {
|
switch ideType {
|
||||||
case enum.IDETypeVSCodeWeb:
|
case enum.IDETypeVSCodeWeb:
|
||||||
{
|
err := InstallToolsForVsCodeWeb(ctx, exec, gitspaceLogger)
|
||||||
output, err := InstallToolsForVsCodeWeb(ctx, exec)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return []byte(output), err
|
|
||||||
}
|
|
||||||
return []byte(output), nil
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
case enum.IDETypeVSCode:
|
case enum.IDETypeVSCode:
|
||||||
{
|
err := InstallToolsForVsCode(ctx, exec, gitspaceLogger)
|
||||||
output, err := InstallToolsForVsCode(ctx, exec)
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return []byte(output), err
|
|
||||||
}
|
|
||||||
return []byte(output), nil
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func InstallToolsForVsCodeWeb(ctx context.Context, exec *devcontainer.Exec) (string, error) {
|
func InstallToolsForVsCodeWeb(
|
||||||
|
ctx context.Context,
|
||||||
|
exec *devcontainer.Exec,
|
||||||
|
gitspaceLogger types.GitspaceLogger,
|
||||||
|
) error {
|
||||||
script, err := template.GenerateScriptFromTemplate(
|
script, err := template.GenerateScriptFromTemplate(
|
||||||
templateVsCodeWebToolsInstallation, &template.InstallToolsPayload{
|
templateVsCodeWebToolsInstallation, &template.InstallToolsPayload{
|
||||||
OSInfoScript: osDetectScript,
|
OSInfoScript: osDetectScript,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"failed to generate scipt to install tools for vs code web from template %s: %w",
|
"failed to generate scipt to install tools for vs code web from template %s: %w",
|
||||||
templateVsCodeWebToolsInstallation, err)
|
templateVsCodeWebToolsInstallation, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
output := "Installing tools for vs code web inside container\n"
|
gitspaceLogger.Info("Installing tools for vs code web inside container")
|
||||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, true, false)
|
gitspaceLogger.Info("Tools installation output...")
|
||||||
|
err = ExecuteCommandInHomeDirAndLog(ctx, exec, script, true, gitspaceLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to install tools for vs code web: %w", err)
|
return fmt.Errorf("failed to install tools for vs code web: %w", err)
|
||||||
}
|
}
|
||||||
|
gitspaceLogger.Info("Successfully installed tools for vs code web")
|
||||||
output += "Successfully installed tools for vs code web\n"
|
return nil
|
||||||
|
|
||||||
return output, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func InstallToolsForVsCode(ctx context.Context, exec *devcontainer.Exec) (string, error) {
|
func InstallToolsForVsCode(
|
||||||
|
ctx context.Context,
|
||||||
|
exec *devcontainer.Exec,
|
||||||
|
gitspaceLogger types.GitspaceLogger,
|
||||||
|
) error {
|
||||||
script, err := template.GenerateScriptFromTemplate(
|
script, err := template.GenerateScriptFromTemplate(
|
||||||
templateVsCodeToolsInstallation, &template.InstallToolsPayload{
|
templateVsCodeToolsInstallation, &template.InstallToolsPayload{
|
||||||
OSInfoScript: osDetectScript,
|
OSInfoScript: osDetectScript,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"failed to generate scipt to install tools for vs code from template %s: %w",
|
"failed to generate scipt to install tools for vs code from template %s: %w",
|
||||||
templateVsCodeToolsInstallation, err)
|
templateVsCodeToolsInstallation, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
output := "Installing tools for vs code inside container\n"
|
gitspaceLogger.Info("Installing tools for vs code in container")
|
||||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, true, false)
|
err = ExecuteCommandInHomeDirAndLog(ctx, exec, script, true, gitspaceLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to install tools for vs code: %w", err)
|
return fmt.Errorf("failed to install tools for vs code: %w", err)
|
||||||
}
|
}
|
||||||
|
gitspaceLogger.Info("Successfully installed tools for vs code")
|
||||||
output += "Successfully installed tools for vs code\n"
|
return nil
|
||||||
|
}
|
||||||
return output, nil
|
|
||||||
|
func SetEnv(
|
||||||
|
ctx context.Context,
|
||||||
|
exec *devcontainer.Exec,
|
||||||
|
gitspaceLogger types.GitspaceLogger,
|
||||||
|
environment []string,
|
||||||
|
) error {
|
||||||
|
// Join the elements with a newline character
|
||||||
|
result := strings.Join(environment, "\n")
|
||||||
|
script, err := template.GenerateScriptFromTemplate(
|
||||||
|
templateSetEnv, &template.SetEnvPayload{
|
||||||
|
EnvVariables: result,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to generate scipt to set env from template %s: %w",
|
||||||
|
templateSetEnv, err)
|
||||||
|
}
|
||||||
|
gitspaceLogger.Info("Setting env...")
|
||||||
|
err = ExecuteCommandInHomeDirAndLog(ctx, exec, script, true, gitspaceLogger)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error while setting env vars: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExecuteCommandInHomeDirAndLog(
|
||||||
|
ctx context.Context,
|
||||||
|
exec *devcontainer.Exec,
|
||||||
|
script string,
|
||||||
|
root bool,
|
||||||
|
gitspaceLogger types.GitspaceLogger,
|
||||||
|
) error {
|
||||||
|
outputCh := make(chan []byte)
|
||||||
|
err := exec.ExecuteCommandInHomeDirectory(ctx, script, root, false, outputCh)
|
||||||
|
for output := range outputCh {
|
||||||
|
// Log output from the command as a string
|
||||||
|
if len(output) > 0 {
|
||||||
|
gitspaceLogger.Info(string(output))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
orchestratorTypes "github.com/harness/gitness/app/gitspace/orchestrator/types"
|
gitspaceTypes "github.com/harness/gitness/app/gitspace/types"
|
||||||
"github.com/harness/gitness/types"
|
"github.com/harness/gitness/types"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
@ -47,7 +47,7 @@ var containerStateMapping = map[string]State{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to log messages and handle error wrapping.
|
// Helper function to log messages and handle error wrapping.
|
||||||
func logStreamWrapError(gitspaceLogger orchestratorTypes.GitspaceLogger, msg string, err error) error {
|
func logStreamWrapError(gitspaceLogger gitspaceTypes.GitspaceLogger, msg string, err error) error {
|
||||||
gitspaceLogger.Error(msg, err)
|
gitspaceLogger.Error(msg, err)
|
||||||
return fmt.Errorf("%s: %w", msg, err)
|
return fmt.Errorf("%s: %w", msg, err)
|
||||||
}
|
}
|
||||||
@ -58,7 +58,7 @@ func ManageContainer(
|
|||||||
action Action,
|
action Action,
|
||||||
containerName string,
|
containerName string,
|
||||||
dockerClient *client.Client,
|
dockerClient *client.Client,
|
||||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
) error {
|
) error {
|
||||||
var err error
|
var err error
|
||||||
switch action {
|
switch action {
|
||||||
@ -123,7 +123,7 @@ func CreateContainer(
|
|||||||
dockerClient *client.Client,
|
dockerClient *client.Client,
|
||||||
imageName string,
|
imageName string,
|
||||||
containerName string,
|
containerName string,
|
||||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
bindMountSource string,
|
bindMountSource string,
|
||||||
bindMountTarget string,
|
bindMountTarget string,
|
||||||
mountType mount.Type,
|
mountType mount.Type,
|
||||||
@ -225,7 +225,7 @@ func PullImage(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
imageName string,
|
imageName string,
|
||||||
dockerClient *client.Client,
|
dockerClient *client.Client,
|
||||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
) error {
|
) error {
|
||||||
gitspaceLogger.Info("Pulling image: " + imageName)
|
gitspaceLogger.Info("Pulling image: " + imageName)
|
||||||
|
|
||||||
|
@ -23,9 +23,9 @@ import (
|
|||||||
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/git"
|
"github.com/harness/gitness/app/gitspace/orchestrator/git"
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/ide"
|
"github.com/harness/gitness/app/gitspace/orchestrator/ide"
|
||||||
orchestratorTypes "github.com/harness/gitness/app/gitspace/orchestrator/types"
|
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/user"
|
"github.com/harness/gitness/app/gitspace/orchestrator/user"
|
||||||
"github.com/harness/gitness/app/gitspace/scm"
|
"github.com/harness/gitness/app/gitspace/scm"
|
||||||
|
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"
|
||||||
)
|
)
|
||||||
@ -34,11 +34,12 @@ import (
|
|||||||
func (e *EmbeddedDockerOrchestrator) setupGitspaceAndIDE(
|
func (e *EmbeddedDockerOrchestrator) setupGitspaceAndIDE(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
ideService ide.IDE,
|
ideService ide.IDE,
|
||||||
gitspaceConfig types.GitspaceConfig,
|
gitspaceConfig types.GitspaceConfig,
|
||||||
resolvedRepoDetails scm.ResolvedDetails,
|
resolvedRepoDetails scm.ResolvedDetails,
|
||||||
defaultBaseImage string,
|
defaultBaseImage string,
|
||||||
|
environment []string,
|
||||||
) error {
|
) error {
|
||||||
homeDir := GetUserHomeDir(gitspaceConfig.GitspaceUser.Identifier)
|
homeDir := GetUserHomeDir(gitspaceConfig.GitspaceUser.Identifier)
|
||||||
devcontainerConfig := resolvedRepoDetails.DevcontainerConfig
|
devcontainerConfig := resolvedRepoDetails.DevcontainerConfig
|
||||||
@ -47,45 +48,49 @@ func (e *EmbeddedDockerOrchestrator) setupGitspaceAndIDE(
|
|||||||
// Register setup steps
|
// Register setup steps
|
||||||
e.RegisterStep("Validate Supported OS", ValidateSupportedOS, true)
|
e.RegisterStep("Validate Supported OS", ValidateSupportedOS, true)
|
||||||
e.RegisterStep("Manage User",
|
e.RegisterStep("Manage User",
|
||||||
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger orchestratorTypes.GitspaceLogger) error {
|
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger gitspaceTypes.GitspaceLogger) error {
|
||||||
return ManageUser(ctx, exec, e.userService, gitspaceLogger)
|
return ManageUser(ctx, exec, e.userService, gitspaceLogger)
|
||||||
}, true)
|
}, true)
|
||||||
|
e.RegisterStep("Set environment",
|
||||||
|
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger gitspaceTypes.GitspaceLogger) error {
|
||||||
|
return SetEnv(ctx, exec, gitspaceLogger, environment)
|
||||||
|
}, true)
|
||||||
e.RegisterStep("Install Tools",
|
e.RegisterStep("Install Tools",
|
||||||
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger orchestratorTypes.GitspaceLogger) error {
|
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger gitspaceTypes.GitspaceLogger) error {
|
||||||
return InstallTools(ctx, exec, gitspaceLogger, gitspaceConfig.IDE)
|
return InstallTools(ctx, exec, gitspaceLogger, gitspaceConfig.IDE)
|
||||||
}, true)
|
}, true)
|
||||||
e.RegisterStep("Setup IDE",
|
e.RegisterStep("Setup IDE",
|
||||||
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger orchestratorTypes.GitspaceLogger) error {
|
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger gitspaceTypes.GitspaceLogger) error {
|
||||||
return SetupIDE(ctx, exec, ideService, gitspaceLogger)
|
return SetupIDE(ctx, exec, ideService, gitspaceLogger)
|
||||||
}, true)
|
}, true)
|
||||||
e.RegisterStep("Run IDE",
|
e.RegisterStep("Run IDE",
|
||||||
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger orchestratorTypes.GitspaceLogger) error {
|
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger gitspaceTypes.GitspaceLogger) error {
|
||||||
return RunIDE(ctx, exec, ideService, gitspaceLogger)
|
return RunIDE(ctx, exec, ideService, gitspaceLogger)
|
||||||
}, true)
|
}, true)
|
||||||
e.RegisterStep("Install Git",
|
e.RegisterStep("Install Git",
|
||||||
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger orchestratorTypes.GitspaceLogger) error {
|
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger gitspaceTypes.GitspaceLogger) error {
|
||||||
return InstallGit(ctx, exec, e.gitService, gitspaceLogger)
|
return InstallGit(ctx, exec, e.gitService, gitspaceLogger)
|
||||||
}, true)
|
}, true)
|
||||||
e.RegisterStep("Setup Git Credentials",
|
e.RegisterStep("Setup Git Credentials",
|
||||||
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger orchestratorTypes.GitspaceLogger) error {
|
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger gitspaceTypes.GitspaceLogger) error {
|
||||||
if resolvedRepoDetails.ResolvedCredentials.Credentials != nil {
|
if resolvedRepoDetails.ResolvedCredentials.Credentials != nil {
|
||||||
return SetupGitCredentials(ctx, exec, resolvedRepoDetails, e.gitService, gitspaceLogger)
|
return SetupGitCredentials(ctx, exec, resolvedRepoDetails, e.gitService, gitspaceLogger)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}, true)
|
}, true)
|
||||||
e.RegisterStep("Clone Code",
|
e.RegisterStep("Clone Code",
|
||||||
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger orchestratorTypes.GitspaceLogger) error {
|
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger gitspaceTypes.GitspaceLogger) error {
|
||||||
return CloneCode(ctx, exec, defaultBaseImage, resolvedRepoDetails, e.gitService, gitspaceLogger)
|
return CloneCode(ctx, exec, defaultBaseImage, resolvedRepoDetails, e.gitService, gitspaceLogger)
|
||||||
}, true)
|
}, true)
|
||||||
|
|
||||||
// Register the Execute Command steps (PostCreate and PostStart)
|
// Register the Execute Command steps (PostCreate and PostStart)
|
||||||
e.RegisterStep("Execute PostCreate Command",
|
e.RegisterStep("Execute PostCreate Command",
|
||||||
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger orchestratorTypes.GitspaceLogger) error {
|
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger gitspaceTypes.GitspaceLogger) error {
|
||||||
command := ExtractCommand(PostCreateAction, devcontainerConfig)
|
command := ExtractCommand(PostCreateAction, devcontainerConfig)
|
||||||
return ExecuteCommand(ctx, exec, codeRepoDir, gitspaceLogger, command, PostCreateAction)
|
return ExecuteCommand(ctx, exec, codeRepoDir, gitspaceLogger, command, PostCreateAction)
|
||||||
}, false)
|
}, false)
|
||||||
e.RegisterStep("Execute PostStart Command",
|
e.RegisterStep("Execute PostStart Command",
|
||||||
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger orchestratorTypes.GitspaceLogger) error {
|
func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger gitspaceTypes.GitspaceLogger) error {
|
||||||
command := ExtractCommand(PostStartAction, devcontainerConfig)
|
command := ExtractCommand(PostStartAction, devcontainerConfig)
|
||||||
return ExecuteCommand(ctx, exec, codeRepoDir, gitspaceLogger, command, PostStartAction)
|
return ExecuteCommand(ctx, exec, codeRepoDir, gitspaceLogger, command, PostStartAction)
|
||||||
}, false)
|
}, false)
|
||||||
@ -100,27 +105,25 @@ func (e *EmbeddedDockerOrchestrator) setupGitspaceAndIDE(
|
|||||||
func InstallTools(
|
func InstallTools(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
ideType enum.IDEType,
|
ideType enum.IDEType,
|
||||||
) error {
|
) error {
|
||||||
output, err := common.InstallTools(ctx, exec, ideType)
|
err := common.InstallTools(ctx, exec, ideType, gitspaceLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logStreamWrapError(gitspaceLogger, "Error while installing tools inside container", err)
|
return logStreamWrapError(gitspaceLogger, "Error while installing tools inside container", err)
|
||||||
}
|
}
|
||||||
gitspaceLogger.Info("Tools installation output...\n" + string(output))
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidateSupportedOS(
|
func ValidateSupportedOS(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
) error {
|
) error {
|
||||||
output, err := common.ValidateSupportedOS(ctx, exec)
|
err := common.ValidateSupportedOS(ctx, exec, gitspaceLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logStreamWrapError(gitspaceLogger, "Error while detecting OS inside container", err)
|
return logStreamWrapError(gitspaceLogger, "Error while detecting OS inside container", err)
|
||||||
}
|
}
|
||||||
gitspaceLogger.Info("Validate supported OSes...\n" + string(output))
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +131,7 @@ func ExecuteCommand(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
codeRepoDir string,
|
codeRepoDir string,
|
||||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
command string,
|
command string,
|
||||||
actionType PostAction,
|
actionType PostAction,
|
||||||
) error {
|
) error {
|
||||||
@ -137,12 +140,17 @@ func ExecuteCommand(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
gitspaceLogger.Info(fmt.Sprintf("Executing %s command: %s", actionType, command))
|
gitspaceLogger.Info(fmt.Sprintf("Executing %s command: %s", actionType, command))
|
||||||
output, err := exec.ExecuteCommand(ctx, command, true, false, codeRepoDir)
|
gitspaceLogger.Info(fmt.Sprintf("%s command execution output...", actionType))
|
||||||
|
// Create a channel to stream command output
|
||||||
|
outputCh := make(chan []byte)
|
||||||
|
err := exec.ExecuteCommand(ctx, command, true, false, codeRepoDir, outputCh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logStreamWrapError(
|
return logStreamWrapError(
|
||||||
gitspaceLogger, fmt.Sprintf("Error while executing %s command", actionType), err)
|
gitspaceLogger, fmt.Sprintf("Error while executing %s command", actionType), err)
|
||||||
}
|
}
|
||||||
gitspaceLogger.Info(fmt.Sprintf("%s command execution output...\n %s", actionType, string(output)))
|
for output := range outputCh {
|
||||||
|
gitspaceLogger.Info(string(output))
|
||||||
|
}
|
||||||
gitspaceLogger.Info(fmt.Sprintf("Successfully executed %s command", actionType))
|
gitspaceLogger.Info(fmt.Sprintf("Successfully executed %s command", actionType))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -153,13 +161,12 @@ func CloneCode(
|
|||||||
defaultBaseImage string,
|
defaultBaseImage string,
|
||||||
resolvedRepoDetails scm.ResolvedDetails,
|
resolvedRepoDetails scm.ResolvedDetails,
|
||||||
gitService git.Service,
|
gitService git.Service,
|
||||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
) error {
|
) error {
|
||||||
output, err := gitService.CloneCode(ctx, exec, resolvedRepoDetails, defaultBaseImage)
|
err := gitService.CloneCode(ctx, exec, resolvedRepoDetails, defaultBaseImage, gitspaceLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logStreamWrapError(gitspaceLogger, "Error while cloning code inside container", err)
|
return logStreamWrapError(gitspaceLogger, "Error while cloning code inside container", err)
|
||||||
}
|
}
|
||||||
gitspaceLogger.Info("Clone output...\n" + string(output))
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,14 +174,12 @@ func InstallGit(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
gitService git.Service,
|
gitService git.Service,
|
||||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
) error {
|
) error {
|
||||||
output, err := gitService.Install(ctx, exec)
|
err := gitService.Install(ctx, exec, gitspaceLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logStreamWrapError(gitspaceLogger, "Error while installing git inside container", err)
|
return logStreamWrapError(gitspaceLogger, "Error while installing git inside container", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gitspaceLogger.Info("Install git output...\n" + string(output))
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,15 +188,13 @@ func SetupGitCredentials(
|
|||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
resolvedRepoDetails scm.ResolvedDetails,
|
resolvedRepoDetails scm.ResolvedDetails,
|
||||||
gitService git.Service,
|
gitService git.Service,
|
||||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
) error {
|
) error {
|
||||||
output, err := gitService.SetupCredentials(ctx, exec, resolvedRepoDetails)
|
err := gitService.SetupCredentials(ctx, exec, resolvedRepoDetails, gitspaceLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logStreamWrapError(
|
return logStreamWrapError(
|
||||||
gitspaceLogger, "Error while setting up git credentials inside container", err)
|
gitspaceLogger, "Error while setting up git credentials inside container", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gitspaceLogger.Info("Setting up git credentials output...\n" + string(output))
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,13 +202,12 @@ func ManageUser(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
userService user.Service,
|
userService user.Service,
|
||||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
) error {
|
) error {
|
||||||
output, err := userService.Manage(ctx, exec)
|
err := userService.Manage(ctx, exec, gitspaceLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logStreamWrapError(gitspaceLogger, "Error while creating user inside container", err)
|
return logStreamWrapError(gitspaceLogger, "Error while creating user inside container", err)
|
||||||
}
|
}
|
||||||
gitspaceLogger.Info("Managing user output...\n" + string(output))
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,17 +215,13 @@ func SetupIDE(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
ideService ide.IDE,
|
ideService ide.IDE,
|
||||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
) error {
|
) error {
|
||||||
gitspaceLogger.Info("Setting up IDE inside container: " + string(ideService.Type()))
|
gitspaceLogger.Info("Setting up IDE inside container: " + string(ideService.Type()))
|
||||||
|
err := ideService.Setup(ctx, exec, gitspaceLogger)
|
||||||
output, err := ideService.Setup(ctx, exec)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logStreamWrapError(gitspaceLogger, "Error while setting up IDE inside container", err)
|
return logStreamWrapError(gitspaceLogger, "Error while setting up IDE inside container", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gitspaceLogger.Info("IDE setup output...\n" + string(output))
|
|
||||||
gitspaceLogger.Info("Successfully set up IDE inside container")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,15 +229,27 @@ func RunIDE(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
ideService ide.IDE,
|
ideService ide.IDE,
|
||||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
) error {
|
) error {
|
||||||
gitspaceLogger.Info("Running the IDE inside container: " + string(ideService.Type()))
|
gitspaceLogger.Info("Running the IDE inside container: " + string(ideService.Type()))
|
||||||
output, err := ideService.Run(ctx, exec)
|
err := ideService.Run(ctx, exec, gitspaceLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return logStreamWrapError(gitspaceLogger, "Error while running IDE inside container", err)
|
return logStreamWrapError(gitspaceLogger, "Error while running IDE inside container", err)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
gitspaceLogger.Info("IDE run output...\n" + string(output))
|
}
|
||||||
gitspaceLogger.Info("Successfully run the IDE inside container")
|
|
||||||
|
func SetEnv(
|
||||||
|
ctx context.Context,
|
||||||
|
exec *devcontainer.Exec,
|
||||||
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
|
environment []string,
|
||||||
|
) error {
|
||||||
|
if len(environment) > 0 {
|
||||||
|
err := common.SetEnv(ctx, exec, gitspaceLogger, environment)
|
||||||
|
if err != nil {
|
||||||
|
return logStreamWrapError(gitspaceLogger, "Error while installing tools inside container", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,9 @@ import (
|
|||||||
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/git"
|
"github.com/harness/gitness/app/gitspace/orchestrator/git"
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/ide"
|
"github.com/harness/gitness/app/gitspace/orchestrator/ide"
|
||||||
orchestratorTypes "github.com/harness/gitness/app/gitspace/orchestrator/types"
|
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/user"
|
"github.com/harness/gitness/app/gitspace/orchestrator/user"
|
||||||
"github.com/harness/gitness/app/gitspace/scm"
|
"github.com/harness/gitness/app/gitspace/scm"
|
||||||
|
gitspaceTypes "github.com/harness/gitness/app/gitspace/types"
|
||||||
"github.com/harness/gitness/infraprovider"
|
"github.com/harness/gitness/infraprovider"
|
||||||
"github.com/harness/gitness/types"
|
"github.com/harness/gitness/types"
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type EmbeddedDockerOrchestrator struct {
|
type EmbeddedDockerOrchestrator struct {
|
||||||
steps []orchestratorTypes.Step // Steps registry
|
steps []gitspaceTypes.Step // Steps registry
|
||||||
dockerClientFactory *infraprovider.DockerClientFactory
|
dockerClientFactory *infraprovider.DockerClientFactory
|
||||||
statefulLogger *logutil.StatefulLogger
|
statefulLogger *logutil.StatefulLogger
|
||||||
gitService git.Service
|
gitService git.Service
|
||||||
@ -51,10 +51,10 @@ type EmbeddedDockerOrchestrator struct {
|
|||||||
// RegisterStep registers a new setup step with an option to stop or continue on failure.
|
// RegisterStep registers a new setup step with an option to stop or continue on failure.
|
||||||
func (e *EmbeddedDockerOrchestrator) RegisterStep(
|
func (e *EmbeddedDockerOrchestrator) RegisterStep(
|
||||||
name string,
|
name string,
|
||||||
execute func(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger orchestratorTypes.GitspaceLogger) error,
|
execute func(ctx context.Context, exec *devcontainer.Exec, logger gitspaceTypes.GitspaceLogger) error,
|
||||||
stopOnFailure bool,
|
stopOnFailure bool,
|
||||||
) {
|
) {
|
||||||
step := orchestratorTypes.Step{
|
step := gitspaceTypes.Step{
|
||||||
Name: name,
|
Name: name,
|
||||||
Execute: execute,
|
Execute: execute,
|
||||||
StopOnFailure: stopOnFailure,
|
StopOnFailure: stopOnFailure,
|
||||||
@ -66,7 +66,7 @@ func (e *EmbeddedDockerOrchestrator) RegisterStep(
|
|||||||
func (e *EmbeddedDockerOrchestrator) ExecuteSteps(
|
func (e *EmbeddedDockerOrchestrator) ExecuteSteps(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
) error {
|
) error {
|
||||||
for _, step := range e.steps {
|
for _, step := range e.steps {
|
||||||
// Execute the step
|
// Execute the step
|
||||||
@ -378,7 +378,7 @@ func (e *EmbeddedDockerOrchestrator) runGitspaceSetupSteps(
|
|||||||
infrastructure types.Infrastructure,
|
infrastructure types.Infrastructure,
|
||||||
resolvedRepoDetails scm.ResolvedDetails,
|
resolvedRepoDetails scm.ResolvedDetails,
|
||||||
defaultBaseImage string,
|
defaultBaseImage string,
|
||||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
) error {
|
) error {
|
||||||
homeDir := GetUserHomeDir(gitspaceConfig.GitspaceUser.Identifier)
|
homeDir := GetUserHomeDir(gitspaceConfig.GitspaceUser.Identifier)
|
||||||
containerName := GetGitspaceContainerName(gitspaceConfig)
|
containerName := GetGitspaceContainerName(gitspaceConfig)
|
||||||
@ -450,6 +450,7 @@ func (e *EmbeddedDockerOrchestrator) runGitspaceSetupSteps(
|
|||||||
gitspaceConfig,
|
gitspaceConfig,
|
||||||
resolvedRepoDetails,
|
resolvedRepoDetails,
|
||||||
defaultBaseImage,
|
defaultBaseImage,
|
||||||
|
environment,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,13 @@
|
|||||||
package devcontainer
|
package devcontainer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/harness/gitness/types/enum"
|
"github.com/harness/gitness/types/enum"
|
||||||
|
|
||||||
@ -28,6 +31,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const RootUser = "root"
|
const RootUser = "root"
|
||||||
|
const ErrMsgTCP = "unable to upgrade to tcp, received 200"
|
||||||
|
|
||||||
type Exec struct {
|
type Exec struct {
|
||||||
ContainerName string
|
ContainerName string
|
||||||
@ -39,8 +43,8 @@ type Exec struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type execResult struct {
|
type execResult struct {
|
||||||
StdOut []byte
|
StdOut io.Reader
|
||||||
StdErr []byte
|
StdErr io.Reader
|
||||||
ExitCode int
|
ExitCode int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,49 +54,48 @@ func (e *Exec) ExecuteCommand(
|
|||||||
root bool,
|
root bool,
|
||||||
detach bool,
|
detach bool,
|
||||||
workingDir string,
|
workingDir string,
|
||||||
) ([]byte, error) {
|
outputCh chan []byte, // channel to stream output as []byte
|
||||||
|
) error {
|
||||||
user := e.UserIdentifier
|
user := e.UserIdentifier
|
||||||
if root {
|
if root {
|
||||||
user = RootUser
|
user = RootUser
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := []string{"/bin/sh", "-c", command}
|
cmd := []string{"/bin/sh", "-c", command}
|
||||||
|
|
||||||
execConfig := container.ExecOptions{
|
execConfig := container.ExecOptions{
|
||||||
User: user,
|
User: user,
|
||||||
AttachStdout: true,
|
AttachStdout: !detach,
|
||||||
AttachStderr: true,
|
AttachStderr: !detach,
|
||||||
Cmd: cmd,
|
Cmd: cmd,
|
||||||
Detach: detach,
|
Detach: detach,
|
||||||
WorkingDir: workingDir,
|
WorkingDir: workingDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
execID, err := e.DockerClient.ContainerExecCreate(ctx, e.ContainerName, execConfig)
|
// Create exec instance for the container
|
||||||
|
containerExecCreate, err := e.DockerClient.ContainerExecCreate(ctx, e.ContainerName, execConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to create docker exec for container %s: %w", e.ContainerName, err)
|
return fmt.Errorf("failed to create docker exec for container %s: %w", e.ContainerName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := e.attachAndInspectExec(ctx, execID.ID, detach)
|
// Attach and inspect exec session to get the output
|
||||||
if err != nil && err.Error() != "unable to upgrade to tcp, received 200" {
|
inspectExec, err := e.attachAndInspectExec(ctx, containerExecCreate.ID, detach)
|
||||||
return nil, fmt.Errorf("failed to start docker exec for container %s: %w", e.ContainerName, err)
|
if err != nil && !strings.Contains(err.Error(), ErrMsgTCP) {
|
||||||
|
return fmt.Errorf("failed to start docker exec for container %s: %w", e.ContainerName, err)
|
||||||
|
}
|
||||||
|
// If in detach mode, exit early as the command will run in the background
|
||||||
|
if detach {
|
||||||
|
close(outputCh)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp != nil && resp.ExitCode != 0 {
|
// Wait for the exit code after the command completes
|
||||||
var errLog string
|
if inspectExec != nil && inspectExec.ExitCode != 0 {
|
||||||
if resp.StdErr != nil {
|
return fmt.Errorf("error during command execution in container %s. exit code %d",
|
||||||
errLog = string(resp.StdErr)
|
e.ContainerName, inspectExec.ExitCode)
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("error during command execution in container %s. exit code %d. log: %s",
|
|
||||||
e.ContainerName, resp.ExitCode, errLog)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var stdOutput []byte
|
e.streamResponse(inspectExec, outputCh)
|
||||||
if resp != nil {
|
return nil
|
||||||
stdOutput = resp.StdOut
|
|
||||||
}
|
|
||||||
|
|
||||||
return stdOutput, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Exec) ExecuteCommandInHomeDirectory(
|
func (e *Exec) ExecuteCommandInHomeDirectory(
|
||||||
@ -100,55 +103,91 @@ func (e *Exec) ExecuteCommandInHomeDirectory(
|
|||||||
command string,
|
command string,
|
||||||
root bool,
|
root bool,
|
||||||
detach bool,
|
detach bool,
|
||||||
) ([]byte, error) {
|
outputCh chan []byte, // channel to stream output as []byte
|
||||||
return e.ExecuteCommand(ctx, command, root, detach, e.HomeDir)
|
) error {
|
||||||
|
return e.ExecuteCommand(ctx, command, root, detach, e.HomeDir, outputCh)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Exec) attachAndInspectExec(ctx context.Context, id string, detach bool) (*execResult, error) {
|
func (e *Exec) attachAndInspectExec(ctx context.Context, id string, detach bool) (*execResult, error) {
|
||||||
resp, attachErr := e.DockerClient.ContainerExecAttach(ctx, id, container.ExecStartOptions{Detach: detach})
|
resp, attachErr := e.DockerClient.ContainerExecAttach(ctx, id, container.ExecStartOptions{Detach: detach})
|
||||||
if attachErr != nil {
|
if attachErr != nil {
|
||||||
return nil, attachErr
|
return nil, fmt.Errorf("failed to attach to exec session: %w", attachErr)
|
||||||
}
|
|
||||||
defer resp.Close()
|
|
||||||
|
|
||||||
var outBuf, errBuf bytes.Buffer
|
|
||||||
copyErr := make(chan error)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
// StdCopy demultiplexes the stream into two buffers
|
|
||||||
_, err := stdcopy.StdCopy(&outBuf, &errBuf, resp.Reader)
|
|
||||||
copyErr <- err
|
|
||||||
}()
|
|
||||||
|
|
||||||
select {
|
|
||||||
case err := <-copyErr:
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
break
|
|
||||||
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil, ctx.Err()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, err := io.ReadAll(&outBuf)
|
// If in detach mode, we just need to close the connection, not process output
|
||||||
if err != nil {
|
if detach {
|
||||||
return nil, fmt.Errorf("failed to read stdout of exec for container %s: %w", e.ContainerName, err)
|
// No need to process output in detach mode, so we simply close the connection
|
||||||
|
resp.Close()
|
||||||
|
return nil, nil //nolint:nilnil
|
||||||
}
|
}
|
||||||
|
|
||||||
stderr, err := io.ReadAll(&errBuf)
|
// Create pipes for stdout and stderr
|
||||||
if err != nil {
|
stdoutPipe, stdoutWriter := io.Pipe()
|
||||||
return nil, fmt.Errorf("failed to read stderr of exec for container %s: %w", e.ContainerName, err)
|
stderrPipe, stderrWriter := io.Pipe()
|
||||||
}
|
|
||||||
|
|
||||||
inspectRes, err := e.DockerClient.ContainerExecInspect(ctx, id)
|
go e.copyOutput(resp.Reader, stdoutWriter, stderrWriter)
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to inspect exec for container %s: %w", e.ContainerName, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Return the output streams and the response
|
||||||
return &execResult{
|
return &execResult{
|
||||||
StdOut: stdout,
|
StdOut: stdoutPipe, // Pipe for stdout
|
||||||
StdErr: stderr,
|
StdErr: stderrPipe, // Pipe for stderr
|
||||||
ExitCode: inspectRes.ExitCode,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Exec) streamResponse(resp *execResult, outputCh chan []byte) {
|
||||||
|
// Stream the output asynchronously if not in detach mode
|
||||||
|
go func() {
|
||||||
|
if resp != nil {
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
// Handle stdout as a streaming reader
|
||||||
|
if resp.StdOut != nil {
|
||||||
|
wg.Add(1)
|
||||||
|
go e.streamStdOut(resp.StdOut, outputCh, &wg)
|
||||||
|
}
|
||||||
|
// Handle stderr as a streaming reader
|
||||||
|
if resp.StdErr != nil {
|
||||||
|
wg.Add(1)
|
||||||
|
go e.streamStdErr(resp.StdErr, outputCh, &wg)
|
||||||
|
}
|
||||||
|
// Wait for all readers to finish before closing the channel
|
||||||
|
wg.Wait()
|
||||||
|
// Close the output channel after all output has been processed
|
||||||
|
close(outputCh)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// copyOutput copies the output from the exec response to the pipes, and is blocking.
|
||||||
|
func (e *Exec) copyOutput(reader io.Reader, stdoutWriter, stderrWriter io.WriteCloser) {
|
||||||
|
_, err := stdcopy.StdCopy(stdoutWriter, stderrWriter, reader)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error copying output: %v", err)
|
||||||
|
}
|
||||||
|
stdoutWriter.Close()
|
||||||
|
stderrWriter.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// streamStdOut reads from the stdout pipe and sends each line to the output channel.
|
||||||
|
func (e *Exec) streamStdOut(stdout io.Reader, outputCh chan []byte, wg *sync.WaitGroup) {
|
||||||
|
defer wg.Done()
|
||||||
|
stdoutReader := bufio.NewScanner(stdout)
|
||||||
|
for stdoutReader.Scan() {
|
||||||
|
outputCh <- stdoutReader.Bytes()
|
||||||
|
}
|
||||||
|
if err := stdoutReader.Err(); err != nil {
|
||||||
|
log.Println("Error reading stdout:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// streamStdErr reads from the stderr pipe and sends each line to the output channel.
|
||||||
|
func (e *Exec) streamStdErr(stderr io.Reader, outputCh chan []byte, wg *sync.WaitGroup) {
|
||||||
|
defer wg.Done()
|
||||||
|
stderrReader := bufio.NewScanner(stderr)
|
||||||
|
for stderrReader.Scan() {
|
||||||
|
outputCh <- []byte("ERR> " + stderrReader.Text())
|
||||||
|
}
|
||||||
|
if err := stderrReader.Err(); err != nil {
|
||||||
|
log.Println("Error reading stderr:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,18 +19,23 @@ import (
|
|||||||
|
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
||||||
"github.com/harness/gitness/app/gitspace/scm"
|
"github.com/harness/gitness/app/gitspace/scm"
|
||||||
|
"github.com/harness/gitness/app/gitspace/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
// Install ensures git is installed in the container.
|
// Install ensures git is installed in the container.
|
||||||
Install(ctx context.Context, exec *devcontainer.Exec) ([]byte, error)
|
Install(ctx context.Context,
|
||||||
|
exec *devcontainer.Exec,
|
||||||
|
gitspaceLogger types.GitspaceLogger,
|
||||||
|
) error
|
||||||
|
|
||||||
// SetupCredentials sets the user's git credentials inside the container.
|
// SetupCredentials sets the user's git credentials inside the container.
|
||||||
SetupCredentials(
|
SetupCredentials(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
resolvedRepoDetails scm.ResolvedDetails,
|
resolvedRepoDetails scm.ResolvedDetails,
|
||||||
) ([]byte, error)
|
gitspaceLogger types.GitspaceLogger,
|
||||||
|
) error
|
||||||
|
|
||||||
// CloneCode clones the code and ensures devcontainer file is present.
|
// CloneCode clones the code and ensures devcontainer file is present.
|
||||||
CloneCode(
|
CloneCode(
|
||||||
@ -38,5 +43,6 @@ type Service interface {
|
|||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
resolvedRepoDetails scm.ResolvedDetails,
|
resolvedRepoDetails scm.ResolvedDetails,
|
||||||
defaultBaseImage string,
|
defaultBaseImage string,
|
||||||
) ([]byte, error)
|
gitspaceLogger types.GitspaceLogger,
|
||||||
|
) error
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/template"
|
"github.com/harness/gitness/app/gitspace/orchestrator/template"
|
||||||
"github.com/harness/gitness/app/gitspace/scm"
|
"github.com/harness/gitness/app/gitspace/scm"
|
||||||
|
"github.com/harness/gitness/app/gitspace/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Service = (*ServiceImpl)(nil)
|
var _ Service = (*ServiceImpl)(nil)
|
||||||
@ -38,50 +39,52 @@ func NewGitServiceImpl() Service {
|
|||||||
return &ServiceImpl{}
|
return &ServiceImpl{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *ServiceImpl) Install(ctx context.Context, exec *devcontainer.Exec) ([]byte, error) {
|
func (g *ServiceImpl) Install(
|
||||||
|
ctx context.Context,
|
||||||
|
exec *devcontainer.Exec,
|
||||||
|
gitspaceLogger types.GitspaceLogger,
|
||||||
|
) error {
|
||||||
script, err := template.GenerateScriptFromTemplate(
|
script, err := template.GenerateScriptFromTemplate(
|
||||||
templateGitInstallScript, &template.SetupGitInstallPayload{
|
templateGitInstallScript, &template.SetupGitInstallPayload{
|
||||||
OSInfoScript: common.GetOSInfoScript(),
|
OSInfoScript: common.GetOSInfoScript(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"failed to generate scipt to setup git install from template %s: %w", templateGitInstallScript, err)
|
"failed to generate scipt to setup git install from template %s: %w", templateGitInstallScript, err)
|
||||||
}
|
}
|
||||||
output := "Setting up git inside container\n"
|
gitspaceLogger.Info("Install git output...")
|
||||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, true, false)
|
gitspaceLogger.Info("Setting up git inside container")
|
||||||
|
err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, script, true, gitspaceLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to setup git: %w", err)
|
return fmt.Errorf("failed to setup git: %w", err)
|
||||||
}
|
}
|
||||||
|
gitspaceLogger.Info("Successfully setup git")
|
||||||
|
|
||||||
output += "Successfully setup git\n"
|
return nil
|
||||||
|
|
||||||
return []byte(output), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *ServiceImpl) SetupCredentials(
|
func (g *ServiceImpl) SetupCredentials(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
resolvedRepoDetails scm.ResolvedDetails,
|
resolvedRepoDetails scm.ResolvedDetails,
|
||||||
) ([]byte, error) {
|
gitspaceLogger types.GitspaceLogger,
|
||||||
|
) error {
|
||||||
script, err := template.GenerateScriptFromTemplate(
|
script, err := template.GenerateScriptFromTemplate(
|
||||||
templateSetupGitCredentials, &template.SetupGitCredentialsPayload{
|
templateSetupGitCredentials, &template.SetupGitCredentialsPayload{
|
||||||
CloneURLWithCreds: resolvedRepoDetails.CloneURL,
|
CloneURLWithCreds: resolvedRepoDetails.CloneURL,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"failed to generate scipt to setup git credentials from template %s: %w", templateSetupGitCredentials, err)
|
"failed to generate scipt to setup git credentials from template %s: %w", templateSetupGitCredentials, err)
|
||||||
}
|
}
|
||||||
|
gitspaceLogger.Info("Setting up git credentials output...")
|
||||||
output := "Setting up git credentials inside container\n"
|
gitspaceLogger.Info("Setting up git credentials inside container")
|
||||||
|
err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, script, false, gitspaceLogger)
|
||||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, false, false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to setup git credentials: %w", err)
|
return fmt.Errorf("failed to setup git credentials: %w", err)
|
||||||
}
|
}
|
||||||
|
gitspaceLogger.Info("Successfully setup git credentials")
|
||||||
output += "Successfully setup git credentials\n"
|
return nil
|
||||||
|
|
||||||
return []byte(output), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *ServiceImpl) CloneCode(
|
func (g *ServiceImpl) CloneCode(
|
||||||
@ -89,10 +92,11 @@ func (g *ServiceImpl) CloneCode(
|
|||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
resolvedRepoDetails scm.ResolvedDetails,
|
resolvedRepoDetails scm.ResolvedDetails,
|
||||||
defaultBaseImage string,
|
defaultBaseImage string,
|
||||||
) ([]byte, error) {
|
gitspaceLogger types.GitspaceLogger,
|
||||||
|
) error {
|
||||||
cloneURL, err := url.Parse(resolvedRepoDetails.CloneURL)
|
cloneURL, err := url.Parse(resolvedRepoDetails.CloneURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"failed to parse clone url %s: %w", resolvedRepoDetails.CloneURL, err)
|
"failed to parse clone url %s: %w", resolvedRepoDetails.CloneURL, err)
|
||||||
}
|
}
|
||||||
cloneURL.User = nil
|
cloneURL.User = nil
|
||||||
@ -109,18 +113,16 @@ func (g *ServiceImpl) CloneCode(
|
|||||||
script, err := template.GenerateScriptFromTemplate(
|
script, err := template.GenerateScriptFromTemplate(
|
||||||
templateCloneCode, data)
|
templateCloneCode, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"failed to generate scipt to clone code from template %s: %w", templateCloneCode, err)
|
"failed to generate scipt to clone code from template %s: %w", templateCloneCode, err)
|
||||||
}
|
}
|
||||||
|
gitspaceLogger.Info("Clone output...")
|
||||||
output := "Cloning code inside container\n"
|
gitspaceLogger.Info("Cloning code inside container")
|
||||||
|
err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, script, false, gitspaceLogger)
|
||||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, false, false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to clone code: %w", err)
|
return fmt.Errorf("failed to clone code: %w", err)
|
||||||
}
|
}
|
||||||
|
gitspaceLogger.Info("Successfully clone code")
|
||||||
|
|
||||||
output += "Successfully clone code\n"
|
return nil
|
||||||
|
|
||||||
return []byte(output), nil
|
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
||||||
|
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"
|
||||||
)
|
)
|
||||||
@ -25,10 +26,10 @@ import (
|
|||||||
type IDE interface {
|
type IDE interface {
|
||||||
// Setup is responsible for doing all the operations for setting up the IDE in the container e.g. installation,
|
// Setup is responsible for doing all the operations for setting up the IDE in the container e.g. installation,
|
||||||
// copying settings and configurations.
|
// copying settings and configurations.
|
||||||
Setup(ctx context.Context, exec *devcontainer.Exec) ([]byte, error)
|
Setup(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger gitspaceTypes.GitspaceLogger) error
|
||||||
|
|
||||||
// Run runs the IDE and supporting services.
|
// Run runs the IDE and supporting services.
|
||||||
Run(ctx context.Context, exec *devcontainer.Exec) ([]byte, error)
|
Run(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger gitspaceTypes.GitspaceLogger) error
|
||||||
|
|
||||||
// Port provides the port which will be used by this IDE.
|
// Port provides the port which will be used by this IDE.
|
||||||
Port() *types.GitspacePort
|
Port() *types.GitspacePort
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/harness/gitness/app/gitspace/orchestrator/common"
|
"github.com/harness/gitness/app/gitspace/orchestrator/common"
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/template"
|
"github.com/harness/gitness/app/gitspace/orchestrator/template"
|
||||||
|
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"
|
||||||
)
|
)
|
||||||
@ -47,7 +48,8 @@ func NewVsCodeService(config *VSCodeConfig) *VSCode {
|
|||||||
func (v *VSCode) Setup(
|
func (v *VSCode) Setup(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
exec *devcontainer.Exec,
|
exec *devcontainer.Exec,
|
||||||
) ([]byte, error) {
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
|
) error {
|
||||||
osInfoScript := common.GetOSInfoScript()
|
osInfoScript := common.GetOSInfoScript()
|
||||||
sshServerScript, err := template.GenerateScriptFromTemplate(
|
sshServerScript, err := template.GenerateScriptFromTemplate(
|
||||||
templateSetupSSHServer, &template.SetupSSHServerPayload{
|
templateSetupSSHServer, &template.SetupSSHServerPayload{
|
||||||
@ -56,43 +58,43 @@ func (v *VSCode) Setup(
|
|||||||
OSInfoScript: osInfoScript,
|
OSInfoScript: osInfoScript,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"failed to generate scipt to setup ssh server from template %s: %w", templateSetupSSHServer, err)
|
"failed to generate scipt to setup ssh server from template %s: %w", templateSetupSSHServer, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
output := "Installing ssh-server inside container\n"
|
gitspaceLogger.Info("Installing ssh-server inside container")
|
||||||
|
gitspaceLogger.Info("IDE setup output...")
|
||||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, sshServerScript, true, false)
|
err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, sshServerScript, true, gitspaceLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to setup SSH serverr: %w", err)
|
return fmt.Errorf("failed to setup SSH serverr: %w", err)
|
||||||
}
|
}
|
||||||
|
gitspaceLogger.Info("Successfully installed ssh-server")
|
||||||
output += "Successfully installed ssh-server\n"
|
gitspaceLogger.Info("Successfully set up IDE inside container")
|
||||||
|
return nil
|
||||||
return []byte(output), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run runs the SSH server inside the container.
|
// Run runs the SSH server inside the container.
|
||||||
func (v *VSCode) Run(ctx context.Context, exec *devcontainer.Exec) ([]byte, error) {
|
func (v *VSCode) Run(
|
||||||
var output = ""
|
ctx context.Context,
|
||||||
|
exec *devcontainer.Exec,
|
||||||
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
|
) error {
|
||||||
runSSHScript, err := template.GenerateScriptFromTemplate(
|
runSSHScript, err := template.GenerateScriptFromTemplate(
|
||||||
templateRunSSHServer, &template.RunSSHServerPayload{
|
templateRunSSHServer, &template.RunSSHServerPayload{
|
||||||
Port: strconv.Itoa(v.config.Port),
|
Port: strconv.Itoa(v.config.Port),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"failed to generate scipt to run ssh server from template %s: %w", templateRunSSHServer, err)
|
"failed to generate scipt to run ssh server from template %s: %w", templateRunSSHServer, err)
|
||||||
}
|
}
|
||||||
|
gitspaceLogger.Info("SSH server run output...")
|
||||||
execOutput, err := exec.ExecuteCommandInHomeDirectory(ctx, runSSHScript, true, false)
|
err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, runSSHScript, true, gitspaceLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to run SSH server: %w", err)
|
return fmt.Errorf("failed to run SSH server: %w", err)
|
||||||
}
|
}
|
||||||
|
gitspaceLogger.Info("Successfully run ssh-server")
|
||||||
|
|
||||||
output += "SSH server run output...\n" + string(execOutput) + "\nSuccessfully run ssh-server\n"
|
return nil
|
||||||
|
|
||||||
return []byte(output), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Port returns the port on which the ssh-server is listening.
|
// Port returns the port on which the ssh-server is listening.
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
|
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/template"
|
"github.com/harness/gitness/app/gitspace/orchestrator/template"
|
||||||
|
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"
|
||||||
|
|
||||||
@ -61,58 +62,75 @@ func NewVsCodeWebService(config *VSCodeWebConfig) *VSCodeWeb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup runs the installScript which downloads the required version of the code-server binary.
|
// Setup runs the installScript which downloads the required version of the code-server binary.
|
||||||
func (v *VSCodeWeb) Setup(ctx context.Context, exec *devcontainer.Exec) ([]byte, error) {
|
func (v *VSCodeWeb) Setup(
|
||||||
output := "Installing VSCode Web inside container.\n"
|
ctx context.Context,
|
||||||
|
exec *devcontainer.Exec,
|
||||||
_, err := exec.ExecuteCommandInHomeDirectory(ctx, installScript, true, false)
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
|
) error {
|
||||||
|
gitspaceLogger.Info("Installing VSCode Web inside container.")
|
||||||
|
gitspaceLogger.Info("IDE setup output...")
|
||||||
|
outputCh := make(chan []byte)
|
||||||
|
err := exec.ExecuteCommandInHomeDirectory(ctx, installScript, true, false, outputCh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to install VSCode Web: %w", err)
|
return fmt.Errorf("failed to install VSCode Web: %w", err)
|
||||||
|
}
|
||||||
|
for chunk := range outputCh {
|
||||||
|
_, err := io.Discard.Write(chunk)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
findOutput, err := exec.ExecuteCommandInHomeDirectory(ctx, findPathScript, true, false)
|
findCh := make(chan []byte)
|
||||||
if err != nil {
|
err = exec.ExecuteCommandInHomeDirectory(ctx, findPathScript, true, false, findCh)
|
||||||
return nil, fmt.Errorf("failed to find VSCode Web install path: %w", err)
|
var findOutput []byte
|
||||||
|
|
||||||
|
for chunk := range findCh {
|
||||||
|
findOutput = append(findOutput, chunk...) // Concatenate each chunk of data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to find VSCode Web install path: %w", err)
|
||||||
|
}
|
||||||
path := string(findOutput)
|
path := string(findOutput)
|
||||||
startIndex := strings.Index(path, startMarker)
|
startIndex := strings.Index(path, startMarker)
|
||||||
endIndex := strings.Index(path, endMarker)
|
endIndex := strings.Index(path, endMarker)
|
||||||
if startIndex == -1 || endIndex == -1 || startIndex >= endIndex {
|
if startIndex == -1 || endIndex == -1 || startIndex >= endIndex {
|
||||||
return nil, fmt.Errorf("could not find media folder path from find output: %s", path)
|
return fmt.Errorf("could not find media folder path from find output: %s", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaFolderPath := path[startIndex+len(startMarker) : endIndex]
|
mediaFolderPath := path[startIndex+len(startMarker) : endIndex]
|
||||||
err = v.copyMediaToContainer(ctx, exec, mediaFolderPath)
|
err = v.copyMediaToContainer(ctx, exec, mediaFolderPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to copy media folder to container at path %s: %w", mediaFolderPath, err)
|
return fmt.Errorf("failed to copy media folder to container at path %s: %w", mediaFolderPath, err)
|
||||||
}
|
}
|
||||||
|
gitspaceLogger.Info("Successfully set up IDE inside container")
|
||||||
output += "Successfully installed VSCode Web inside container.\n"
|
return nil
|
||||||
|
|
||||||
return []byte(output), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run runs the code-server binary.
|
// Run runs the code-server binary.
|
||||||
func (v *VSCodeWeb) Run(ctx context.Context, exec *devcontainer.Exec) ([]byte, error) {
|
func (v *VSCodeWeb) Run(
|
||||||
var output []byte
|
ctx context.Context,
|
||||||
|
exec *devcontainer.Exec,
|
||||||
|
gitspaceLogger gitspaceTypes.GitspaceLogger) error {
|
||||||
runScript, err := template.GenerateScriptFromTemplate(
|
runScript, err := template.GenerateScriptFromTemplate(
|
||||||
templateRunVSCodeWeb, &template.RunVSCodeWebPayload{
|
templateRunVSCodeWeb, &template.RunVSCodeWebPayload{
|
||||||
Port: strconv.Itoa(v.config.Port),
|
Port: strconv.Itoa(v.config.Port),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"failed to generate scipt to run VSCode Web from template %s: %w",
|
"failed to generate scipt to run VSCode Web from template %s: %w",
|
||||||
templateRunVSCodeWeb,
|
templateRunVSCodeWeb,
|
||||||
err,
|
err,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
gitspaceLogger.Info("Starting IDE ...")
|
||||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, runScript, false, true)
|
outputCh := make(chan []byte)
|
||||||
|
err = exec.ExecuteCommandInHomeDirectory(ctx, runScript, false, false, outputCh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to run VSCode Web: %w", err)
|
return fmt.Errorf("failed to run VSCode Web: %w", err)
|
||||||
}
|
}
|
||||||
return output, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PortAndProtocol returns the port on which the code-server is listening.
|
// PortAndProtocol returns the port on which the code-server is listening.
|
||||||
|
@ -82,6 +82,10 @@ type SupportedOSDistributionPayload struct {
|
|||||||
OSInfoScript string
|
OSInfoScript string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SetEnvPayload struct {
|
||||||
|
EnvVariables string
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
err := LoadTemplates()
|
err := LoadTemplates()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
29
app/gitspace/orchestrator/template/templates/set_env.sh
Normal file
29
app/gitspace/orchestrator/template/templates/set_env.sh
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
VARIABLES={{ .EnvVariables }}
|
||||||
|
# Check if the script is run as root, as modifying /etc/profile requires root privileges
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
echo "This script must be run as root."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# Path to /etc/profile
|
||||||
|
PROFILE_FILE="/etc/profile"
|
||||||
|
# Process each line in the VARIABLES string
|
||||||
|
echo "$VARIABLES" | while IFS= read -r line; do
|
||||||
|
# Skip empty lines
|
||||||
|
[[ -z "$line" ]] && continue
|
||||||
|
|
||||||
|
# Extract the variable name and value
|
||||||
|
var_name="${line%%=*}" # Part before '='
|
||||||
|
var_value="${line#*=}" # Part after '='
|
||||||
|
|
||||||
|
# Create the export statement
|
||||||
|
export_statement="export $var_name=$var_value"
|
||||||
|
|
||||||
|
# Check if the variable is already present in /etc/profile
|
||||||
|
if ! grep -q "^export $var_name=" "$PROFILE_FILE"; then
|
||||||
|
echo "$export_statement" >> "$PROFILE_FILE"
|
||||||
|
echo "Added $export_statement to $PROFILE_FILE"
|
||||||
|
else
|
||||||
|
echo "$var_name is already present in $PROFILE_FILE"
|
||||||
|
fi
|
||||||
|
done
|
@ -18,9 +18,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
||||||
|
"github.com/harness/gitness/app/gitspace/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
// Manage manager the linux user in the container.
|
// Manage manager the linux user in the container.
|
||||||
Manage(ctx context.Context, exec *devcontainer.Exec) ([]byte, error)
|
Manage(ctx context.Context, exec *devcontainer.Exec, gitspaceLogger types.GitspaceLogger) error
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/harness/gitness/app/gitspace/orchestrator/common"
|
"github.com/harness/gitness/app/gitspace/orchestrator/common"
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
||||||
"github.com/harness/gitness/app/gitspace/orchestrator/template"
|
"github.com/harness/gitness/app/gitspace/orchestrator/template"
|
||||||
|
gitspaceTypes "github.com/harness/gitness/app/gitspace/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Service = (*ServiceImpl)(nil)
|
var _ Service = (*ServiceImpl)(nil)
|
||||||
@ -34,7 +35,11 @@ func NewUserServiceImpl() Service {
|
|||||||
return &ServiceImpl{}
|
return &ServiceImpl{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ServiceImpl) Manage(ctx context.Context, exec *devcontainer.Exec) ([]byte, error) {
|
func (u *ServiceImpl) Manage(
|
||||||
|
ctx context.Context,
|
||||||
|
exec *devcontainer.Exec,
|
||||||
|
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||||
|
) error {
|
||||||
osInfoScript := common.GetOSInfoScript()
|
osInfoScript := common.GetOSInfoScript()
|
||||||
script, err := template.GenerateScriptFromTemplate(
|
script, err := template.GenerateScriptFromTemplate(
|
||||||
templateManagerUser, &template.SetupUserPayload{
|
templateManagerUser, &template.SetupUserPayload{
|
||||||
@ -45,17 +50,18 @@ func (u *ServiceImpl) Manage(ctx context.Context, exec *devcontainer.Exec) ([]by
|
|||||||
OSInfoScript: osInfoScript,
|
OSInfoScript: osInfoScript,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
output := "Setting up user inside container\n"
|
gitspaceLogger.Info("Setting up user inside container")
|
||||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, true, false)
|
gitspaceLogger.Info("Managing user output...")
|
||||||
|
err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, script, true, gitspaceLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to setup user: %w", err)
|
return fmt.Errorf("failed to setup user: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
output += "Successfully setup user\n"
|
gitspaceLogger.Info("Successfully setup user")
|
||||||
|
|
||||||
return []byte(output), nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
|
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import "github.com/rs/zerolog"
|
import (
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
)
|
||||||
|
|
||||||
// NewZerologAdapter creates a new adapter from a zerolog.Logger.
|
// NewZerologAdapter creates a new adapter from a zerolog.Logger.
|
||||||
func NewZerologAdapter(logger *zerolog.Logger) *ZerologAdapter {
|
func NewZerologAdapter(logger *zerolog.Logger) *ZerologAdapter {
|
Loading…
x
Reference in New Issue
Block a user