Skip to content

Commit 4b1a751

Browse files
authored
docker-push: use isolated client configuration (#96)
* docker-push: use isolated client configuration When running multiple `docker-push` post processors concurrently, there was a race condition where one `docker-push` post processor would finish and call `docker logout` to remove the credentials for a given registry while another `docker-push` post processor was still running, causing the other `docker-push` post processor to no longer have access to the registry credentials to perform a `docker push`. Since the underlying `DockerDriver` shells out to raw `docker` commands, calls to `Login` store registry credentials in the default Docker client configuration directory. Additionally, calls to `Logout` remove registry credentials from the default Docker client configuration directory. Since Packer post processors are unaware of each other, one `docker-push` post processor was removing registry credentials that another `docker-push` post processor relied on. These changes modify the `docker-push` post processor to use a temporary, isolated Docker client configuration directory. This allows each `docker-push` post processor to store registry credentials in an isolated file that will not be accessed by another `docker-push` post processor. The implementation not modify the `Driver` interface, choosing instead to add an exported field to the `DockerDriver` type that the `docker-push` sets. * Implement pull request feedback * Update variable name
1 parent debb39a commit 4b1a751

File tree

2 files changed

+51
-8
lines changed

2 files changed

+51
-8
lines changed

builder/docker/driver_docker.go

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ type DockerDriver struct {
2020
Ui packersdk.Ui
2121
Ctx *interpolate.Context
2222

23+
// The directory Docker should use to store its client configuration.
24+
// Provides an isolated client configuration to each Docker operation to
25+
// prevent race conditions.
26+
ConfigDir string
27+
2328
l sync.Mutex
2429
}
2530

@@ -220,8 +225,7 @@ func (d *DockerDriver) Login(repo, user, pass string) error {
220225
return err
221226
}
222227

223-
cmd := exec.Command("docker")
224-
cmd.Args = append(cmd.Args, "login")
228+
cmd := d.newCommandWithConfig("login")
225229

226230
if user != "" {
227231
cmd.Args = append(cmd.Args, "-u", user)
@@ -260,24 +264,26 @@ func (d *DockerDriver) Login(repo, user, pass string) error {
260264
}
261265

262266
func (d *DockerDriver) Logout(repo string) error {
263-
args := []string{"logout"}
267+
cmd := d.newCommandWithConfig("logout")
268+
264269
if repo != "" {
265-
args = append(args, repo)
270+
cmd.Args = append(cmd.Args, repo)
266271
}
267272

268-
cmd := exec.Command("docker", args...)
269273
err := runAndStream(cmd, d.Ui)
270274
d.l.Unlock()
271275
return err
272276
}
273277

274278
func (d *DockerDriver) Pull(image string) error {
275-
cmd := exec.Command("docker", "pull", image)
279+
cmd := d.newCommandWithConfig("pull", image)
280+
276281
return runAndStream(cmd, d.Ui)
277282
}
278283

279284
func (d *DockerDriver) Push(name string) error {
280-
cmd := exec.Command("docker", "push", name)
285+
cmd := d.newCommandWithConfig("push", name)
286+
281287
return runAndStream(cmd, d.Ui)
282288
}
283289

@@ -453,3 +459,15 @@ func (d *DockerDriver) Version() (*version.Version, error) {
453459

454460
return version.NewVersion(string(match[0]))
455461
}
462+
463+
func (d *DockerDriver) newCommandWithConfig(args ...string) *exec.Cmd {
464+
cmd := exec.Command("docker")
465+
466+
if d.ConfigDir != "" {
467+
cmd.Args = append(cmd.Args, "--config", d.ConfigDir)
468+
}
469+
470+
cmd.Args = append(cmd.Args, args...)
471+
472+
return cmd
473+
}

post-processor/docker-push/post-processor.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package dockerpush
55
import (
66
"context"
77
"fmt"
8+
"os"
89

910
"github.com/hashicorp/hcl/v2/hcldec"
1011
"github.com/hashicorp/packer-plugin-docker/builder/docker"
@@ -69,8 +70,32 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packersdk.Ui, artifa
6970

7071
driver := p.Driver
7172
if driver == nil {
73+
var configDir string
74+
75+
if _, ok := os.LookupEnv("DOCKER_CONFIG"); !ok {
76+
ui.Message("Creating temporary Docker configuration directory")
77+
tmpDir, err := os.MkdirTemp("", "packer")
78+
if err != nil {
79+
return nil, false, false, fmt.Errorf(
80+
"Error creating temporary Docker configuration directory: %s", err)
81+
}
82+
configDir = tmpDir
83+
84+
defer func() {
85+
ui.Message("Removing temporary Docker configuration directory")
86+
if err := os.RemoveAll(tmpDir); err != nil {
87+
ui.Error(
88+
fmt.Sprintf("Error removing temporary Docker configuration directory: %s", err))
89+
}
90+
}()
91+
}
92+
7293
// If no driver is set, then we use the real driver
73-
driver = &docker.DockerDriver{Ctx: &p.config.ctx, Ui: ui}
94+
driver = &docker.DockerDriver{
95+
Ctx: &p.config.ctx,
96+
Ui: ui,
97+
ConfigDir: configDir,
98+
}
7499
}
75100

76101
if p.config.EcrLogin {

0 commit comments

Comments
 (0)