Browse code

Merge pull request #23265 from vdemeester/migrate-login-logout-to-cobra

Use spf13/cobra for docker login and docker logout

Alexander Morozov authored on 2016/06/14 06:15:46
Showing 11 changed files
... ...
@@ -7,8 +7,6 @@ func (cli *DockerCli) Command(name string) func(...string) error {
7 7
 		"exec":    cli.CmdExec,
8 8
 		"info":    cli.CmdInfo,
9 9
 		"inspect": cli.CmdInspect,
10
-		"login":   cli.CmdLogin,
11
-		"logout":  cli.CmdLogout,
12 10
 		"ps":      cli.CmdPs,
13 11
 		"pull":    cli.CmdPull,
14 12
 		"push":    cli.CmdPush,
15 13
new file mode 100644
... ...
@@ -0,0 +1,44 @@
0
+package client
1
+
2
+import (
3
+	"github.com/docker/docker/cliconfig/configfile"
4
+	"github.com/docker/docker/cliconfig/credentials"
5
+	"github.com/docker/engine-api/types"
6
+)
7
+
8
+// GetCredentials loads the user credentials from a credentials store.
9
+// The store is determined by the config file settings.
10
+func GetCredentials(c *configfile.ConfigFile, serverAddress string) (types.AuthConfig, error) {
11
+	s := LoadCredentialsStore(c)
12
+	return s.Get(serverAddress)
13
+}
14
+
15
+// GetAllCredentials loads all credentials from a credentials store.
16
+// The store is determined by the config file settings.
17
+func GetAllCredentials(c *configfile.ConfigFile) (map[string]types.AuthConfig, error) {
18
+	s := LoadCredentialsStore(c)
19
+	return s.GetAll()
20
+}
21
+
22
+// StoreCredentials saves the user credentials in a credentials store.
23
+// The store is determined by the config file settings.
24
+func StoreCredentials(c *configfile.ConfigFile, auth types.AuthConfig) error {
25
+	s := LoadCredentialsStore(c)
26
+	return s.Store(auth)
27
+}
28
+
29
+// EraseCredentials removes the user credentials from a credentials store.
30
+// The store is determined by the config file settings.
31
+func EraseCredentials(c *configfile.ConfigFile, serverAddress string) error {
32
+	s := LoadCredentialsStore(c)
33
+	return s.Erase(serverAddress)
34
+}
35
+
36
+// LoadCredentialsStore initializes a new credentials store based
37
+// in the settings provided in the configuration file.
38
+func LoadCredentialsStore(c *configfile.ConfigFile) credentials.Store {
39
+	if c.CredentialsStore != "" {
40
+		return credentials.NewNativeStore(c)
41
+	}
42
+	return credentials.NewFileStore(c)
43
+}
... ...
@@ -52,8 +52,8 @@ func NewSearchCommand(dockerCli *client.DockerCli) *cobra.Command {
52 52
 	flags.BoolVar(&opts.automated, "automated", false, "Only show automated builds")
53 53
 	flags.UintVarP(&opts.stars, "stars", "s", 0, "Only displays with at least x stars")
54 54
 
55
-	flags.MarkDeprecated("automated", "Use --filter=automated=true instead")
56
-	flags.MarkDeprecated("stars", "Use --filter=stars=3 instead")
55
+	flags.MarkDeprecated("automated", "use --filter=automated=true instead")
56
+	flags.MarkDeprecated("stars", "use --filter=stars=3 instead")
57 57
 
58 58
 	return cmd
59 59
 }
60 60
deleted file mode 100644
... ...
@@ -1,184 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"bufio"
5
-	"fmt"
6
-	"io"
7
-	"os"
8
-	"runtime"
9
-	"strings"
10
-
11
-	"golang.org/x/net/context"
12
-
13
-	Cli "github.com/docker/docker/cli"
14
-	"github.com/docker/docker/cliconfig/configfile"
15
-	"github.com/docker/docker/cliconfig/credentials"
16
-	flag "github.com/docker/docker/pkg/mflag"
17
-	"github.com/docker/docker/pkg/term"
18
-	"github.com/docker/engine-api/types"
19
-)
20
-
21
-// CmdLogin logs in a user to a Docker registry service.
22
-//
23
-// If no server is specified, the user will be logged into or registered to the registry's index server.
24
-//
25
-// Usage: docker login SERVER
26
-func (cli *DockerCli) CmdLogin(args ...string) error {
27
-	cmd := Cli.Subcmd("login", []string{"[SERVER]"}, Cli.DockerCommands["login"].Description+".\nIf no server is specified, the default is defined by the daemon.", true)
28
-	cmd.Require(flag.Max, 1)
29
-
30
-	flUser := cmd.String([]string{"u", "-username"}, "", "Username")
31
-	flPassword := cmd.String([]string{"p", "-password"}, "", "Password")
32
-
33
-	// Deprecated in 1.11: Should be removed in docker 1.13
34
-	cmd.String([]string{"#e", "#-email"}, "", "Email")
35
-
36
-	cmd.ParseFlags(args, true)
37
-
38
-	// On Windows, force the use of the regular OS stdin stream. Fixes #14336/#14210
39
-	if runtime.GOOS == "windows" {
40
-		cli.in = os.Stdin
41
-	}
42
-
43
-	ctx := context.Background()
44
-	var serverAddress string
45
-	var isDefaultRegistry bool
46
-	if len(cmd.Args()) > 0 {
47
-		serverAddress = cmd.Arg(0)
48
-	} else {
49
-		serverAddress = cli.electAuthServer(ctx)
50
-		isDefaultRegistry = true
51
-	}
52
-	authConfig, err := cli.configureAuth(*flUser, *flPassword, serverAddress, isDefaultRegistry)
53
-	if err != nil {
54
-		return err
55
-	}
56
-	response, err := cli.client.RegistryLogin(ctx, authConfig)
57
-	if err != nil {
58
-		return err
59
-	}
60
-	if response.IdentityToken != "" {
61
-		authConfig.Password = ""
62
-		authConfig.IdentityToken = response.IdentityToken
63
-	}
64
-	if err := storeCredentials(cli.configFile, authConfig); err != nil {
65
-		return fmt.Errorf("Error saving credentials: %v", err)
66
-	}
67
-
68
-	if response.Status != "" {
69
-		fmt.Fprintln(cli.out, response.Status)
70
-	}
71
-	return nil
72
-}
73
-
74
-func (cli *DockerCli) promptWithDefault(prompt string, configDefault string) {
75
-	if configDefault == "" {
76
-		fmt.Fprintf(cli.out, "%s: ", prompt)
77
-	} else {
78
-		fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
79
-	}
80
-}
81
-
82
-func (cli *DockerCli) configureAuth(flUser, flPassword, serverAddress string, isDefaultRegistry bool) (types.AuthConfig, error) {
83
-	authconfig, err := getCredentials(cli.configFile, serverAddress)
84
-	if err != nil {
85
-		return authconfig, err
86
-	}
87
-
88
-	// Some links documenting this:
89
-	// - https://code.google.com/archive/p/mintty/issues/56
90
-	// - https://github.com/docker/docker/issues/15272
91
-	// - https://mintty.github.io/ (compatibility)
92
-	// Linux will hit this if you attempt `cat | docker login`, and Windows
93
-	// will hit this if you attempt docker login from mintty where stdin
94
-	// is a pipe, not a character based console.
95
-	if flPassword == "" && !cli.isTerminalIn {
96
-		return authconfig, fmt.Errorf("Error: Cannot perform an interactive logon from a non TTY device")
97
-	}
98
-
99
-	authconfig.Username = strings.TrimSpace(authconfig.Username)
100
-
101
-	if flUser = strings.TrimSpace(flUser); flUser == "" {
102
-		if isDefaultRegistry {
103
-			// if this is a defauly registry (docker hub), then display the following message.
104
-			fmt.Fprintln(cli.out, "Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.")
105
-		}
106
-		cli.promptWithDefault("Username", authconfig.Username)
107
-		flUser = readInput(cli.in, cli.out)
108
-		flUser = strings.TrimSpace(flUser)
109
-		if flUser == "" {
110
-			flUser = authconfig.Username
111
-		}
112
-	}
113
-	if flUser == "" {
114
-		return authconfig, fmt.Errorf("Error: Non-null Username Required")
115
-	}
116
-	if flPassword == "" {
117
-		oldState, err := term.SaveState(cli.inFd)
118
-		if err != nil {
119
-			return authconfig, err
120
-		}
121
-		fmt.Fprintf(cli.out, "Password: ")
122
-		term.DisableEcho(cli.inFd, oldState)
123
-
124
-		flPassword = readInput(cli.in, cli.out)
125
-		fmt.Fprint(cli.out, "\n")
126
-
127
-		term.RestoreTerminal(cli.inFd, oldState)
128
-		if flPassword == "" {
129
-			return authconfig, fmt.Errorf("Error: Password Required")
130
-		}
131
-	}
132
-
133
-	authconfig.Username = flUser
134
-	authconfig.Password = flPassword
135
-	authconfig.ServerAddress = serverAddress
136
-	authconfig.IdentityToken = ""
137
-
138
-	return authconfig, nil
139
-}
140
-
141
-func readInput(in io.Reader, out io.Writer) string {
142
-	reader := bufio.NewReader(in)
143
-	line, _, err := reader.ReadLine()
144
-	if err != nil {
145
-		fmt.Fprintln(out, err.Error())
146
-		os.Exit(1)
147
-	}
148
-	return string(line)
149
-}
150
-
151
-// getCredentials loads the user credentials from a credentials store.
152
-// The store is determined by the config file settings.
153
-func getCredentials(c *configfile.ConfigFile, serverAddress string) (types.AuthConfig, error) {
154
-	s := loadCredentialsStore(c)
155
-	return s.Get(serverAddress)
156
-}
157
-
158
-func getAllCredentials(c *configfile.ConfigFile) (map[string]types.AuthConfig, error) {
159
-	s := loadCredentialsStore(c)
160
-	return s.GetAll()
161
-}
162
-
163
-// storeCredentials saves the user credentials in a credentials store.
164
-// The store is determined by the config file settings.
165
-func storeCredentials(c *configfile.ConfigFile, auth types.AuthConfig) error {
166
-	s := loadCredentialsStore(c)
167
-	return s.Store(auth)
168
-}
169
-
170
-// eraseCredentials removes the user credentials from a credentials store.
171
-// The store is determined by the config file settings.
172
-func eraseCredentials(c *configfile.ConfigFile, serverAddress string) error {
173
-	s := loadCredentialsStore(c)
174
-	return s.Erase(serverAddress)
175
-}
176
-
177
-// loadCredentialsStore initializes a new credentials store based
178
-// in the settings provided in the configuration file.
179
-func loadCredentialsStore(c *configfile.ConfigFile) credentials.Store {
180
-	if c.CredentialsStore != "" {
181
-		return credentials.NewNativeStore(c)
182
-	}
183
-	return credentials.NewFileStore(c)
184
-}
185 1
deleted file mode 100644
... ...
@@ -1,43 +0,0 @@
1
-package client
2
-
3
-import (
4
-	"fmt"
5
-
6
-	"golang.org/x/net/context"
7
-
8
-	Cli "github.com/docker/docker/cli"
9
-	flag "github.com/docker/docker/pkg/mflag"
10
-)
11
-
12
-// CmdLogout logs a user out from a Docker registry.
13
-//
14
-// If no server is specified, the user will be logged out from the registry's index server.
15
-//
16
-// Usage: docker logout [SERVER]
17
-func (cli *DockerCli) CmdLogout(args ...string) error {
18
-	cmd := Cli.Subcmd("logout", []string{"[SERVER]"}, Cli.DockerCommands["logout"].Description+".\nIf no server is specified, the default is defined by the daemon.", true)
19
-	cmd.Require(flag.Max, 1)
20
-
21
-	cmd.ParseFlags(args, true)
22
-
23
-	var serverAddress string
24
-	if len(cmd.Args()) > 0 {
25
-		serverAddress = cmd.Arg(0)
26
-	} else {
27
-		serverAddress = cli.electAuthServer(context.Background())
28
-	}
29
-
30
-	// check if we're logged in based on the records in the config file
31
-	// which means it couldn't have user/pass cause they may be in the creds store
32
-	if _, ok := cli.configFile.AuthConfigs[serverAddress]; !ok {
33
-		fmt.Fprintf(cli.out, "Not logged in to %s\n", serverAddress)
34
-		return nil
35
-	}
36
-
37
-	fmt.Fprintf(cli.out, "Remove login credentials for %s\n", serverAddress)
38
-	if err := eraseCredentials(cli.configFile, serverAddress); err != nil {
39
-		fmt.Fprintf(cli.out, "WARNING: could not erase credentials: %v\n", err)
40
-	}
41
-
42
-	return nil
43
-}
44 1
new file mode 100644
... ...
@@ -0,0 +1,159 @@
0
+package client
1
+
2
+import (
3
+	"bufio"
4
+	"encoding/base64"
5
+	"encoding/json"
6
+	"fmt"
7
+	"io"
8
+	"os"
9
+	"runtime"
10
+	"strings"
11
+
12
+	"golang.org/x/net/context"
13
+
14
+	"github.com/docker/docker/pkg/term"
15
+	"github.com/docker/docker/registry"
16
+	"github.com/docker/engine-api/types"
17
+	registrytypes "github.com/docker/engine-api/types/registry"
18
+)
19
+
20
+// ElectAuthServer returns the default registry to use (by asking the daemon)
21
+func (cli *DockerCli) ElectAuthServer(ctx context.Context) string {
22
+	// The daemon `/info` endpoint informs us of the default registry being
23
+	// used. This is essential in cross-platforms environment, where for
24
+	// example a Linux client might be interacting with a Windows daemon, hence
25
+	// the default registry URL might be Windows specific.
26
+	serverAddress := registry.IndexServer
27
+	if info, err := cli.client.Info(ctx); err != nil {
28
+		fmt.Fprintf(cli.out, "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, serverAddress)
29
+	} else {
30
+		serverAddress = info.IndexServerAddress
31
+	}
32
+	return serverAddress
33
+}
34
+
35
+// EncodeAuthToBase64 serializes the auth configuration as JSON base64 payload
36
+func EncodeAuthToBase64(authConfig types.AuthConfig) (string, error) {
37
+	buf, err := json.Marshal(authConfig)
38
+	if err != nil {
39
+		return "", err
40
+	}
41
+	return base64.URLEncoding.EncodeToString(buf), nil
42
+}
43
+
44
+// RegistryAuthenticationPrivilegedFunc return a RequestPrivilegeFunc from the specified registry index info
45
+// for the given command.
46
+func (cli *DockerCli) RegistryAuthenticationPrivilegedFunc(index *registrytypes.IndexInfo, cmdName string) types.RequestPrivilegeFunc {
47
+	return func() (string, error) {
48
+		fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName)
49
+		indexServer := registry.GetAuthConfigKey(index)
50
+		authConfig, err := cli.ConfigureAuth("", "", indexServer, false)
51
+		if err != nil {
52
+			return "", err
53
+		}
54
+		return EncodeAuthToBase64(authConfig)
55
+	}
56
+}
57
+
58
+func (cli *DockerCli) promptWithDefault(prompt string, configDefault string) {
59
+	if configDefault == "" {
60
+		fmt.Fprintf(cli.out, "%s: ", prompt)
61
+	} else {
62
+		fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
63
+	}
64
+}
65
+
66
+// ResolveAuthConfig is like registry.ResolveAuthConfig, but if using the
67
+// default index, it uses the default index name for the daemon's platform,
68
+// not the client's platform.
69
+func (cli *DockerCli) ResolveAuthConfig(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig {
70
+	configKey := index.Name
71
+	if index.Official {
72
+		configKey = cli.ElectAuthServer(ctx)
73
+	}
74
+
75
+	a, _ := GetCredentials(cli.configFile, configKey)
76
+	return a
77
+}
78
+
79
+// RetrieveAuthConfigs return all credentials.
80
+func (cli *DockerCli) RetrieveAuthConfigs() map[string]types.AuthConfig {
81
+	acs, _ := GetAllCredentials(cli.configFile)
82
+	return acs
83
+}
84
+
85
+// ConfigureAuth returns an AuthConfig from the specified user, password and server.
86
+func (cli *DockerCli) ConfigureAuth(flUser, flPassword, serverAddress string, isDefaultRegistry bool) (types.AuthConfig, error) {
87
+	// On Windows, force the use of the regular OS stdin stream. Fixes #14336/#14210
88
+	if runtime.GOOS == "windows" {
89
+		cli.in = os.Stdin
90
+	}
91
+
92
+	authconfig, err := GetCredentials(cli.configFile, serverAddress)
93
+	if err != nil {
94
+		return authconfig, err
95
+	}
96
+
97
+	// Some links documenting this:
98
+	// - https://code.google.com/archive/p/mintty/issues/56
99
+	// - https://github.com/docker/docker/issues/15272
100
+	// - https://mintty.github.io/ (compatibility)
101
+	// Linux will hit this if you attempt `cat | docker login`, and Windows
102
+	// will hit this if you attempt docker login from mintty where stdin
103
+	// is a pipe, not a character based console.
104
+	if flPassword == "" && !cli.isTerminalIn {
105
+		return authconfig, fmt.Errorf("Error: Cannot perform an interactive logon from a non TTY device")
106
+	}
107
+
108
+	authconfig.Username = strings.TrimSpace(authconfig.Username)
109
+
110
+	if flUser = strings.TrimSpace(flUser); flUser == "" {
111
+		if isDefaultRegistry {
112
+			// if this is a defauly registry (docker hub), then display the following message.
113
+			fmt.Fprintln(cli.out, "Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.")
114
+		}
115
+		cli.promptWithDefault("Username", authconfig.Username)
116
+		flUser = readInput(cli.in, cli.out)
117
+		flUser = strings.TrimSpace(flUser)
118
+		if flUser == "" {
119
+			flUser = authconfig.Username
120
+		}
121
+	}
122
+	if flUser == "" {
123
+		return authconfig, fmt.Errorf("Error: Non-null Username Required")
124
+	}
125
+	if flPassword == "" {
126
+		oldState, err := term.SaveState(cli.inFd)
127
+		if err != nil {
128
+			return authconfig, err
129
+		}
130
+		fmt.Fprintf(cli.out, "Password: ")
131
+		term.DisableEcho(cli.inFd, oldState)
132
+
133
+		flPassword = readInput(cli.in, cli.out)
134
+		fmt.Fprint(cli.out, "\n")
135
+
136
+		term.RestoreTerminal(cli.inFd, oldState)
137
+		if flPassword == "" {
138
+			return authconfig, fmt.Errorf("Error: Password Required")
139
+		}
140
+	}
141
+
142
+	authconfig.Username = flUser
143
+	authconfig.Password = flPassword
144
+	authconfig.ServerAddress = serverAddress
145
+	authconfig.IdentityToken = ""
146
+
147
+	return authconfig, nil
148
+}
149
+
150
+func readInput(in io.Reader, out io.Writer) string {
151
+	reader := bufio.NewReader(in)
152
+	line, _, err := reader.ReadLine()
153
+	if err != nil {
154
+		fmt.Fprintln(out, err.Error())
155
+		os.Exit(1)
156
+	}
157
+	return string(line)
158
+}
0 159
new file mode 100644
... ...
@@ -0,0 +1,81 @@
0
+package registry
1
+
2
+import (
3
+	"fmt"
4
+
5
+	"golang.org/x/net/context"
6
+
7
+	"github.com/docker/docker/api/client"
8
+	"github.com/docker/docker/cli"
9
+	"github.com/spf13/cobra"
10
+)
11
+
12
+type loginOptions struct {
13
+	serverAddress string
14
+	user          string
15
+	password      string
16
+	email         string
17
+}
18
+
19
+// NewLoginCommand creates a new `docker login` command
20
+func NewLoginCommand(dockerCli *client.DockerCli) *cobra.Command {
21
+	var opts loginOptions
22
+
23
+	cmd := &cobra.Command{
24
+		Use:   "login [OPTIONS] [SERVER]",
25
+		Short: "Log in to a Docker registry.",
26
+		Long:  "Log in to a Docker registry.\nIf no server is specified, the default is defined by the daemon.",
27
+		Args:  cli.RequiresMaxArgs(1),
28
+		RunE: func(cmd *cobra.Command, args []string) error {
29
+			if len(args) > 0 {
30
+				opts.serverAddress = args[0]
31
+			}
32
+			return runLogin(dockerCli, opts)
33
+		},
34
+	}
35
+
36
+	flags := cmd.Flags()
37
+
38
+	flags.StringVarP(&opts.user, "username", "u", "", "Username")
39
+	flags.StringVarP(&opts.password, "password", "p", "", "Password")
40
+
41
+	// Deprecated in 1.11: Should be removed in docker 1.13
42
+	flags.StringVarP(&opts.email, "email", "e", "", "Email")
43
+	flags.MarkDeprecated("email", "will be removed in 1.13.")
44
+
45
+	return cmd
46
+}
47
+
48
+func runLogin(dockerCli *client.DockerCli, opts loginOptions) error {
49
+	ctx := context.Background()
50
+	clnt := dockerCli.Client()
51
+
52
+	var serverAddress string
53
+	var isDefaultRegistry bool
54
+	if opts.serverAddress != "" {
55
+		serverAddress = opts.serverAddress
56
+	} else {
57
+		serverAddress = dockerCli.ElectAuthServer(ctx)
58
+		isDefaultRegistry = true
59
+	}
60
+	authConfig, err := dockerCli.ConfigureAuth(opts.user, opts.password, serverAddress, isDefaultRegistry)
61
+	if err != nil {
62
+		return err
63
+	}
64
+	response, err := clnt.RegistryLogin(ctx, authConfig)
65
+	if err != nil {
66
+		return err
67
+	}
68
+	if response.IdentityToken != "" {
69
+		authConfig.Password = ""
70
+		authConfig.IdentityToken = response.IdentityToken
71
+	}
72
+	if err := client.StoreCredentials(dockerCli.ConfigFile(), authConfig); err != nil {
73
+		return fmt.Errorf("Error saving credentials: %v", err)
74
+	}
75
+
76
+	if response.Status != "" {
77
+		fmt.Fprintln(dockerCli.Out(), response.Status)
78
+	}
79
+	return nil
80
+}
0 81
new file mode 100644
... ...
@@ -0,0 +1,52 @@
0
+package registry
1
+
2
+import (
3
+	"fmt"
4
+
5
+	"golang.org/x/net/context"
6
+
7
+	"github.com/docker/docker/api/client"
8
+	"github.com/docker/docker/cli"
9
+	"github.com/spf13/cobra"
10
+)
11
+
12
+// NewLogoutCommand creates a new `docker login` command
13
+func NewLogoutCommand(dockerCli *client.DockerCli) *cobra.Command {
14
+	cmd := &cobra.Command{
15
+		Use:   "logout [SERVER]",
16
+		Short: "Log out from a Docker registry.",
17
+		Long:  "Log out from a Docker registry.\nIf no server is specified, the default is defined by the daemon.",
18
+		Args:  cli.RequiresMaxArgs(1),
19
+		RunE: func(cmd *cobra.Command, args []string) error {
20
+			var serverAddress string
21
+			if len(args) > 0 {
22
+				serverAddress = args[0]
23
+			}
24
+			return runLogout(dockerCli, serverAddress)
25
+		},
26
+	}
27
+
28
+	return cmd
29
+}
30
+
31
+func runLogout(dockerCli *client.DockerCli, serverAddress string) error {
32
+	ctx := context.Background()
33
+
34
+	if serverAddress == "" {
35
+		serverAddress = dockerCli.ElectAuthServer(ctx)
36
+	}
37
+
38
+	// check if we're logged in based on the records in the config file
39
+	// which means it couldn't have user/pass cause they may be in the creds store
40
+	if _, ok := dockerCli.ConfigFile().AuthConfigs[serverAddress]; !ok {
41
+		fmt.Fprintf(dockerCli.Out(), "Not logged in to %s\n", serverAddress)
42
+		return nil
43
+	}
44
+
45
+	fmt.Fprintf(dockerCli.Out(), "Remove login credentials for %s\n", serverAddress)
46
+	if err := client.EraseCredentials(dockerCli.ConfigFile(), serverAddress); err != nil {
47
+		fmt.Fprintf(dockerCli.Out(), "WARNING: could not erase credentials: %v\n", err)
48
+	}
49
+
50
+	return nil
51
+}
... ...
@@ -1,8 +1,6 @@
1 1
 package client
2 2
 
3 3
 import (
4
-	"encoding/base64"
5
-	"encoding/json"
6 4
 	"fmt"
7 5
 	"io"
8 6
 	"io/ioutil"
... ...
@@ -17,49 +15,10 @@ import (
17 17
 	"github.com/Sirupsen/logrus"
18 18
 	"github.com/docker/docker/pkg/signal"
19 19
 	"github.com/docker/docker/pkg/term"
20
-	"github.com/docker/docker/registry"
21 20
 	"github.com/docker/engine-api/client"
22 21
 	"github.com/docker/engine-api/types"
23
-	registrytypes "github.com/docker/engine-api/types/registry"
24 22
 )
25 23
 
26
-func (cli *DockerCli) electAuthServer(ctx context.Context) string {
27
-	// The daemon `/info` endpoint informs us of the default registry being
28
-	// used. This is essential in cross-platforms environment, where for
29
-	// example a Linux client might be interacting with a Windows daemon, hence
30
-	// the default registry URL might be Windows specific.
31
-	serverAddress := registry.IndexServer
32
-	if info, err := cli.client.Info(ctx); err != nil {
33
-		fmt.Fprintf(cli.out, "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, serverAddress)
34
-	} else {
35
-		serverAddress = info.IndexServerAddress
36
-	}
37
-	return serverAddress
38
-}
39
-
40
-// EncodeAuthToBase64 serializes the auth configuration as JSON base64 payload
41
-func EncodeAuthToBase64(authConfig types.AuthConfig) (string, error) {
42
-	buf, err := json.Marshal(authConfig)
43
-	if err != nil {
44
-		return "", err
45
-	}
46
-	return base64.URLEncoding.EncodeToString(buf), nil
47
-}
48
-
49
-// RegistryAuthenticationPrivilegedFunc return a RequestPrivilegeFunc from the specified registry index info
50
-// for the given command.
51
-func (cli *DockerCli) RegistryAuthenticationPrivilegedFunc(index *registrytypes.IndexInfo, cmdName string) types.RequestPrivilegeFunc {
52
-	return func() (string, error) {
53
-		fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName)
54
-		indexServer := registry.GetAuthConfigKey(index)
55
-		authConfig, err := cli.configureAuth("", "", indexServer, false)
56
-		if err != nil {
57
-			return "", err
58
-		}
59
-		return EncodeAuthToBase64(authConfig)
60
-	}
61
-}
62
-
63 24
 func (cli *DockerCli) resizeTty(ctx context.Context, id string, isExec bool) {
64 25
 	height, width := cli.GetTtySize()
65 26
 	cli.ResizeTtyTo(ctx, id, height, width, isExec)
... ...
@@ -174,26 +133,7 @@ func CopyToFile(outfile string, r io.Reader) error {
174 174
 	return nil
175 175
 }
176 176
 
177
-// ResolveAuthConfig is like registry.ResolveAuthConfig, but if using the
178
-// default index, it uses the default index name for the daemon's platform,
179
-// not the client's platform.
180
-func (cli *DockerCli) ResolveAuthConfig(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig {
181
-	configKey := index.Name
182
-	if index.Official {
183
-		configKey = cli.electAuthServer(ctx)
184
-	}
185
-
186
-	a, _ := getCredentials(cli.configFile, configKey)
187
-	return a
188
-}
189
-
190
-// RetrieveAuthConfigs return all credentials.
191
-func (cli *DockerCli) RetrieveAuthConfigs() map[string]types.AuthConfig {
192
-	acs, _ := getAllCredentials(cli.configFile)
193
-	return acs
194
-}
195
-
196
-// ForwardAllSignals forwards signals to the container
177
+// ForwardAllSignals forwards signals to the contianer
197 178
 // TODO: this can be unexported again once all container commands are under
198 179
 // api/client/container
199 180
 func (cli *DockerCli) ForwardAllSignals(ctx context.Context, cid string) chan os.Signal {
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"github.com/docker/docker/api/client/container"
6 6
 	"github.com/docker/docker/api/client/image"
7 7
 	"github.com/docker/docker/api/client/network"
8
+	"github.com/docker/docker/api/client/registry"
8 9
 	"github.com/docker/docker/api/client/system"
9 10
 	"github.com/docker/docker/api/client/volume"
10 11
 	"github.com/docker/docker/cli"
... ...
@@ -65,6 +66,8 @@ func NewCobraAdaptor(clientFlags *cliflags.ClientFlags) CobraAdaptor {
65 65
 		image.NewTagCommand(dockerCli),
66 66
 		network.NewNetworkCommand(dockerCli),
67 67
 		system.NewEventsCommand(dockerCli),
68
+		registry.NewLoginCommand(dockerCli),
69
+		registry.NewLogoutCommand(dockerCli),
68 70
 		system.NewVersionCommand(dockerCli),
69 71
 		volume.NewVolumeCommand(dockerCli),
70 72
 	)
... ...
@@ -12,8 +12,6 @@ var DockerCommandUsage = []Command{
12 12
 	{"exec", "Run a command in a running container"},
13 13
 	{"info", "Display system-wide information"},
14 14
 	{"inspect", "Return low-level information on a container or image"},
15
-	{"login", "Log in to a Docker registry"},
16
-	{"logout", "Log out from a Docker registry"},
17 15
 	{"ps", "List containers"},
18 16
 	{"pull", "Pull an image or a repository from a registry"},
19 17
 	{"push", "Push an image or a repository to a registry"},