mirror of
https://github.com/containers/podman.git
synced 2025-07-02 00:30:00 +08:00
[WIP] Refactor podman system connection
* Add support to manage multiple connections * Add connection * Remove connection * Rename connection * Set connection as default * Add markdown/man pages * Fix recursion in hack/xref-helpmsgs-manpages Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
@ -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"
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
223
cmd/podman/system/connection/add.go
Normal file
223
cmd/podman/system/connection/add.go
Normal file
@ -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
|
||||
}
|
46
cmd/podman/system/connection/default.go
Normal file
46
cmd/podman/system/connection/default.go
Normal file
@ -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()
|
||||
}
|
84
cmd/podman/system/connection/list.go
Normal file
84
cmd/podman/system/connection/list.go
Normal file
@ -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)
|
||||
}
|
49
cmd/podman/system/connection/remove.go
Normal file
49
cmd/podman/system/connection/remove.go
Normal file
@ -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()
|
||||
}
|
54
cmd/podman/system/connection/rename.go
Normal file
54
cmd/podman/system/connection/rename.go
Normal file
@ -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()
|
||||
}
|
46
docs/source/markdown/podman-system-connection-add.1.md
Normal file
46
docs/source/markdown/podman-system-connection-add.1.md
Normal file
@ -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)
|
20
docs/source/markdown/podman-system-connection-default.1.md
Normal file
20
docs/source/markdown/podman-system-connection-default.1.md
Normal file
@ -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)
|
24
docs/source/markdown/podman-system-connection-list.1.md
Normal file
24
docs/source/markdown/podman-system-connection-list.1.md
Normal file
@ -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)
|
20
docs/source/markdown/podman-system-connection-remove.1.md
Normal file
20
docs/source/markdown/podman-system-connection-remove.1.md
Normal file
@ -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)
|
20
docs/source/markdown/podman-system-connection-rename.1.md
Normal file
20
docs/source/markdown/podman-system-connection-rename.1.md
Normal file
@ -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)
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
176
test/e2e/system_connection_test.go
Normal file
176
test/e2e/system_connection_test.go
Normal file
@ -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(""))
|
||||
})
|
||||
})
|
Reference in New Issue
Block a user