-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.go
196 lines (171 loc) · 5.16 KB
/
utils.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
package client
import (
"encoding/base64"
"encoding/json"
"fmt"
"os"
gosignal "os/signal"
"runtime"
"strings"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/term"
"github.com/docker/docker/registry"
"github.com/docker/engine-api/client"
"github.com/docker/engine-api/types"
registrytypes "github.com/docker/engine-api/types/registry"
)
func (cli *DockerCli) electAuthServer() string {
// The daemon `/info` endpoint informs us of the default registry being
// used. This is essential in cross-platforms environment, where for
// example a Linux client might be interacting with a Windows daemon, hence
// the default registry URL might be Windows specific.
serverAddress := registry.IndexServer
if info, err := cli.client.Info(); err != nil {
fmt.Fprintf(cli.out, "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, serverAddress)
} else {
serverAddress = info.IndexServerAddress
}
return serverAddress
}
// encodeAuthToBase64 serializes the auth configuration as JSON base64 payload
func encodeAuthToBase64(authConfig types.AuthConfig) (string, error) {
buf, err := json.Marshal(authConfig)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(buf), nil
}
func (cli *DockerCli) encodeRegistryAuth(index *registrytypes.IndexInfo) (string, error) {
authConfig := registry.ResolveAuthConfig(cli.configFile.AuthConfigs, index)
return encodeAuthToBase64(authConfig)
}
func (cli *DockerCli) registryAuthenticationPrivilegedFunc(index *registrytypes.IndexInfo, cmdName string) client.RequestPrivilegeFunc {
return func() (string, error) {
fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName)
indexServer := registry.GetAuthConfigKey(index)
authConfig, err := cli.configureAuth("", "", "", indexServer)
if err != nil {
return "", err
}
return encodeAuthToBase64(authConfig)
}
}
func (cli *DockerCli) resizeTty(id string, isExec bool) {
height, width := cli.getTtySize()
if height == 0 && width == 0 {
return
}
options := types.ResizeOptions{
ID: id,
Height: height,
Width: width,
}
var err error
if isExec {
err = cli.client.ContainerExecResize(options)
} else {
err = cli.client.ContainerResize(options)
}
if err != nil {
logrus.Debugf("Error resize: %s", err)
}
}
// getExitCode perform an inspect on the container. It returns
// the running state and the exit code.
func getExitCode(cli *DockerCli, containerID string) (bool, int, error) {
c, err := cli.client.ContainerInspect(containerID)
if err != nil {
// If we can't connect, then the daemon probably died.
if err != client.ErrConnectionFailed {
return false, -1, err
}
return false, -1, nil
}
return c.State.Running, c.State.ExitCode, nil
}
// getExecExitCode perform an inspect on the exec command. It returns
// the running state and the exit code.
func getExecExitCode(cli *DockerCli, execID string) (bool, int, error) {
resp, err := cli.client.ContainerExecInspect(execID)
if err != nil {
// If we can't connect, then the daemon probably died.
if err != client.ErrConnectionFailed {
return false, -1, err
}
return false, -1, nil
}
return resp.Running, resp.ExitCode, nil
}
func (cli *DockerCli) monitorTtySize(id string, isExec bool) error {
cli.resizeTty(id, isExec)
if runtime.GOOS == "windows" {
go func() {
prevH, prevW := cli.getTtySize()
for {
time.Sleep(time.Millisecond * 250)
h, w := cli.getTtySize()
if prevW != w || prevH != h {
cli.resizeTty(id, isExec)
}
prevH = h
prevW = w
}
}()
} else {
sigchan := make(chan os.Signal, 1)
gosignal.Notify(sigchan, signal.SIGWINCH)
go func() {
for range sigchan {
cli.resizeTty(id, isExec)
}
}()
}
return nil
}
func (cli *DockerCli) getTtySize() (int, int) {
if !cli.isTerminalOut {
return 0, 0
}
ws, err := term.GetWinsize(cli.outFd)
if err != nil {
logrus.Debugf("Error getting size: %s", err)
if ws == nil {
return 0, 0
}
}
return int(ws.Height), int(ws.Width)
}
// resolveAuthConfig is like registry.ResolveAuthConfig, but if using the
// default index, it uses the default index name for the daemon's platform,
// not the client's platform.
func (cli *DockerCli) resolveAuthConfig(authConfigs map[string]types.AuthConfig, index *registrytypes.IndexInfo) types.AuthConfig {
configKey := index.Name
if index.Official {
configKey = cli.electAuthServer()
}
// First try the happy case
if c, found := authConfigs[configKey]; found || index.Official {
return c
}
convertToHostname := func(url string) string {
stripped := url
if strings.HasPrefix(url, "http://") {
stripped = strings.Replace(url, "http://", "", 1)
} else if strings.HasPrefix(url, "https://") {
stripped = strings.Replace(url, "https://", "", 1)
}
nameParts := strings.SplitN(stripped, "/", 2)
return nameParts[0]
}
// Maybe they have a legacy config file, we will iterate the keys converting
// them to the new format and testing
for registry, ac := range authConfigs {
if configKey == convertToHostname(registry) {
return ac
}
}
// When all else fails, return an empty auth config
return types.AuthConfig{}
}