Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add podman remote support #61

Merged
merged 13 commits into from
May 4, 2024
3 changes: 3 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ type Podman struct {
// The initial integer that is the starting point for a
// Random Number Generator's algorithm.
RngSeed int64 `json:"rngSeed"`
// Specify the optional --connection parameter for podman
RuntimeContext *string `json:"runtimeContext"`
}

// Deployment contains the information about deploying the plugin.
Expand All @@ -45,6 +47,7 @@ type Deployment struct {
HostConfig *container.HostConfig `json:"host"`
ImagePullPolicy ImagePullPolicy `json:"imagePullPolicy"`
ImagePlatform *string `json:"imagePlatform"`
RuntimeContext *string `json:"runtimeContext"`
}

// Timeouts drive the timeouts for various interactions in relation to Docker.
Expand Down
6 changes: 5 additions & 1 deletion factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ func (f factory) Create(config *Config, logger log.Logger) (deployer.Connector,
if err != nil {
return &Connector{}, fmt.Errorf("podman binary check failed with error: %w", err)
}
podman := cliwrapper.NewCliWrapper(podmanPath, logger)
runtimeContext := ""
if config.Podman.RuntimeContext != nil {
runtimeContext = *config.Podman.RuntimeContext
}
podman := cliwrapper.NewCliWrapper(podmanPath, logger, runtimeContext)

var rngSeed int64
if config.Podman.RngSeed == 0 {
Expand Down
89 changes: 50 additions & 39 deletions internal/cliwrapper/cliwrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,18 @@ import (
type cliWrapper struct {
podmanFullPath string
logger log.Logger
runtimeContext []string
ewchong marked this conversation as resolved.
Show resolved Hide resolved
}

func NewCliWrapper(fullPath string, logger log.Logger) CliWrapper {
func NewCliWrapper(fullPath string, logger log.Logger, context string) CliWrapper {
// Specify podman --connection string if provided
if context != "" {
context = "--connection=" + context
}
ewchong marked this conversation as resolved.
Show resolved Hide resolved
return &cliWrapper{
podmanFullPath: fullPath,
logger: logger,
runtimeContext: []string{context},
}
}
webbnh marked this conversation as resolved.
Show resolved Hide resolved

Expand All @@ -33,50 +39,32 @@ func (p *cliWrapper) decorateImageName(image string) string {
}

func (p *cliWrapper) ImageExists(image string) (*bool, error) {
image = p.decorateImageName(image)
cmd := exec.Command(p.podmanFullPath, "image", "ls", "--format", "{{.Repository}}:{{.Tag}}") //nolint:gosec
var out bytes.Buffer
var errOut bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &errOut
p.logger.Debugf("Checking whether image exists with command %v", cmd.Args)
if err := cmd.Run(); err != nil {
return nil, fmt.Errorf(
"error while determining if image exists. Stdout: '%s', Stderr: '%s', Cmd error: (%w)",
out.String(), errOut.String(), err)
outStr, err := p.runPodmanCmd(
"checking whether image exists",
"image", "ls", "--format", "{{.Repository}}:{{.Tag}}",
)
if err != nil {
return nil, err
}
outStr := out.String()
outSlice := strings.Split(outStr, "\n")
exists := util.SliceContains(outSlice, image)
exists := util.SliceContains(outSlice, p.decorateImageName(image))
return &exists, nil
}

func (p *cliWrapper) PullImage(image string, platform *string) error {
commandArgs := []string{"pull"}
if platform != nil {
commandArgs = append(commandArgs, []string{"--platform", *platform}...)
commandArgs = append(commandArgs, "--platform", *platform)
}
image = p.decorateImageName(image)
commandArgs = append(commandArgs, image)
cmd := exec.Command(p.podmanFullPath, commandArgs...) //nolint:gosec
p.logger.Debugf("Pulling image with command %v", cmd.Args)
var out bytes.Buffer
var errOut bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &errOut
if err := cmd.Run(); err != nil {
return fmt.Errorf(
"error while pulling image. Stdout: '%s', Stderr: '%s', Cmd error: (%w)",
out.String(), errOut.String(), err)
}
return nil
commandArgs = append(commandArgs, p.decorateImageName(image))
_, err := p.runPodmanCmd("pulling image", commandArgs...)
return err
}

func (p *cliWrapper) Deploy(image string, podmanArgs []string, containerArgs []string) (io.WriteCloser, io.ReadCloser, error) {
image = p.decorateImageName(image)
podmanArgs = append(podmanArgs, image)
podmanArgs = append(podmanArgs, p.decorateImageName(image))
podmanArgs = append(podmanArgs, containerArgs...)
deployCommand := exec.Command(p.podmanFullPath, podmanArgs...) //nolint:gosec
deployCommand := p.getPodmanCmd(podmanArgs...)
p.logger.Debugf("Deploying with command %v", deployCommand.Args)
stdin, err := deployCommand.StdinPipe()
if err != nil {
Expand All @@ -93,22 +81,45 @@ func (p *cliWrapper) Deploy(image string, podmanArgs []string, containerArgs []s
}

func (p *cliWrapper) KillAndClean(containerName string) error {
cmdKill := exec.Command(p.podmanFullPath, "kill", containerName) //nolint:gosec
cmdKill := p.getPodmanCmd("kill", containerName)
p.logger.Debugf("Killing with command %v", cmdKill.Args)
if err := cmdKill.Run(); err != nil {
p.logger.Warningf("failed to kill pod %s, probably the execution terminated earlier", containerName)
} else {
p.logger.Warningf("successfully killed container %s", containerName)
}

var cmdRmContainerStderr bytes.Buffer
cmdRmContainer := exec.Command(p.podmanFullPath, "rm", "--force", containerName) //nolint:gosec
p.logger.Debugf("Removing container with command %v", cmdRmContainer.Args)
cmdRmContainer.Stderr = &cmdRmContainerStderr
if err := cmdRmContainer.Run(); err != nil {
p.logger.Errorf("failed to remove container %s: %s", containerName, cmdRmContainerStderr.String())
msg := "removing container " + containerName
_, err := p.runPodmanCmd(msg, "rm", "--force", containerName)
if err != nil {
p.logger.Errorf(err.Error())
} else {
p.logger.Infof("successfully removed container %s", containerName)
}
return nil
}

func (p *cliWrapper) getPodmanCmd(cmdArgs ...string) *exec.Cmd {
var commandArgs []string
if len(p.runtimeContext) > 0 && p.runtimeContext[0] != "" {
commandArgs = append(commandArgs, p.runtimeContext...)
}
ewchong marked this conversation as resolved.
Show resolved Hide resolved
commandArgs = append(commandArgs, cmdArgs...)
return exec.Command(p.podmanFullPath, commandArgs...) //#nosec G204 -- command line is internally generated
}

func (p *cliWrapper) runPodmanCmd(msg string, cmdArgs ...string) (string, error) {
var out bytes.Buffer
var errOut bytes.Buffer

cmd := p.getPodmanCmd(cmdArgs...)
cmd.Stdout = &out
cmd.Stderr = &errOut
p.logger.Debugf(msg+" with command %v", cmd.Args)
if err := cmd.Run(); err != nil {
return "", fmt.Errorf(
"error while %s. Stdout: '%s', Stderr: '%s', Cmd error: (%w)",
msg, strings.TrimSpace(out.String()), strings.TrimSpace(errOut.String()), err)
}
return out.String(), nil
}
4 changes: 2 additions & 2 deletions internal/cliwrapper/cliwrapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func TestPodman_ImageExists(t *testing.T) {
logger := log.NewTestLogger(t)
tests.RemoveImage(logger, tests.TestImage)

podman := NewCliWrapper(tests.GetPodmanPath(), logger)
podman := NewCliWrapper(tests.GetPodmanPath(), logger, "")

assert.NotNil(t, tests.GetPodmanPath())

Expand Down Expand Up @@ -52,7 +52,7 @@ func TestPodman_PullImage(t *testing.T) {
logger := log.NewTestLogger(t)
tests.RemoveImage(logger, tests.TestImageMultiPlatform)

podman := NewCliWrapper(tests.GetPodmanPath(), logger)
podman := NewCliWrapper(tests.GetPodmanPath(), logger, "")
ewchong marked this conversation as resolved.
Show resolved Hide resolved
assert.NotNil(t, tests.GetPodmanPath())

// pull without platform
Expand Down
10 changes: 10 additions & 0 deletions schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ var Schema = schema.NewTypedScopeSchema[*Config](
nil,
nil,
),
"runtimeContext": schema.NewPropertySchema(
schema.NewStringSchema(nil, nil, nil),
schema.NewDisplayValue(schema.PointerTo("Connection"), schema.PointerTo("Connection to use for remote podman"), nil),
false,
nil,
nil,
nil,
nil,
nil,
),
},
),
schema.NewStructMappedObjectSchema[Deployment](
Expand Down
Loading