mirror of
https://github.com/harness/drone.git
synced 2025-05-05 15:32:56 +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 (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
||||
"github.com/harness/gitness/app/gitspace/orchestrator/template"
|
||||
"github.com/harness/gitness/app/gitspace/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
|
||||
const templateSupportedOSDistribution = "supported_os_distribution.sh"
|
||||
const templateVsCodeWebToolsInstallation = "install_tools_vs_code_web.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.
|
||||
// For alpine wee need to install multiple things from
|
||||
// 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,
|
||||
})
|
||||
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)
|
||||
}
|
||||
|
||||
output, err := exec.ExecuteCommandInHomeDirectory(ctx, script, true, false)
|
||||
gitspaceLogger.Info("Validate supported OSes...")
|
||||
err = ExecuteCommandInHomeDirAndLog(ctx, exec, script, true, gitspaceLogger)
|
||||
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 {
|
||||
case enum.IDETypeVSCodeWeb:
|
||||
{
|
||||
output, err := InstallToolsForVsCodeWeb(ctx, exec)
|
||||
if err != nil {
|
||||
return []byte(output), err
|
||||
}
|
||||
return []byte(output), nil
|
||||
err := InstallToolsForVsCodeWeb(ctx, exec, gitspaceLogger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
case enum.IDETypeVSCode:
|
||||
{
|
||||
output, err := InstallToolsForVsCode(ctx, exec)
|
||||
if err != nil {
|
||||
return []byte(output), err
|
||||
}
|
||||
return []byte(output), nil
|
||||
err := InstallToolsForVsCode(ctx, exec, gitspaceLogger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
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(
|
||||
templateVsCodeWebToolsInstallation, &template.InstallToolsPayload{
|
||||
OSInfoScript: osDetectScript,
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf(
|
||||
return fmt.Errorf(
|
||||
"failed to generate scipt to install tools for vs code web from template %s: %w",
|
||||
templateVsCodeWebToolsInstallation, err)
|
||||
}
|
||||
|
||||
output := "Installing tools for vs code web inside container\n"
|
||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, true, false)
|
||||
gitspaceLogger.Info("Installing tools for vs code web inside container")
|
||||
gitspaceLogger.Info("Tools installation output...")
|
||||
err = ExecuteCommandInHomeDirAndLog(ctx, exec, script, true, gitspaceLogger)
|
||||
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)
|
||||
}
|
||||
|
||||
output += "Successfully installed tools for vs code web\n"
|
||||
|
||||
return output, nil
|
||||
gitspaceLogger.Info("Successfully installed tools for vs code web")
|
||||
return 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(
|
||||
templateVsCodeToolsInstallation, &template.InstallToolsPayload{
|
||||
OSInfoScript: osDetectScript,
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf(
|
||||
return fmt.Errorf(
|
||||
"failed to generate scipt to install tools for vs code from template %s: %w",
|
||||
templateVsCodeToolsInstallation, err)
|
||||
}
|
||||
|
||||
output := "Installing tools for vs code inside container\n"
|
||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, true, false)
|
||||
gitspaceLogger.Info("Installing tools for vs code in container")
|
||||
err = ExecuteCommandInHomeDirAndLog(ctx, exec, script, true, gitspaceLogger)
|
||||
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)
|
||||
}
|
||||
|
||||
output += "Successfully installed tools for vs code\n"
|
||||
|
||||
return output, nil
|
||||
gitspaceLogger.Info("Successfully installed tools for vs code")
|
||||
return 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"
|
||||
"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/docker/docker/api/types/container"
|
||||
@ -47,7 +47,7 @@ var containerStateMapping = map[string]State{
|
||||
}
|
||||
|
||||
// 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)
|
||||
return fmt.Errorf("%s: %w", msg, err)
|
||||
}
|
||||
@ -58,7 +58,7 @@ func ManageContainer(
|
||||
action Action,
|
||||
containerName string,
|
||||
dockerClient *client.Client,
|
||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
var err error
|
||||
switch action {
|
||||
@ -123,7 +123,7 @@ func CreateContainer(
|
||||
dockerClient *client.Client,
|
||||
imageName string,
|
||||
containerName string,
|
||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
bindMountSource string,
|
||||
bindMountTarget string,
|
||||
mountType mount.Type,
|
||||
@ -225,7 +225,7 @@ func PullImage(
|
||||
ctx context.Context,
|
||||
imageName string,
|
||||
dockerClient *client.Client,
|
||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
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/git"
|
||||
"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/scm"
|
||||
gitspaceTypes "github.com/harness/gitness/app/gitspace/types"
|
||||
"github.com/harness/gitness/types"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
)
|
||||
@ -34,11 +34,12 @@ import (
|
||||
func (e *EmbeddedDockerOrchestrator) setupGitspaceAndIDE(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
ideService ide.IDE,
|
||||
gitspaceConfig types.GitspaceConfig,
|
||||
resolvedRepoDetails scm.ResolvedDetails,
|
||||
defaultBaseImage string,
|
||||
environment []string,
|
||||
) error {
|
||||
homeDir := GetUserHomeDir(gitspaceConfig.GitspaceUser.Identifier)
|
||||
devcontainerConfig := resolvedRepoDetails.DevcontainerConfig
|
||||
@ -47,45 +48,49 @@ func (e *EmbeddedDockerOrchestrator) setupGitspaceAndIDE(
|
||||
// Register setup steps
|
||||
e.RegisterStep("Validate Supported OS", ValidateSupportedOS, true)
|
||||
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)
|
||||
}, 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",
|
||||
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)
|
||||
}, true)
|
||||
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)
|
||||
}, true)
|
||||
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)
|
||||
}, true)
|
||||
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)
|
||||
}, true)
|
||||
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 {
|
||||
return SetupGitCredentials(ctx, exec, resolvedRepoDetails, e.gitService, gitspaceLogger)
|
||||
}
|
||||
return nil
|
||||
}, true)
|
||||
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)
|
||||
}, true)
|
||||
|
||||
// Register the Execute Command steps (PostCreate and PostStart)
|
||||
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)
|
||||
return ExecuteCommand(ctx, exec, codeRepoDir, gitspaceLogger, command, PostCreateAction)
|
||||
}, false)
|
||||
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)
|
||||
return ExecuteCommand(ctx, exec, codeRepoDir, gitspaceLogger, command, PostStartAction)
|
||||
}, false)
|
||||
@ -100,27 +105,25 @@ func (e *EmbeddedDockerOrchestrator) setupGitspaceAndIDE(
|
||||
func InstallTools(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
ideType enum.IDEType,
|
||||
) error {
|
||||
output, err := common.InstallTools(ctx, exec, ideType)
|
||||
err := common.InstallTools(ctx, exec, ideType, gitspaceLogger)
|
||||
if err != nil {
|
||||
return logStreamWrapError(gitspaceLogger, "Error while installing tools inside container", err)
|
||||
}
|
||||
gitspaceLogger.Info("Tools installation output...\n" + string(output))
|
||||
return nil
|
||||
}
|
||||
|
||||
func ValidateSupportedOS(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
output, err := common.ValidateSupportedOS(ctx, exec)
|
||||
err := common.ValidateSupportedOS(ctx, exec, gitspaceLogger)
|
||||
if err != nil {
|
||||
return logStreamWrapError(gitspaceLogger, "Error while detecting OS inside container", err)
|
||||
}
|
||||
gitspaceLogger.Info("Validate supported OSes...\n" + string(output))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -128,7 +131,7 @@ func ExecuteCommand(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
codeRepoDir string,
|
||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
command string,
|
||||
actionType PostAction,
|
||||
) error {
|
||||
@ -137,12 +140,17 @@ func ExecuteCommand(
|
||||
return nil
|
||||
}
|
||||
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 {
|
||||
return logStreamWrapError(
|
||||
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))
|
||||
return nil
|
||||
}
|
||||
@ -153,13 +161,12 @@ func CloneCode(
|
||||
defaultBaseImage string,
|
||||
resolvedRepoDetails scm.ResolvedDetails,
|
||||
gitService git.Service,
|
||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
output, err := gitService.CloneCode(ctx, exec, resolvedRepoDetails, defaultBaseImage)
|
||||
err := gitService.CloneCode(ctx, exec, resolvedRepoDetails, defaultBaseImage, gitspaceLogger)
|
||||
if err != nil {
|
||||
return logStreamWrapError(gitspaceLogger, "Error while cloning code inside container", err)
|
||||
}
|
||||
gitspaceLogger.Info("Clone output...\n" + string(output))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -167,14 +174,12 @@ func InstallGit(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
gitService git.Service,
|
||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
output, err := gitService.Install(ctx, exec)
|
||||
err := gitService.Install(ctx, exec, gitspaceLogger)
|
||||
if err != nil {
|
||||
return logStreamWrapError(gitspaceLogger, "Error while installing git inside container", err)
|
||||
}
|
||||
|
||||
gitspaceLogger.Info("Install git output...\n" + string(output))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -183,15 +188,13 @@ func SetupGitCredentials(
|
||||
exec *devcontainer.Exec,
|
||||
resolvedRepoDetails scm.ResolvedDetails,
|
||||
gitService git.Service,
|
||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
output, err := gitService.SetupCredentials(ctx, exec, resolvedRepoDetails)
|
||||
err := gitService.SetupCredentials(ctx, exec, resolvedRepoDetails, gitspaceLogger)
|
||||
if err != nil {
|
||||
return logStreamWrapError(
|
||||
gitspaceLogger, "Error while setting up git credentials inside container", err)
|
||||
}
|
||||
|
||||
gitspaceLogger.Info("Setting up git credentials output...\n" + string(output))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -199,13 +202,12 @@ func ManageUser(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
userService user.Service,
|
||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
output, err := userService.Manage(ctx, exec)
|
||||
err := userService.Manage(ctx, exec, gitspaceLogger)
|
||||
if err != nil {
|
||||
return logStreamWrapError(gitspaceLogger, "Error while creating user inside container", err)
|
||||
}
|
||||
gitspaceLogger.Info("Managing user output...\n" + string(output))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -213,17 +215,13 @@ func SetupIDE(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
ideService ide.IDE,
|
||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
gitspaceLogger.Info("Setting up IDE inside container: " + string(ideService.Type()))
|
||||
|
||||
output, err := ideService.Setup(ctx, exec)
|
||||
err := ideService.Setup(ctx, exec, gitspaceLogger)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
@ -231,15 +229,27 @@ func RunIDE(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
ideService ide.IDE,
|
||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
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 {
|
||||
return logStreamWrapError(gitspaceLogger, "Error while running IDE inside container", err)
|
||||
}
|
||||
|
||||
gitspaceLogger.Info("IDE run output...\n" + string(output))
|
||||
gitspaceLogger.Info("Successfully run the IDE inside container")
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ import (
|
||||
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
||||
"github.com/harness/gitness/app/gitspace/orchestrator/git"
|
||||
"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/scm"
|
||||
gitspaceTypes "github.com/harness/gitness/app/gitspace/types"
|
||||
"github.com/harness/gitness/infraprovider"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
@ -41,7 +41,7 @@ const (
|
||||
)
|
||||
|
||||
type EmbeddedDockerOrchestrator struct {
|
||||
steps []orchestratorTypes.Step // Steps registry
|
||||
steps []gitspaceTypes.Step // Steps registry
|
||||
dockerClientFactory *infraprovider.DockerClientFactory
|
||||
statefulLogger *logutil.StatefulLogger
|
||||
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.
|
||||
func (e *EmbeddedDockerOrchestrator) RegisterStep(
|
||||
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,
|
||||
) {
|
||||
step := orchestratorTypes.Step{
|
||||
step := gitspaceTypes.Step{
|
||||
Name: name,
|
||||
Execute: execute,
|
||||
StopOnFailure: stopOnFailure,
|
||||
@ -66,7 +66,7 @@ func (e *EmbeddedDockerOrchestrator) RegisterStep(
|
||||
func (e *EmbeddedDockerOrchestrator) ExecuteSteps(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
for _, step := range e.steps {
|
||||
// Execute the step
|
||||
@ -378,7 +378,7 @@ func (e *EmbeddedDockerOrchestrator) runGitspaceSetupSteps(
|
||||
infrastructure types.Infrastructure,
|
||||
resolvedRepoDetails scm.ResolvedDetails,
|
||||
defaultBaseImage string,
|
||||
gitspaceLogger orchestratorTypes.GitspaceLogger,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
homeDir := GetUserHomeDir(gitspaceConfig.GitspaceUser.Identifier)
|
||||
containerName := GetGitspaceContainerName(gitspaceConfig)
|
||||
@ -450,6 +450,7 @@ func (e *EmbeddedDockerOrchestrator) runGitspaceSetupSteps(
|
||||
gitspaceConfig,
|
||||
resolvedRepoDetails,
|
||||
defaultBaseImage,
|
||||
environment,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -15,10 +15,13 @@
|
||||
package devcontainer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
@ -28,6 +31,7 @@ import (
|
||||
)
|
||||
|
||||
const RootUser = "root"
|
||||
const ErrMsgTCP = "unable to upgrade to tcp, received 200"
|
||||
|
||||
type Exec struct {
|
||||
ContainerName string
|
||||
@ -39,8 +43,8 @@ type Exec struct {
|
||||
}
|
||||
|
||||
type execResult struct {
|
||||
StdOut []byte
|
||||
StdErr []byte
|
||||
StdOut io.Reader
|
||||
StdErr io.Reader
|
||||
ExitCode int
|
||||
}
|
||||
|
||||
@ -50,49 +54,48 @@ func (e *Exec) ExecuteCommand(
|
||||
root bool,
|
||||
detach bool,
|
||||
workingDir string,
|
||||
) ([]byte, error) {
|
||||
outputCh chan []byte, // channel to stream output as []byte
|
||||
) error {
|
||||
user := e.UserIdentifier
|
||||
if root {
|
||||
user = RootUser
|
||||
}
|
||||
|
||||
cmd := []string{"/bin/sh", "-c", command}
|
||||
|
||||
execConfig := container.ExecOptions{
|
||||
User: user,
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
AttachStdout: !detach,
|
||||
AttachStderr: !detach,
|
||||
Cmd: cmd,
|
||||
Detach: detach,
|
||||
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 {
|
||||
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)
|
||||
if err != nil && err.Error() != "unable to upgrade to tcp, received 200" {
|
||||
return nil, fmt.Errorf("failed to start docker exec for container %s: %w", e.ContainerName, err)
|
||||
// Attach and inspect exec session to get the output
|
||||
inspectExec, err := e.attachAndInspectExec(ctx, containerExecCreate.ID, detach)
|
||||
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 {
|
||||
var errLog string
|
||||
if resp.StdErr != nil {
|
||||
errLog = string(resp.StdErr)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("error during command execution in container %s. exit code %d. log: %s",
|
||||
e.ContainerName, resp.ExitCode, errLog)
|
||||
// Wait for the exit code after the command completes
|
||||
if inspectExec != nil && inspectExec.ExitCode != 0 {
|
||||
return fmt.Errorf("error during command execution in container %s. exit code %d",
|
||||
e.ContainerName, inspectExec.ExitCode)
|
||||
}
|
||||
|
||||
var stdOutput []byte
|
||||
if resp != nil {
|
||||
stdOutput = resp.StdOut
|
||||
}
|
||||
|
||||
return stdOutput, nil
|
||||
e.streamResponse(inspectExec, outputCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Exec) ExecuteCommandInHomeDirectory(
|
||||
@ -100,55 +103,91 @@ func (e *Exec) ExecuteCommandInHomeDirectory(
|
||||
command string,
|
||||
root bool,
|
||||
detach bool,
|
||||
) ([]byte, error) {
|
||||
return e.ExecuteCommand(ctx, command, root, detach, e.HomeDir)
|
||||
outputCh chan []byte, // channel to stream output as []byte
|
||||
) error {
|
||||
return e.ExecuteCommand(ctx, command, root, detach, e.HomeDir, outputCh)
|
||||
}
|
||||
|
||||
func (e *Exec) attachAndInspectExec(ctx context.Context, id string, detach bool) (*execResult, error) {
|
||||
resp, attachErr := e.DockerClient.ContainerExecAttach(ctx, id, container.ExecStartOptions{Detach: detach})
|
||||
if attachErr != nil {
|
||||
return nil, 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()
|
||||
return nil, fmt.Errorf("failed to attach to exec session: %w", attachErr)
|
||||
}
|
||||
|
||||
stdout, err := io.ReadAll(&outBuf)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read stdout of exec for container %s: %w", e.ContainerName, err)
|
||||
// If in detach mode, we just need to close the connection, not process output
|
||||
if detach {
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read stderr of exec for container %s: %w", e.ContainerName, err)
|
||||
}
|
||||
// Create pipes for stdout and stderr
|
||||
stdoutPipe, stdoutWriter := io.Pipe()
|
||||
stderrPipe, stderrWriter := io.Pipe()
|
||||
|
||||
inspectRes, err := e.DockerClient.ContainerExecInspect(ctx, id)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to inspect exec for container %s: %w", e.ContainerName, err)
|
||||
}
|
||||
go e.copyOutput(resp.Reader, stdoutWriter, stderrWriter)
|
||||
|
||||
// Return the output streams and the response
|
||||
return &execResult{
|
||||
StdOut: stdout,
|
||||
StdErr: stderr,
|
||||
ExitCode: inspectRes.ExitCode,
|
||||
StdOut: stdoutPipe, // Pipe for stdout
|
||||
StdErr: stderrPipe, // Pipe for stderr
|
||||
}, 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/scm"
|
||||
"github.com/harness/gitness/app/gitspace/types"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
// 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(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
resolvedRepoDetails scm.ResolvedDetails,
|
||||
) ([]byte, error)
|
||||
gitspaceLogger types.GitspaceLogger,
|
||||
) error
|
||||
|
||||
// CloneCode clones the code and ensures devcontainer file is present.
|
||||
CloneCode(
|
||||
@ -38,5 +43,6 @@ type Service interface {
|
||||
exec *devcontainer.Exec,
|
||||
resolvedRepoDetails scm.ResolvedDetails,
|
||||
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/template"
|
||||
"github.com/harness/gitness/app/gitspace/scm"
|
||||
"github.com/harness/gitness/app/gitspace/types"
|
||||
)
|
||||
|
||||
var _ Service = (*ServiceImpl)(nil)
|
||||
@ -38,50 +39,52 @@ func NewGitServiceImpl() Service {
|
||||
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(
|
||||
templateGitInstallScript, &template.SetupGitInstallPayload{
|
||||
OSInfoScript: common.GetOSInfoScript(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
return fmt.Errorf(
|
||||
"failed to generate scipt to setup git install from template %s: %w", templateGitInstallScript, err)
|
||||
}
|
||||
output := "Setting up git inside container\n"
|
||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, true, false)
|
||||
gitspaceLogger.Info("Install git output...")
|
||||
gitspaceLogger.Info("Setting up git inside container")
|
||||
err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, script, true, gitspaceLogger)
|
||||
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 []byte(output), nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *ServiceImpl) SetupCredentials(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
resolvedRepoDetails scm.ResolvedDetails,
|
||||
) ([]byte, error) {
|
||||
gitspaceLogger types.GitspaceLogger,
|
||||
) error {
|
||||
script, err := template.GenerateScriptFromTemplate(
|
||||
templateSetupGitCredentials, &template.SetupGitCredentialsPayload{
|
||||
CloneURLWithCreds: resolvedRepoDetails.CloneURL,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
return fmt.Errorf(
|
||||
"failed to generate scipt to setup git credentials from template %s: %w", templateSetupGitCredentials, err)
|
||||
}
|
||||
|
||||
output := "Setting up git credentials inside container\n"
|
||||
|
||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, false, false)
|
||||
gitspaceLogger.Info("Setting up git credentials output...")
|
||||
gitspaceLogger.Info("Setting up git credentials inside container")
|
||||
err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, script, false, gitspaceLogger)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to setup git credentials: %w", err)
|
||||
return fmt.Errorf("failed to setup git credentials: %w", err)
|
||||
}
|
||||
|
||||
output += "Successfully setup git credentials\n"
|
||||
|
||||
return []byte(output), nil
|
||||
gitspaceLogger.Info("Successfully setup git credentials")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *ServiceImpl) CloneCode(
|
||||
@ -89,10 +92,11 @@ func (g *ServiceImpl) CloneCode(
|
||||
exec *devcontainer.Exec,
|
||||
resolvedRepoDetails scm.ResolvedDetails,
|
||||
defaultBaseImage string,
|
||||
) ([]byte, error) {
|
||||
gitspaceLogger types.GitspaceLogger,
|
||||
) error {
|
||||
cloneURL, err := url.Parse(resolvedRepoDetails.CloneURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
return fmt.Errorf(
|
||||
"failed to parse clone url %s: %w", resolvedRepoDetails.CloneURL, err)
|
||||
}
|
||||
cloneURL.User = nil
|
||||
@ -109,18 +113,16 @@ func (g *ServiceImpl) CloneCode(
|
||||
script, err := template.GenerateScriptFromTemplate(
|
||||
templateCloneCode, data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
return fmt.Errorf(
|
||||
"failed to generate scipt to clone code from template %s: %w", templateCloneCode, err)
|
||||
}
|
||||
|
||||
output := "Cloning code inside container\n"
|
||||
|
||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, false, false)
|
||||
gitspaceLogger.Info("Clone output...")
|
||||
gitspaceLogger.Info("Cloning code inside container")
|
||||
err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, script, false, gitspaceLogger)
|
||||
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 []byte(output), nil
|
||||
return nil
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
|
||||
"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/enum"
|
||||
)
|
||||
@ -25,10 +26,10 @@ import (
|
||||
type IDE interface {
|
||||
// Setup is responsible for doing all the operations for setting up the IDE in the container e.g. installation,
|
||||
// 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(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() *types.GitspacePort
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"github.com/harness/gitness/app/gitspace/orchestrator/common"
|
||||
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
||||
"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/enum"
|
||||
)
|
||||
@ -47,7 +48,8 @@ func NewVsCodeService(config *VSCodeConfig) *VSCode {
|
||||
func (v *VSCode) Setup(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
) ([]byte, error) {
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
osInfoScript := common.GetOSInfoScript()
|
||||
sshServerScript, err := template.GenerateScriptFromTemplate(
|
||||
templateSetupSSHServer, &template.SetupSSHServerPayload{
|
||||
@ -56,43 +58,43 @@ func (v *VSCode) Setup(
|
||||
OSInfoScript: osInfoScript,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
return fmt.Errorf(
|
||||
"failed to generate scipt to setup ssh server from template %s: %w", templateSetupSSHServer, err)
|
||||
}
|
||||
|
||||
output := "Installing ssh-server inside container\n"
|
||||
|
||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, sshServerScript, true, false)
|
||||
gitspaceLogger.Info("Installing ssh-server inside container")
|
||||
gitspaceLogger.Info("IDE setup output...")
|
||||
err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, sshServerScript, true, gitspaceLogger)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to setup SSH serverr: %w", err)
|
||||
return fmt.Errorf("failed to setup SSH serverr: %w", err)
|
||||
}
|
||||
|
||||
output += "Successfully installed ssh-server\n"
|
||||
|
||||
return []byte(output), nil
|
||||
gitspaceLogger.Info("Successfully installed ssh-server")
|
||||
gitspaceLogger.Info("Successfully set up IDE inside container")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run runs the SSH server inside the container.
|
||||
func (v *VSCode) Run(ctx context.Context, exec *devcontainer.Exec) ([]byte, error) {
|
||||
var output = ""
|
||||
|
||||
func (v *VSCode) Run(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger,
|
||||
) error {
|
||||
runSSHScript, err := template.GenerateScriptFromTemplate(
|
||||
templateRunSSHServer, &template.RunSSHServerPayload{
|
||||
Port: strconv.Itoa(v.config.Port),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
return fmt.Errorf(
|
||||
"failed to generate scipt to run ssh server from template %s: %w", templateRunSSHServer, err)
|
||||
}
|
||||
|
||||
execOutput, err := exec.ExecuteCommandInHomeDirectory(ctx, runSSHScript, true, false)
|
||||
gitspaceLogger.Info("SSH server run output...")
|
||||
err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, runSSHScript, true, gitspaceLogger)
|
||||
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 []byte(output), nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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/template"
|
||||
gitspaceTypes "github.com/harness/gitness/app/gitspace/types"
|
||||
"github.com/harness/gitness/types"
|
||||
"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.
|
||||
func (v *VSCodeWeb) Setup(ctx context.Context, exec *devcontainer.Exec) ([]byte, error) {
|
||||
output := "Installing VSCode Web inside container.\n"
|
||||
|
||||
_, err := exec.ExecuteCommandInHomeDirectory(ctx, installScript, true, false)
|
||||
func (v *VSCodeWeb) Setup(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
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 {
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find VSCode Web install path: %w", err)
|
||||
findCh := make(chan []byte)
|
||||
err = exec.ExecuteCommandInHomeDirectory(ctx, findPathScript, true, false, findCh)
|
||||
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)
|
||||
startIndex := strings.Index(path, startMarker)
|
||||
endIndex := strings.Index(path, endMarker)
|
||||
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]
|
||||
err = v.copyMediaToContainer(ctx, exec, mediaFolderPath)
|
||||
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)
|
||||
}
|
||||
|
||||
output += "Successfully installed VSCode Web inside container.\n"
|
||||
|
||||
return []byte(output), nil
|
||||
gitspaceLogger.Info("Successfully set up IDE inside container")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run runs the code-server binary.
|
||||
func (v *VSCodeWeb) Run(ctx context.Context, exec *devcontainer.Exec) ([]byte, error) {
|
||||
var output []byte
|
||||
|
||||
func (v *VSCodeWeb) Run(
|
||||
ctx context.Context,
|
||||
exec *devcontainer.Exec,
|
||||
gitspaceLogger gitspaceTypes.GitspaceLogger) error {
|
||||
runScript, err := template.GenerateScriptFromTemplate(
|
||||
templateRunVSCodeWeb, &template.RunVSCodeWebPayload{
|
||||
Port: strconv.Itoa(v.config.Port),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
return fmt.Errorf(
|
||||
"failed to generate scipt to run VSCode Web from template %s: %w",
|
||||
templateRunVSCodeWeb,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, runScript, false, true)
|
||||
gitspaceLogger.Info("Starting IDE ...")
|
||||
outputCh := make(chan []byte)
|
||||
err = exec.ExecuteCommandInHomeDirectory(ctx, runScript, false, false, outputCh)
|
||||
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.
|
||||
|
@ -82,6 +82,10 @@ type SupportedOSDistributionPayload struct {
|
||||
OSInfoScript string
|
||||
}
|
||||
|
||||
type SetEnvPayload struct {
|
||||
EnvVariables string
|
||||
}
|
||||
|
||||
func init() {
|
||||
err := LoadTemplates()
|
||||
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"
|
||||
|
||||
"github.com/harness/gitness/app/gitspace/orchestrator/devcontainer"
|
||||
"github.com/harness/gitness/app/gitspace/types"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
// 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/devcontainer"
|
||||
"github.com/harness/gitness/app/gitspace/orchestrator/template"
|
||||
gitspaceTypes "github.com/harness/gitness/app/gitspace/types"
|
||||
)
|
||||
|
||||
var _ Service = (*ServiceImpl)(nil)
|
||||
@ -34,7 +35,11 @@ func NewUserServiceImpl() Service {
|
||||
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()
|
||||
script, err := template.GenerateScriptFromTemplate(
|
||||
templateManagerUser, &template.SetupUserPayload{
|
||||
@ -45,17 +50,18 @@ func (u *ServiceImpl) Manage(ctx context.Context, exec *devcontainer.Exec) ([]by
|
||||
OSInfoScript: osInfoScript,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
return fmt.Errorf(
|
||||
"failed to generate scipt to manager user from template %s: %w", templateManagerUser, err)
|
||||
}
|
||||
|
||||
output := "Setting up user inside container\n"
|
||||
_, err = exec.ExecuteCommandInHomeDirectory(ctx, script, true, false)
|
||||
gitspaceLogger.Info("Setting up user inside container")
|
||||
gitspaceLogger.Info("Managing user output...")
|
||||
err = common.ExecuteCommandInHomeDirAndLog(ctx, exec, script, true, gitspaceLogger)
|
||||
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
|
||||
|
||||
import "github.com/rs/zerolog"
|
||||
import (
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
// NewZerologAdapter creates a new adapter from a zerolog.Logger.
|
||||
func NewZerologAdapter(logger *zerolog.Logger) *ZerologAdapter {
|
Loading…
x
Reference in New Issue
Block a user