From 2ce78aace682084393f1cda07c2bca0bbb773c95 Mon Sep 17 00:00:00 2001 From: Jhon Honce Date: Tue, 29 Jun 2021 16:24:03 -0700 Subject: Enhance system connection add URL input * Add support for the tcp and unix schemes in connection URLs. Signed-off-by: Jhon Honce --- cmd/podman/system/connection/add.go | 77 ++++++++++++++++------ .../markdown/podman-system-connection-add.1.md | 6 ++ test/e2e/system_connection_test.go | 64 +++++++++++++++++- 3 files changed, 126 insertions(+), 21 deletions(-) diff --git a/cmd/podman/system/connection/add.go b/cmd/podman/system/connection/add.go index ecfeb6608..912193d0b 100644 --- a/cmd/podman/system/connection/add.go +++ b/cmd/podman/system/connection/add.go @@ -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()) - } + switch uri.Scheme { + case "ssh": + if uri.User.Username() == "" { + if uri.User, err = getUserInfo(uri); err != nil { + return err + } + } - if uri.Port() == "" { - uri.Host = net.JoinHostPort(uri.Hostname(), cmd.Flag("port").DefValue) - } + if cmd.Flags().Changed("port") { + uri.Host = net.JoinHostPort(uri.Hostname(), cmd.Flag("port").Value.String()) + } - if uri.Path == "" || uri.Path == "/" { - if uri.Path, err = getUDS(cmd, uri); err != nil { + 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() diff --git a/docs/source/markdown/podman-system-connection-add.1.md b/docs/source/markdown/podman-system-connection-add.1.md index 32c16d6a1..ad9acb4d8 100644 --- a/docs/source/markdown/podman-system-connection-add.1.md +++ b/docs/source/markdown/podman-system-connection-add.1.md @@ -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) diff --git a/test/e2e/system_connection_test.go b/test/e2e/system_connection_test.go index 7c922a648..21398887a 100644 --- a/test/e2e/system_connection_test.go +++ b/test/e2e/system_connection_test.go @@ -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", -- cgit v1.2.3-54-g00ecf