Enhance system connection add URL input

* Add support for the tcp and unix schemes in connection URLs.

Signed-off-by: Jhon Honce <jhonce@redhat.com>
This commit is contained in:
Jhon Honce 2021-06-29 16:24:03 -07:00
parent 1846070f05
commit 2ce78aace6
3 changed files with 129 additions and 24 deletions

View File

@ -23,22 +23,24 @@ import (
"golang.org/x/crypto/ssh/agent"
)
const schemaPattern = "^[A-Za-z][A-Za-z0-9+.-]*:"
var (
addCmd = &cobra.Command{
Use: "add [options] 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]
"destination" is one of the form:
[user@]hostname (will default to ssh)
ssh://[user@]hostname[:port][/path] (will obtain socket path from service, if not given.)
tcp://hostname:port (not secured)
unix://path (absolute path required)
`,
RunE: add,
ValidArgsFunction: completion.AutocompleteNone,
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
podman system connection add debug tcp://localhost:8080
`,
}
@ -74,9 +76,9 @@ func init() {
}
func add(cmd *cobra.Command, args []string) error {
// Default to ssh: schema if none given
// Default to ssh schema if none given
dest := args[1]
if match, err := regexp.Match(schemaPattern, []byte(dest)); err != nil {
if match, err := regexp.Match("^[A-Za-z][A-Za-z0-9+.-]*://", []byte(dest)); err != nil {
return errors.Wrapf(err, "invalid destination")
} else if !match {
dest = "ssh://" + dest
@ -87,28 +89,63 @@ func add(cmd *cobra.Command, args []string) error {
return err
}
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 == "" || uri.Path == "/" {
if uri.Path, err = getUDS(cmd, uri); err != nil {
return err
switch uri.Scheme {
case "ssh":
if uri.User.Username() == "" {
if uri.User, err = getUserInfo(uri); err != nil {
return err
}
}
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 == "" || uri.Path == "/" {
if uri.Path, err = getUDS(cmd, uri); err != nil {
return err
}
}
case "unix":
if cmd.Flags().Changed("identity") {
return errors.New("--identity option not supported for unix scheme")
}
if cmd.Flags().Changed("socket-path") {
uri.Path = cmd.Flag("socket-path").Value.String()
}
info, err := os.Stat(uri.Path)
switch {
case errors.Is(err, os.ErrNotExist):
logrus.Warnf("%q does not exists", uri.Path)
case errors.Is(err, os.ErrPermission):
logrus.Warnf("You do not have permission to read %q", uri.Path)
case err != nil:
return err
case info.Mode()&os.ModeSocket == 0:
return fmt.Errorf("%q exists and is not a unix domain socket", uri.Path)
}
case "tcp":
if cmd.Flags().Changed("socket-path") {
return errors.New("--socket-path option not supported for tcp scheme")
}
if cmd.Flags().Changed("identity") {
return errors.New("--identity option not supported for tcp scheme")
}
if uri.Port() == "" {
return errors.New("tcp scheme requires a port either via --port or in destination URL")
}
default:
logrus.Warnf("%q unknown scheme, no validation provided", uri.Scheme)
}
cfg, err := config.ReadCustomConfig()

View File

@ -10,6 +10,8 @@ podman\-system\-connection\-add - Record destination for the Podman service
Record ssh destination for remote podman service(s). The ssh destination is given as one of:
- [user@]hostname[:port]
- ssh://[user@]hostname[:port]
- unix://path
- tcp://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.
@ -38,6 +40,10 @@ Path to the Podman service unix domain socket on the ssh destination host
$ podman system connection add QA podman.example.com
$ podman system connection add --identity ~/.ssh/dev_rsa production ssh://root@server.example.com:2222
$ podman system connection add unix:///run/podman/podman.sock
$ podman system connection add tcp://localhost:8080
```
## SEE ALSO
podman-system(1) , podman-system-connection(1) , containers.conf(5)

View File

@ -53,7 +53,7 @@ var _ = Describe("podman system connection", func() {
GinkgoWriter.Write([]byte(timedResult))
})
It("add", func() {
It("add ssh://", func() {
cmd := []string{"system", "connection", "add",
"--default",
"--identity", "~/.ssh/id_rsa",
@ -94,6 +94,68 @@ var _ = Describe("podman system connection", func() {
))
})
It("add UDS", func() {
cmd := []string{"system", "connection", "add",
"QA-UDS",
"unix:///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-UDS"))
Expect(cfg.Engine.ServiceDestinations["QA-UDS"]).To(Equal(
config.Destination{
URI: "unix:///run/podman/podman.sock",
Identity: "",
},
))
cmd = []string{"system", "connection", "add",
"QA-UDS1",
"--socket-path", "/run/user/podman/podman.sock",
"unix:///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-UDS"))
Expect(cfg.Engine.ServiceDestinations["QA-UDS1"]).To(Equal(
config.Destination{
URI: "unix:///run/user/podman/podman.sock",
Identity: "",
},
))
})
It("add tcp", func() {
cmd := []string{"system", "connection", "add",
"QA-TCP",
"tcp://localhost:8080",
}
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-TCP"))
Expect(cfg.Engine.ServiceDestinations["QA-TCP"]).To(Equal(
config.Destination{
URI: "tcp://localhost:8080",
Identity: "",
},
))
})
It("remove", func() {
cmd := []string{"system", "connection", "add",
"--default",