diff options
72 files changed, 1043 insertions, 346 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 9a5e0472f..37c9108eb 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -39,7 +39,7 @@ env: UBUNTU_NAME: "ubuntu-20" PRIOR_UBUNTU_NAME: "ubuntu-19" - _BUILT_IMAGE_SUFFIX: "libpod-6508632441356288" + _BUILT_IMAGE_SUFFIX: "podman-5869602141896704" FEDORA_CACHE_IMAGE_NAME: "${FEDORA_NAME}-${_BUILT_IMAGE_SUFFIX}" PRIOR_FEDORA_CACHE_IMAGE_NAME: "${PRIOR_FEDORA_NAME}-${_BUILT_IMAGE_SUFFIX}" UBUNTU_CACHE_IMAGE_NAME: "${UBUNTU_NAME}-${_BUILT_IMAGE_SUFFIX}" @@ -5,7 +5,7 @@ Podman (the POD MANager) is a tool for managing containers and images, volumes mounted into those containers, and pods made from groups of containers. Podman is based on libpod, a library for container lifecycle management that is also contained in this repository. The libpod library provides APIs for managing containers, pods, container images, and volumes. -* [Latest Version: 2.0.2](https://github.com/containers/libpod/releases/latest) +* [Latest Version: 2.0.3](https://github.com/containers/libpod/releases/latest) * Latest Remote client for Windows * Latest Remote client for MacOs * Latest Static Remote client for Linux diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 898a09d70..96ee8a02c 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,43 @@ # Release Notes +## 2.0.3 +### Features +- The `podman search` command now allows wildcards in search terms. +- The `podman play kube` command now supports the `IfNotPresent` pull type. + +### Changes +- The `--disable-content-trust` flag has been added to Podman for Docker compatibility. This is a Docker-specific option and has no effect in Podman; it is provided only to ensure command line compatibility for scripts ([#7034](https://github.com/containers/podman/issues/7034)). +- Setting a static IP address or MAC address for rootless containers and pods now causes an error; previously, they were silently ignored. +- The `/sys/dev` folder is now masked in containers to prevent a potential information leak from the host. + +### Bugfixes +- Fixed a bug where rootless Podman would select the wrong cgroup manager on cgroups v1 systems where the user in question had an active systemd user session ([#6982](https://github.com/containers/podman/issues/6982)). +- Fixed a bug where systems with Apparmor could not run privileged containers ([#6933](https://github.com/containers/podman/issues/6933)). +- Fixed a bug where ENTRYPOINT and CMD from images were improperly handled by `podman play kube` ([#6995](https://github.com/containers/podman/issues/6995)). +- Fixed a bug where the `--pids-limit` flag to `podman create` and `podman run` was parsed incorrectly and was unusable ([#6908](https://github.com/containers/podman/issues/6908)). +- Fixed a bug where the `podman system df` command would error if untagged images were present ([#7015](https://github.com/containers/podman/issues/7015)). +- Fixed a bug where the `podman images` command would display incorrect tags if a port number was included in the repository. +- Fixed a bug where Podman did not set a default umask and default rlimits ([#6989](https://github.com/containers/podman/issues/6989)). +- Fixed a bug where protocols in port mappings were not recognized unless they were lower-case ([#6948](https://github.com/containers/podman/issues/6948)). +- Fixed a bug where information on pod infra containers was not included in the output of `podman pod inspect`. +- Fixed a bug where Podman's systemd detection (activated by the enabled-by-default `--systemd=true` flag) would not flag a container for systemd mode if systemd was part of the entrypoint, not the command ([#6920](https://github.com/containers/podman/issues/6920)). +- Fixed a bug where `podman start --attach` was not defaulting `--sig-proxy` to true ([#6928](https://github.com/containers/podman/issues/6928)). +- Fixed a bug where `podman inspect` would show an incorrect command (`podman system service`, the command used to start the server) for containers created by a remote Podman client. +- Fixed a bug where the `podman exec` command with the remote client would not print output if the `-t` or `-i` flags where not provided. +- Fixed a bug where some variations of the `--format {{ json . }}` to `podman info` (involving added or removed whitespace) would not be accepted ([#6927](https://github.com/containers/podman/issues/6927)). +- Fixed a bug where Entrypoint could not be cleared at the command line (if unset via `--entrypoint=""`, it would be reset to the image's entrypoint) ([#6935](https://github.com/containers/podman/issues/6935)). + +### API +- Fixed a bug where the events endpoints (both libpod and compat) could potentially panic on parsing filters. +- Fixed a bug where the compat Create endpoint for containers did not properly handle Entrypoint and Command. +- Fixed a bug where the Logs endpoint for containers (both libpod and compat) would not properly handle client disconnect, resulting in high CPU usage. +- The type of filters on the compat events endpoint has been adjusted to match Docker's implementation ([#6899](https://github.com/containers/podman/issues/6899)). +- The idle connection counter now properly handles hijacked connections. +- All endpoints that hijack will now properly print headers per RFC 7230 standards. + +### Misc +- Updated containers/common to v0.14.6 + ## 2.0.2 ### Changes - The `podman system connection` command has been temporarily disabled, as it was not functioning as expected. diff --git a/cmd/podman/main.go b/cmd/podman/main.go index 5f740a006..f46f74547 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -14,6 +14,7 @@ import ( _ "github.com/containers/libpod/v2/cmd/podman/pods" "github.com/containers/libpod/v2/cmd/podman/registry" _ "github.com/containers/libpod/v2/cmd/podman/system" + _ "github.com/containers/libpod/v2/cmd/podman/system/connection" _ "github.com/containers/libpod/v2/cmd/podman/volumes" "github.com/containers/libpod/v2/pkg/rootless" "github.com/containers/libpod/v2/pkg/terminal" diff --git a/cmd/podman/registry/config.go b/cmd/podman/registry/config.go index a7e368115..f5a231172 100644 --- a/cmd/podman/registry/config.go +++ b/cmd/podman/registry/config.go @@ -44,11 +44,12 @@ func newPodmanConfig() { case "linux": // Some linux clients might only be compiled without ABI // support (e.g., podman-remote). - if abiSupport && !remoteOverride { + if abiSupport && !IsRemote() { mode = entities.ABIMode } else { mode = entities.TunnelMode } + default: fmt.Fprintf(os.Stderr, "%s is not a supported OS", runtime.GOOS) os.Exit(1) diff --git a/cmd/podman/root.go b/cmd/podman/root.go index c6ced21c0..e9f1ff710 100644 --- a/cmd/podman/root.go +++ b/cmd/podman/root.go @@ -236,16 +236,12 @@ func loggingHook() { func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { cfg := opts.Config + uri, ident := resolveDestination() lFlags := cmd.Flags() - custom, _ := config.ReadCustomConfig() - defaultURI := custom.Engine.RemoteURI - if defaultURI == "" { - defaultURI = registry.DefaultAPIAddress() - } lFlags.BoolVarP(&opts.Remote, "remote", "r", false, "Access remote Podman service (default false)") - lFlags.StringVar(&opts.URI, "url", defaultURI, "URL to access Podman service (CONTAINER_HOST)") - lFlags.StringVar(&opts.Identity, "identity", custom.Engine.RemoteIdentity, "path to SSH identity file, (CONTAINER_SSHKEY)") + lFlags.StringVar(&opts.URI, "url", uri, "URL to access Podman service (CONTAINER_HOST)") + lFlags.StringVar(&opts.Identity, "identity", ident, "path to SSH identity file, (CONTAINER_SSHKEY)") pFlags := cmd.PersistentFlags() pFlags.StringVar(&cfg.Engine.CgroupManager, "cgroup-manager", cfg.Engine.CgroupManager, "Cgroup manager to use (\"cgroupfs\"|\"systemd\")") @@ -292,3 +288,24 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { pFlags.BoolVar(&useSyslog, "syslog", false, "Output logging information to syslog as well as the console (default false)") } } + +func resolveDestination() (string, string) { + if uri, found := os.LookupEnv("CONTAINER_HOST"); found { + var ident string + if v, found := os.LookupEnv("CONTAINER_SSHKEY"); found { + ident = v + } + return uri, ident + } + + cfg, err := config.ReadCustomConfig() + if err != nil { + return registry.DefaultAPIAddress(), "" + } + + uri, ident, err := cfg.ActiveDestination() + if err != nil { + return registry.DefaultAPIAddress(), "" + } + return uri, ident +} diff --git a/cmd/podman/system/connection.go b/cmd/podman/system/connection.go index 9f26a0df6..b1c538803 100644 --- a/cmd/podman/system/connection.go +++ b/cmd/podman/system/connection.go @@ -1,209 +1,34 @@ package system import ( - "bytes" - "fmt" - "net" - "net/url" - "os" - "os/user" - "regexp" - - "github.com/containers/common/pkg/config" "github.com/containers/libpod/v2/cmd/podman/registry" - "github.com/containers/libpod/v2/libpod/define" + "github.com/containers/libpod/v2/cmd/podman/validate" "github.com/containers/libpod/v2/pkg/domain/entities" - "github.com/containers/libpod/v2/pkg/terminal" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "golang.org/x/crypto/ssh" - "golang.org/x/crypto/ssh/agent" ) -const schemaPattern = "^[A-Za-z][A-Za-z0-9+.-]*:" - var ( - // Skip creating engines since this command will obtain connection information to engine + // Skip creating engines since this command will obtain connection information to said engines noOp = func(cmd *cobra.Command, args []string) error { return nil } - connectionCmd = &cobra.Command{ - Use: "connection [flags] DESTINATION", - Args: cobra.ExactArgs(1), - Long: `Store ssh destination information in podman configuration. - "destination" is of the form [user@]hostname or - an URI of the form ssh://[user@]hostname[:port] -`, - Short: "Record remote ssh destination", - PersistentPreRunE: noOp, - PersistentPostRunE: noOp, - TraverseChildren: false, - RunE: connection, - Example: `podman system connection server.fubar.com - podman system connection --identity ~/.ssh/dev_rsa ssh://root@server.fubar.com:2222 - podman system connection --identity ~/.ssh/dev_rsa --port 22 root@server.fubar.com`, - } - cOpts = struct { - Identity string - Port int - UDSPath string - }{} + ConnectionCmd = &cobra.Command{ + Use: "connection", + Short: "Manage remote ssh destinations", + Long: `Manage ssh destination information in podman configuration`, + DisableFlagsInUseLine: true, + PersistentPreRunE: noOp, + RunE: validate.SubCommandExists, + PersistentPostRunE: noOp, + TraverseChildren: false, + } ) func init() { registry.Commands = append(registry.Commands, registry.CliCommand{ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, - Command: connectionCmd, + Command: ConnectionCmd, Parent: systemCmd, }) - - flags := connectionCmd.Flags() - flags.IntVarP(&cOpts.Port, "port", "p", 22, "SSH port number for destination") - flags.StringVar(&cOpts.Identity, "identity", "", "path to SSH identity file") - flags.StringVar(&cOpts.UDSPath, "socket-path", "", "path to podman socket on remote host. (default '/run/podman/podman.sock' or '/run/user/{uid}/podman/podman.sock)") -} - -func connection(cmd *cobra.Command, args []string) error { - // Default to ssh: schema if none given - dest := []byte(args[0]) - if match, err := regexp.Match(schemaPattern, dest); err != nil { - return errors.Wrapf(err, "internal regex error %q", schemaPattern) - } else if !match { - dest = append([]byte("ssh://"), dest...) - } - - uri, err := url.Parse(string(dest)) - if err != nil { - return errors.Wrapf(err, "failed to parse %q", string(dest)) - } - - if uri.User.Username() == "" { - if uri.User, err = getUserInfo(uri); err != nil { - return err - } - } - - if cmd.Flag("socket-path").Changed { - uri.Path = cmd.Flag("socket-path").Value.String() - } - - if cmd.Flag("port").Changed { - uri.Host = net.JoinHostPort(uri.Hostname(), cmd.Flag("port").Value.String()) - } - - if uri.Port() == "" { - uri.Host = net.JoinHostPort(uri.Hostname(), cmd.Flag("port").DefValue) - } - - if uri.Path == "" { - if uri.Path, err = getUDS(cmd, uri); err != nil { - return errors.Wrapf(err, "failed to connect to %q", uri.String()) - } - } - - custom, err := config.ReadCustomConfig() - if err != nil { - return err - } - - if cmd.Flag("identity").Changed { - custom.Engine.RemoteIdentity = cOpts.Identity - } - - custom.Engine.RemoteURI = uri.String() - return custom.Write() -} - -func getUserInfo(uri *url.URL) (*url.Userinfo, error) { - var ( - usr *user.User - err error - ) - if u, found := os.LookupEnv("_CONTAINERS_ROOTLESS_UID"); found { - usr, err = user.LookupId(u) - if err != nil { - return nil, errors.Wrapf(err, "failed to find user %q", u) - } - } else { - usr, err = user.Current() - if err != nil { - return nil, errors.Wrapf(err, "failed to obtain current user") - } - } - - pw, set := uri.User.Password() - if set { - return url.UserPassword(usr.Username, pw), nil - } - return url.User(usr.Username), nil -} - -func getUDS(cmd *cobra.Command, uri *url.URL) (string, error) { - var authMethods []ssh.AuthMethod - passwd, set := uri.User.Password() - if set { - authMethods = append(authMethods, ssh.Password(passwd)) - } - - ident := cmd.Flag("identity") - if ident.Changed { - auth, err := terminal.PublicKey(ident.Value.String(), []byte(passwd)) - if err != nil { - return "", errors.Wrapf(err, "Failed to read identity %q", ident.Value.String()) - } - authMethods = append(authMethods, auth) - } - - if sock, found := os.LookupEnv("SSH_AUTH_SOCK"); found { - logrus.Debugf("Found SSH_AUTH_SOCK %q, ssh-agent signer enabled", sock) - - c, err := net.Dial("unix", sock) - if err != nil { - return "", err - } - a := agent.NewClient(c) - authMethods = append(authMethods, ssh.PublicKeysCallback(a.Signers)) - } - - config := &ssh.ClientConfig{ - User: uri.User.Username(), - Auth: authMethods, - HostKeyCallback: ssh.InsecureIgnoreHostKey(), - } - dial, err := ssh.Dial("tcp", uri.Host, config) - if err != nil { - return "", errors.Wrapf(err, "failed to connect to %q", uri.Host) - } - defer dial.Close() - - session, err := dial.NewSession() - if err != nil { - return "", errors.Wrapf(err, "failed to create new ssh session on %q", uri.Host) - } - defer session.Close() - - // Override podman binary for testing etc - podman := "podman" - if v, found := os.LookupEnv("PODMAN_BINARY"); found { - podman = v - } - run := podman + " info --format=json" - - var buffer bytes.Buffer - session.Stdout = &buffer - if err := session.Run(run); err != nil { - return "", errors.Wrapf(err, "failed to run %q", run) - } - - var info define.Info - if err := json.Unmarshal(buffer.Bytes(), &info); err != nil { - return "", errors.Wrapf(err, "failed to parse 'podman info' results") - } - - if info.Host.RemoteSocket == nil || len(info.Host.RemoteSocket.Path) == 0 { - return "", fmt.Errorf("remote podman %q failed to report its UDS socket", uri.Host) - } - return info.Host.RemoteSocket.Path, nil } diff --git a/cmd/podman/system/connection/add.go b/cmd/podman/system/connection/add.go new file mode 100644 index 000000000..7522eb190 --- /dev/null +++ b/cmd/podman/system/connection/add.go @@ -0,0 +1,223 @@ +package connection + +import ( + "bytes" + "encoding/json" + "fmt" + "net" + "net/url" + "os" + "os/user" + "regexp" + + "github.com/containers/common/pkg/config" + "github.com/containers/libpod/v2/cmd/podman/registry" + "github.com/containers/libpod/v2/cmd/podman/system" + "github.com/containers/libpod/v2/libpod/define" + "github.com/containers/libpod/v2/pkg/domain/entities" + "github.com/containers/libpod/v2/pkg/terminal" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "golang.org/x/crypto/ssh" + "golang.org/x/crypto/ssh/agent" +) + +const schemaPattern = "^[A-Za-z][A-Za-z0-9+.-]*:" + +var ( + addCmd = &cobra.Command{ + Use: "add [flags] NAME DESTINATION", + Args: cobra.ExactArgs(2), + Short: "Record destination for the Podman service", + Long: `Add destination to podman configuration. + "destination" is of the form [user@]hostname or + an URI of the form ssh://[user@]hostname[:port] +`, + RunE: add, + Example: `podman system connection add laptop server.fubar.com + podman system connection add --identity ~/.ssh/dev_rsa testing ssh://root@server.fubar.com:2222 + podman system connection add --identity ~/.ssh/dev_rsa --port 22 production root@server.fubar.com + `, + } + + cOpts = struct { + Identity string + Port int + UDSPath string + Default bool + }{} +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: addCmd, + Parent: system.ConnectionCmd, + }) + + flags := addCmd.Flags() + flags.IntVarP(&cOpts.Port, "port", "p", 22, "SSH port number for destination") + flags.StringVar(&cOpts.Identity, "identity", "", "path to SSH identity file") + flags.StringVar(&cOpts.UDSPath, "socket-path", "", "path to podman socket on remote host. (default '/run/podman/podman.sock' or '/run/user/{uid}/podman/podman.sock)") + flags.BoolVarP(&cOpts.Default, "default", "d", false, "Set connection to be default") +} + +func add(cmd *cobra.Command, args []string) error { + // Default to ssh: schema if none given + dest := args[1] + if match, err := regexp.Match(schemaPattern, []byte(dest)); err != nil { + return errors.Wrapf(err, "internal regex error %q", schemaPattern) + } else if !match { + dest = "ssh://" + dest + } + + uri, err := url.Parse(dest) + if err != nil { + return errors.Wrapf(err, "failed to parse %q", dest) + } + + if uri.User.Username() == "" { + if uri.User, err = getUserInfo(uri); err != nil { + return err + } + } + + if cmd.Flags().Changed("socket-path") { + uri.Path = cmd.Flag("socket-path").Value.String() + } + + if cmd.Flags().Changed("port") { + uri.Host = net.JoinHostPort(uri.Hostname(), cmd.Flag("port").Value.String()) + } + + if uri.Port() == "" { + uri.Host = net.JoinHostPort(uri.Hostname(), cmd.Flag("port").DefValue) + } + + if uri.Path == "" { + if uri.Path, err = getUDS(cmd, uri); err != nil { + return errors.Wrapf(err, "failed to connect to %q", uri.String()) + } + } + + cfg, err := config.ReadCustomConfig() + if err != nil { + return err + } + + if cmd.Flags().Changed("default") { + if cOpts.Default { + cfg.Engine.ActiveService = args[0] + } + } + + dst := config.Destination{ + URI: uri.String(), + } + + if cmd.Flags().Changed("identity") { + dst.Identity = cOpts.Identity + } + + if cfg.Engine.ServiceDestinations == nil { + cfg.Engine.ServiceDestinations = map[string]config.Destination{ + args[0]: dst, + } + } else { + cfg.Engine.ServiceDestinations[args[0]] = dst + } + return cfg.Write() +} + +func getUserInfo(uri *url.URL) (*url.Userinfo, error) { + var ( + usr *user.User + err error + ) + if u, found := os.LookupEnv("_CONTAINERS_ROOTLESS_UID"); found { + usr, err = user.LookupId(u) + if err != nil { + return nil, errors.Wrapf(err, "failed to find user %q", u) + } + } else { + usr, err = user.Current() + if err != nil { + return nil, errors.Wrapf(err, "failed to obtain current user") + } + } + + pw, set := uri.User.Password() + if set { + return url.UserPassword(usr.Username, pw), nil + } + return url.User(usr.Username), nil +} + +func getUDS(cmd *cobra.Command, uri *url.URL) (string, error) { + var authMethods []ssh.AuthMethod + passwd, set := uri.User.Password() + if set { + authMethods = append(authMethods, ssh.Password(passwd)) + } + + if cmd.Flags().Changed("identity") { + value := cmd.Flag("identity").Value.String() + auth, err := terminal.PublicKey(value, []byte(passwd)) + if err != nil { + return "", errors.Wrapf(err, "Failed to read identity %q", value) + } + authMethods = append(authMethods, auth) + } + + if sock, found := os.LookupEnv("SSH_AUTH_SOCK"); found { + logrus.Debugf("Found SSH_AUTH_SOCK %q, ssh-agent signer enabled", sock) + + c, err := net.Dial("unix", sock) + if err != nil { + return "", err + } + a := agent.NewClient(c) + authMethods = append(authMethods, ssh.PublicKeysCallback(a.Signers)) + } + + config := &ssh.ClientConfig{ + User: uri.User.Username(), + Auth: authMethods, + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + } + dial, err := ssh.Dial("tcp", uri.Host, config) + if err != nil { + return "", errors.Wrapf(err, "failed to connect to %q", uri.Host) + } + defer dial.Close() + + session, err := dial.NewSession() + if err != nil { + return "", errors.Wrapf(err, "failed to create new ssh session on %q", uri.Host) + } + defer session.Close() + + // Override podman binary for testing etc + podman := "podman" + if v, found := os.LookupEnv("PODMAN_BINARY"); found { + podman = v + } + run := podman + " info --format=json" + + var buffer bytes.Buffer + session.Stdout = &buffer + if err := session.Run(run); err != nil { + return "", errors.Wrapf(err, "failed to run %q", run) + } + + var info define.Info + if err := json.Unmarshal(buffer.Bytes(), &info); err != nil { + return "", errors.Wrapf(err, "failed to parse 'podman info' results") + } + + if info.Host.RemoteSocket == nil || len(info.Host.RemoteSocket.Path) == 0 { + return "", fmt.Errorf("remote podman %q failed to report its UDS socket", uri.Host) + } + return info.Host.RemoteSocket.Path, nil +} diff --git a/cmd/podman/system/connection/default.go b/cmd/podman/system/connection/default.go new file mode 100644 index 000000000..b85343dc2 --- /dev/null +++ b/cmd/podman/system/connection/default.go @@ -0,0 +1,46 @@ +package connection + +import ( + "fmt" + + "github.com/containers/common/pkg/config" + "github.com/containers/libpod/v2/cmd/podman/registry" + "github.com/containers/libpod/v2/cmd/podman/system" + "github.com/containers/libpod/v2/pkg/domain/entities" + "github.com/spf13/cobra" +) + +var ( + // Skip creating engines since this command will obtain connection information to said engines + dfltCmd = &cobra.Command{ + Use: "default NAME", + Args: cobra.ExactArgs(1), + Short: "Set named destination as default", + Long: `Set named destination as default for the Podman service`, + DisableFlagsInUseLine: true, + RunE: defaultRunE, + Example: `podman system connection default testing`, + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: dfltCmd, + Parent: system.ConnectionCmd, + }) +} + +func defaultRunE(cmd *cobra.Command, args []string) error { + cfg, err := config.ReadCustomConfig() + if err != nil { + return err + } + + if _, found := cfg.Engine.ServiceDestinations[args[0]]; !found { + return fmt.Errorf("%q destination is not defined. See \"podman system connection add ...\" to create a connection", args[0]) + } + + cfg.Engine.ActiveService = args[0] + return cfg.Write() +} diff --git a/cmd/podman/system/connection/list.go b/cmd/podman/system/connection/list.go new file mode 100644 index 000000000..c0a9087f5 --- /dev/null +++ b/cmd/podman/system/connection/list.go @@ -0,0 +1,84 @@ +package connection + +import ( + "os" + "text/tabwriter" + "text/template" + + "github.com/containers/common/pkg/config" + "github.com/containers/libpod/v2/cmd/podman/registry" + "github.com/containers/libpod/v2/cmd/podman/system" + "github.com/containers/libpod/v2/cmd/podman/validate" + "github.com/containers/libpod/v2/pkg/domain/entities" + "github.com/spf13/cobra" +) + +var ( + listCmd = &cobra.Command{ + Use: "list", + Aliases: []string{"ls"}, + Args: validate.NoArgs, + Short: "List destination for the Podman service(s)", + Long: `List destination information for the Podman service(s) in podman configuration`, + DisableFlagsInUseLine: true, + Example: `podman system connection list + podman system connection ls`, + RunE: list, + TraverseChildren: false, + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: listCmd, + Parent: system.ConnectionCmd, + }) +} + +type namedDestination struct { + Name string + config.Destination +} + +func list(_ *cobra.Command, _ []string) error { + cfg, err := config.ReadCustomConfig() + if err != nil { + return err + } + + if len(cfg.Engine.ServiceDestinations) == 0 { + return nil + } + + hdrs := []map[string]string{{ + "Identity": "Identity", + "Name": "Name", + "URI": "URI", + }} + + rows := make([]namedDestination, 0) + for k, v := range cfg.Engine.ServiceDestinations { + if k == cfg.Engine.ActiveService { + k += "*" + } + + r := namedDestination{ + Name: k, + Destination: config.Destination{ + Identity: v.Identity, + URI: v.URI, + }, + } + rows = append(rows, r) + } + + // TODO: Allow user to override format + format := "{{range . }}{{.Name}}\t{{.Identity}}\t{{.URI}}\n{{end}}" + tmpl := template.Must(template.New("connection").Parse(format)) + w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0) + defer w.Flush() + + _ = tmpl.Execute(w, hdrs) + return tmpl.Execute(w, rows) +} diff --git a/cmd/podman/system/connection/remove.go b/cmd/podman/system/connection/remove.go new file mode 100644 index 000000000..a2ca66c8d --- /dev/null +++ b/cmd/podman/system/connection/remove.go @@ -0,0 +1,49 @@ +package connection + +import ( + "github.com/containers/common/pkg/config" + "github.com/containers/libpod/v2/cmd/podman/registry" + "github.com/containers/libpod/v2/cmd/podman/system" + "github.com/containers/libpod/v2/pkg/domain/entities" + "github.com/spf13/cobra" +) + +var ( + // Skip creating engines since this command will obtain connection information to said engines + rmCmd = &cobra.Command{ + Use: "remove NAME", + Args: cobra.ExactArgs(1), + Aliases: []string{"rm"}, + Long: `Delete named destination from podman configuration`, + Short: "Delete named destination", + DisableFlagsInUseLine: true, + RunE: rm, + Example: `podman system connection remove devl + podman system connection rm devl`, + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: rmCmd, + Parent: system.ConnectionCmd, + }) +} + +func rm(_ *cobra.Command, args []string) error { + cfg, err := config.ReadCustomConfig() + if err != nil { + return err + } + + if cfg.Engine.ServiceDestinations != nil { + delete(cfg.Engine.ServiceDestinations, args[0]) + } + + if cfg.Engine.ActiveService == args[0] { + cfg.Engine.ActiveService = "" + } + + return cfg.Write() +} diff --git a/cmd/podman/system/connection/rename.go b/cmd/podman/system/connection/rename.go new file mode 100644 index 000000000..d6cd55c31 --- /dev/null +++ b/cmd/podman/system/connection/rename.go @@ -0,0 +1,54 @@ +package connection + +import ( + "fmt" + + "github.com/containers/common/pkg/config" + "github.com/containers/libpod/v2/cmd/podman/registry" + "github.com/containers/libpod/v2/cmd/podman/system" + "github.com/containers/libpod/v2/pkg/domain/entities" + "github.com/spf13/cobra" +) + +var ( + // Skip creating engines since this command will obtain connection information to said engines + renameCmd = &cobra.Command{ + Use: "rename OLD NEW", + Aliases: []string{"mv"}, + Args: cobra.ExactArgs(2), + Short: "Rename \"old\" to \"new\"", + Long: `Rename destination for the Podman service from "old" to "new"`, + DisableFlagsInUseLine: true, + RunE: rename, + Example: `podman system connection rename laptop devl, + podman system connection mv laptop devl`, + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: renameCmd, + Parent: system.ConnectionCmd, + }) +} + +func rename(cmd *cobra.Command, args []string) error { + cfg, err := config.ReadCustomConfig() + if err != nil { + return err + } + + if _, found := cfg.Engine.ServiceDestinations[args[0]]; !found { + return fmt.Errorf("%q destination is not defined. See \"podman system connection add ...\" to create a connection", args[0]) + } + + cfg.Engine.ServiceDestinations[args[1]] = cfg.Engine.ServiceDestinations[args[0]] + delete(cfg.Engine.ServiceDestinations, args[0]) + + if cfg.Engine.ActiveService == args[0] { + cfg.Engine.ActiveService = args[1] + } + + return cfg.Write() +} diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh index 2375d512e..91eeb7a7f 100644 --- a/contrib/cirrus/lib.sh +++ b/contrib/cirrus/lib.sh @@ -299,13 +299,13 @@ is_release() { } setup_rootless() { - req_env_var ROOTLESS_USER GOSRC SECRET_ENV_RE ROOTLESS_ENV_RE + req_env_var ROOTLESS_USER GOPATH GOSRC SECRET_ENV_RE ROOTLESS_ENV_RE # Only do this once if passwd --status $ROOTLESS_USER then echo "Updating $ROOTLESS_USER user permissions on possibly changed libpod code" - chown -R $ROOTLESS_USER:$ROOTLESS_USER "$GOSRC" + chown -R $ROOTLESS_USER:$ROOTLESS_USER "$GOPATH" "$GOSRC" return 0 fi @@ -316,7 +316,7 @@ setup_rootless() { echo "creating $ROOTLESS_UID:$ROOTLESS_GID $ROOTLESS_USER user" groupadd -g $ROOTLESS_GID $ROOTLESS_USER useradd -g $ROOTLESS_GID -u $ROOTLESS_UID --no-user-group --create-home $ROOTLESS_USER - chown -R $ROOTLESS_USER:$ROOTLESS_USER "$GOSRC" + chown -R $ROOTLESS_USER:$ROOTLESS_USER "$GOPATH" "$GOSRC" echo "creating ssh keypair for $USER" [[ -r "$HOME/.ssh/id_rsa" ]] || \ diff --git a/contrib/cirrus/logformatter b/contrib/cirrus/logformatter index 86de98803..b56a829c5 100755 --- a/contrib/cirrus/logformatter +++ b/contrib/cirrus/logformatter @@ -303,14 +303,15 @@ END_HTML # (bindings test sometimes emits 'Running' with leading bullet char) elsif ($line =~ /^•?Running:/) { # Highlight the important (non-boilerplate) podman command. + $line =~ s/\s+--remote\s+/ /g; # --remote takes no args # Strip out the global podman options, but show them on hover - $line =~ s{(\S+\/podman)((\s+--(root|runroot|runtime|tmpdir|storage-opt|conmon|cgroup-manager|cni-config-dir|storage-driver|events-backend) \S+)*)(.*)}{ - my ($full_path, $options, $args) = ($1, $2, $5); + $line =~ s{(\S+\/podman(-remote)?)((\s+--(root|runroot|runtime|tmpdir|storage-opt|conmon|cgroup-manager|cni-config-dir|storage-driver|events-backend|url) \S+)*)(.*)}{ + my ($full_path, $remote, $options, $args) = ($1, $2||'', $3, $6); $options =~ s/^\s+//; # Separate each '--foo bar' with newlines for readability $options =~ s/ --/\n--/g; - qq{<span title="$full_path"><b>podman</b></span> <span class=\"boring\" title=\"$options\">[options]</span><b>$args</b>}; + qq{<span title="$full_path"><b>podman$remote</b></span> <span class=\"boring\" title=\"$options\">[options]</span><b>$args</b>}; }e; $current_output = ''; } diff --git a/contrib/cirrus/logformatter.t b/contrib/cirrus/logformatter.t index d2193cc6c..440299cc2 100755 --- a/contrib/cirrus/logformatter.t +++ b/contrib/cirrus/logformatter.t @@ -132,6 +132,8 @@ $SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP} [+0103s] /var/tmp/go/src/github.com/containers/libpod/test/e2e/pod_restart_test.go:28 [+0103s] Running: /var/tmp/go/src/github.com/containers/libpod/bin/podman --storage-opt vfs.imagestore=/tmp/podman/imagecachedir --root /tmp/podman_test553496330/crio --runroot /tmp/podman_test553496330/crio-run --runtime /usr/bin/runc --conmon /usr/bin/conmon --cni-config-dir /etc/cni/net.d --cgroup-manager systemd --tmpdir /tmp/podman_test553496330 --events-backend file --storage-driver vfs pod rm -fa [+0103s] 4810be0cfbd42241e349dbe7d50fbc54405cd320a6637c65fd5323f34d64af89 +[+0104s] Running: /var/tmp/go/src/github.com/containers/libpod/bin/podman-remote --storage-opt vfs.imagestore=/tmp/podman/imagecachedir --root /tmp/podman_test553496330/crio --runroot /tmp/podman_test553496330/crio-run --runtime /usr/bin/runc --conmon /usr/bin/conmon --cni-config-dir /etc/cni/net.d --cgroup-manager systemd --tmpdir /tmp/podman_test553496330 --events-backend file --storage-driver vfs --remote --url unix:/run/user/12345/podman-xyz.sock pod rm -fa +[+0104s] 4810be0cfbd42241e349dbe7d50fbc54405cd320a6637c65fd5323f34d64af89 again [+0107s] • [+0107s] ------------------------------ [+0107s] podman system reset @@ -186,6 +188,21 @@ $SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP} --events-backend file --storage-driver vfs">[options]</span><b> pod rm -fa</b> <span class="timestamp"> </span>4810be0cfbd42241e349dbe7d50fbc54405cd320a6637c65fd5323f34d64af89 + +<span class="timestamp">[+0104s] </span>Running: <span title="/var/tmp/go/src/github.com/containers/libpod/bin/podman-remote"><b>podman-remote</b></span> <span class="boring" title="--storage-opt vfs.imagestore=/tmp/podman/imagecachedir +--root /tmp/podman_test553496330/crio +--runroot /tmp/podman_test553496330/crio-run +--runtime /usr/bin/runc +--conmon /usr/bin/conmon +--cni-config-dir /etc/cni/net.d +--cgroup-manager systemd +--tmpdir /tmp/podman_test553496330 +--events-backend file +--storage-driver vfs +--url unix:/run/user/12345/podman-xyz.sock">[options]</span><b> pod rm -fa</b> +<span class="timestamp"> </span>4810be0cfbd42241e349dbe7d50fbc54405cd320a6637c65fd5323f34d64af89 again + + <span class="timestamp">[+0107s] </span>• </pre> <hr /> diff --git a/contrib/cirrus/packer/Makefile b/contrib/cirrus/packer/Makefile index a911cafdb..c5a8e4cac 100644 --- a/contrib/cirrus/packer/Makefile +++ b/contrib/cirrus/packer/Makefile @@ -5,7 +5,8 @@ PACKER_DIST_FILENAME := packer_${PACKER_VER}_linux_${GOARCH}.zip # Only needed for libpod_base_images target TIMESTAMP := $(shell date +%s) -GOSRC ?= $(shell realpath "./../../../") +GOPATH ?= /var/tmp/go +GOSRC ?= $(GOPATH)/src/github.com/containers/libpod PACKER_BASE ?= contrib/cirrus/packer SCRIPT_BASE ?= contrib/cirrus POST_MERGE_BUCKET_SUFFIX ?= @@ -54,6 +55,7 @@ libpod_images: guard-PACKER_BUILDS libpod_images.json packer ./packer build \ -force \ $(shell test -z "${PACKER_BUILDS}" || echo "-only=${PACKER_BUILDS}") \ + -var GOPATH=$(GOPATH) \ -var GOSRC=$(GOSRC) \ -var PACKER_BASE=$(PACKER_BASE) \ -var SCRIPT_BASE=$(SCRIPT_BASE) \ diff --git a/contrib/cirrus/packer/fedora_packaging.sh b/contrib/cirrus/packer/fedora_packaging.sh index aecaaef93..b4a3a2062 100644 --- a/contrib/cirrus/packer/fedora_packaging.sh +++ b/contrib/cirrus/packer/fedora_packaging.sh @@ -74,6 +74,7 @@ INSTALL_PACKAGES=(\ gpgme-devel grubby hostname + httpd-tools iproute iptables jq @@ -168,5 +169,9 @@ fi echo "Installing runtime tooling" # Save some runtime by having these already available cd $GOSRC +# Required since initially go was not installed +source $GOSRC/$SCRIPT_BASE/lib.sh +echo "Go environment has been setup:" +go env $SUDO make install.tools $SUDO $GOSRC/hack/install_catatonit.sh diff --git a/contrib/cirrus/packer/libpod_images.yml b/contrib/cirrus/packer/libpod_images.yml index 754626a2e..38f5a8250 100644 --- a/contrib/cirrus/packer/libpod_images.yml +++ b/contrib/cirrus/packer/libpod_images.yml @@ -3,6 +3,7 @@ # All of these are required variables: BUILT_IMAGE_SUFFIX: '{{env `BUILT_IMAGE_SUFFIX`}}' + GOPATH: '{{env `GOPATH`}}' GOSRC: '{{env `GOSRC`}}' PACKER_BASE: '{{env `PACKER_BASE`}}' SCRIPT_BASE: '{{env `SCRIPT_BASE`}}' @@ -62,15 +63,22 @@ builders: # The brains of the operation, making actual modifications to the base-image. provisioners: + - type: 'shell' + inline: + - 'set -ex' + # The 'file' provisioner item (below) will create the final component + - 'mkdir -vp $(dirname {{user `GOSRC`}})' + - type: 'file' source: '{{user `GOSRC`}}' - destination: '/tmp/libpod' + destination: '{{user `GOSRC`}}' - type: 'shell' script: '{{user `GOSRC`}}/{{user `PACKER_BASE`}}/{{split build_name "-" 0}}_setup.sh' environment_vars: - 'PACKER_BUILDER_NAME={{build_name}}' - - 'GOSRC=/tmp/libpod' + - 'GOPATH={{user `GOPATH`}}' + - 'GOSRC={{user `GOSRC`}}' - 'PACKER_BASE={{user `PACKER_BASE`}}' - 'SCRIPT_BASE={{user `SCRIPT_BASE`}}' diff --git a/contrib/cirrus/packer/ubuntu_packaging.sh b/contrib/cirrus/packer/ubuntu_packaging.sh index 09f9aab9f..d11c612c5 100644 --- a/contrib/cirrus/packer/ubuntu_packaging.sh +++ b/contrib/cirrus/packer/ubuntu_packaging.sh @@ -36,6 +36,7 @@ ooe.sh curl -L -o /tmp/Release.key "https://download.opensuse.org/repositories/d ooe.sh $SUDO apt-key add - < /tmp/Release.key INSTALL_PACKAGES=(\ + apache2-utils apparmor aufs-tools autoconf @@ -153,7 +154,12 @@ if [[ ${#DOWNLOAD_PACKAGES[@]} -gt 0 ]]; then fi echo "Installing runtime tooling" +# Save some runtime by having these already available cd $GOSRC +# Required since initially go was not installed +source $GOSRC/$SCRIPT_BASE/lib.sh +echo "Go environment has been setup:" +go env $SUDO hack/install_catatonit.sh $SUDO make install.libseccomp.sudo $SUDO make install.tools diff --git a/docs/source/index.rst b/docs/source/index.rst index 18a5554ca..715ca2744 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -2,13 +2,13 @@ What is Podman? ================================== -Podman_ is a daemonless, open source, Linux native tool designed to make it easy to find, run, build, share and deploy applications using Open Containers Initiative (OCI_) Containers_ and `Container Images`_. Podman provides a command line interface (CLI) familiar to anyone who has used the Docker `Container Engine`_. Most users can simply alias Docker to Podman (`alias docker=podman`) without any problems. Similar to other common `Container Engines`_ (Docker, CRI-O, containerd), Podman relies on an OCI compliant `Container Runtime`_ (runc, crun, runv, etc) to interface with the operating system and create the running containers.This makes the running containers created by Podman nearly indistinguishable from those created by any other common container engine. +Podman_ is a daemonless, open source, Linux native tool designed to make it easy to find, run, build, share and deploy applications using Open Containers Initiative (OCI_) Containers_ and `Container Images`_. Podman provides a command line interface (CLI) familiar to anyone who has used the Docker `Container Engine`_. Most users can simply alias Docker to Podman (`alias docker=podman`) without any problems. Similar to other common `Container Engines`_ (Docker, CRI-O, containerd), Podman relies on an OCI compliant `Container Runtime`_ (runc, crun, runv, etc) to interface with the operating system and create the running containers. This makes the running containers created by Podman nearly indistinguishable from those created by any other common container engine. Containers under the control of Podman can either be run by root or by a non-privileged user. Podman manages the entire container ecosystem which includes pods, containers, container images, and container volumes using the libpod_ library. Podman specializes in all of the commands and functions that help you to maintain and modify OCI container images, such as pulling and tagging. It allows you to create, run, and maintain those containers and container images in a production environment. The Podman service runs only on Linux platforms, however a REST API and clients are currently under development which will allow Mac and Windows platforms to call the service. There is currently a RESTful based remote client which runs on Mac or Windows platforms that allows the remote client to talk to the Podman server on a Linux platform. In addition to those clients, there is also a Mac client. -If you are completely new to containers, we recommend that you check out the :doc:`Introduction`. For power users or those comming from Docker, check out our :doc:`Tutorials`. For advanced users and contributors, you can get very detailed information about the Podman CLI by looking our :doc:`Commands` page. Finally, for Developers looking at how to interact with the Podman API, please see our API documentation :doc:`Reference`. +If you are completely new to containers, we recommend that you check out the :doc:`Introduction`. For power users or those coming from Docker, check out our :doc:`Tutorials`. For advanced users and contributors, you can get very detailed information about the Podman CLI by looking at our :doc:`Commands` page. Finally, for Developers looking at how to interact with the Podman API, please see our API documentation :doc:`Reference`. .. toctree:: :maxdepth: 2 diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md index 303d025b0..b959b947f 100644 --- a/docs/source/markdown/podman-run.1.md +++ b/docs/source/markdown/podman-run.1.md @@ -1129,7 +1129,7 @@ the exit codes follow the **chroot**(1) standard, see below: **Exit code** _contained command_ exit code - $ podman run busybox /bin/sh -c 'exit 3' + $ podman run busybox /bin/sh -c 'exit 3'; echo $? 3 ## EXAMPLES diff --git a/docs/source/markdown/podman-system-connection-add.1.md b/docs/source/markdown/podman-system-connection-add.1.md new file mode 100644 index 000000000..5059803a2 --- /dev/null +++ b/docs/source/markdown/podman-system-connection-add.1.md @@ -0,0 +1,46 @@ +% podman-system-connection-add(1) + +## NAME +podman\-system\-connection\-add - Record destination for the Podman service + +## SYNOPSIS +**podman system connection add** [*options*] *name* *destination* + +## DESCRIPTION +Record ssh destination for remote podman service(s). The ssh destination is given as one of: + - [user@]hostname[:port] + - ssh://[user@]hostname[:port] + +The user will be prompted for the remote ssh login password or key file pass phrase as required. The `ssh-agent` is supported if it is running. + +## OPTIONS + +**-d**, **--default**=*false* + +Make the new destination the default for this user. + +**--identity**=*path* + +Path to ssh identity file. If the identity file has been encrypted, Podman prompts the user for the passphrase. +If no identity file is provided and no user is given, Podman defaults to the user running the podman command. +Podman prompts for the login password on the remote server. + +**-p**, **--port**=*port* + +Port for ssh destination. The default value is `22`. + +**--socket-path**=*path* + +Path to the Podman service unix domain socket on the ssh destination host + +## EXAMPLE +``` +$ podman system connection add QA podman.example.com + +$ podman system connection add --identity ~/.ssh/dev_rsa production ssh://root@server.example.com:2222 +``` +## SEE ALSO +podman-system(1) , podman-system-connection(1) , containers.conf(5) + +## HISTORY +June 2020, Originally compiled by Jhon Honce (jhonce at redhat dot com) diff --git a/docs/source/markdown/podman-system-connection-default.1.md b/docs/source/markdown/podman-system-connection-default.1.md new file mode 100644 index 000000000..f324f8c01 --- /dev/null +++ b/docs/source/markdown/podman-system-connection-default.1.md @@ -0,0 +1,20 @@ +% podman-system-connection-default(1) + +## NAME +podman\-system\-connection\-default - Set named destination as default for the Podman service + +## SYNOPSIS +**podman system connection default** *name* + +## DESCRIPTION +Set named ssh destination as default destination for the Podman service. + +## EXAMPLE +``` +$ podman system connection default production +``` +## SEE ALSO +podman-system(1) , podman-system-connection(1) , containers.conf(5) + +## HISTORY +July 2020, Originally compiled by Jhon Honce (jhonce at redhat dot com) diff --git a/docs/source/markdown/podman-system-connection-list.1.md b/docs/source/markdown/podman-system-connection-list.1.md new file mode 100644 index 000000000..f5fb5c8e3 --- /dev/null +++ b/docs/source/markdown/podman-system-connection-list.1.md @@ -0,0 +1,24 @@ +% podman-system-connection-list(1) + +## NAME +podman\-system\-connection\-list - List the destination for the Podman service(s) + +## SYNOPSIS +**podman system connection list** + +**podman system connection ls** + +## DESCRIPTION +List ssh destination(s) for podman service(s). + +## EXAMPLE +``` +$ podman system connection list +Name URI Identity +devl ssh://root@example.com/run/podman/podman.sock ~/.ssh/id_rsa +``` +## SEE ALSO +podman-system(1) , containers.conf(5) + +## HISTORY +July 2020, Originally compiled by Jhon Honce (jhonce at redhat dot com) diff --git a/docs/source/markdown/podman-system-connection-remove.1.md b/docs/source/markdown/podman-system-connection-remove.1.md new file mode 100644 index 000000000..faa767176 --- /dev/null +++ b/docs/source/markdown/podman-system-connection-remove.1.md @@ -0,0 +1,20 @@ +% podman-system-connection-remove(1) + +## NAME +podman\-system\-connection\-remove - Delete named destination + +## SYNOPSIS +**podman system connection remove** *name* + +## DESCRIPTION +Delete named ssh destination. + +## EXAMPLE +``` +$ podman system connection remove production +``` +## SEE ALSO +podman-system(1) , podman-system-connection(1) , containers.conf(5) + +## HISTORY +July 2020, Originally compiled by Jhon Honce (jhonce at redhat dot com) diff --git a/docs/source/markdown/podman-system-connection-rename.1.md b/docs/source/markdown/podman-system-connection-rename.1.md new file mode 100644 index 000000000..819cb697f --- /dev/null +++ b/docs/source/markdown/podman-system-connection-rename.1.md @@ -0,0 +1,20 @@ +% podman-system-connection-rename(1) + +## NAME +podman\-system\-connection\-rename - Rename the destination for Podman service + +## SYNOPSIS +**podman system connection rename** *old* *new* + +## DESCRIPTION +Rename ssh destination from *old* to *new*. + +## EXAMPLE +``` +$ podman system connection rename laptop devel +``` +## SEE ALSO +podman-system(1) , podman-system-connection(1) , containers.conf(5) + +## HISTORY +July 2020, Originally compiled by Jhon Honce (jhonce at redhat dot com) diff --git a/docs/source/markdown/podman-system-connection.1.md b/docs/source/markdown/podman-system-connection.1.md index 66cb656ae..86199c6b9 100644 --- a/docs/source/markdown/podman-system-connection.1.md +++ b/docs/source/markdown/podman-system-connection.1.md @@ -1,43 +1,34 @@ % podman-system-connection(1) ## NAME -podman\-system\-connection - Record ssh destination for remote podman service +podman\-system\-connection - Manage the destination(s) for Podman service(s) -## SYNOPSIS -**podman system connection** [*options*] [*ssh destination*] +## SYNOPSISManage the destination(s) for Podman service(s) +**podman system connection** *subcommand* ## DESCRIPTION -Record ssh destination for remote podman service(s). The ssh destination is given as one of: - - [user@]hostname[:port] - - ssh://[user@]hostname[:port] +Manage the destination(s) for Podman service(s). -The user will be prompted for the remote ssh login password or key file pass phrase as required. `ssh-agent` is supported if it is running. +The user will be prompted for the ssh login password or key file pass phrase as required. The `ssh-agent` is supported if it is running. -## OPTIONS +## COMMANDS -**--identity**=*path* - -Path to ssh identity file. If the identity file has been encrypted, Podman prompts the user for the passphrase. -If no identity file is provided and no user is given, Podman defaults to the user running the podman command. -Podman prompts for the login password on the remote server. - -**-p**, **--port**=*port* - -Port for ssh destination. The default value is `22`. - -**--socket-path**=*path* - -Path to podman service unix domain socket on the ssh destination host +| Command | Man Page | Description | +| ------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------- | +| add | [podman-system-connection-add(1)](podman-system-connection-add.1.md) | Record destination for the Podman service | +| default | [podman-system-connection-default(1)](podman-system-connection-default.1.md) | Set named destination as default for the Podman service | +| list | [podman-system-connection-list(1)](podman-system-connection-list.1.md) | List the destination for the Podman service(s) | +| remove | [podman-system-connection-remove(1)](podman-system-connection-remove.1.md) | Delete named destination | +| rename | [podman-system-connection-rename(1)](podman-system-connection-rename.1.md) | Rename the destination for Podman service | ## EXAMPLE ``` -$ podman system connection podman.fubar.com - -$ podman system connection --identity ~/.ssh/dev_rsa ssh://root@server.fubar.com:2222 - +$ podman system connection list +Name URI Identity +devl ssh://root@example.com/run/podman/podman.sock ~/.ssh/id_rsa ``` ## SEE ALSO -podman-system(1) , containers.conf(5) , connections.conf(5) +podman-system(1) , containers.conf(5) ## HISTORY June 2020, Originally compiled by Jhon Honce (jhonce at redhat dot com) diff --git a/docs/source/markdown/podman-system-reset.1.md b/docs/source/markdown/podman-system-reset.1.md index f290e26d5..3294bac9b 100644 --- a/docs/source/markdown/podman-system-reset.1.md +++ b/docs/source/markdown/podman-system-reset.1.md @@ -7,7 +7,7 @@ podman\-system\-reset - Reset storage back to initial state **podman system reset** [*options*] ## DESCRIPTION -**podman system reset** removes all pods, containers, images and volumes. +**podman system reset** removes all pods, containers, images and volumes. Must be run after changing any of the following values in the `containers.conf` file: `static_dir`, `tmp_dir` or `volume_path`. ## OPTIONS **--force**, **-f** diff --git a/docs/source/markdown/podman-system.1.md b/docs/source/markdown/podman-system.1.md index 1f19fd0b6..9ac73237e 100644 --- a/docs/source/markdown/podman-system.1.md +++ b/docs/source/markdown/podman-system.1.md @@ -11,17 +11,16 @@ The system command allows you to manage the podman systems ## COMMANDS -| Command | Man Page | Description | -| ------- | --------------------------------------------------- | ---------------------------------------------------------------------------- | -| df | [podman-system-df(1)](podman-system-df.1.md) | Show podman disk usage. | -| connection | [podman-system-connection(1)](podman-system-connection.1.md) | Record ssh destination for remote podman service. | -| info | [podman-system-info(1)](podman-info.1.md) | Displays Podman related system information. | -| migrate | [podman-system-migrate(1)](podman-system-migrate.1.md) | Migrate existing containers to a new podman version. | -| prune | [podman-system-prune(1)](podman-system-prune.1.md) | Remove all unused container, image and volume data. | -| renumber | [podman-system-renumber(1)](podman-system-renumber.1.md) | Migrate lock numbers to handle a change in maximum number of locks. | -| reset | [podman-system-reset(1)](podman-system-reset.1.md) | Reset storage back to initial state. | -| service | [podman-service(1)](podman-system-service.1.md) | Run an API service | - +| Command | Man Page | Description | +| ------- | ------------------------------------------------------------ | -------------------------------------------------------------------- | +| connection | [podman-system-connection(1)](podman-system-connection.1.md) | Manage the destination(s) for Podman service(s) | +| df | [podman-system-df(1)](podman-system-df.1.md) | Show podman disk usage. | +| info | [podman-system-info(1)](podman-info.1.md) | Displays Podman related system information. | +| migrate | [podman-system-migrate(1)](podman-system-migrate.1.md) | Migrate existing containers to a new podman version. | +| prune | [podman-system-prune(1)](podman-system-prune.1.md) | Remove all unused container, image and volume data. | +| renumber | [podman-system-renumber(1)](podman-system-renumber.1.md) | Migrate lock numbers to handle a change in maximum number of locks. | +| reset | [podman-system-reset(1)](podman-system-reset.1.md) | Reset storage back to initial state. | +| service | [podman-system-service(1)](podman-system-service.1.md) | Run an API service | ## SEE ALSO podman(1) diff --git a/docs/source/system.rst b/docs/source/system.rst index 2f2b7ea8f..2d93a1d6d 100644 --- a/docs/source/system.rst +++ b/docs/source/system.rst @@ -10,3 +10,5 @@ System :doc:`prune <markdown/podman-system-prune.1>` Remove unused data :doc:`renumber <markdown/podman-system-renumber.1>` Migrate lock numbers + +:doc:`reset <markdown/podman-system-reset.1>` Reset podman storage @@ -11,7 +11,7 @@ require ( github.com/containernetworking/cni v0.7.2-0.20200304161608-4fae32b84921 github.com/containernetworking/plugins v0.8.6 github.com/containers/buildah v1.15.1-0.20200708111410-d2ea9429455d - github.com/containers/common v0.17.0 + github.com/containers/common v0.18.0 github.com/containers/conmon v2.0.19+incompatible github.com/containers/image/v5 v5.5.1 github.com/containers/psgo v1.5.1 @@ -73,8 +73,8 @@ github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHV github.com/containers/buildah v1.15.1-0.20200708111410-d2ea9429455d h1:HgJJn1UBFjM464NpEmgLwVje5vSF/fBYAdLLoww9HgU= github.com/containers/buildah v1.15.1-0.20200708111410-d2ea9429455d/go.mod h1:HUAiD1mCGPFPcIuk5zls1LElLhXo7Q3hWDwheojjyAs= github.com/containers/common v0.15.2/go.mod h1:rhpXuGLTEKsk/xX/x0iKGHjRadMHpBd2ZiNDugwXPEM= -github.com/containers/common v0.17.0 h1:3wkcSLw92UYPEhPSHeG1szyIe1qFgi9Jtj18l/tTii0= -github.com/containers/common v0.17.0/go.mod h1:bG22Wvr0iyWJ8UvIkL5dA5OEZFDqAJx1MejmWZb51HE= +github.com/containers/common v0.18.0 h1:pZB6f17N5QV43TcT06gtx1lb0rxd/4StFdVhP9CtgQg= +github.com/containers/common v0.18.0/go.mod h1:H2Wqvx6wkqdzT4RcTCqIG4W0HSOZwUbbNiUTX1+VohU= github.com/containers/conmon v2.0.19+incompatible h1:1bDVRvHy2MUNTUT/SW6LlHsJHQBTSwXvnKNdcB/a1vQ= github.com/containers/conmon v2.0.19+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/image/v5 v5.5.1 h1:h1FCOXH6Ux9/p/E4rndsQOC4yAdRU0msRTfLVeQ7FDQ= @@ -86,8 +86,6 @@ github.com/containers/ocicrypt v1.0.2/go.mod h1:nsOhbP19flrX6rE7ieGFvBlr7modwmNj github.com/containers/psgo v1.5.1 h1:MQNb7FLbXqBdqz6u4lI2QWizVz4RSTzs1+Nk9XT1iVA= github.com/containers/psgo v1.5.1/go.mod h1:2ubh0SsreMZjSXW1Hif58JrEcFudQyIy9EzPUWfawVU= github.com/containers/storage v1.20.2/go.mod h1:oOB9Ie8OVPojvoaKWEGSEtHbXUAs+tSyr7RO7ZGteMc= -github.com/containers/storage v1.21.1 h1:FGA2c7+0Bn8ndrlrj+HHmKeVjFD3yVhvYa0gijsrg1M= -github.com/containers/storage v1.21.1/go.mod h1:I1EIAA7B4OwWRSA0b4yq2AW1wjvvfcY0zLWQuwTa4zw= github.com/containers/storage v1.21.2 h1:bf9IqA+g6ClBviqVG5lVCp5tTH9lvWwjYws7mVYSti0= github.com/containers/storage v1.21.2/go.mod h1:I1EIAA7B4OwWRSA0b4yq2AW1wjvvfcY0zLWQuwTa4zw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= diff --git a/hack/xref-helpmsgs-manpages b/hack/xref-helpmsgs-manpages index c1e9dffc4..16b596589 100755 --- a/hack/xref-helpmsgs-manpages +++ b/hack/xref-helpmsgs-manpages @@ -16,6 +16,9 @@ our $VERSION = '0.1'; # For debugging, show data structures using DumpTree($var) #use Data::TreeDumper; $Data::TreeDumper::Displayaddress = 0; +# unbuffer output +$| = 1; + ############################################################################### # BEGIN user-customizable section @@ -266,12 +269,16 @@ sub podman_man { elsif ($section eq 'commands') { # In podman.1.md if ($line =~ /^\|\s*\[podman-(\S+?)\(\d\)\]/) { - $man{$1} = podman_man("podman-$1"); + # $1 will be changed by recursion _*BEFORE*_ left-hand assignment + my $subcmd = $1; + $man{$subcmd} = podman_man("podman-$1"); } # In podman-<subcommand>.1.md elsif ($line =~ /^\|\s+(\S+)\s+\|\s+\[\S+\]\((\S+)\.1\.md\)/) { - $man{$1} = podman_man($2); + # $1 will be changed by recursion _*BEFORE*_ left-hand assignment + my $subcmd = $1; + $man{$subcmd} = podman_man($2); } } diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go index 4ad6aa862..cbcda474a 100644 --- a/pkg/api/handlers/compat/containers_create.go +++ b/pkg/api/handlers/compat/containers_create.go @@ -159,10 +159,10 @@ func makeCreateConfig(ctx context.Context, containerConfig *config.Config, input User: input.User, } pidConfig := createconfig.PidConfig{PidMode: namespaces.PidMode(input.HostConfig.PidMode)} - volumes := make([]string, 0, len(input.Volumes)) - for k := range input.Volumes { - volumes = append(volumes, k) - } + // TODO: We should check that these binds are all listed in the `Volumes` + // key since it doesn't make sense to define a `Binds` element for a + // container path which isn't defined as a volume + volumes := input.HostConfig.Binds // Docker is more flexible about its input where podman throws // away incorrectly formatted variables so we cannot reuse the diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 888811958..52a62a25d 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -340,9 +340,7 @@ func getPodPorts(containers []v1.Container) []ocicni.PortMapping { HostPort: p.HostPort, ContainerPort: p.ContainerPort, Protocol: strings.ToLower(string(p.Protocol)), - } - if p.HostIP != "" { - logrus.Debug("HostIP on port bindings is not supported") + HostIP: p.HostIP, } // only hostPort is utilized in podman context, all container ports // are accessible inside the shared network namespace diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index f475a927c..4fc5b3da9 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -152,6 +152,8 @@ var _ = SynchronizedBeforeSuite(func() []byte { return []byte(path) }, func(data []byte) { + cwd, _ := os.Getwd() + INTEGRATION_ROOT = filepath.Join(cwd, "../../") LockTmpDir = string(data) }) @@ -618,3 +620,9 @@ func SkipIfCgroupV2() { Skip("Skip on systems with cgroup V2 systems") } } + +// PodmanAsUser is the exec call to podman on the filesystem with the specified uid/gid and environment +func (p *PodmanTestIntegration) PodmanAsUser(args []string, uid, gid uint32, cwd string, env []string) *PodmanSessionIntegration { + podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env, false, false, nil) + return &PodmanSessionIntegration{podmanSession} +} diff --git a/test/e2e/create_staticip_test.go b/test/e2e/create_staticip_test.go index a1a08045a..a6f4f830b 100644 --- a/test/e2e/create_staticip_test.go +++ b/test/e2e/create_staticip_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index 49e4e53cd..bfd898108 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -46,12 +46,6 @@ func (p *PodmanTestIntegration) PodmanNoEvents(args []string) *PodmanSessionInte return &PodmanSessionIntegration{podmanSession} } -// PodmanAsUser is the exec call to podman on the filesystem with the specified uid/gid and environment -func (p *PodmanTestIntegration) PodmanAsUser(args []string, uid, gid uint32, cwd string, env []string) *PodmanSessionIntegration { - podmanSession := p.PodmanAsUserBase(args, uid, gid, cwd, env, false, false, nil) - return &PodmanSessionIntegration{podmanSession} -} - func (p *PodmanTestIntegration) setDefaultRegistriesConfigEnv() { defaultFile := filepath.Join(INTEGRATION_ROOT, "test/registries.conf") os.Setenv("REGISTRIES_CONFIG_PATH", defaultFile) diff --git a/test/e2e/login_logout_test.go b/test/e2e/login_logout_test.go index 3bdce970b..66f764925 100644 --- a/test/e2e/login_logout_test.go +++ b/test/e2e/login_logout_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/namespace_test.go b/test/e2e/namespace_test.go index 70472f384..5756a8fa2 100644 --- a/test/e2e/namespace_test.go +++ b/test/e2e/namespace_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -35,6 +33,7 @@ var _ = Describe("Podman namespaces", func() { }) It("podman namespace test", func() { + SkipIfRemote() podman1 := podmanTest.Podman([]string{"--namespace", "test1", "run", "-d", ALPINE, "echo", "hello"}) podman1.WaitWithDefaultTimeout() Expect(podman1.ExitCode()).To(Equal(0)) diff --git a/test/e2e/network_create_test.go b/test/e2e/network_create_test.go index 83b0ce32c..24f711ae7 100644 --- a/test/e2e/network_create_test.go +++ b/test/e2e/network_create_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -140,6 +138,7 @@ var _ = Describe("Podman network create", func() { }) It("podman network create with name and subnet", func() { + SkipIfRemote() var ( results []network.NcList ) diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index 4b68f6232..052db3842 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -87,6 +85,11 @@ spec: {{ end }} privileged: false readOnlyRootFilesystem: false + ports: + - containerPort: {{ .Port }} + hostIP: {{ .HostIP }} + hostPort: {{ .Port }} + protocol: TCP workingDir: / {{ end }} {{ end }} @@ -338,12 +341,14 @@ type Ctr struct { CapAdd []string CapDrop []string PullPolicy string + HostIP string + Port string } // getCtr takes a list of ctrOptions and returns a Ctr with sane defaults // and the configured options func getCtr(options ...ctrOption) *Ctr { - c := Ctr{defaultCtrName, defaultCtrImage, defaultCtrCmd, defaultCtrArg, true, false, nil, nil, ""} + c := Ctr{defaultCtrName, defaultCtrImage, defaultCtrCmd, defaultCtrArg, true, false, nil, nil, "", "", ""} for _, option := range options { option(&c) } @@ -396,6 +401,13 @@ func withPullPolicy(policy string) ctrOption { } } +func withHostIP(ip string, port string) ctrOption { + return func(c *Ctr) { + c.HostIP = ip + c.Port = port + } +} + func getCtrNameInPod(pod *Pod) string { return fmt.Sprintf("%s-%s", pod.Name, defaultCtrName) } @@ -447,6 +459,7 @@ var _ = Describe("Podman generate kube", func() { }) It("podman play kube test correct command", func() { + SkipIfRemote() pod := getPod() err := generatePodKubeYaml(pod, kubeYaml) Expect(err).To(BeNil()) @@ -464,6 +477,7 @@ var _ = Describe("Podman generate kube", func() { }) It("podman play kube test correct command with only set command in yaml file", func() { + SkipIfRemote() pod := getPod(withCtr(getCtr(withCmd([]string{"echo", "hello"}), withArg(nil)))) err := generatePodKubeYaml(pod, kubeYaml) Expect(err).To(BeNil()) @@ -498,6 +512,7 @@ var _ = Describe("Podman generate kube", func() { }) It("podman play kube test correct output", func() { + SkipIfRemote() p := getPod(withCtr(getCtr(withCmd([]string{"echo", "hello"}), withArg([]string{"world"})))) err := generatePodKubeYaml(p, kubeYaml) @@ -601,6 +616,7 @@ var _ = Describe("Podman generate kube", func() { }) It("podman play kube seccomp container level", func() { + SkipIfRemote() // expect play kube is expected to set a seccomp label if it's applied as an annotation jsonFile, err := podmanTest.CreateSeccompJson(seccompPwdEPERM) if err != nil { @@ -627,6 +643,7 @@ var _ = Describe("Podman generate kube", func() { }) It("podman play kube seccomp pod level", func() { + SkipIfRemote() // expect play kube is expected to set a seccomp label if it's applied as an annotation jsonFile, err := podmanTest.CreateSeccompJson(seccompPwdEPERM) if err != nil { @@ -778,6 +795,7 @@ spec: // Deployment related tests It("podman play kube deployment 1 replica test correct command", func() { + SkipIfRemote() deployment := getDeployment() err := generateDeploymentKubeYaml(deployment, kubeYaml) Expect(err).To(BeNil()) @@ -796,6 +814,7 @@ spec: }) It("podman play kube deployment more than 1 replica test correct command", func() { + SkipIfRemote() var i, numReplicas int32 numReplicas = 5 deployment := getDeployment(withReplicas(numReplicas)) @@ -815,4 +834,23 @@ spec: Expect(inspect.OutputToString()).To(ContainSubstring(correctCmd)) } }) + + It("podman play kube test with network portbindings", func() { + ip := "127.0.0.100" + port := "5000" + ctr := getCtr(withHostIP(ip, port), withImage(BB)) + + pod := getPod(withCtr(ctr)) + err := generatePodKubeYaml(pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube.ExitCode()).To(Equal(0)) + + inspect := podmanTest.Podman([]string{"port", getCtrNameInPod(pod)}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(Equal(0)) + Expect(inspect.OutputToString()).To(Equal("5000/tcp -> 127.0.0.100:5000")) + }) }) diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go index 49105310b..a5fa21187 100644 --- a/test/e2e/pod_infra_container_test.go +++ b/test/e2e/pod_infra_container_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -227,6 +225,7 @@ var _ = Describe("Podman pod create", func() { }) It("podman pod container can override pod pid NS", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"pod", "create", "--share", "pid"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -258,6 +257,7 @@ var _ = Describe("Podman pod create", func() { }) It("podman pod container can override pod not sharing pid", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"pod", "create", "--share", "net"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -283,6 +283,7 @@ var _ = Describe("Podman pod create", func() { }) It("podman pod container can override pod ipc NS", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"pod", "create", "--share", "ipc"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/pod_pod_namespaces.go b/test/e2e/pod_pod_namespaces.go index fce131e20..7a6223158 100644 --- a/test/e2e/pod_pod_namespaces.go +++ b/test/e2e/pod_pod_namespaces.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -63,6 +61,7 @@ var _ = Describe("Podman pod create", func() { }) It("podman pod container dontshare PIDNS", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"pod", "create"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/pod_stats_test.go b/test/e2e/pod_stats_test.go index 74d1c1838..04068de06 100644 --- a/test/e2e/pod_stats_test.go +++ b/test/e2e/pod_stats_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/pod_top_test.go b/test/e2e/pod_top_test.go index f86d23d84..40e8d77d8 100644 --- a/test/e2e/pod_top_test.go +++ b/test/e2e/pod_top_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -58,6 +56,7 @@ var _ = Describe("Podman top", func() { }) It("podman pod top on pod", func() { + SkipIfRemote() _, ec, podid := podmanTest.CreatePod("") Expect(ec).To(Equal(0)) diff --git a/test/e2e/port_test.go b/test/e2e/port_test.go index 897505588..b247fcaa3 100644 --- a/test/e2e/port_test.go +++ b/test/e2e/port_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -49,6 +47,7 @@ var _ = Describe("Podman port", func() { }) It("podman port -l nginx", func() { + SkipIfRemote() session, cid := podmanTest.RunNginxWithHealthCheck("") Expect(session.ExitCode()).To(Equal(0)) @@ -64,6 +63,7 @@ var _ = Describe("Podman port", func() { }) It("podman container port -l nginx", func() { + SkipIfRemote() session, cid := podmanTest.RunNginxWithHealthCheck("") Expect(session.ExitCode()).To(Equal(0)) @@ -79,6 +79,7 @@ var _ = Describe("Podman port", func() { }) It("podman port -l port nginx", func() { + SkipIfRemote() session, cid := podmanTest.RunNginxWithHealthCheck("") Expect(session.ExitCode()).To(Equal(0)) @@ -127,18 +128,18 @@ var _ = Describe("Podman port", func() { lock2 := GetPortLock("5001") defer lock2.Unlock() - setup := podmanTest.Podman([]string{"run", "-dt", "-p", "5000:5000", "-p", "5001:5001", ALPINE, "top"}) + setup := podmanTest.Podman([]string{"run", "--name", "test", "-dt", "-p", "5000:5000", "-p", "5001:5001", ALPINE, "top"}) setup.WaitWithDefaultTimeout() Expect(setup.ExitCode()).To(BeZero()) // Check that the first port was honored - result1 := podmanTest.Podman([]string{"port", "-l", "5000"}) + result1 := podmanTest.Podman([]string{"port", "test", "5000"}) result1.WaitWithDefaultTimeout() Expect(result1.ExitCode()).To(BeZero()) Expect(result1.LineInOuputStartsWith("0.0.0.0:5000")).To(BeTrue()) // Check that the second port was honored - result2 := podmanTest.Podman([]string{"port", "-l", "5001"}) + result2 := podmanTest.Podman([]string{"port", "test", "5001"}) result2.WaitWithDefaultTimeout() Expect(result2.ExitCode()).To(BeZero()) Expect(result2.LineInOuputStartsWith("0.0.0.0:5001")).To(BeTrue()) diff --git a/test/e2e/run_cleanup_test.go b/test/e2e/run_cleanup_test.go index 7c83acc40..596c224aa 100644 --- a/test/e2e/run_cleanup_test.go +++ b/test/e2e/run_cleanup_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -35,6 +33,7 @@ var _ = Describe("Podman run exit", func() { }) It("podman run -d mount cleanup test", func() { + SkipIfRemote() SkipIfRootless() result := podmanTest.Podman([]string{"run", "-dt", ALPINE, "top"}) diff --git a/test/e2e/run_cpu_test.go b/test/e2e/run_cpu_test.go index b4785c513..b1fb0e628 100644 --- a/test/e2e/run_cpu_test.go +++ b/test/e2e/run_cpu_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_device_test.go b/test/e2e/run_device_test.go index b1a4c9cb2..8798b2dc1 100644 --- a/test/e2e/run_device_test.go +++ b/test/e2e/run_device_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_dns_test.go b/test/e2e/run_dns_test.go index beed80fd2..a44fb7187 100644 --- a/test/e2e/run_dns_test.go +++ b/test/e2e/run_dns_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_entrypoint_test.go b/test/e2e/run_entrypoint_test.go index 741019770..f6019b37a 100644 --- a/test/e2e/run_entrypoint_test.go +++ b/test/e2e/run_entrypoint_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -46,6 +44,7 @@ CMD [] }) It("podman run entrypoint", func() { + SkipIfRemote() dockerfile := `FROM docker.io/library/alpine:latest ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] ` @@ -57,6 +56,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] }) It("podman run entrypoint with cmd", func() { + SkipIfRemote() dockerfile := `FROM docker.io/library/alpine:latest CMD [ "-v"] ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] @@ -69,6 +69,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] }) It("podman run entrypoint with user cmd overrides image cmd", func() { + SkipIfRemote() dockerfile := `FROM docker.io/library/alpine:latest CMD [ "-v"] ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] @@ -81,6 +82,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] }) It("podman run entrypoint with user cmd no image cmd", func() { + SkipIfRemote() dockerfile := `FROM docker.io/library/alpine:latest ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] ` @@ -92,6 +94,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] }) It("podman run user entrypoint overrides image entrypoint and image cmd", func() { + SkipIfRemote() dockerfile := `FROM docker.io/library/alpine:latest CMD ["-i"] ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] @@ -109,6 +112,7 @@ ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] }) It("podman run user entrypoint with command overrides image entrypoint and image cmd", func() { + SkipIfRemote() dockerfile := `FROM docker.io/library/alpine:latest CMD ["-i"] ENTRYPOINT ["grep", "Alpine", "/etc/os-release"] diff --git a/test/e2e/run_env_test.go b/test/e2e/run_env_test.go index c6fb1ad1b..305e37c12 100644 --- a/test/e2e/run_env_test.go +++ b/test/e2e/run_env_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_memory_test.go b/test/e2e/run_memory_test.go index 5ae45b62f..379e74629 100644 --- a/test/e2e/run_memory_test.go +++ b/test/e2e/run_memory_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index 317f760db..a22f79180 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -265,10 +263,10 @@ var _ = Describe("Podman run networking", func() { }) It("podman run network expose ports in image metadata", func() { - session := podmanTest.Podman([]string{"create", "-dt", "-P", nginx}) + session := podmanTest.Podman([]string{"create", "--name", "test", "-dt", "-P", nginx}) session.Wait(90) Expect(session.ExitCode()).To(Equal(0)) - results := podmanTest.Podman([]string{"inspect", "-l"}) + results := podmanTest.Podman([]string{"inspect", "test"}) results.Wait(30) Expect(results.ExitCode()).To(Equal(0)) Expect(results.OutputToString()).To(ContainSubstring(`"80/tcp":`)) @@ -277,11 +275,11 @@ var _ = Describe("Podman run networking", func() { It("podman run network expose duplicate host port results in error", func() { SkipIfRootless() - session := podmanTest.Podman([]string{"run", "-dt", "-p", "80", ALPINE, "/bin/sh"}) + session := podmanTest.Podman([]string{"run", "--name", "test", "-dt", "-p", "80", ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - inspect := podmanTest.Podman([]string{"inspect", "-l"}) + inspect := podmanTest.Podman([]string{"inspect", "test"}) inspect.WaitWithDefaultTimeout() Expect(inspect.ExitCode()).To(Equal(0)) @@ -436,6 +434,7 @@ var _ = Describe("Podman run networking", func() { }) It("podman run in custom CNI network with --static-ip", func() { + SkipIfRemote() SkipIfRootless() netName := "podmantestnetwork" ipAddr := "10.20.30.128" diff --git a/test/e2e/run_ns_test.go b/test/e2e/run_ns_test.go index 96ca2fc56..181b453c1 100644 --- a/test/e2e/run_ns_test.go +++ b/test/e2e/run_ns_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_restart_test.go b/test/e2e/run_restart_test.go index 0a1c7e134..fa9cb2495 100644 --- a/test/e2e/run_restart_test.go +++ b/test/e2e/run_restart_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -35,11 +33,12 @@ var _ = Describe("Podman run restart containers", func() { }) It("Podman start after successful run", func() { - session := podmanTest.Podman([]string{"run", ALPINE, "ls"}) + SkipIfRemote() + session := podmanTest.Podman([]string{"run", "--name", "test", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session2 := podmanTest.Podman([]string{"start", "--attach", "--latest"}) + session2 := podmanTest.Podman([]string{"start", "--attach", "test"}) session2.WaitWithDefaultTimeout() Expect(session2.ExitCode()).To(Equal(0)) }) diff --git a/test/e2e/run_seccomp.go b/test/e2e/run_seccomp.go index a6a14618c..ec688135b 100644 --- a/test/e2e/run_seccomp.go +++ b/test/e2e/run_seccomp.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_security_labels.go b/test/e2e/run_security_labels.go index 148b18daa..50209a989 100644 --- a/test/e2e/run_security_labels.go +++ b/test/e2e/run_security_labels.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -129,6 +127,7 @@ var _ = Describe("Podman generate kube", func() { }) It("podman container runlabel (podman --version)", func() { + SkipIfRemote() PodmanDockerfile := ` FROM alpine:latest LABEL io.containers.capabilities=chown,mknod` diff --git a/test/e2e/run_selinux_test.go b/test/e2e/run_selinux_test.go index 7c1946534..c88441fbc 100644 --- a/test/e2e/run_selinux_test.go +++ b/test/e2e/run_selinux_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_staticip_test.go b/test/e2e/run_staticip_test.go index 8377636cf..de7663cc2 100644 --- a/test/e2e/run_staticip_test.go +++ b/test/e2e/run_staticip_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_userns_test.go b/test/e2e/run_userns_test.go index 42f13537d..b82fa7acb 100644 --- a/test/e2e/run_userns_test.go +++ b/test/e2e/run_userns_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go index 2b806ac2b..63aa116f8 100644 --- a/test/e2e/run_volume_test.go +++ b/test/e2e/run_volume_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -199,6 +197,7 @@ var _ = Describe("Podman run with volumes", func() { }) It("podman run with volumes and suid/dev/exec options", func() { + SkipIfRemote() mountPath := filepath.Join(podmanTest.TempDir, "secrets") os.Mkdir(mountPath, 0755) @@ -228,6 +227,7 @@ var _ = Describe("Podman run with volumes", func() { }) It("podman run with tmpfs named volume mounts and unmounts", func() { + SkipIfRemote() SkipIfRootless() volName := "testvol" mkVolume := podmanTest.Podman([]string{"volume", "create", "--opt", "type=tmpfs", "--opt", "device=tmpfs", "--opt", "o=nodev", "testvol"}) @@ -315,6 +315,7 @@ var _ = Describe("Podman run with volumes", func() { }) It("podman run with anonymous volume", func() { + SkipIfRemote() list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"}) list1.WaitWithDefaultTimeout() Expect(list1.ExitCode()).To(Equal(0)) @@ -333,6 +334,7 @@ var _ = Describe("Podman run with volumes", func() { }) It("podman rm -v removes anonymous volume", func() { + SkipIfRemote() list1 := podmanTest.Podman([]string{"volume", "list", "--quiet"}) list1.WaitWithDefaultTimeout() Expect(list1.ExitCode()).To(Equal(0)) @@ -434,6 +436,7 @@ var _ = Describe("Podman run with volumes", func() { }) It("Podman mount over image volume with trailing /", func() { + SkipIfRemote() image := "podman-volume-test:trailing" dockerfile := ` FROM alpine:latest @@ -453,6 +456,7 @@ VOLUME /test/` }) It("podman run with overlay volume flag", func() { + SkipIfRemote() if os.Getenv("container") != "" { Skip("Overlay mounts not supported when running in a container") } diff --git a/test/e2e/runlabel_test.go b/test/e2e/runlabel_test.go index 3383fbd1e..aae193aa0 100644 --- a/test/e2e/runlabel_test.go +++ b/test/e2e/runlabel_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -48,6 +46,7 @@ var _ = Describe("podman container runlabel", func() { }) It("podman container runlabel (podman --version)", func() { + SkipIfRemote() image := "podman-runlabel-test:podman" podmanTest.BuildImage(PodmanDockerfile, image, "false") @@ -61,6 +60,7 @@ var _ = Describe("podman container runlabel", func() { }) It("podman container runlabel (ls -la)", func() { + SkipIfRemote() image := "podman-runlabel-test:ls" podmanTest.BuildImage(LsDockerfile, image, "false") diff --git a/test/e2e/system_connection_test.go b/test/e2e/system_connection_test.go new file mode 100644 index 000000000..4c750ee7f --- /dev/null +++ b/test/e2e/system_connection_test.go @@ -0,0 +1,176 @@ +package integration + +import ( + "fmt" + "io/ioutil" + "os" + + "github.com/containers/common/pkg/config" + . "github.com/containers/libpod/v2/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gbytes" + . "github.com/onsi/gomega/gexec" +) + +var _ = Describe("podman system connection", func() { + ConfPath := struct { + Value string + IsSet bool + }{} + + var ( + podmanTest *PodmanTestIntegration + ) + + BeforeEach(func() { + ConfPath.Value, ConfPath.IsSet = os.LookupEnv("CONTAINERS_CONF") + conf, err := ioutil.TempFile("", "containersconf") + if err != nil { + panic(err) + } + os.Setenv("CONTAINERS_CONF", conf.Name()) + + tempdir, err := CreateTempDirInTempDir() + if err != nil { + panic(err) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.Setup() + }) + + AfterEach(func() { + podmanTest.Cleanup() + os.Remove(os.Getenv("CONTAINERS_CONF")) + if ConfPath.IsSet { + os.Setenv("CONTAINERS_CONF", ConfPath.Value) + } else { + os.Unsetenv("CONTAINERS_CONF") + } + + f := CurrentGinkgoTestDescription() + timedResult := fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds()) + GinkgoWriter.Write([]byte(timedResult)) + }) + + It("add", func() { + cmd := []string{"system", "connection", "add", + "--default", + "--identity", "~/.ssh/id_rsa", + "QA", + "ssh://root@server.fubar.com:2222/run/podman/podman.sock", + } + session := podmanTest.Podman(cmd) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.Out).Should(Say("")) + + cfg, err := config.ReadCustomConfig() + Expect(err).ShouldNot(HaveOccurred()) + Expect(cfg.Engine.ActiveService).To(Equal("QA")) + Expect(cfg.Engine.ServiceDestinations["QA"]).To(Equal( + config.Destination{ + URI: "ssh://root@server.fubar.com:2222/run/podman/podman.sock", + Identity: "~/.ssh/id_rsa", + }, + )) + + cmd = []string{"system", "connection", "rename", + "QA", + "QE", + } + session = podmanTest.Podman(cmd) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + cfg, err = config.ReadCustomConfig() + Expect(err).ShouldNot(HaveOccurred()) + Expect(cfg.Engine.ActiveService).To(Equal("QE")) + Expect(cfg.Engine.ServiceDestinations["QE"]).To(Equal( + config.Destination{ + URI: "ssh://root@server.fubar.com:2222/run/podman/podman.sock", + Identity: "~/.ssh/id_rsa", + }, + )) + }) + + It("remove", func() { + cmd := []string{"system", "connection", "add", + "--default", + "--identity", "~/.ssh/id_rsa", + "QA", + "ssh://root@server.fubar.com:2222/run/podman/podman.sock", + } + session := podmanTest.Podman(cmd) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + for i := 0; i < 2; i++ { + cmd = []string{"system", "connection", "remove", "QA"} + session = podmanTest.Podman(cmd) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.Out).Should(Say("")) + + cfg, err := config.ReadCustomConfig() + Expect(err).ShouldNot(HaveOccurred()) + Expect(cfg.Engine.ActiveService).To(BeEmpty()) + Expect(cfg.Engine.ServiceDestinations).To(BeEmpty()) + } + }) + + It("default", func() { + for _, name := range []string{"devl", "qe"} { + cmd := []string{"system", "connection", "add", + "--default", + "--identity", "~/.ssh/id_rsa", + name, + "ssh://root@server.fubar.com:2222/run/podman/podman.sock", + } + session := podmanTest.Podman(cmd) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + } + + cmd := []string{"system", "connection", "default", "devl"} + session := podmanTest.Podman(cmd) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.Out).Should(Say("")) + + cfg, err := config.ReadCustomConfig() + Expect(err).ShouldNot(HaveOccurred()) + Expect(cfg.Engine.ActiveService).To(Equal("devl")) + + cmd = []string{"system", "connection", "list"} + session = podmanTest.Podman(cmd) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.Out).Should(Say("Name *Identity *URI")) + }) + + It("failed default", func() { + cmd := []string{"system", "connection", "default", "devl"} + session := podmanTest.Podman(cmd) + session.WaitWithDefaultTimeout() + Expect(session).ShouldNot(Exit(0)) + Expect(session.Err).Should(Say("destination is not defined")) + }) + + It("failed rename", func() { + cmd := []string{"system", "connection", "rename", "devl", "QE"} + session := podmanTest.Podman(cmd) + session.WaitWithDefaultTimeout() + Expect(session).ShouldNot(Exit(0)) + Expect(session.Err).Should(Say("destination is not defined")) + }) + + It("empty list", func() { + cmd := []string{"system", "connection", "list"} + session := podmanTest.Podman(cmd) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.Out).Should(Say("")) + Expect(session.Err).Should(Say("")) + }) +}) diff --git a/test/e2e/system_df_test.go b/test/e2e/system_df_test.go index f17afaec1..b179a29d4 100644 --- a/test/e2e/system_df_test.go +++ b/test/e2e/system_df_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -37,6 +35,7 @@ var _ = Describe("podman system df", func() { }) It("podman system df", func() { + SkipIfRemote() session := podmanTest.Podman([]string{"create", ALPINE}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go index 7b9be2275..268f62f5b 100644 --- a/test/e2e/systemd_test.go +++ b/test/e2e/systemd_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/test/e2e/top_test.go b/test/e2e/top_test.go index 157a7fe46..f4d1ec857 100644 --- a/test/e2e/top_test.go +++ b/test/e2e/top_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( @@ -55,22 +53,22 @@ var _ = Describe("Podman top", func() { }) It("podman top on container", func() { - session := podmanTest.Podman([]string{"run", "-d", ALPINE, "top", "-d", "2"}) + session := podmanTest.Podman([]string{"run", "--name", "test", "-d", ALPINE, "top", "-d", "2"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"top", "-l"}) + result := podmanTest.Podman([]string{"top", "test"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) Expect(len(result.OutputToStringArray())).To(BeNumerically(">", 1)) }) It("podman container top on container", func() { - session := podmanTest.Podman([]string{"container", "run", "-d", ALPINE, "top", "-d", "2"}) + session := podmanTest.Podman([]string{"container", "run", "--name", "test", "-d", ALPINE, "top", "-d", "2"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - result := podmanTest.Podman([]string{"container", "top", "-l"}) + result := podmanTest.Podman([]string{"container", "top", "test"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) Expect(len(result.OutputToStringArray())).To(BeNumerically(">", 1)) diff --git a/test/e2e/volume_prune_test.go b/test/e2e/volume_prune_test.go index c4fafa406..d98b02824 100644 --- a/test/e2e/volume_prune_test.go +++ b/test/e2e/volume_prune_test.go @@ -1,5 +1,3 @@ -// +build !remote - package integration import ( diff --git a/vendor/github.com/containers/common/pkg/config/systemd.go b/vendor/github.com/containers/common/pkg/config/systemd.go index e02f52192..02e5c4ac2 100644 --- a/vendor/github.com/containers/common/pkg/config/systemd.go +++ b/vendor/github.com/containers/common/pkg/config/systemd.go @@ -2,7 +2,17 @@ package config +import ( + "github.com/containers/common/pkg/cgroupv2" + "github.com/containers/storage/pkg/unshare" +) + func defaultCgroupManager() string { + enabled, err := cgroupv2.Enabled() + if err == nil && !enabled && unshare.IsRootless() { + return CgroupfsCgroupsManager + } + return SystemdCgroupsManager } func defaultEventsLogger() string { diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go index 2913fe974..6b226eabe 100644 --- a/vendor/github.com/containers/common/version/version.go +++ b/vendor/github.com/containers/common/version/version.go @@ -1,4 +1,4 @@ package version // Version is the version of the build. -const Version = "0.17.0" +const Version = "0.18.0" diff --git a/vendor/modules.txt b/vendor/modules.txt index 1d97f810a..7cd0f86df 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -84,7 +84,7 @@ github.com/containers/buildah/pkg/secrets github.com/containers/buildah/pkg/supplemented github.com/containers/buildah/pkg/umask github.com/containers/buildah/util -# github.com/containers/common v0.17.0 +# github.com/containers/common v0.18.0 github.com/containers/common/pkg/apparmor github.com/containers/common/pkg/auth github.com/containers/common/pkg/capabilities |