diff --git a/cmd/podman/login.go b/cmd/podman/login.go index 369e0da16d..e5ff273b8c 100644 --- a/cmd/podman/login.go +++ b/cmd/podman/login.go @@ -12,6 +12,7 @@ import ( "github.com/containers/image/v5/types" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/libpod/image" + "github.com/containers/libpod/pkg/registries" "github.com/docker/docker-credential-helpers/credentials" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -67,10 +68,19 @@ func loginCmd(c *cliconfig.LoginValues) error { if len(args) > 1 { return errors.Errorf("too many arguments, login takes only 1 argument") } + var server string if len(args) == 0 { - return errors.Errorf("please specify a registry to login to") + registriesFromFile, err := registries.GetRegistries() + if err != nil || len(registriesFromFile) == 0 { + return errors.Errorf("please specify a registry to login to") + } + + server = registriesFromFile[0] + logrus.Debugf("registry not specified, default to the first registry %q from registries.conf", server) + + } else { + server = registryFromFullName(scrubServer(args[0])) } - server := registryFromFullName(scrubServer(args[0])) sc := image.GetSystemContext("", c.Authfile, false) if c.Flag("tls-verify").Changed { diff --git a/cmd/podman/logout.go b/cmd/podman/logout.go index 4a113b1d01..dec6822cf2 100644 --- a/cmd/podman/logout.go +++ b/cmd/podman/logout.go @@ -8,7 +8,9 @@ import ( "github.com/containers/image/v5/pkg/docker/config" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/cmd/podman/shared" + "github.com/containers/libpod/pkg/registries" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -51,10 +53,16 @@ func logoutCmd(c *cliconfig.LogoutValues) error { if len(args) > 1 { return errors.Errorf("too many arguments, logout takes at most 1 argument") } + var server string if len(args) == 0 && !c.All { - return errors.Errorf("registry must be given") + registriesFromFile, err := registries.GetRegistries() + if err != nil || len(registriesFromFile) == 0 { + return errors.Errorf("no registries found in registries.conf, a registry must be provided") + } + + server = registriesFromFile[0] + logrus.Debugf("registry not specified, default to the first registry %q from registries.conf", server) } - var server string if len(args) == 1 { server = scrubServer(args[0]) } diff --git a/docs/source/markdown/podman-login.1.md b/docs/source/markdown/podman-login.1.md index 8a84d359d6..a69b311ebc 100644 --- a/docs/source/markdown/podman-login.1.md +++ b/docs/source/markdown/podman-login.1.md @@ -4,11 +4,12 @@ podman\-login - Login to a container registry ## SYNOPSIS -**podman login** [*options*] *registry* +**podman login** [*options*] [*registry*] ## DESCRIPTION **podman login** logs into a specified registry server with the correct username -and password. **podman login** reads in the username and password from STDIN. +and password. If the registry is not specified, the first registry under [registries.search] +from registries.conf will be used. **podman login** reads in the username and password from STDIN. The username and password can also be set using the **username** and **password** flags. The path of the authentication file can be specified by the user by setting the **authfile** flag. The default path used is **${XDG\_RUNTIME\_DIR}/containers/auth.json**. @@ -17,7 +18,7 @@ flag. The default path used is **${XDG\_RUNTIME\_DIR}/containers/auth.json**. **podman login [GLOBAL OPTIONS]** -**podman login [OPTIONS] REGISTRY [GLOBAL OPTIONS]** +**podman login [OPTIONS] [REGISTRY] [GLOBAL OPTIONS]** ## OPTIONS diff --git a/docs/source/markdown/podman-logout.1.md b/docs/source/markdown/podman-logout.1.md index 01dc52ecda..8b9f757609 100644 --- a/docs/source/markdown/podman-logout.1.md +++ b/docs/source/markdown/podman-logout.1.md @@ -8,7 +8,8 @@ podman\-logout - Logout of a container registry ## DESCRIPTION **podman logout** logs out of a specified registry server by deleting the cached credentials -stored in the **auth.json** file. The path of the authentication file can be overridden by the user by setting the **authfile** flag. +stored in the **auth.json** file. If the registry is not specified, the first registry under [registries.search] +from registries.conf will be used. The path of the authentication file can be overridden by the user by setting the **authfile** flag. The default path used is **${XDG\_RUNTIME\_DIR}/containers/auth.json**. All the cached credentials can be removed by setting the **all** flag. diff --git a/test/e2e/login_logout_test.go b/test/e2e/login_logout_test.go index 78c9b52d90..42698d2707 100644 --- a/test/e2e/login_logout_test.go +++ b/test/e2e/login_logout_test.go @@ -19,14 +19,15 @@ import ( var _ = Describe("Podman login and logout", func() { var ( - tempdir string - err error - podmanTest *PodmanTestIntegration - authPath string - certPath string - port int - server string - testImg string + tempdir string + err error + podmanTest *PodmanTestIntegration + authPath string + certPath string + port int + server string + testImg string + registriesConfWithSearch []byte ) BeforeEach(func() { @@ -64,6 +65,9 @@ var _ = Describe("Podman login and logout", func() { f.Sync() port = 4999 + config.GinkgoConfig.ParallelNode server = strings.Join([]string{"localhost", strconv.Itoa(port)}, ":") + + registriesConfWithSearch = []byte(fmt.Sprintf("[registries.search]\nregistries = ['%s']", server)) + testImg = strings.Join([]string{server, "test-apline"}, "/") os.MkdirAll(filepath.Join("/etc/containers/certs.d", server), os.ModePerm) @@ -113,6 +117,38 @@ var _ = Describe("Podman login and logout", func() { Expect(session).To(ExitWithError()) }) + It("podman login and logout without registry parameter", func() { + SkipIfRootless() + + registriesConf, err := ioutil.TempFile("", "TestLoginWithoutParameter") + Expect(err).To(BeNil()) + defer registriesConf.Close() + defer os.Remove(registriesConf.Name()) + + err = ioutil.WriteFile(registriesConf.Name(), []byte(registriesConfWithSearch), os.ModePerm) + Expect(err).To(BeNil()) + + // Environment is per-process, so this looks very unsafe; actually it seems fine because tests are not + // run in parallel unless they opt in by calling t.Parallel(). So don’t do that. + oldRCP, hasRCP := os.LookupEnv("REGISTRIES_CONFIG_PATH") + defer func() { + if hasRCP { + os.Setenv("REGISTRIES_CONFIG_PATH", oldRCP) + } else { + os.Unsetenv("REGISTRIES_CONFIG_PATH") + } + }() + os.Setenv("REGISTRIES_CONFIG_PATH", registriesConf.Name()) + + session := podmanTest.Podman([]string{"login", "-u", "podmantest", "-p", "test"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To((Equal(0))) + + session = podmanTest.Podman([]string{"logout"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman login and logout with flag --authfile", func() { SkipIfRootless() authFile := filepath.Join(podmanTest.TempDir, "auth.json")