diff options
-rw-r--r-- | cmd/podman/cliconfig/config.go | 4 | ||||
-rw-r--r-- | cmd/podman/main_remote.go | 6 | ||||
-rw-r--r-- | cmd/podman/shared/intermediate_varlink.go | 3 | ||||
-rw-r--r-- | cmd/podman/varlink.go | 34 | ||||
-rw-r--r-- | cmd/podman/version.go | 50 | ||||
-rw-r--r-- | docs/podman-create.1.md | 2 | ||||
-rw-r--r-- | docs/podman-run.1.md | 2 | ||||
-rw-r--r-- | docs/podman-varlink.1.md | 19 | ||||
-rw-r--r-- | libpod/runtime_pod_linux.go | 126 | ||||
-rw-r--r-- | pkg/adapter/client.go | 35 | ||||
-rw-r--r-- | pkg/adapter/client_config.go | 4 | ||||
-rw-r--r-- | pkg/adapter/containers.go | 7 | ||||
-rw-r--r-- | pkg/adapter/runtime.go | 8 | ||||
-rw-r--r-- | pkg/adapter/runtime_remote.go | 50 | ||||
-rw-r--r-- | pkg/varlinkapi/attach.go | 1 | ||||
-rw-r--r-- | pkg/varlinkapi/system.go | 17 | ||||
-rw-r--r-- | test/e2e/negative_test.go | 38 | ||||
-rw-r--r-- | test/e2e/version_test.go | 4 | ||||
-rw-r--r-- | vendor.conf | 2 | ||||
-rw-r--r-- | vendor/github.com/varlink/go/varlink/bridge.go | 11 | ||||
-rw-r--r-- | vendor/github.com/varlink/go/varlink/bridge_windows.go | 11 |
21 files changed, 325 insertions, 109 deletions
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go index b770aaca0..aaa4513d8 100644 --- a/cmd/podman/cliconfig/config.go +++ b/cmd/podman/cliconfig/config.go @@ -32,6 +32,10 @@ type MainFlags struct { CpuProfile string LogLevel string TmpDir string + + RemoteUserName string + RemoteHost string + VarlinkAddress string } type AttachValues struct { diff --git a/cmd/podman/main_remote.go b/cmd/podman/main_remote.go index 753730b56..c8bb3ad3e 100644 --- a/cmd/podman/main_remote.go +++ b/cmd/podman/main_remote.go @@ -9,7 +9,11 @@ import ( const remote = true func init() { - // remote client specific flags can go here. + rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteUserName, "username", "", "username on the remote host") + rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteHost, "remote-host", "", "remote host") + // TODO maybe we allow the altering of this for bridge connections? + //rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.VarlinkAddress, "varlink-address", adapter.DefaultAddress, "address of the varlink socket") + rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.LogLevel, "log-level", "error", "Log messages above specified level: debug, info, warn, error, fatal or panic") } func setSyslog() error { diff --git a/cmd/podman/shared/intermediate_varlink.go b/cmd/podman/shared/intermediate_varlink.go index 5e21245e3..4742d4909 100644 --- a/cmd/podman/shared/intermediate_varlink.go +++ b/cmd/podman/shared/intermediate_varlink.go @@ -3,8 +3,6 @@ package shared import ( - "fmt" - "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/varlink" "github.com/containers/libpod/pkg/rootless" @@ -209,7 +207,6 @@ func boolFromVarlink(v *bool, flagName string, defaultValue bool) CRBool { cr.Val = defaultValue cr.Changed = false } else { - fmt.Println(flagName, cr.Val) cr.Val = *v cr.Changed = true } diff --git a/cmd/podman/varlink.go b/cmd/podman/varlink.go index 978678a84..215542d2c 100644 --- a/cmd/podman/varlink.go +++ b/cmd/podman/varlink.go @@ -3,11 +3,17 @@ package main import ( + "fmt" + "os" + "path/filepath" "time" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/libpodruntime" iopodman "github.com/containers/libpod/cmd/podman/varlink" + "github.com/containers/libpod/pkg/adapter" + "github.com/containers/libpod/pkg/rootless" + "github.com/containers/libpod/pkg/util" "github.com/containers/libpod/pkg/varlinkapi" "github.com/containers/libpod/version" "github.com/pkg/errors" @@ -45,13 +51,31 @@ func init() { } func varlinkCmd(c *cliconfig.VarlinkValues) error { - args := c.InputArgs - if len(args) < 1 { - return errors.Errorf("you must provide a varlink URI") + varlinkURI := adapter.DefaultAddress + if rootless.IsRootless() { + xdg, err := util.GetRootlessRuntimeDir() + if err != nil { + return err + } + socketDir := filepath.Join(xdg, "podman/io.podman") + if _, err := os.Stat(filepath.Dir(socketDir)); os.IsNotExist(err) { + if err := os.Mkdir(filepath.Dir(socketDir), 0755); err != nil { + return err + } + } + varlinkURI = fmt.Sprintf("unix:%s", socketDir) } + args := c.InputArgs + if len(args) > 1 { - return errors.Errorf("too many arguments. Requires exactly 1") + return errors.Errorf("too many arguments. you may optionally provide 1") + } + + if len(args) > 0 { + varlinkURI = args[0] } + + logrus.Debugf("Using varlink socket: %s", varlinkURI) timeout := time.Duration(c.Timeout) * time.Millisecond // Create a single runtime for varlink @@ -81,7 +105,7 @@ func varlinkCmd(c *cliconfig.VarlinkValues) error { } // Run the varlink server at the given address - if err = service.Listen(args[0], timeout); err != nil { + if err = service.Listen(varlinkURI, timeout); err != nil { switch err.(type) { case varlink.ServiceTimeoutError: logrus.Infof("varlink service expired (use --timeout to increase session time beyond %d ms, 0 means never timeout)", c.Int64("timeout")) diff --git a/cmd/podman/version.go b/cmd/podman/version.go index e964bdbb5..439a1cca6 100644 --- a/cmd/podman/version.go +++ b/cmd/podman/version.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "io" "os" "strings" "text/tabwriter" @@ -10,6 +11,7 @@ import ( "github.com/containers/buildah/pkg/formats" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/libpod" + "github.com/containers/libpod/pkg/adapter" "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -38,7 +40,7 @@ func init() { // versionCmd gets and prints version info for version command func versionCmd(c *cliconfig.VersionValues) error { - output, err := libpod.GetVersion() + clientVersion, err := libpod.GetVersion() if err != nil { errors.Wrapf(err, "unable to determine version") } @@ -51,25 +53,49 @@ func versionCmd(c *cliconfig.VersionValues) error { var out formats.Writer switch versionOutputFormat { case formats.JSONString: - out = formats.JSONStruct{Output: output} + out = formats.JSONStruct{Output: clientVersion} default: - out = formats.StdoutTemplate{Output: output, Template: versionOutputFormat} + out = formats.StdoutTemplate{Output: clientVersion, Template: versionOutputFormat} } return formats.Writer(out).Out() } w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) defer w.Flush() - fmt.Fprintf(w, "Version:\t%s\n", output.Version) - fmt.Fprintf(w, "RemoteAPI Version:\t%d\n", output.RemoteAPIVersion) - fmt.Fprintf(w, "Go Version:\t%s\n", output.GoVersion) - if output.GitCommit != "" { - fmt.Fprintf(w, "Git Commit:\t%s\n", output.GitCommit) + + if remote { + fmt.Fprintf(w, "Client:\n") + } + formatVersion(w, clientVersion) + + if remote { + fmt.Fprintf(w, "\nService:\n") + + runtime, err := adapter.GetRuntime(getContext(), nil) + if err != nil { + return errors.Wrapf(err, "could not get runtime") + } + defer runtime.Shutdown(false) + + serviceVersion, err := runtime.GetVersion() + if err != nil { + return err + } + formatVersion(w, serviceVersion) + } + return nil +} + +func formatVersion(writer io.Writer, version libpod.Version) { + fmt.Fprintf(writer, "Version:\t%s\n", version.Version) + fmt.Fprintf(writer, "RemoteAPI Version:\t%d\n", version.RemoteAPIVersion) + fmt.Fprintf(writer, "Go Version:\t%s\n", version.GoVersion) + if version.GitCommit != "" { + fmt.Fprintf(writer, "Git Commit:\t%s\n", version.GitCommit) } // Prints out the build time in readable format - if output.Built != 0 { - fmt.Fprintf(w, "Built:\t%s\n", time.Unix(output.Built, 0).Format(time.ANSIC)) + if version.Built != 0 { + fmt.Fprintf(writer, "Built:\t%s\n", time.Unix(version.Built, 0).Format(time.ANSIC)) } - fmt.Fprintf(w, "OS/Arch:\t%s\n", output.OsArch) - return nil + fmt.Fprintf(writer, "OS/Arch:\t%s\n", version.OsArch) } diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md index da5750209..cf36106e8 100644 --- a/docs/podman-create.1.md +++ b/docs/podman-create.1.md @@ -592,7 +592,7 @@ Automatically remove the container when it exits. The default is *false*. Note that the container will not be removed when it could not be created or started successfully. This allows the user to inspect the container after -failure. The `--rm` flag is incompatible with the `-d` flag. +failure. **--rootfs** diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md index 00b1a70c6..1840e0f0b 100644 --- a/docs/podman-run.1.md +++ b/docs/podman-run.1.md @@ -614,7 +614,7 @@ Automatically remove the container when it exits. The default is *false*. Note that the container will not be removed when it could not be created or started successfully. This allows the user to inspect the container after -failure. The `--rm` flag is incompatible with the `-d` flag. +failure. **--rootfs** diff --git a/docs/podman-varlink.1.md b/docs/podman-varlink.1.md index 7eeb3dd66..0501d853f 100644 --- a/docs/podman-varlink.1.md +++ b/docs/podman-varlink.1.md @@ -7,8 +7,10 @@ podman\-varlink - Runs the varlink backend interface **podman varlink** [*options*] *uri* ## DESCRIPTION -Starts the varlink service listening on *uri* that allows varlink clients to interact with podman. This should generally be done -with systemd. See _Configuration_ below. +Starts the varlink service listening on *uri* that allows varlink clients to interact with podman. If no *uri* is provided, a default +URI will be used depending on the user calling the varlink service. The default for the root user is `unix:/run/podman/io.podman`. Regular +users will have a default *uri* of `$XDG_RUNTIME_DIR/podman/io.podman`. For example, `unix:/run/user/1000/podman/io.podman` +The varlink service should generally be done with systemd. See _Configuration_ below. ## GLOBAL OPTIONS @@ -23,16 +25,23 @@ second. A value of `0` means no timeout and the session will not expire. ## EXAMPLES -Run the podman varlink service manually and accept the default timeout. +Run the podman varlink service accepting all default options. ``` -$ podman varlink unix:/run/podman/io.podman +$ podman varlink +``` + + +Run the podman varlink service with an alternate URI and accept the default timeout. + +``` +$ podman varlink unix:/tmp/io.podman ``` Run the podman varlink service manually with a 5 second timeout. ``` -$ podman varlink --timeout 5000 unix:/run/podman/io.podman +$ podman varlink --timeout 5000 ``` ## CONFIGURATION diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go index 0011c771a..5867b1f87 100644 --- a/libpod/runtime_pod_linux.go +++ b/libpod/runtime_pod_linux.go @@ -149,10 +149,10 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) } // Go through and lock all containers so we can operate on them all at once - dependencies := make(map[string][]string) for _, ctr := range ctrs { - ctr.lock.Lock() - defer ctr.lock.Unlock() + ctrLock := ctr.lock + ctrLock.Lock() + defer ctrLock.Unlock() // Sync all containers if err := ctr.syncContainer(); err != nil { @@ -177,23 +177,12 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) if len(ctr.state.ExecSessions) != 0 && !force { return errors.Wrapf(ErrCtrStateInvalid, "pod %s contains container %s which has active exec sessions", p.ID(), ctr.ID()) } - - deps, err := r.state.ContainerInUse(ctr) - if err != nil { - return err - } - dependencies[ctr.ID()] = deps } - // Check if containers have dependencies - // If they do, and the dependencies are not in the pod, error - for ctr, deps := range dependencies { - for _, dep := range deps { - if _, ok := dependencies[dep]; !ok { - return errors.Wrapf(ErrCtrExists, "container %s depends on container %s not in pod %s", ctr, dep, p.ID()) - } - } - } + // We maintain the invariant that container dependencies must all exist + // within the container's pod. + // No need to check dependencies as such - we're removing all containers + // in the pod at once, no dependency issues. // First loop through all containers and stop them // Do not remove in this loop to ensure that we don't remove unless all @@ -220,18 +209,40 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) } } - // Start removing containers - // We can remove containers even if they have dependencies now - // As we have guaranteed their dependencies are in the pod + // Remove all containers in the pod from the state. + if err := r.state.RemovePodContainers(p); err != nil { + return err + } + + var removalErr error + + // Clean up after our removed containers. + // Errors here are nonfatal - the containers have already been evicted. + // We'll do our best to clean up after them, but we have to keep going + // and remove the pod as well. + // From here until we remove the pod from the state, no error returns. for _, ctr := range ctrs { + // The container no longer exists in the state, mark invalid. + ctr.valid = false + + ctr.newContainerEvent(events.Remove) + // Clean up network namespace, cgroups, mounts if err := ctr.cleanup(ctx); err != nil { - return err + if removalErr == nil { + removalErr = err + } else { + logrus.Errorf("Unable to clean up container %s: %v", ctr.ID(), err) + } } // Stop container's storage if err := ctr.teardownStorage(); err != nil { - return err + if removalErr == nil { + removalErr = err + } else { + logrus.Errorf("Unable to tear down container %s storage: %v", ctr.ID(), err) + } } // Delete the container from runtime (only if we are not @@ -239,26 +250,24 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) if ctr.state.State != ContainerStateConfigured && ctr.state.State != ContainerStateExited { if err := ctr.delete(ctx); err != nil { - return err + if removalErr == nil { + removalErr = err + } else { + logrus.Errorf("Unable to remove container %s from OCI runtime: %v", ctr.ID(), err) + } } } // Free the container's lock if err := ctr.lock.Free(); err != nil { - return err + if removalErr == nil { + removalErr = errors.Wrapf(err, "error freeing container %s lock", ctr.ID()) + } else { + logrus.Errorf("Unable to free container %s lock: %v", ctr.ID(), err) + } } } - // Remove containers from the state - if err := r.state.RemovePodContainers(p); err != nil { - return err - } - - // Mark containers invalid - for _, ctr := range ctrs { - ctr.valid = false - } - // Remove pod cgroup, if present if p.state.CgroupPath != "" { logrus.Debugf("Removing pod cgroup %s", p.state.CgroupPath) @@ -266,10 +275,11 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) switch p.runtime.config.CgroupManager { case SystemdCgroupsManager: if err := deleteSystemdCgroup(p.state.CgroupPath); err != nil { - // The pod is already almost gone. - // No point in hard-failing if we fail - // this bit of cleanup. - logrus.Errorf("Error deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err) + if removalErr == nil { + removalErr = errors.Wrapf(err, "error removing pod %s cgroup", p.ID()) + } else { + logrus.Errorf("Error deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err) + } } case CgroupfsCgroupsManager: // Delete the cgroupfs cgroup @@ -280,34 +290,60 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) conmonCgroupPath := filepath.Join(p.state.CgroupPath, "conmon") conmonCgroup, err := cgroups.Load(v1CGroups, cgroups.StaticPath(conmonCgroupPath)) if err != nil && err != cgroups.ErrCgroupDeleted { - return err + if removalErr == nil { + removalErr = errors.Wrapf(err, "error retrieving pod %s conmon cgroup", p.ID()) + } else { + logrus.Debugf("Error retrieving pod %s conmon cgroup %s: %v", p.ID(), conmonCgroupPath, err) + } } if err == nil { if err := conmonCgroup.Delete(); err != nil { - logrus.Errorf("Error deleting pod %s conmon cgroup %s: %v", p.ID(), conmonCgroupPath, err) + if removalErr == nil { + removalErr = errors.Wrapf(err, "error removing pod %s conmon cgroup", p.ID()) + } else { + logrus.Errorf("Error deleting pod %s conmon cgroup %s: %v", p.ID(), conmonCgroupPath, err) + } } } cgroup, err := cgroups.Load(v1CGroups, cgroups.StaticPath(p.state.CgroupPath)) if err != nil && err != cgroups.ErrCgroupDeleted { - return err + if removalErr == nil { + removalErr = errors.Wrapf(err, "error retrieving pod %s cgroup", p.ID()) + } else { + logrus.Errorf("Error retrieving pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err) + } } if err == nil { if err := cgroup.Delete(); err != nil { - logrus.Errorf("Error deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err) + if removalErr == nil { + removalErr = errors.Wrapf(err, "error removing pod %s cgroup", p.ID()) + } else { + logrus.Errorf("Error deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err) + } } } default: - return errors.Wrapf(ErrInvalidArg, "unknown cgroups manager %s specified", p.runtime.config.CgroupManager) + // This should be caught much earlier, but let's still + // keep going so we make sure to evict the pod before + // ending up with an inconsistent state. + if removalErr == nil { + removalErr = errors.Wrapf(ErrInternal, "unrecognized cgroup manager %s when removing pod %s cgroups", p.runtime.config.CgroupManager, p.ID()) + } else { + logrus.Errorf("Unknown cgroups manager %s specified - cannot remove pod %s cgroup", p.runtime.config.CgroupManager, p.ID()) + } } } // Remove pod from state if err := r.state.RemovePod(p); err != nil { + if removalErr != nil { + logrus.Errorf("%v", removalErr) + } return err } // Mark pod invalid p.valid = false p.newPodEvent(events.Remove) - return nil + return removalErr } diff --git a/pkg/adapter/client.go b/pkg/adapter/client.go index 6512a5952..f672a92a6 100644 --- a/pkg/adapter/client.go +++ b/pkg/adapter/client.go @@ -3,30 +3,45 @@ package adapter import ( + "fmt" "os" - "github.com/sirupsen/logrus" + "github.com/pkg/errors" "github.com/varlink/go/varlink" ) -// DefaultAddress is the default address of the varlink socket -const DefaultAddress = "unix:/run/podman/io.podman" +type VarlinkConnectionInfo struct { + RemoteUserName string + RemoteHost string + VarlinkAddress string +} // Connect provides a varlink connection func (r RemoteRuntime) Connect() (*varlink.Connection, error) { - var err error - var connection *varlink.Connection - if bridge := os.Getenv("PODMAN_VARLINK_BRIDGE"); bridge != "" { - logrus.Infof("Connecting with varlink bridge") - logrus.Debugf("%s", bridge) + var ( + err error + connection *varlink.Connection + ) + + logLevel := r.cmd.LogLevel + + // I'm leaving this here for now as a document of the birdge format. It can be removed later once the bridge + // function is more flushed out. + //bridge := `ssh -T root@192.168.122.1 "/usr/bin/varlink -A '/usr/bin/podman varlink \$VARLINK_ADDRESS' bridge"` + if len(r.cmd.RemoteHost) > 0 { + // The user has provided a remote host endpoint + if len(r.cmd.RemoteUserName) < 1 { + return nil, errors.New("you must provide a username when providing a remote host name") + } + bridge := fmt.Sprintf(`ssh -T %s@%s /usr/bin/varlink -A \'/usr/bin/podman --log-level=%s varlink \\\$VARLINK_ADDRESS\' bridge`, r.cmd.RemoteUserName, r.cmd.RemoteHost, logLevel) + connection, err = varlink.NewBridge(bridge) + } else if bridge := os.Getenv("PODMAN_VARLINK_BRIDGE"); bridge != "" { connection, err = varlink.NewBridge(bridge) } else { address := os.Getenv("PODMAN_VARLINK_ADDRESS") if address == "" { address = DefaultAddress } - logrus.Infof("Connecting with varlink address") - logrus.Debugf("%s", address) connection, err = varlink.NewConnection(address) } if err != nil { diff --git a/pkg/adapter/client_config.go b/pkg/adapter/client_config.go new file mode 100644 index 000000000..d165ef1cc --- /dev/null +++ b/pkg/adapter/client_config.go @@ -0,0 +1,4 @@ +package adapter + +// DefaultAddress is the default address of the varlink socket +const DefaultAddress = "unix:/run/podman/io.podman" diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go index 82d999202..ff7b6377a 100644 --- a/pkg/adapter/containers.go +++ b/pkg/adapter/containers.go @@ -413,7 +413,9 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode } if c.IsSet("rm") { - r.Runtime.RemoveContainer(ctx, ctr, false, true) + if err := r.Runtime.RemoveContainer(ctx, ctr, false, false); err != nil { + logrus.Errorf("Error removing container %s: %v", ctr.ID(), err) + } } return exitCode, nil @@ -965,8 +967,9 @@ func (r *LocalRuntime) CleanupContainers(ctx context.Context, cli *cliconfig.Cle return ok, failures, nil } +// Only used when cleaning up containers func removeContainer(ctx context.Context, ctr *libpod.Container, runtime *LocalRuntime) error { - if err := runtime.RemoveContainer(ctx, ctr, false, true); err != nil { + if err := runtime.RemoveContainer(ctx, ctr, false, false); err != nil { return errors.Wrapf(err, "failed to cleanup and remove container %v", ctr.ID()) } return nil diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go index 0d840d65b..21613c425 100644 --- a/pkg/adapter/runtime.go +++ b/pkg/adapter/runtime.go @@ -5,12 +5,13 @@ package adapter import ( "bufio" "context" - "github.com/containers/libpod/cmd/podman/shared" "io" "io/ioutil" "os" "text/template" + "github.com/containers/libpod/cmd/podman/shared" + "github.com/containers/buildah" "github.com/containers/buildah/imagebuildah" "github.com/containers/buildah/pkg/parse" @@ -392,3 +393,8 @@ func (r *LocalRuntime) GetPodsByStatus(statuses []string) ([]*libpod.Pod, error) return pods, nil } + +// GetVersion is an alias to satisfy interface{} +func (r *LocalRuntime) GetVersion() (libpod.Version, error) { + return libpod.GetVersion() +} diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go index 4986d16f7..e86287462 100644 --- a/pkg/adapter/runtime_remote.go +++ b/pkg/adapter/runtime_remote.go @@ -9,12 +9,13 @@ import ( "fmt" "io" "io/ioutil" - v1 "k8s.io/api/core/v1" "os" "strings" "text/template" "time" + v1 "k8s.io/api/core/v1" + "github.com/containers/buildah/imagebuildah" "github.com/containers/image/docker/reference" "github.com/containers/image/types" @@ -38,6 +39,7 @@ type RemoteImageRuntime struct{} type RemoteRuntime struct { Conn *varlink.Connection Remote bool + cmd cliconfig.MainFlags } // LocalRuntime describes a typical libpod runtime @@ -47,17 +49,17 @@ type LocalRuntime struct { // GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime, error) { - runtime := RemoteRuntime{} + runtime := RemoteRuntime{ + Remote: true, + cmd: c.GlobalFlags, + } conn, err := runtime.Connect() if err != nil { return nil, err } - + runtime.Conn = conn return &LocalRuntime{ - &RemoteRuntime{ - Conn: conn, - Remote: true, - }, + &runtime, }, nil } @@ -414,19 +416,19 @@ func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, opti Compression: string(options.Compression), DefaultsMountFilePath: options.DefaultMountsFilePath, Dockerfiles: dockerfiles, - //Err: string(options.Err), + // Err: string(options.Err), ForceRmIntermediateCtrs: options.ForceRmIntermediateCtrs, Iidfile: options.IIDFile, Label: options.Labels, Layers: options.Layers, Nocache: options.NoCache, - //Out: + // Out: Output: options.Output, OutputFormat: options.OutputFormat, PullPolicy: options.PullPolicy.String(), Quiet: options.Quiet, RemoteIntermediateCtrs: options.RemoveIntermediateCtrs, - //ReportWriter: + // ReportWriter: RuntimeArgs: options.RuntimeArgs, SignaturePolicyPath: options.SignaturePolicyPath, Squash: options.Squash, @@ -610,7 +612,7 @@ func (r *LocalRuntime) InspectVolumes(ctx context.Context, c *cliconfig.VolumeIn return varlinkVolumeToVolume(r, reply), nil } -//Volumes returns a slice of adapter.volumes based on information about libpod +// Volumes returns a slice of adapter.volumes based on information about libpod // volumes over a varlink connection func (r *LocalRuntime) Volumes(ctx context.Context) ([]*Volume, error) { reply, err := iopodman.GetVolumes().Call(r.Conn, []string{}, true) @@ -906,3 +908,29 @@ func (r *LocalRuntime) GetContainersByContext(all bool, latest bool, namesOrIDs } return containers, nil } + +// GetVersion returns version information from service +func (r *LocalRuntime) GetVersion() (libpod.Version, error) { + version, goVersion, gitCommit, built, osArch, apiVersion, err := iopodman.GetVersion().Call(r.Conn) + if err != nil { + return libpod.Version{}, errors.Wrapf(err, "Unable to obtain server version information") + } + + var buildTime int64 + if built != "" { + t, err := time.Parse(time.RFC3339, built) + if err != nil { + return libpod.Version{}, nil + } + buildTime = t.Unix() + } + + return libpod.Version{ + RemoteAPIVersion: apiVersion, + Version: version, + GoVersion: goVersion, + GitCommit: gitCommit, + Built: buildTime, + OsArch: osArch, + }, nil +} diff --git a/pkg/varlinkapi/attach.go b/pkg/varlinkapi/attach.go index 6c62d3514..2234899a5 100644 --- a/pkg/varlinkapi/attach.go +++ b/pkg/varlinkapi/attach.go @@ -60,6 +60,7 @@ func (i *LibpodAPI) Attach(call iopodman.VarlinkCall, name string, detachKeys st if !start && state != libpod.ContainerStateRunning { return call.ReplyErrorOccurred("container must be running to attach") } + call.Reply(nil) reader, writer, _, pw, streams := setupStreams(call) go func() { diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go index 7f436a954..59bfec75b 100644 --- a/pkg/varlinkapi/system.go +++ b/pkg/varlinkapi/system.go @@ -86,15 +86,18 @@ func (i *LibpodAPI) GetInfo(call iopodman.VarlinkCall) error { Graph_status: graphStatus, } - registriesInterface := info[2].Data["registries"] - insecureRegistriesInterface := info[3].Data["registries"] - if registriesInterface != nil { - registries = registriesInterface.([]string) + if len(info) > 2 { + registriesInterface := info[2].Data["registries"] + if registriesInterface != nil { + registries = registriesInterface.([]string) + } } - if insecureRegistriesInterface != nil { - insecureRegistries = insecureRegistriesInterface.([]string) + if len(info) > 3 { + insecureRegistriesInterface := info[3].Data["registries"] + if insecureRegistriesInterface != nil { + insecureRegistries = insecureRegistriesInterface.([]string) + } } - podmanInfo.Store = infoStore podmanInfo.Podman = pmaninfo podmanInfo.Registries = registries diff --git a/test/e2e/negative_test.go b/test/e2e/negative_test.go new file mode 100644 index 000000000..3cb54a20a --- /dev/null +++ b/test/e2e/negative_test.go @@ -0,0 +1,38 @@ +package integration + +import ( + "os" + + . "github.com/containers/libpod/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Podman negative command-line", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + processTestResult(f) + + }) + + It("podman snuffleupagus exits non-zero", func() { + session := podmanTest.Podman([]string{"snuffleupagus"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + }) +}) diff --git a/test/e2e/version_test.go b/test/e2e/version_test.go index f546158a9..35ee21e49 100644 --- a/test/e2e/version_test.go +++ b/test/e2e/version_test.go @@ -31,6 +31,7 @@ var _ = Describe("Podman version", func() { }) It("podman version", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"version"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -38,6 +39,7 @@ var _ = Describe("Podman version", func() { }) It("podman version --format json", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"version", "--format", "json"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -45,6 +47,7 @@ var _ = Describe("Podman version", func() { }) It("podman version --format json", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"version", "--format", "{{ json .}}"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -52,6 +55,7 @@ var _ = Describe("Podman version", func() { }) It("podman version --format GO template", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"version", "--format", "{{ .Version }}"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/vendor.conf b/vendor.conf index d5e2b60bd..2f7e36d85 100644 --- a/vendor.conf +++ b/vendor.conf @@ -93,8 +93,8 @@ k8s.io/api kubernetes-1.10.13-beta.0 https://github.com/kubernetes/api k8s.io/apimachinery kubernetes-1.10.13-beta.0 https://github.com/kubernetes/apimachinery k8s.io/client-go kubernetes-1.10.13-beta.0 https://github.com/kubernetes/client-go github.com/mrunalp/fileutils 7d4729fb36185a7c1719923406c9d40e54fb93c7 -github.com/varlink/go 64e07fabffa33e385817b41971cf2674f692f391 github.com/containers/buildah v1.8.2 +github.com/varlink/go 0f1d566d194b9d6d48e0d47c5e4d822628919066 # TODO: Gotty has not been updated since 2012. Can we find replacement? github.com/Nvveen/Gotty cd527374f1e5bff4938207604a14f2e38a9cf512 github.com/fsouza/go-dockerclient v1.3.0 diff --git a/vendor/github.com/varlink/go/varlink/bridge.go b/vendor/github.com/varlink/go/varlink/bridge.go index 0ea5de682..c478dcd88 100644 --- a/vendor/github.com/varlink/go/varlink/bridge.go +++ b/vendor/github.com/varlink/go/varlink/bridge.go @@ -6,6 +6,7 @@ import ( "bufio" "io" "net" + "os" "os/exec" ) @@ -30,12 +31,13 @@ func (p PipeCon) Close() error { return nil } -// NewConnection returns a new connection to the given address. -func NewBridge(bridge string) (*Connection, error) { +// NewBridgeWithStderr returns a new connection with the given bridge. +func NewBridgeWithStderr(bridge string, stderr io.Writer) (*Connection, error) { //var err error c := Connection{} cmd := exec.Command("sh", "-c", bridge) + cmd.Stderr = stderr r, err := cmd.StdoutPipe() if err != nil { return nil, err @@ -56,3 +58,8 @@ func NewBridge(bridge string) (*Connection, error) { return &c, nil } + +// NewBridge returns a new connection with the given bridge. +func NewBridge(bridge string) (*Connection, error) { + return NewBridgeWithStderr(bridge, os.Stderr) +} diff --git a/vendor/github.com/varlink/go/varlink/bridge_windows.go b/vendor/github.com/varlink/go/varlink/bridge_windows.go index 751224ec8..42953b871 100644 --- a/vendor/github.com/varlink/go/varlink/bridge_windows.go +++ b/vendor/github.com/varlink/go/varlink/bridge_windows.go @@ -4,6 +4,7 @@ import ( "bufio" "io" "net" + "os" "os/exec" ) @@ -28,12 +29,13 @@ func (p PipeCon) Close() error { return nil } -// NewConnection returns a new connection to the given address. -func NewBridge(bridge string) (*Connection, error) { +// NewBridgeWithStderr returns a new connection with the given bridge. +func NewBridgeWithStderr(bridge string, stderr io.Writer) (*Connection, error) { //var err error c := Connection{} cmd := exec.Command("cmd", "/C", bridge) + cmd.Stderr = stderr r, err := cmd.StdoutPipe() if err != nil { return nil, err @@ -54,3 +56,8 @@ func NewBridge(bridge string) (*Connection, error) { return &c, nil } + +// NewBridge returns a new connection with the given bridge. +func NewBridge(bridge string) (*Connection, error) { + return NewBridgeWithStderr(bridge, os.Stderr) +}
\ No newline at end of file |