From 3c0147e55916335ea605972999c594fdf52716e8 Mon Sep 17 00:00:00 2001 From: baude Date: Thu, 11 Apr 2019 14:42:28 -0500 Subject: podman-remote start enable the ability to start containers from the remote-client. also, enable start integration tests for remote testing. Signed-off-by: baude --- cmd/podman/commands.go | 2 - cmd/podman/container.go | 1 + cmd/podman/main.go | 1 + cmd/podman/shared/intermediate_varlink.go | 14 +++- cmd/podman/start.go | 104 ++---------------------------- pkg/adapter/containers.go | 97 ++++++++++++++++++++++++++++ pkg/adapter/containers_remote.go | 66 ++++++++++++++----- test/e2e/search_test.go | 2 +- test/e2e/start_test.go | 2 - 9 files changed, 166 insertions(+), 123 deletions(-) diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go index 0e5deb627..1a2da86cf 100644 --- a/cmd/podman/commands.go +++ b/cmd/podman/commands.go @@ -22,7 +22,6 @@ func getMainCommands() []*cobra.Command { _refreshCommand, _restartCommand, _searchCommand, - _startCommand, _statsCommand, _topCommand, _unpauseCommand, @@ -57,7 +56,6 @@ func getContainerSubCommands() []*cobra.Command { _restartCommand, _restoreCommand, _runlabelCommand, - _startCommand, _statsCommand, _stopCommand, _topCommand, diff --git a/cmd/podman/container.go b/cmd/podman/container.go index 39c4f0c5d..1477d158f 100644 --- a/cmd/podman/container.go +++ b/cmd/podman/container.go @@ -61,6 +61,7 @@ var ( _logsCommand, _runCommand, _rmCommand, + _startCommand, _waitCommand, } ) diff --git a/cmd/podman/main.go b/cmd/podman/main.go index e8c3e14ea..2748df5f5 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -59,6 +59,7 @@ var mainCommands = []*cobra.Command{ _versionCommand, _waitCommand, imageCommand.Command, + _startCommand, systemCommand.Command, } diff --git a/cmd/podman/shared/intermediate_varlink.go b/cmd/podman/shared/intermediate_varlink.go index 95a0d6287..d62a65955 100644 --- a/cmd/podman/shared/intermediate_varlink.go +++ b/cmd/podman/shared/intermediate_varlink.go @@ -4,8 +4,10 @@ package shared import ( "fmt" + "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/varlink" + "github.com/containers/libpod/pkg/rootless" "github.com/pkg/errors" ) @@ -318,6 +320,12 @@ func VarlinkCreateToGeneric(opts iopodman.Create) GenericCLIResults { // We do not get a default network over varlink. Unlike the other default values for some cli // elements, it seems it gets set to the default anyway. + var memSwapDefault int64 = -1 + netModeDefault := "bridge" + if rootless.IsRootless() { + netModeDefault = "slirp4netns" + } + m := make(map[string]GenericCLIResult) m["add-host"] = stringSliceFromVarlink(opts.AddHost, "add-host", nil) m["annotation"] = stringSliceFromVarlink(opts.Annotation, "annotation", nil) @@ -374,10 +382,10 @@ func VarlinkCreateToGeneric(opts iopodman.Create) GenericCLIResults { m["memory"] = stringFromVarlink(opts.Memory, "memory", nil) m["memory-reservation"] = stringFromVarlink(opts.MemoryReservation, "memory-reservation", nil) m["memory-swap"] = stringFromVarlink(opts.MemorySwap, "memory-swap", nil) - m["memory-swappiness"] = int64FromVarlink(opts.MemorySwappiness, "memory-swappiness", nil) + m["memory-swappiness"] = int64FromVarlink(opts.MemorySwappiness, "memory-swappiness", &memSwapDefault) m["name"] = stringFromVarlink(opts.Name, "name", nil) - m["net"] = stringFromVarlink(opts.Net, "net", nil) - m["network"] = stringFromVarlink(opts.Network, "network", nil) + m["net"] = stringFromVarlink(opts.Net, "net", &netModeDefault) + m["network"] = stringFromVarlink(opts.Network, "network", &netModeDefault) m["no-hosts"] = boolFromVarlink(opts.NoHosts, "no-hosts", false) m["oom-kill-disable"] = boolFromVarlink(opts.OomKillDisable, "oon-kill-disable", false) m["oom-score-adj"] = intFromVarlink(opts.OomScoreAdj, "oom-score-adj", nil) diff --git a/cmd/podman/start.go b/cmd/podman/start.go index ec05ce90e..9f93061f9 100644 --- a/cmd/podman/start.go +++ b/cmd/podman/start.go @@ -1,16 +1,11 @@ package main import ( - "fmt" - "os" - "github.com/containers/libpod/cmd/podman/cliconfig" - "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/adapter" - opentracing "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go" "github.com/pkg/errors" - "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -48,7 +43,7 @@ func init() { } func startCmd(c *cliconfig.StartValues) error { - if c.Bool("trace") { + if !remoteclient && c.Bool("trace") { span, _ := opentracing.StartSpanFromContext(Ctx, "startCmd") defer span.Finish() } @@ -70,100 +65,11 @@ func startCmd(c *cliconfig.StartValues) error { return errors.Wrapf(libpod.ErrInvalidArg, "you cannot use sig-proxy without --attach") } - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(&c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } defer runtime.Shutdown(false) - if c.Latest { - lastCtr, err := runtime.GetLatestContainer() - if err != nil { - return errors.Wrapf(err, "unable to get latest container") - } - args = append(args, lastCtr.ID()) - } - - ctx := getContext() - - var lastError error - for _, container := range args { - ctr, err := runtime.LookupContainer(container) - if err != nil { - if lastError != nil { - fmt.Fprintln(os.Stderr, lastError) - } - lastError = errors.Wrapf(err, "unable to find container %s", container) - continue - } - - ctrState, err := ctr.State() - if err != nil { - return errors.Wrapf(err, "unable to get container state") - } - - ctrRunning := ctrState == libpod.ContainerStateRunning - - if attach { - inputStream := os.Stdin - if !c.Interactive { - inputStream = nil - } - - // attach to the container and also start it not already running - // If the container is in a pod, also set to recursively start dependencies - err = adapter.StartAttachCtr(ctx, ctr, os.Stdout, os.Stderr, inputStream, c.DetachKeys, sigProxy, !ctrRunning, ctr.PodID() != "") - if errors.Cause(err) == libpod.ErrDetach { - // User manually detached - // Exit cleanly immediately - exitCode = 0 - return nil - } - - if ctrRunning { - return err - } - - if err != nil { - return errors.Wrapf(err, "unable to start container %s", ctr.ID()) - } - - if ecode, err := ctr.Wait(); err != nil { - if errors.Cause(err) == libpod.ErrNoSuchCtr { - // The container may have been removed - // Go looking for an exit file - rtc, err := runtime.GetConfig() - if err != nil { - return err - } - ctrExitCode, err := adapter.ReadExitFile(rtc.TmpDir, ctr.ID()) - if err != nil { - logrus.Errorf("Cannot get exit code: %v", err) - exitCode = 127 - } else { - exitCode = ctrExitCode - } - } - } else { - exitCode = int(ecode) - } - - return nil - } - if ctrRunning { - fmt.Println(ctr.ID()) - continue - } - // Handle non-attach start - // If the container is in a pod, also set to recursively start dependencies - if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil { - if lastError != nil { - fmt.Fprintln(os.Stderr, lastError) - } - lastError = errors.Wrapf(err, "unable to start container %q", container) - continue - } - fmt.Println(container) - } - - return lastError + exitCode, err = runtime.Start(getContext(), c, sigProxy) + return err } diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go index 931c55a57..063ecfbfb 100644 --- a/pkg/adapter/containers.go +++ b/pkg/adapter/containers.go @@ -510,3 +510,100 @@ func (r *LocalRuntime) Restore(c *cliconfig.RestoreValues, options libpod.Contai } return lastError } + +// Start will start a container +func (r *LocalRuntime) Start(ctx context.Context, c *cliconfig.StartValues, sigProxy bool) (int, error) { + var ( + exitCode = 125 + lastError error + ) + + args := c.InputArgs + if c.Latest { + lastCtr, err := r.GetLatestContainer() + if err != nil { + return 0, errors.Wrapf(err, "unable to get latest container") + } + args = append(args, lastCtr.ID()) + } + + for _, container := range args { + ctr, err := r.LookupContainer(container) + if err != nil { + if lastError != nil { + fmt.Fprintln(os.Stderr, lastError) + } + lastError = errors.Wrapf(err, "unable to find container %s", container) + continue + } + + ctrState, err := ctr.State() + if err != nil { + return exitCode, errors.Wrapf(err, "unable to get container state") + } + + ctrRunning := ctrState == libpod.ContainerStateRunning + + if c.Attach { + inputStream := os.Stdin + if !c.Interactive { + inputStream = nil + } + + // attach to the container and also start it not already running + // If the container is in a pod, also set to recursively start dependencies + err = StartAttachCtr(ctx, ctr.Container, os.Stdout, os.Stderr, inputStream, c.DetachKeys, sigProxy, !ctrRunning, ctr.PodID() != "") + if errors.Cause(err) == libpod.ErrDetach { + // User manually detached + // Exit cleanly immediately + exitCode = 0 + return exitCode, nil + } + + if ctrRunning { + return 0, err + } + + if err != nil { + return exitCode, errors.Wrapf(err, "unable to start container %s", ctr.ID()) + } + + if ecode, err := ctr.Wait(); err != nil { + if errors.Cause(err) == libpod.ErrNoSuchCtr { + // The container may have been removed + // Go looking for an exit file + rtc, err := r.GetConfig() + if err != nil { + return 0, err + } + ctrExitCode, err := ReadExitFile(rtc.TmpDir, ctr.ID()) + if err != nil { + logrus.Errorf("Cannot get exit code: %v", err) + exitCode = 127 + } else { + exitCode = ctrExitCode + } + } + } else { + exitCode = int(ecode) + } + + return exitCode, nil + } + if ctrRunning { + fmt.Println(ctr.ID()) + continue + } + // Handle non-attach start + // If the container is in a pod, also set to recursively start dependencies + if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil { + if lastError != nil { + fmt.Fprintln(os.Stderr, lastError) + } + lastError = errors.Wrapf(err, "unable to start container %q", container) + continue + } + fmt.Println(container) + } + return exitCode, lastError +} diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go index 50cff9fa0..d5314c382 100644 --- a/pkg/adapter/containers_remote.go +++ b/pkg/adapter/containers_remote.go @@ -327,22 +327,12 @@ func (r *LocalRuntime) Log(c *cliconfig.LogsValues, options *libpod.LogOptions) // CreateContainer creates a container from the cli over varlink func (r *LocalRuntime) CreateContainer(ctx context.Context, c *cliconfig.CreateValues) (string, error) { - if !c.Bool("detach") { - // TODO need to add attach when that function becomes available - return "", errors.New("the remote client only supports detached containers") - } results := shared.NewIntermediateLayer(&c.PodmanCommand, true) return iopodman.CreateContainer().Call(r.Conn, results.MakeVarlink()) } // Run creates a container overvarlink and then starts it func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode int) (int, error) { - // FIXME - // podman-remote run -it alpine ls DOES NOT WORK YET - // podman-remote run -it alpine /bin/sh does, i suspect there is some sort of - // timing issue between the socket availability and terminal setup and the command - // being run. - // TODO the exit codes for run need to be figured out for remote connections results := shared.NewIntermediateLayer(&c.PodmanCommand, true) cid, err := iopodman.CreateContainer().Call(r.Conn, results.MakeVarlink()) @@ -354,8 +344,7 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode fmt.Println(cid) return 0, err } - - errChan, err := r.attach(ctx, os.Stdin, os.Stdout, cid, true) + errChan, err := r.attach(ctx, os.Stdin, os.Stdout, cid, true, c.String("detach-keys")) if err != nil { return 0, err } @@ -367,7 +356,7 @@ func ReadExitFile(runtimeTmp, ctrID string) (int, error) { return 0, libpod.ErrNotImplemented } -// Ps ... +// Ps lists containers based on criteria from user func (r *LocalRuntime) Ps(c *cliconfig.PsValues, opts shared.PsOptions) ([]shared.PsContainerOutput, error) { var psContainers []shared.PsContainerOutput last := int64(c.Last) @@ -439,7 +428,7 @@ func (r *LocalRuntime) Ps(c *cliconfig.PsValues, opts shared.PsOptions) ([]share return psContainers, nil } -func (r *LocalRuntime) attach(ctx context.Context, stdin, stdout *os.File, cid string, start bool) (chan error, error) { +func (r *LocalRuntime) attach(ctx context.Context, stdin, stdout *os.File, cid string, start bool, detachKeys string) (chan error, error) { var ( oldTermState *term.State ) @@ -470,7 +459,7 @@ func (r *LocalRuntime) attach(ctx context.Context, stdin, stdout *os.File, cid s } // TODO add detach keys support - _, err = iopodman.Attach().Send(r.Conn, varlink.Upgrade, cid, "", start) + _, err = iopodman.Attach().Send(r.Conn, varlink.Upgrade, cid, detachKeys, start) if err != nil { restoreTerminal(oldTermState) return nil, err @@ -531,7 +520,7 @@ func (r *LocalRuntime) Attach(ctx context.Context, c *cliconfig.AttachValues) er if c.NoStdin { inputStream = nil } - errChan, err := r.attach(ctx, inputStream, os.Stdout, c.InputArgs[0], false) + errChan, err := r.attach(ctx, inputStream, os.Stdout, c.InputArgs[0], false, c.DetachKeys) if err != nil { return err } @@ -609,3 +598,48 @@ func (r *LocalRuntime) Restore(c *cliconfig.RestoreValues, options libpod.Contai } return lastError } + +// Start starts an already created container +func (r *LocalRuntime) Start(ctx context.Context, c *cliconfig.StartValues, sigProxy bool) (int, error) { + var ( + finalErr error + exitCode = 125 + ) + // TODO Figure out how to deal with exit codes + inputStream := os.Stdin + if !c.Interactive { + inputStream = nil + } + + containerIDs, err := iopodman.GetContainersByContext().Call(r.Conn, false, c.Latest, c.InputArgs) + if err != nil { + return exitCode, err + } + if len(containerIDs) < 1 { + return exitCode, errors.New("failed to find containers to start") + } + // start.go makes sure that if attach, there can be only one ctr + if c.Attach { + errChan, err := r.attach(ctx, inputStream, os.Stdout, containerIDs[0], true, c.DetachKeys) + if err != nil { + return exitCode, nil + } + err = <-errChan + return 0, err + } + + // TODO the notion of starting a pod container and its deps still needs to be worked through + // Everything else is detached + for _, cid := range containerIDs { + reply, err := iopodman.StartContainer().Call(r.Conn, cid) + if err != nil { + if finalErr != nil { + fmt.Println(err) + } + finalErr = err + } else { + fmt.Println(reply) + } + } + return exitCode, finalErr +} diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go index 61d581c6d..72b083de8 100644 --- a/test/e2e/search_test.go +++ b/test/e2e/search_test.go @@ -344,7 +344,7 @@ registries = ['{{.Host}}:{{.Port}}']` defer lock8.Unlock() podmanTest.RestoreArtifact(registry) - registryLocal := podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%s:5000", registryEndpoints[7].Port), + registryLocal := podmanTest.Podman([]string{"run", "-d", "--net=host", "-p", fmt.Sprintf("%s:5000", registryEndpoints[7].Port), "--name", "registry7", registry}) registryLocal.WaitWithDefaultTimeout() Expect(registryLocal.ExitCode()).To(Equal(0)) diff --git a/test/e2e/start_test.go b/test/e2e/start_test.go index 28f1c2393..c92da9777 100644 --- a/test/e2e/start_test.go +++ b/test/e2e/start_test.go @@ -1,5 +1,3 @@ -// +build !remoteclient - package integration import ( -- cgit v1.2.3-54-g00ecf