-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
docker.go
126 lines (107 loc) · 2.82 KB
/
docker.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
package docker
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/url"
"os"
"os/exec"
"github.com/docker/docker/client"
"github.com/docker/docker/api/types"
)
type RegistryConfig struct {
URL *url.URL
Username string
Password string
}
func (c RegistryConfig) GetAuthConfig() types.AuthConfig {
return types.AuthConfig{
Username: c.Username,
Password: c.Password,
ServerAddress: c.URL.Host,
}
}
func (c RegistryConfig) GetRegistryAuth() (string, error) {
authConfig := types.AuthConfig{
Username: c.Username,
Password: c.Password,
}
encodedJSON, err := json.Marshal(authConfig)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(encodedJSON), nil
}
func (c RegistryConfig) GetBasicAuthorization() string {
return fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", c.Username, c.Password))))
}
type Docker struct {
cli *client.Client
}
func New() (Docker, error) {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return Docker{}, err
}
return Docker{
cli: cli,
}, nil
}
func (d Docker) Login(conf RegistryConfig) error {
auth := conf.GetAuthConfig()
return exec.Command("docker", "login", "-u", auth.Username, "-p", auth.Password, auth.ServerAddress).Run()
}
func (d Docker) Logout(conf RegistryConfig) error {
auth := conf.GetAuthConfig()
return exec.Command("docker", "logout", auth.ServerAddress).Run()
}
// ReplicateImage tags the given imagePath and pushes it to the given dest registry.
func (d Docker) ReplicateImage(ctx context.Context, imageRef, imagePath string, dest RegistryConfig) error {
// remove existing Image if any
_, _ = d.cli.ImageRemove(ctx, imageRef, types.ImageRemoveOptions{
Force: true,
PruneChildren: true,
})
testfile, err := os.Open(imagePath)
if err != nil {
return err
}
// load image into docker engine
resp, err := d.cli.ImageLoad(ctx, testfile, true)
if err != nil {
return err
}
if _, err := io.Copy(io.Discard, resp.Body); err != nil {
return err
}
defer resp.Body.Close()
targetImageRef := fmt.Sprintf("%s/%s", dest.URL.Host, imageRef)
if err = d.cli.ImageTag(ctx, imageRef, targetImageRef); err != nil {
return err
}
defer func() {
_, _ = d.cli.ImageRemove(ctx, imageRef, types.ImageRemoveOptions{
Force: true,
PruneChildren: true,
})
_, _ = d.cli.ImageRemove(ctx, targetImageRef, types.ImageRemoveOptions{
Force: true,
PruneChildren: true,
})
}()
auth, err := dest.GetRegistryAuth()
if err != nil {
return err
}
pushOut, err := d.cli.ImagePush(ctx, targetImageRef, types.ImagePushOptions{RegistryAuth: auth})
if err != nil {
return err
}
defer pushOut.Close()
if _, err = io.Copy(io.Discard, pushOut); err != nil {
return err
}
return nil
}