diff --git a/app/gitspace/orchestrator/container/embedded_docker.go b/app/gitspace/orchestrator/container/embedded_docker.go index 436d739fc..a86edd3be 100644 --- a/app/gitspace/orchestrator/container/embedded_docker.go +++ b/app/gitspace/orchestrator/container/embedded_docker.go @@ -25,8 +25,9 @@ import ( "github.com/harness/gitness/app/gitspace/logutil" "github.com/harness/gitness/app/gitspace/orchestrator/devcontainer" + "github.com/harness/gitness/app/gitspace/orchestrator/git" "github.com/harness/gitness/app/gitspace/orchestrator/ide" - "github.com/harness/gitness/app/gitspace/orchestrator/template" + "github.com/harness/gitness/app/gitspace/orchestrator/user" "github.com/harness/gitness/app/gitspace/scm" "github.com/harness/gitness/infraprovider" "github.com/harness/gitness/types" @@ -43,29 +44,32 @@ import ( var _ Orchestrator = (*EmbeddedDockerOrchestrator)(nil) const ( - loggingKey = "gitspace.container" - catchAllIP = "0.0.0.0" - containerStateRunning = "running" - containerStateRemoved = "removed" - containerStateStopped = "exited" - templateCloneGit = "clone_git.sh" - templateAuthenticateGit = "authenticate_git.sh" - templateManageUser = "manage_user.sh" - mountType = mount.TypeVolume + loggingKey = "gitspace.container" + catchAllIP = "0.0.0.0" + containerStateRunning = "running" + containerStateRemoved = "removed" + containerStateStopped = "exited" + mountType = mount.TypeVolume ) type EmbeddedDockerOrchestrator struct { dockerClientFactory *infraprovider.DockerClientFactory statefulLogger *logutil.StatefulLogger + gitService git.Service + userService user.Service } func NewEmbeddedDockerOrchestrator( dockerClientFactory *infraprovider.DockerClientFactory, statefulLogger *logutil.StatefulLogger, + gitService git.Service, + userService user.Service, ) Orchestrator { return &EmbeddedDockerOrchestrator{ dockerClientFactory: dockerClientFactory, statefulLogger: statefulLogger, + gitService: gitService, + userService: userService, } } @@ -148,7 +152,7 @@ func (e *EmbeddedDockerOrchestrator) CreateAndStartGitspace( } if resolvedRepoDetails.Credentials != nil { - authErr := e.authenticateGit(ctx, exec, resolvedRepoDetails, codeRepoDir) + authErr := e.setupGitCredentials(ctx, exec, resolvedRepoDetails, logStreamInstance) if authErr != nil { return nil, authErr } @@ -285,6 +289,18 @@ func (e *EmbeddedDockerOrchestrator) startGitspace( return err } + err = e.installGit(ctx, exec, logStreamInstance) + if err != nil { + return err + } + + if resolvedRepoDetails.Credentials != nil { + err = e.setupGitCredentials(ctx, exec, resolvedRepoDetails, logStreamInstance) + if err != nil { + return err + } + } + err = e.cloneCode(ctx, exec, defaultBaseImage, resolvedRepoDetails, logStreamInstance) if err != nil { return err @@ -401,75 +417,77 @@ func (e *EmbeddedDockerOrchestrator) getContainerInfo( return inspectResp.ID, usedPorts, nil } -func (e *EmbeddedDockerOrchestrator) authenticateGit( - ctx context.Context, - exec *devcontainer.Exec, - resolvedRepoDetails scm.ResolvedDetails, - codeRepoDir string, -) error { - data := &template.AuthenticateGitPayload{ - Email: resolvedRepoDetails.Credentials.Email, - Name: resolvedRepoDetails.Credentials.Name, - Password: resolvedRepoDetails.Credentials.Password, - Host: resolvedRepoDetails.Credentials.Host, - Protocol: resolvedRepoDetails.Credentials.Protocol, - Path: resolvedRepoDetails.Credentials.Path, - } - gitAuthenticateScript, err := template.GenerateScriptFromTemplate( - templateAuthenticateGit, data) - if err != nil { - return fmt.Errorf("failed to generate scipt to authenticate git from template %s: %w", templateAuthenticateGit, err) - } - - _, err = exec.ExecuteCommand(ctx, gitAuthenticateScript, false, false, codeRepoDir) - if err != nil { - err = fmt.Errorf("failed to authenticate git in container: %w", err) - return err - } - - return nil -} - func (e *EmbeddedDockerOrchestrator) manageUser( ctx context.Context, exec *devcontainer.Exec, logStreamInstance *logutil.LogStreamInstance, ) error { - data := template.SetupUserPayload{ - Username: exec.UserIdentifier, - AccessKey: exec.AccessKey, - AccessType: exec.AccessType, - HomeDir: exec.HomeDir, - } - manageUserScript, err := template.GenerateScriptFromTemplate( - templateManageUser, data) + output, err := e.userService.Manage(ctx, exec) if err != nil { - return fmt.Errorf("failed to generate scipt to manage user from template %s: %w", templateManageUser, err) - } - loggingErr := logStreamInstance.Write( - "Creating user inside container: " + data.Username) - if loggingErr != nil { - return fmt.Errorf("logging error: %w", loggingErr) - } + loggingErr := logStreamInstance.Write("Error while creating user inside container: " + err.Error()) - output, err := exec.ExecuteCommandInHomeDirectory(ctx, manageUserScript, true, false) - if err != nil { - loggingErr = logStreamInstance.Write("Error while creating user inside container : " + err.Error()) - - err = fmt.Errorf("failed to create user: %w", err) + err = fmt.Errorf("failed to create user gitspace %s: %w", exec.ContainerName, err) if loggingErr != nil { err = fmt.Errorf("original error: %w; logging error: %w", err, loggingErr) } + return err } - loggingErr = logStreamInstance.Write("Managing user output...\n" + string(output)) + loggingErr := logStreamInstance.Write("Managing user output...\n" + string(output)) if loggingErr != nil { return fmt.Errorf("logging error: %w", loggingErr) } - loggingErr = logStreamInstance.Write("Successfully created user inside container") + return nil +} + +func (e *EmbeddedDockerOrchestrator) installGit( + ctx context.Context, + exec *devcontainer.Exec, + logStreamInstance *logutil.LogStreamInstance, +) error { + output, err := e.gitService.Install(ctx, exec) + if err != nil { + loggingErr := logStreamInstance.Write("Error while installing git inside container: " + err.Error()) + + err = fmt.Errorf("failed to install git for gitspace %s: %w", exec.ContainerName, err) + + if loggingErr != nil { + err = fmt.Errorf("original error: %w; logging error: %w", err, loggingErr) + } + + return err + } + + loggingErr := logStreamInstance.Write("Install git output...\n" + string(output)) + if loggingErr != nil { + return fmt.Errorf("logging error: %w", loggingErr) + } + + return nil +} +func (e *EmbeddedDockerOrchestrator) setupGitCredentials( + ctx context.Context, + exec *devcontainer.Exec, + resolvedRepoDetails scm.ResolvedDetails, + logStreamInstance *logutil.LogStreamInstance, +) error { + output, err := e.gitService.SetupCredentials(ctx, exec, resolvedRepoDetails) + if err != nil { + loggingErr := logStreamInstance.Write("Error while setting up git credentials inside container: " + err.Error()) + + err = fmt.Errorf("failed to setup git credentials for gitspace %s: %w", exec.ContainerName, err) + + if loggingErr != nil { + err = fmt.Errorf("original error: %w; logging error: %w", err, loggingErr) + } + + return err + } + + loggingErr := logStreamInstance.Write("Setting up git credentials output...\n" + string(output)) if loggingErr != nil { return fmt.Errorf("logging error: %w", loggingErr) } @@ -484,35 +502,11 @@ func (e *EmbeddedDockerOrchestrator) cloneCode( resolvedRepoDetails scm.ResolvedDetails, logStreamInstance *logutil.LogStreamInstance, ) error { - data := &template.CloneGitPayload{ - RepoURL: resolvedRepoDetails.CloneURL, - Image: defaultBaseImage, - Branch: resolvedRepoDetails.Branch, - RepoName: resolvedRepoDetails.RepoName, - } - if resolvedRepoDetails.Credentials != nil { - data.Email = resolvedRepoDetails.Credentials.Email - data.Name = resolvedRepoDetails.Credentials.Name - data.Password = resolvedRepoDetails.Credentials.Password - data.Host = resolvedRepoDetails.Credentials.Host - data.Protocol = resolvedRepoDetails.Credentials.Protocol - data.Path = resolvedRepoDetails.Credentials.Path - } - gitCloneScript, err := template.GenerateScriptFromTemplate(templateCloneGit, data) + output, err := e.gitService.CloneCode(ctx, exec, resolvedRepoDetails, defaultBaseImage) if err != nil { - return fmt.Errorf("failed to generate scipt to clone git from template %s: %w", templateCloneGit, err) - } - loggingErr := logStreamInstance.Write( - "Cloning git repo inside container: " + resolvedRepoDetails.CloneURL + " branch: " + resolvedRepoDetails.Branch) - if loggingErr != nil { - return fmt.Errorf("logging error: %w", loggingErr) - } + loggingErr := logStreamInstance.Write("Error while cloning code inside container: " + err.Error()) - output, err := exec.ExecuteCommandInHomeDirectory(ctx, gitCloneScript, false, false) - if err != nil { - loggingErr = logStreamInstance.Write("Error while cloning git repo inside container: " + err.Error()) - - err = fmt.Errorf("failed to clone code: %w", err) + err = fmt.Errorf("failed to clone code gitspace %s: %w", exec.ContainerName, err) if loggingErr != nil { err = fmt.Errorf("original error: %w; logging error: %w", err, loggingErr) @@ -521,12 +515,7 @@ func (e *EmbeddedDockerOrchestrator) cloneCode( return err } - loggingErr = logStreamInstance.Write("Cloning git repo output...\n" + string(output)) - if loggingErr != nil { - return fmt.Errorf("logging error: %w", loggingErr) - } - - loggingErr = logStreamInstance.Write("Successfully cloned git repo inside container") + loggingErr := logStreamInstance.Write("Clone output...\n" + string(output)) if loggingErr != nil { return fmt.Errorf("logging error: %w", loggingErr) } @@ -744,7 +733,7 @@ func (e *EmbeddedDockerOrchestrator) pullImage( } // StopGitspace stops a container. If it is removed, it returns an error. -func (e EmbeddedDockerOrchestrator) StopGitspace( +func (e *EmbeddedDockerOrchestrator) StopGitspace( ctx context.Context, gitspaceConfig types.GitspaceConfig, infra types.Infrastructure, @@ -804,7 +793,7 @@ func (e EmbeddedDockerOrchestrator) StopGitspace( return nil } -func (e EmbeddedDockerOrchestrator) stopContainer( +func (e *EmbeddedDockerOrchestrator) stopContainer( ctx context.Context, containerName string, dockerClient *client.Client, @@ -930,7 +919,7 @@ func (e *EmbeddedDockerOrchestrator) StopAndRemoveGitspace( return nil } -func (e EmbeddedDockerOrchestrator) removeContainer( +func (e *EmbeddedDockerOrchestrator) removeContainer( ctx context.Context, containerName string, dockerClient *client.Client, diff --git a/app/gitspace/orchestrator/container/wire.go b/app/gitspace/orchestrator/container/wire.go index 2ce5c3ab5..e51d082d7 100644 --- a/app/gitspace/orchestrator/container/wire.go +++ b/app/gitspace/orchestrator/container/wire.go @@ -16,6 +16,8 @@ package container import ( "github.com/harness/gitness/app/gitspace/logutil" + "github.com/harness/gitness/app/gitspace/orchestrator/git" + "github.com/harness/gitness/app/gitspace/orchestrator/user" "github.com/harness/gitness/infraprovider" "github.com/google/wire" @@ -28,9 +30,13 @@ var WireSet = wire.NewSet( func ProvideEmbeddedDockerOrchestrator( dockerClientFactory *infraprovider.DockerClientFactory, statefulLogger *logutil.StatefulLogger, + gitService git.Service, + userService user.Service, ) Orchestrator { return NewEmbeddedDockerOrchestrator( dockerClientFactory, statefulLogger, + gitService, + userService, ) } diff --git a/app/gitspace/orchestrator/git/git.go b/app/gitspace/orchestrator/git/git.go new file mode 100644 index 000000000..25b9d4233 --- /dev/null +++ b/app/gitspace/orchestrator/git/git.go @@ -0,0 +1,42 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package git + +import ( + "context" + + "github.com/harness/gitness/app/gitspace/orchestrator/devcontainer" + "github.com/harness/gitness/app/gitspace/scm" +) + +type Service interface { + // Install ensures git is installed in the container. + Install(ctx context.Context, exec *devcontainer.Exec) ([]byte, error) + + // SetupCredentials sets the user's git credentials inside the container. + SetupCredentials( + ctx context.Context, + exec *devcontainer.Exec, + resolvedRepoDetails scm.ResolvedDetails, + ) ([]byte, error) + + // CloneCode clones the code and ensures devcontainer file is present. + CloneCode( + ctx context.Context, + exec *devcontainer.Exec, + resolvedRepoDetails scm.ResolvedDetails, + defaultBaseImage string, + ) ([]byte, error) +} diff --git a/app/gitspace/orchestrator/git/git_impl.go b/app/gitspace/orchestrator/git/git_impl.go new file mode 100644 index 000000000..780611539 --- /dev/null +++ b/app/gitspace/orchestrator/git/git_impl.go @@ -0,0 +1,115 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package git + +import ( + "context" + "fmt" + + "github.com/harness/gitness/app/gitspace/orchestrator/devcontainer" + "github.com/harness/gitness/app/gitspace/orchestrator/template" + "github.com/harness/gitness/app/gitspace/scm" + + _ "embed" +) + +var _ Service = (*ServiceImpl)(nil) + +//go:embed script/install_git.sh +var installScript string + +const templateSetupGitCredentials = "setup_git_credentials.sh" // nolint:gosec +const templateCloneCode = "clone_code.sh" + +type ServiceImpl struct { +} + +func NewGitServiceImpl() Service { + return &ServiceImpl{} +} + +func (g *ServiceImpl) Install(ctx context.Context, exec *devcontainer.Exec) ([]byte, error) { + output := "Setting up git inside container\n" + + _, err := exec.ExecuteCommandInHomeDirectory(ctx, installScript, false, false) + if err != nil { + return nil, fmt.Errorf("failed to setup git: %w", err) + } + + output += "Successfully setup git\n" + + return []byte(output), nil +} + +func (g *ServiceImpl) SetupCredentials( + ctx context.Context, + exec *devcontainer.Exec, + resolvedRepoDetails scm.ResolvedDetails, +) ([]byte, error) { + script, err := template.GenerateScriptFromTemplate( + templateSetupGitCredentials, &template.SetupGitCredentialsPayload{ + Email: resolvedRepoDetails.Credentials.Email, + Name: resolvedRepoDetails.Credentials.Name, + Password: resolvedRepoDetails.Credentials.Password, + Host: resolvedRepoDetails.Credentials.Host, + Protocol: resolvedRepoDetails.Credentials.Protocol, + Path: resolvedRepoDetails.Credentials.Path, + }) + if err != nil { + return nil, 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) + if err != nil { + return nil, fmt.Errorf("failed to setup git credentials: %w", err) + } + + output += "Successfully setup git credentials\n" + + return []byte(output), nil +} + +func (g *ServiceImpl) CloneCode( + ctx context.Context, + exec *devcontainer.Exec, + resolvedRepoDetails scm.ResolvedDetails, + defaultBaseImage string, +) ([]byte, error) { + script, err := template.GenerateScriptFromTemplate( + templateCloneCode, &template.CloneCodePayload{ + RepoURL: resolvedRepoDetails.CloneURL, + Image: defaultBaseImage, + Branch: resolvedRepoDetails.Branch, + RepoName: resolvedRepoDetails.RepoName, + }) + if err != nil { + return nil, 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) + if err != nil { + return nil, fmt.Errorf("failed to clone code: %w", err) + } + + output += "Successfully clone code\n" + + return []byte(output), nil +} diff --git a/app/gitspace/orchestrator/git/script/install_git.sh b/app/gitspace/orchestrator/git/script/install_git.sh new file mode 100644 index 000000000..364252de6 --- /dev/null +++ b/app/gitspace/orchestrator/git/script/install_git.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +# Check if Git is installed +if ! command -v git >/dev/null 2>&1; then + echo "Git is not installed. Installing Git..." + apt-get update + apt-get install -y git +fi + +if ! command -v git >/dev/null 2>&1; then + echo "Git is not installed. Exiting..." + exit 1 +fi \ No newline at end of file diff --git a/app/gitspace/orchestrator/git/wire.go b/app/gitspace/orchestrator/git/wire.go new file mode 100644 index 000000000..e2e19d0c9 --- /dev/null +++ b/app/gitspace/orchestrator/git/wire.go @@ -0,0 +1,27 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package git + +import ( + "github.com/google/wire" +) + +var WireSet = wire.NewSet( + ProvideGitServiceImpl, +) + +func ProvideGitServiceImpl() Service { + return NewGitServiceImpl() +} diff --git a/app/gitspace/orchestrator/template/template.go b/app/gitspace/orchestrator/template/template.go index faab1a731..34555d34c 100644 --- a/app/gitspace/orchestrator/template/template.go +++ b/app/gitspace/orchestrator/template/template.go @@ -35,15 +35,14 @@ var ( scriptTemplates map[string]*template.Template ) -type CloneGitPayload struct { +type CloneCodePayload struct { RepoURL string Image string Branch string RepoName string - AuthenticateGitPayload } -type AuthenticateGitPayload struct { +type SetupGitCredentialsPayload struct { Email string Name string Password string diff --git a/app/gitspace/orchestrator/template/templates/clone_git.sh b/app/gitspace/orchestrator/template/templates/clone_code.sh similarity index 50% rename from app/gitspace/orchestrator/template/templates/clone_git.sh rename to app/gitspace/orchestrator/template/templates/clone_code.sh index bed988d75..537072559 100644 --- a/app/gitspace/orchestrator/template/templates/clone_git.sh +++ b/app/gitspace/orchestrator/template/templates/clone_code.sh @@ -5,42 +5,6 @@ image={{ .Image }} branch={{ .Branch }} repo_name={{ .RepoName }} -password={{ .Password }} -email={{ .Email }} -name={{ .Name }} -host={{ .Host }} -protocol={{ .Protocol }} -path={{ .Path }} - -# Check if Git is installed -if ! command -v git >/dev/null 2>&1; then - echo "Git is not installed. Installing Git..." - apt-get update - apt-get install -y git -fi - -if ! command -v git >/dev/null 2>&1; then - echo "Git is not installed. Exiting..." - exit 1 -fi -if [ -z "$password" ]; then - echo "setting up without credentials" -else - git config --global credential.helper 'cache --timeout=2592000' - git config --global user.email "$email" - git config --global user.name "$name" - touch .gitcontext - echo "host="$host >> .gitcontext - echo "protocol="$protocol >> .gitcontext - echo "path="$path >> .gitcontext - echo "username="$email >> .gitcontext - echo "password="$password >> .gitcontext - echo "" >> .gitcontext - - cat .gitcontext | git credential approve - rm .gitcontext -fi - # Clone the repository inside the working directory if it doesn't exist if [ ! -d "$HOME/$repo_name/.git" ]; then echo "Cloning the repository..." diff --git a/app/gitspace/orchestrator/template/templates/manage_user.sh b/app/gitspace/orchestrator/template/templates/manage_user.sh index 4b0793972..e23581315 100644 --- a/app/gitspace/orchestrator/template/templates/manage_user.sh +++ b/app/gitspace/orchestrator/template/templates/manage_user.sh @@ -1,7 +1,7 @@ #!/bin/sh username={{ .Username }} -accessKey={{ .AccessKey }} +accessKey="{{ .AccessKey }}" homeDir={{ .HomeDir }} accessType={{ .AccessType }} @@ -29,6 +29,10 @@ if [ "ssh_key" = "$accessType" ] ; then echo $accessKey > $homeDir/.ssh/authorized_keys chmod 600 $homeDir/.ssh/authorized_keys chown -R $username:$username $homeDir/.ssh -else + echo "$username:$username" | chpasswd +elif [ "user_credentials" = "$accessType" ] ; then echo "$username:$accessKey" | chpasswd +else + echo "Unsupported accessType $accessType" >&2 + exit 1 fi \ No newline at end of file diff --git a/app/gitspace/orchestrator/template/templates/authenticate_git.sh b/app/gitspace/orchestrator/template/templates/setup_git_credentials.sh similarity index 100% rename from app/gitspace/orchestrator/template/templates/authenticate_git.sh rename to app/gitspace/orchestrator/template/templates/setup_git_credentials.sh diff --git a/app/gitspace/orchestrator/user/user.go b/app/gitspace/orchestrator/user/user.go new file mode 100644 index 000000000..e9cfc11ed --- /dev/null +++ b/app/gitspace/orchestrator/user/user.go @@ -0,0 +1,26 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package user + +import ( + "context" + + "github.com/harness/gitness/app/gitspace/orchestrator/devcontainer" +) + +type Service interface { + // Manage manager the linux user in the container. + Manage(ctx context.Context, exec *devcontainer.Exec) ([]byte, error) +} diff --git a/app/gitspace/orchestrator/user/user_impl.go b/app/gitspace/orchestrator/user/user_impl.go new file mode 100644 index 000000000..1370551c5 --- /dev/null +++ b/app/gitspace/orchestrator/user/user_impl.go @@ -0,0 +1,58 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package user + +import ( + "context" + "fmt" + + "github.com/harness/gitness/app/gitspace/orchestrator/devcontainer" + "github.com/harness/gitness/app/gitspace/orchestrator/template" +) + +var _ Service = (*ServiceImpl)(nil) + +const templateManagerUser = "manage_user.sh" + +type ServiceImpl struct { +} + +func NewUserServiceImpl() Service { + return &ServiceImpl{} +} + +func (u *ServiceImpl) Manage(ctx context.Context, exec *devcontainer.Exec) ([]byte, error) { + script, err := template.GenerateScriptFromTemplate( + templateManagerUser, &template.SetupUserPayload{ + Username: exec.UserIdentifier, + AccessKey: exec.AccessKey, + AccessType: exec.AccessType, + HomeDir: exec.HomeDir, + }) + if err != nil { + return nil, 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) + if err != nil { + return nil, fmt.Errorf("failed to setup user: %w", err) + } + + output += "Successfully setup user\n" + + return []byte(output), nil +} diff --git a/app/gitspace/orchestrator/user/wire.go b/app/gitspace/orchestrator/user/wire.go new file mode 100644 index 000000000..427f8c50b --- /dev/null +++ b/app/gitspace/orchestrator/user/wire.go @@ -0,0 +1,27 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package user + +import ( + "github.com/google/wire" +) + +var WireSet = wire.NewSet( + ProvideUserServiceImpl, +) + +func ProvideUserServiceImpl() Service { + return NewUserServiceImpl() +} diff --git a/app/services/gitspaceinfraevent/handler.go b/app/services/gitspaceinfraevent/handler.go index b1d92a43f..16e00fc2a 100644 --- a/app/services/gitspaceinfraevent/handler.go +++ b/app/services/gitspaceinfraevent/handler.go @@ -24,6 +24,8 @@ import ( "github.com/harness/gitness/events" "github.com/harness/gitness/types" "github.com/harness/gitness/types/enum" + + "github.com/rs/zerolog/log" ) func (s *Service) handleGitspaceInfraEvent( @@ -43,44 +45,49 @@ func (s *Service) handleGitspaceInfraEvent( switch payload.Type { case enum.InfraEventProvision: - updatedInstance, err := s.orchestrator.ResumeStartGitspace(ctx, *config, payload.Infra) - if err != nil { + updatedInstance, resumeStartErr := s.orchestrator.ResumeStartGitspace(ctx, *config, payload.Infra) + if resumeStartErr != nil { s.emitGitspaceConfigEvent(ctx, config, enum.GitspaceEventTypeGitspaceActionStartFailed) - return fmt.Errorf("failed to resume start gitspace: %w", err) + err = fmt.Errorf("failed to resume start gitspace: %w", resumeStartErr) } instance = &updatedInstance case enum.InfraEventStop: - instanceState, err := s.orchestrator.ResumeStopGitspace(ctx, *config, payload.Infra) - if err != nil { + instanceState, resumeStopErr := s.orchestrator.ResumeStopGitspace(ctx, *config, payload.Infra) + if resumeStopErr != nil { s.emitGitspaceConfigEvent(ctx, config, enum.GitspaceEventTypeGitspaceActionStopFailed) - return fmt.Errorf("failed to resume stop gitspace: %w", err) + err = fmt.Errorf("failed to resume stop gitspace: %w", resumeStopErr) } instance.State = instanceState case enum.InfraEventDeprovision: - instanceState, err := s.orchestrator.ResumeDeleteGitspace(ctx, *config, payload.Infra) - if err != nil { - return fmt.Errorf("failed to resume delete gitspace: %w", err) + instanceState, resumeDeleteErr := s.orchestrator.ResumeDeleteGitspace(ctx, *config, payload.Infra) + if resumeDeleteErr != nil { + err = fmt.Errorf("failed to resume delete gitspace: %w", resumeDeleteErr) + } else { + config.IsDeleted = true + updateErr := s.gitspaceSvc.UpdateConfig(ctx, config) + if updateErr != nil { + err = fmt.Errorf("failed to delete gitspace config with ID: %s %w", config.Identifier, updateErr) + } } instance.State = instanceState - - config.IsDeleted = true - if err = s.gitspaceSvc.UpdateConfig(ctx, config); err != nil { - return fmt.Errorf("failed to delete gitspace config with ID: %s %w", config.Identifier, err) - } - default: return fmt.Errorf("unknown event type: %s", event.Payload.Type) } - err = s.gitspaceSvc.UpdateInstance(ctx, instance) + + updateErr := s.gitspaceSvc.UpdateInstance(ctx, instance) + if updateErr != nil { + log.Err(updateErr).Msgf("failed to update gitspace instance") + } + if err != nil { - return fmt.Errorf("failed to update gitspace instance: %w", err) + log.Err(err).Msgf("error while handling gitspace infra event") } return nil diff --git a/cmd/gitness/wire.go b/cmd/gitness/wire.go index 3e49707ca..2446f791a 100644 --- a/cmd/gitness/wire.go +++ b/cmd/gitness/wire.go @@ -63,7 +63,9 @@ import ( "github.com/harness/gitness/app/gitspace/logutil" "github.com/harness/gitness/app/gitspace/orchestrator" containerorchestrator "github.com/harness/gitness/app/gitspace/orchestrator/container" + containerGit "github.com/harness/gitness/app/gitspace/orchestrator/git" "github.com/harness/gitness/app/gitspace/orchestrator/ide" + containerUser "github.com/harness/gitness/app/gitspace/orchestrator/user" "github.com/harness/gitness/app/gitspace/scm" gitspacesecret "github.com/harness/gitness/app/gitspace/secret" "github.com/harness/gitness/app/pipeline/canceler" @@ -264,6 +266,8 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e capabilities.WireSet, capabilitiesservice.WireSet, secretservice.WireSet, + containerGit.WireSet, + containerUser.WireSet, ) return &cliserver.System{}, nil } diff --git a/cmd/gitness/wire_gen.go b/cmd/gitness/wire_gen.go index b9c518377..d3d3df09b 100644 --- a/cmd/gitness/wire_gen.go +++ b/cmd/gitness/wire_gen.go @@ -52,7 +52,9 @@ import ( "github.com/harness/gitness/app/gitspace/logutil" "github.com/harness/gitness/app/gitspace/orchestrator" "github.com/harness/gitness/app/gitspace/orchestrator/container" + git2 "github.com/harness/gitness/app/gitspace/orchestrator/git" "github.com/harness/gitness/app/gitspace/orchestrator/ide" + user2 "github.com/harness/gitness/app/gitspace/orchestrator/user" "github.com/harness/gitness/app/gitspace/scm" secret2 "github.com/harness/gitness/app/gitspace/secret" "github.com/harness/gitness/app/pipeline/canceler" @@ -384,7 +386,9 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro infrastructureConfig := server.ProvideGitspaceInfraProvisionerConfig(config) infraProvisioner := infrastructure.ProvideInfraProvisionerService(infraProviderConfigStore, infraProviderResourceStore, factory, infraProviderTemplateStore, infraProvisionedStore, infrastructureConfig) statefulLogger := logutil.ProvideStatefulLogger(logStream) - containerOrchestrator := container.ProvideEmbeddedDockerOrchestrator(dockerClientFactory, statefulLogger) + gitService := git2.ProvideGitServiceImpl() + userService := user2.ProvideUserServiceImpl() + containerOrchestrator := container.ProvideEmbeddedDockerOrchestrator(dockerClientFactory, statefulLogger, gitService, userService) orchestratorConfig := server.ProvideGitspaceOrchestratorConfig(config) vsCodeConfig := server.ProvideIDEVSCodeConfig(config) vsCode := ide.ProvideVSCodeService(vsCodeConfig)