diff --git a/app.go b/app.go index 22f534c..8ee4064 100644 --- a/app.go +++ b/app.go @@ -1,6 +1,7 @@ package docker import ( + "log" "os" "github.com/drone-plugins/drone-plugin-lib/drone" @@ -225,6 +226,21 @@ func Run() { Usage: "docker password", EnvVar: "PLUGIN_PASSWORD,DOCKER_PASSWORD", }, + cli.StringFlag{ + Name: "docker.baseimageusername", + Usage: "Docker username for base image registry", + EnvVar: "PLUGIN_DOCKER_USERNAME,PLUGIN_BASE_IMAGE_USERNAME", + }, + cli.StringFlag{ + Name: "docker.baseimagepassword", + Usage: "Docker password for base image registry", + EnvVar: "PLUGIN_DOCKER_PASSWORD,PLUGIN_BASE_IMAGE_PASSWORD", + }, + cli.StringFlag{ + Name: "docker.baseimageregistry", + Usage: "Docker registry for base image registry", + EnvVar: "PLUGIN_DOCKER_REGISTRY,PLUGIN_BASE_IMAGE_REGISTRY", + }, cli.StringFlag{ Name: "docker.email", Usage: "docker email", @@ -344,12 +360,11 @@ func run(c *cli.Context) error { Dryrun: c.Bool("dry-run"), Cleanup: c.BoolT("docker.purge"), Login: Login{ - Registry: c.String("docker.registry"), - Username: c.String("docker.username"), - Password: c.String("docker.password"), - Email: c.String("docker.email"), - Config: c.String("docker.config"), - AccessToken: c.String("access-token"), + Registry: c.String("docker.registry"), + Username: c.String("docker.username"), + Password: c.String("docker.password"), + Email: c.String("docker.email"), + Config: c.String("docker.config"), }, CardPath: c.String("drone-card-path"), MetadataFile: c.String("metadata-file"), @@ -405,6 +420,9 @@ func run(c *cli.Context) error { DriverOpts: c.Generic("builder-driver-opts").(*CustomStringSliceFlag).GetValue(), RemoteConn: c.String("builder-remote-conn"), }, + BaseImageRegistry: c.String("docker.baseimageregistry"), + BaseImageUsername: c.String("docker.baseimageusername"), + BaseImagePassword: c.String("docker.baseimagepassword"), } if c.Bool("tags.auto") { diff --git a/docker.go b/docker.go index 8a0be98..3ad8c8f 100644 --- a/docker.go +++ b/docker.go @@ -40,12 +40,12 @@ type ( // Login defines Docker login parameters. Login struct { - Registry string // Docker registry address - Username string // Docker registry username - Password string // Docker registry password - Email string // Docker registry email - Config string // Docker Auth Config - AccessToken string // External Access Token + Registry string // Docker registry address + Username string // Docker registry username + Password string // Docker registry password + Email string // Docker registry email + Config string // Docker Auth Config + AccessToken string // External Access Token } // Build defines Docker build parameters. @@ -82,15 +82,18 @@ type ( // Plugin defines the Docker plugin parameters. Plugin struct { - Login Login // Docker login configuration - Build Build // Docker build configuration - Builder Builder // Docker Buildx builder configuration - Daemon Daemon // Docker daemon configuration - Dryrun bool // Docker push is skipped - Cleanup bool // Docker purge is enabled - CardPath string // Card path to write file to - MetadataFile string // Location to write the metadata file - ArtifactFile string // Artifact path to write file to + Login Login // Docker login configuration + Build Build // Docker build configuration + Builder Builder // Docker Buildx builder configuration + Daemon Daemon // Docker daemon configuration + Dryrun bool // Docker push is skipped + Cleanup bool // Docker purge is enabled + CardPath string // Card path to write file to + MetadataFile string // Location to write the metadata file + ArtifactFile string // Artifact path to write file to + BaseImageRegistry string // Docker registry to pull base image + BaseImageUsername string // Docker registry username to pull base image + BaseImagePassword string // Docker registry password to pull base image } Card []struct { @@ -170,29 +173,6 @@ func (p Plugin) Exec() error { } } - // login to the Docker registry - if p.Login.Password != "" { - cmd := commandLogin(p.Login) - raw, err := cmd.CombinedOutput() - if err != nil { - out := string(raw) - out = strings.Replace(out, "WARNING! Using --password via the CLI is insecure. Use --password-stdin.", "", -1) - fmt.Println(out) - return fmt.Errorf("Error authenticating: exit status 1") - } - } else if p.Login.AccessToken != "" { - cmd := commandLoginAccessToken(p.Login, p.Login.AccessToken) - output, err := cmd.CombinedOutput() - if err != nil { - return fmt.Errorf("error logging in to Docker registry: %s", err) - } - if strings.Contains(string(output), "Login Succeeded") { - fmt.Println("Login successful") - } else { - return fmt.Errorf("login did not succeed") - } - } - // cache export feature is currently not supported for docker driver hence we have to create docker-container driver if len(p.Build.CacheTo) > 0 && (p.Builder.Driver == "" || p.Builder.Driver == defaultDriver) { p.Builder.Driver = dockerContainerDriver @@ -224,9 +204,38 @@ func (p Plugin) Exec() error { cmds = append(cmds, commandVersion()) // docker version cmds = append(cmds, commandInfo()) // docker info - // Command to build, tag and push + // login to base image registry + baseImageLogin := Login{ + Registry: p.BaseImageRegistry, + Username: p.BaseImageUsername, + Password: p.BaseImagePassword, + } + var cmdPushLogin, cmdBaseImageLogin *exec.Cmd + // just process the login command to push registry, don't append to list of commands yet + if p.Login.Password != "" { + cmdPushLogin = commandLogin(p.Login) + } else if p.Login.AccessToken != "" { + cmdPushLogin = commandLoginAccessToken(p.Login, p.Login.AccessToken) + } + if p.BaseImagePassword != "" { + cmdBaseImageLogin = commandLogin(baseImageLogin) + } else{ + cmdBaseImageLogin = cmdPushLogin + } + // 1. append login command for base image docker registry if provided, else the login command of push registry + cmds = append(cmds, cmdBaseImageLogin) + + // 2. Command to only build tag (no-push) - as for push there is a possibility of authentication to different registry cmds = append(cmds, commandBuildx(p.Build, p.Builder, p.Dryrun, p.MetadataFile)) // docker build + // 3. login to push registry + cmds = append(cmds, cmdPushLogin) + + // 4. command to only push the image, if dryrun not set + if !p.Dryrun { + cmds = append(cmds, commandPush(p.Build, p.Build.Tags[0])) + } + // execute all commands in batch mode. for _, cmd := range cmds { cmd.Stdout = os.Stdout @@ -307,12 +316,9 @@ func commandLogin(login Login) *exec.Cmd { if login.Email != "" { return commandLoginEmail(login) } - return exec.Command( - dockerExe, "login", - "-u", login.Username, - "-p", login.Password, - login.Registry, - ) + cmd := exec.Command(dockerExe, "login", "-u", login.Username, "--password-stdin", login.Registry) + cmd.Stdin = strings.NewReader(login.Password) + return cmd } // helper to login via access token @@ -361,7 +367,7 @@ func commandBuildx(build Build, builder Builder, dryrun bool, metadataFile strin args := []string{ "buildx", "build", - "--rm=true", + //"--rm=true", "-f", build.Dockerfile, } @@ -371,13 +377,7 @@ func commandBuildx(build Build, builder Builder, dryrun bool, metadataFile strin for _, t := range build.Tags { args = append(args, "-t", fmt.Sprintf("%s:%s", build.Repo, t)) } - if dryrun { - if build.BuildxLoad { - args = append(args, "--load") - } - } else { - args = append(args, "--push") - } + args = append(args, "--load") args = append(args, build.Context) if metadataFile != "" { args = append(args, "--metadata-file", metadataFile) diff --git a/plugin.yml b/plugin.yml index 0e71d48..ff41de9 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,3 +1,3 @@ run: binary: - source: https://github.com/drone-plugins/drone-buildx/releases/download/{{ release }}/drone-buildx-{{ os }}-{{ arch }}.zst \ No newline at end of file + source: https://elasticbeanstalk-us-east-1-734046833946.s3.amazonaws.com/drone-docker-2