Skip to content

Commit 6cade1e

Browse files
Merge pull request #446 from Aishwarya-Lad/CI-11718-part2
update docker config for base image
2 parents 292ebe0 + 0a2f635 commit 6cade1e

File tree

6 files changed

+223
-8
lines changed

6 files changed

+223
-8
lines changed

cmd/drone-docker/main.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,21 @@ func main() {
222222
Usage: "docker password",
223223
EnvVar: "PLUGIN_PASSWORD,DOCKER_PASSWORD",
224224
},
225+
cli.StringFlag{
226+
Name: "docker.baseimageusername",
227+
Usage: "Docker username for base image registry",
228+
EnvVar: "PLUGIN_DOCKER_USERNAME,PLUGIN_BASE_IMAGE_USERNAME,DOCKER_BASE_IMAGE_USERNAME",
229+
},
230+
cli.StringFlag{
231+
Name: "docker.baseimagepassword",
232+
Usage: "Docker password for base image registry",
233+
EnvVar: "PLUGIN_DOCKER_PASSWORD,PLUGIN_BASE_IMAGE_PASSWORD,DOCKER_BASE_IMAGE_PASSWORD",
234+
},
235+
cli.StringFlag{
236+
Name: "docker.baseimageregistry",
237+
Usage: "Docker registry for base image registry",
238+
EnvVar: "PLUGIN_DOCKER_REGISTRY,PLUGIN_BASE_IMAGE_REGISTRY,DOCKER_BASE_IMAGE_REGISTRY",
239+
},
225240
cli.StringFlag{
226241
Name: "docker.email",
227242
Usage: "docker email",
@@ -367,6 +382,9 @@ func run(c *cli.Context) error {
367382
Experimental: c.Bool("daemon.experimental"),
368383
RegistryType: registryType,
369384
},
385+
BaseImageRegistry: c.String("docker.baseimageregistry"),
386+
BaseImageUsername: c.String("docker.baseimageusername"),
387+
BaseImagePassword: c.String("docker.baseimagepassword"),
370388
}
371389

372390
if c.Bool("tags.auto") {

docker.go

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"strings"
1111
"time"
1212

13+
"github.com/drone-plugins/drone-docker/internal/docker"
1314
"github.com/drone-plugins/drone-plugin-lib/drone"
1415
)
1516

@@ -75,13 +76,16 @@ type (
7576

7677
// Plugin defines the Docker plugin parameters.
7778
Plugin struct {
78-
Login Login // Docker login configuration
79-
Build Build // Docker build configuration
80-
Daemon Daemon // Docker daemon configuration
81-
Dryrun bool // Docker push is skipped
82-
Cleanup bool // Docker purge is enabled
83-
CardPath string // Card path to write file to
84-
ArtifactFile string // Artifact path to write file to
79+
Login Login // Docker login configuration
80+
Build Build // Docker build configuration
81+
Daemon Daemon // Docker daemon configuration
82+
Dryrun bool // Docker push is skipped
83+
Cleanup bool // Docker purge is enabled
84+
CardPath string // Card path to write file to
85+
ArtifactFile string // Artifact path to write file to
86+
BaseImageRegistry string // Docker registry to pull base image
87+
BaseImageUsername string // Docker registry username to pull base image
88+
BaseImagePassword string // Docker registry password to pull base image
8589
}
8690

8791
Card []struct {
@@ -154,7 +158,32 @@ func (p Plugin) Exec() error {
154158
os.MkdirAll(dockerHome, 0600)
155159

156160
path := filepath.Join(dockerHome, "config.json")
157-
err := os.WriteFile(path, []byte(p.Login.Config), 0600)
161+
file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
162+
if err != nil {
163+
return fmt.Errorf("Error writing config.json: %s", err)
164+
}
165+
err = os.WriteFile(path, []byte(p.Login.Config), 0600)
166+
if err != nil {
167+
return fmt.Errorf("Error writing config.json: %s", err)
168+
}
169+
file.Close()
170+
}
171+
172+
// add base image docker credentials to the existing config file, else create new
173+
if p.BaseImagePassword != "" {
174+
json, err := setDockerAuth(p.Login.Username, p.Login.Password, p.Login.Registry,
175+
p.BaseImageUsername, p.BaseImagePassword, p.BaseImageRegistry)
176+
if err != nil {
177+
return fmt.Errorf("Failed to set authentication in docker config %s", err)
178+
}
179+
os.MkdirAll(dockerHome, 0600)
180+
path := filepath.Join(dockerHome, "config.json")
181+
file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
182+
if err != nil {
183+
return fmt.Errorf("Error opening config.json: %s", err)
184+
}
185+
defer file.Close()
186+
_, err = file.Write(json)
158187
if err != nil {
159188
return fmt.Errorf("Error writing config.json: %s", err)
160189
}
@@ -270,6 +299,35 @@ func (p Plugin) Exec() error {
270299
return nil
271300
}
272301

302+
// helper function to set the credentials
303+
func setDockerAuth(username, password, registry, baseImageUsername,
304+
baseImagePassword, baseImageRegistry string) ([]byte, error) {
305+
var credentials []docker.RegistryCredentials
306+
// add only docker registry to the config
307+
dockerConfig := docker.NewConfig()
308+
if password != "" {
309+
pushToRegistryCreds := docker.RegistryCredentials{
310+
Registry: registry,
311+
Username: username,
312+
Password: password,
313+
}
314+
// push registry auth
315+
credentials = append(credentials, pushToRegistryCreds)
316+
}
317+
318+
if baseImageRegistry != "" {
319+
pullFromRegistryCreds := docker.RegistryCredentials{
320+
Registry: baseImageRegistry,
321+
Username: baseImageUsername,
322+
Password: baseImagePassword,
323+
}
324+
// base image registry auth
325+
credentials = append(credentials, pullFromRegistryCreds)
326+
}
327+
// Creates docker config for both the registries used for authentication
328+
return dockerConfig.CreateDockerConfigJson(credentials)
329+
}
330+
273331
// helper function to create the docker login command.
274332
func commandLogin(login Login) *exec.Cmd {
275333
if login.Email != "" {

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ require (
99
github.com/inhies/go-bytesize v0.0.0-20210819104631-275770b98743
1010
github.com/joho/godotenv v1.3.0
1111
github.com/sirupsen/logrus v1.9.0
12+
github.com/stretchr/testify v1.8.1
1213
github.com/urfave/cli v1.22.2
1314
golang.org/x/oauth2 v0.13.0
1415
)
@@ -17,13 +18,15 @@ require (
1718
cloud.google.com/go/compute v1.23.1 // indirect
1819
cloud.google.com/go/compute/metadata v0.2.3 // indirect
1920
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
21+
github.com/davecgh/go-spew v1.1.1 // indirect
2022
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
2123
github.com/golang/protobuf v1.5.3 // indirect
2224
github.com/google/s2a-go v0.1.7 // indirect
2325
github.com/google/uuid v1.3.1 // indirect
2426
github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect
2527
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
2628
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
29+
github.com/pmezard/go-difflib v1.0.0 // indirect
2730
github.com/russross/blackfriday/v2 v2.1.0 // indirect
2831
go.opencensus.io v0.24.0 // indirect
2932
golang.org/x/crypto v0.14.0 // indirect

go.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
9090
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
9191
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
9292
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
93+
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
9394
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
9495
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
9596
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=

internal/docker/config.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package docker
2+
3+
import (
4+
"encoding/base64"
5+
"encoding/json"
6+
"errors"
7+
"fmt"
8+
"strings"
9+
)
10+
11+
const (
12+
v2HubRegistryURL string = "https://registry.hub.docker.com/v2/"
13+
v1RegistryURL string = "https://index.docker.io/v1/" // Default registry
14+
v2RegistryURL string = "https://index.docker.io/v2/" // v2 registry is not supported
15+
)
16+
17+
type (
18+
Auth struct {
19+
Auth string `json:"auth"`
20+
}
21+
22+
Config struct {
23+
Auths map[string]Auth `json:"auths"`
24+
CredHelpers map[string]string `json:"credHelpers,omitempty"`
25+
}
26+
)
27+
28+
type RegistryCredentials struct {
29+
Registry string
30+
Username string
31+
Password string
32+
}
33+
34+
func NewConfig() *Config {
35+
return &Config{
36+
Auths: make(map[string]Auth),
37+
CredHelpers: make(map[string]string),
38+
}
39+
}
40+
41+
func (c *Config) SetAuth(registry, username, password string) {
42+
authBytes := []byte(username + ":" + password)
43+
encodedString := base64.StdEncoding.EncodeToString(authBytes)
44+
c.Auths[registry] = Auth{Auth: encodedString}
45+
}
46+
47+
func (c *Config) SetCredHelper(registry, helper string) {
48+
c.CredHelpers[registry] = helper
49+
}
50+
51+
func (c *Config) CreateDockerConfigJson(credentials []RegistryCredentials) ([]byte, error) {
52+
for _, cred := range credentials {
53+
if cred.Registry != "" && strings.Contains(cred.Registry, "docker") {
54+
55+
if cred.Username == "" {
56+
return nil, fmt.Errorf("Username must be specified for registry: %s", cred.Registry)
57+
}
58+
if cred.Password == "" {
59+
return nil, fmt.Errorf("Password must be specified for registry: %s", cred.Registry)
60+
}
61+
c.SetAuth(cred.Registry, cred.Username, cred.Password)
62+
}
63+
}
64+
65+
jsonBytes, err := json.Marshal(c)
66+
if err != nil {
67+
return nil, errors.New("failed to serialize docker config json")
68+
}
69+
70+
return jsonBytes, nil
71+
}

internal/docker/config_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package docker
2+
3+
import (
4+
"encoding/json"
5+
"io/ioutil"
6+
"os"
7+
"path/filepath"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
const (
14+
RegistryV1 string = "https://index.docker.io/v1/"
15+
RegistryV2 string = "https://index.docker.io/v2/"
16+
RegistryECRPublic string = "public.ecr.aws"
17+
)
18+
19+
func TestConfig(t *testing.T) {
20+
c := NewConfig()
21+
assert.NotNil(t, c.Auths)
22+
assert.NotNil(t, c.CredHelpers)
23+
24+
c.SetAuth(RegistryV1, "test", "password")
25+
expectedAuth := Auth{Auth: "dGVzdDpwYXNzd29yZA=="}
26+
assert.Equal(t, expectedAuth, c.Auths[RegistryV1])
27+
28+
c.SetCredHelper(RegistryECRPublic, "ecr-login")
29+
assert.Equal(t, "ecr-login", c.CredHelpers[RegistryECRPublic])
30+
31+
tempDir, err := ioutil.TempDir("", "docker-config-test")
32+
assert.NoError(t, err)
33+
defer os.RemoveAll(tempDir)
34+
35+
credentials := []RegistryCredentials{
36+
{
37+
Registry: "https://index.docker.io/v1/",
38+
Username: "user1",
39+
Password: "pass1",
40+
},
41+
{
42+
Registry: "gcr.io",
43+
Username: "user2",
44+
Password: "pass2",
45+
},
46+
}
47+
48+
jsonBytes, err := c.CreateDockerConfigJson(credentials)
49+
assert.NoError(t, err)
50+
51+
configPath := filepath.Join(tempDir, "config.json")
52+
err = ioutil.WriteFile(configPath, jsonBytes, 0644)
53+
assert.NoError(t, err)
54+
55+
data, err := ioutil.ReadFile(configPath)
56+
assert.NoError(t, err)
57+
58+
var configFromFile Config
59+
err = json.Unmarshal(data, &configFromFile)
60+
assert.NoError(t, err)
61+
62+
assert.Equal(t, c.Auths, configFromFile.Auths)
63+
assert.Equal(t, c.CredHelpers, configFromFile.CredHelpers)
64+
}

0 commit comments

Comments
 (0)