mirror of
https://github.com/containers/podman.git
synced 2025-07-03 17:27:18 +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/pods"
|
||||||
"github.com/containers/libpod/v2/cmd/podman/registry"
|
"github.com/containers/libpod/v2/cmd/podman/registry"
|
||||||
_ "github.com/containers/libpod/v2/cmd/podman/system"
|
_ "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/cmd/podman/volumes"
|
||||||
"github.com/containers/libpod/v2/pkg/rootless"
|
"github.com/containers/libpod/v2/pkg/rootless"
|
||||||
"github.com/containers/libpod/v2/pkg/terminal"
|
"github.com/containers/libpod/v2/pkg/terminal"
|
||||||
|
@ -236,16 +236,12 @@ func loggingHook() {
|
|||||||
|
|
||||||
func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) {
|
func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) {
|
||||||
cfg := opts.Config
|
cfg := opts.Config
|
||||||
|
uri, ident := resolveDestination()
|
||||||
|
|
||||||
lFlags := cmd.Flags()
|
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.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.URI, "url", uri, "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.Identity, "identity", ident, "path to SSH identity file, (CONTAINER_SSHKEY)")
|
||||||
|
|
||||||
pFlags := cmd.PersistentFlags()
|
pFlags := cmd.PersistentFlags()
|
||||||
pFlags.StringVar(&cfg.Engine.CgroupManager, "cgroup-manager", cfg.Engine.CgroupManager, "Cgroup manager to use (\"cgroupfs\"|\"systemd\")")
|
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)")
|
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
|
package system
|
||||||
|
|
||||||
import (
|
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/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/domain/entities"
|
||||||
"github.com/containers/libpod/v2/pkg/terminal"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"github.com/spf13/cobra"
|
"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 (
|
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 {
|
noOp = func(cmd *cobra.Command, args []string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
connectionCmd = &cobra.Command{
|
|
||||||
Use: "connection [flags] DESTINATION",
|
ConnectionCmd = &cobra.Command{
|
||||||
Args: cobra.ExactArgs(1),
|
Use: "connection",
|
||||||
Long: `Store ssh destination information in podman configuration.
|
Short: "Manage remote ssh destinations",
|
||||||
"destination" is of the form [user@]hostname or
|
Long: `Manage ssh destination information in podman configuration`,
|
||||||
an URI of the form ssh://[user@]hostname[:port]
|
DisableFlagsInUseLine: true,
|
||||||
`,
|
|
||||||
Short: "Record remote ssh destination",
|
|
||||||
PersistentPreRunE: noOp,
|
PersistentPreRunE: noOp,
|
||||||
|
RunE: validate.SubCommandExists,
|
||||||
PersistentPostRunE: noOp,
|
PersistentPostRunE: noOp,
|
||||||
TraverseChildren: false,
|
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
|
|
||||||
}{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||||
Command: connectionCmd,
|
Command: ConnectionCmd,
|
||||||
Parent: systemCmd,
|
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)
|
% podman-system-connection(1)
|
||||||
|
|
||||||
## NAME
|
## NAME
|
||||||
podman\-system\-connection - Record ssh destination for remote podman service
|
podman\-system\-connection - Manage the destination(s) for Podman service(s)
|
||||||
|
|
||||||
## SYNOPSIS
|
## SYNOPSISManage the destination(s) for Podman service(s)
|
||||||
**podman system connection** [*options*] [*ssh destination*]
|
**podman system connection** *subcommand*
|
||||||
|
|
||||||
## DESCRIPTION
|
## DESCRIPTION
|
||||||
Record ssh destination for remote podman service(s). The ssh destination is given as one of:
|
Manage the destination(s) for Podman service(s).
|
||||||
- [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. `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*
|
| Command | Man Page | Description |
|
||||||
|
| ------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------- |
|
||||||
Path to ssh identity file. If the identity file has been encrypted, Podman prompts the user for the passphrase.
|
| add | [podman-system-connection-add(1)](podman-system-connection-add.1.md) | Record destination for the Podman service |
|
||||||
If no identity file is provided and no user is given, Podman defaults to the user running the podman command.
|
| default | [podman-system-connection-default(1)](podman-system-connection-default.1.md) | Set named destination as default for the Podman service |
|
||||||
Podman prompts for the login password on the remote server.
|
| 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 |
|
||||||
**-p**, **--port**=*port*
|
| rename | [podman-system-connection-rename(1)](podman-system-connection-rename.1.md) | Rename the destination for Podman service |
|
||||||
|
|
||||||
Port for ssh destination. The default value is `22`.
|
|
||||||
|
|
||||||
**--socket-path**=*path*
|
|
||||||
|
|
||||||
Path to podman service unix domain socket on the ssh destination host
|
|
||||||
|
|
||||||
## EXAMPLE
|
## EXAMPLE
|
||||||
```
|
```
|
||||||
$ podman system connection podman.fubar.com
|
$ podman system connection list
|
||||||
|
Name URI Identity
|
||||||
$ podman system connection --identity ~/.ssh/dev_rsa ssh://root@server.fubar.com:2222
|
devl ssh://root@example.com/run/podman/podman.sock ~/.ssh/id_rsa
|
||||||
|
|
||||||
```
|
```
|
||||||
## SEE ALSO
|
## SEE ALSO
|
||||||
podman-system(1) , containers.conf(5) , connections.conf(5)
|
podman-system(1) , containers.conf(5)
|
||||||
|
|
||||||
## HISTORY
|
## HISTORY
|
||||||
June 2020, Originally compiled by Jhon Honce (jhonce at redhat dot com)
|
June 2020, Originally compiled by Jhon Honce (jhonce at redhat dot com)
|
||||||
|
@ -12,16 +12,15 @@ The system command allows you to manage the podman systems
|
|||||||
## COMMANDS
|
## COMMANDS
|
||||||
|
|
||||||
| Command | Man Page | Description |
|
| 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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
| 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 |
|
| service | [podman-system-service(1)](podman-system-service.1.md) | Run an API service |
|
||||||
|
|
||||||
|
|
||||||
## SEE ALSO
|
## SEE ALSO
|
||||||
podman(1)
|
podman(1)
|
||||||
|
@ -16,6 +16,9 @@ our $VERSION = '0.1';
|
|||||||
# For debugging, show data structures using DumpTree($var)
|
# For debugging, show data structures using DumpTree($var)
|
||||||
#use Data::TreeDumper; $Data::TreeDumper::Displayaddress = 0;
|
#use Data::TreeDumper; $Data::TreeDumper::Displayaddress = 0;
|
||||||
|
|
||||||
|
# unbuffer output
|
||||||
|
$| = 1;
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# BEGIN user-customizable section
|
# BEGIN user-customizable section
|
||||||
|
|
||||||
@ -266,12 +269,16 @@ sub podman_man {
|
|||||||
elsif ($section eq 'commands') {
|
elsif ($section eq 'commands') {
|
||||||
# In podman.1.md
|
# In podman.1.md
|
||||||
if ($line =~ /^\|\s*\[podman-(\S+?)\(\d\)\]/) {
|
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
|
# In podman-<subcommand>.1.md
|
||||||
elsif ($line =~ /^\|\s+(\S+)\s+\|\s+\[\S+\]\((\S+)\.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