drone/app/gitspace/orchestrator/devcontainer/exec.go
Ansuman Satapathy 2f3b6a6f85 feat: [CDE-177]: Update listing page for CDE (#2506)
* feat: [CDE-207]: Fixed typecheck (#2513)

* feat: [CDE-207]: remove currentUserInfo app prop
* Merge branch 'CDE-207-FixTypeCheck' of https://git0.harness.io/l7B_kbSEQD2wjrM7PShm5w/PROD/Harness_Commons/gitness into CDE-207-FixTypeCheck
* feat: [CDE-207]: remove currentUserInfo app prop
* feat: [CDE-207]: Fixed typecheck
* feat: [CDE-207]: Fixed typecheck
* feat: [CDE-207]: Fixed typecheck
* feat: [CDE-207]: Fixed typecheck
* fix lint errors (#2520)

* add copyright header
* add copyright header
* fix lint errors
* feat: [CDE-192]: mark stuck actions as error
* feat: [CDE-192]: mark stuck actions as error
* feat: [CDE-192]: mark stuck actions as error
* feat: [CDE-192]: fix gitspace instance store
* Merge remote-tracking branch 'origin/main' into CDE-New
* add secret resolver in gitness (#2493)

* rename identifier to space identifier
* update factory method
* remove access_key from gitspace table
* add access key and type to devcontainer exec
* add migration for gitspace access key ref
* fix error message for resolver factory
* update resolver interface
* add secret resolver in gitness
* feat: [CDE-192]: correctly update date and sync update
* Merge remote-tracking branch 'origin/main' into CDE-New

# Conflicts:
#	app/api/controller/gitspace/action.go
#	app/api/controller/gitspace/delete.go
* feat: [CDE-192]: correctly update dates for updated
* feat: [CDE-192]: handle empty inputparams
* feat: [CDE-192]: handle empty inputparams
* Merge remote-tracking branch 'origin/main' into CDE-New
* Merge remote-tracking branch 'origin/main' into CDE-New
* feat: [CDE-207]: Use SCM api hook (#2499)

* feat: [CDE-207]: Updated Strings
* feat: [CDE-207]: Use SCM api hook
* feat: fixed string issue (#2476)

* feat: [CDE-211]: fixed lint issues
* feat: [CDE-211]: fixed lint issues
* feat: fixed string issue
* feat: fixed string issue (#2474)

* feat: fixed string issue
* add ssh identifier in map functions in gitness store
* add ssh fields in types
* feat: fixed GitspaceCodeRepoType in create payload
* feat: updated common hooks
* feat: update for listing
* feat: update for listing
* feat: removed cde folder
* feat: [CDE-177]: Update listing page for CDE
2024-08-16 06:46:02 +00:00

155 lines
3.7 KiB
Go

// 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 devcontainer
import (
"bytes"
"context"
"fmt"
"io"
"github.com/harness/gitness/types/enum"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/docker/docker/pkg/stdcopy"
)
const RootUser = "root"
type Exec struct {
ContainerName string
DockerClient *client.Client
HomeDir string
UserIdentifier string
AccessKey string
AccessType enum.GitspaceAccessType
}
type execResult struct {
StdOut []byte
StdErr []byte
ExitCode int
}
func (e *Exec) ExecuteCommand(
ctx context.Context,
command string,
root bool,
detach bool,
workingDir string,
) ([]byte, error) {
user := e.UserIdentifier
if root {
user = RootUser
}
cmd := []string{"/bin/sh", "-c", command}
execConfig := container.ExecOptions{
User: user,
AttachStdout: true,
AttachStderr: true,
Cmd: cmd,
Detach: detach,
WorkingDir: workingDir,
}
execID, 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)
}
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)
}
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)
}
var stdOutput []byte
if resp != nil {
stdOutput = resp.StdOut
}
return stdOutput, nil
}
func (e *Exec) ExecuteCommandInHomeDirectory(
ctx context.Context,
command string,
root bool,
detach bool,
) ([]byte, error) {
return e.ExecuteCommand(ctx, command, root, detach, e.HomeDir)
}
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()
}
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)
}
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)
}
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)
}
return &execResult{
StdOut: stdout,
StdErr: stderr,
ExitCode: inspectRes.ExitCode,
}, nil
}