diff --git a/.drone.yml b/.drone.yml index 39966f5f9..8ef77337d 100644 --- a/.drone.yml +++ b/.drone.yml @@ -11,7 +11,9 @@ pipeline: # Test the code test: - image: golang + image: asoldatenko/dnd-golang + volumes: + - /var/run/docker.sock:/var/run/docker.sock commands: - make test diff --git a/Dockerfile-dev b/Dockerfile-dev new file mode 100644 index 000000000..a139dedae --- /dev/null +++ b/Dockerfile-dev @@ -0,0 +1,12 @@ +FROM docker:dind + +RUN apk add --no-cache git make musl-dev go + +# Configure Go +ENV GOROOT /usr/lib/go +ENV GOPATH /go +ENV PATH /go/bin:$PATH + +RUN mkdir -p ${GOPATH}/src ${GOPATH}/bin + +WORKDIR $GOPATH \ No newline at end of file diff --git a/docker/docker.go b/docker/docker.go index 0b6240f2e..27d5e8e79 100644 --- a/docker/docker.go +++ b/docker/docker.go @@ -1,11 +1,16 @@ package docker import ( - "io" - "log" + "context" "os" "os/exec" + "github.com/docker/docker/registry" + + cliconfig "github.com/docker/cli/cli/config" + "github.com/docker/docker/api/types" + registrytypes "github.com/docker/docker/api/types/registry" + "github.com/docker/docker/client" "github.com/pkg/errors" ) @@ -14,6 +19,13 @@ const ( Docker = "docker" ) +type loginOptions struct { + serverAddress string + user string + password string + passwordStdin bool +} + // Exec executes a docker command func Exec(args ...string) error { _, lookErr := exec.LookPath(Docker) @@ -33,32 +45,40 @@ func Exec(args ...string) error { return nil } -// ExecLogin executes a docker login -// Is a workaround for submitting password to stdin without prompting user again -func ExecLogin(registry, username, password string) error { - _, lookErr := exec.LookPath(Docker) - if lookErr != nil { - panic(lookErr) - } +// ExecLogin executes a docker login similar to docker login command +func ExecLogin(serverAddress, username, password string) error { + var response registrytypes.AuthenticateOKBody + ctx := context.Background() - cmd := exec.Command("docker", "login", registry, "-u", username, "--password-stdin") - stdin, err := cmd.StdinPipe() + cli, err := client.NewClientWithOpts(client.FromEnv) if err != nil { - log.Fatal(err) + panic(err) } - go func() { - defer stdin.Close() - io.WriteString(stdin, password) - }() + // Remove http|https from serverAddress + serverAddress = registry.ConvertToHostname(serverAddress) - _, err = cmd.CombinedOutput() + authConfig := &types.AuthConfig{ + ServerAddress: serverAddress, + Username: username, + Password: password, + } - cmd.Stdout = os.Stdout - cmd.Stdin = os.Stdin - cmd.Stderr = os.Stderr + response, _ = cli.RegistryLogin(ctx, *authConfig) + + configFile := cliconfig.LoadDefaultConfigFile(os.Stderr) + + creds := configFile.GetCredentialsStore(serverAddress) + + if err := creds.Store(types.AuthConfig(*authConfig)); err != nil { + return errors.Errorf("Error saving credentials: %v", err) + } + + if response.Status != "" { + return errors.Errorf("Error saving credentials: %v", response.Status) + } - return err + return nil } // AirflowCommand is the main method of interaction with Airflow @@ -71,7 +91,7 @@ func AirflowCommand(id string, airflowCommand string) string { out, err := cmd.Output() if err != nil { - errors.Wrapf(err, "error encountered") + _ = errors.Wrapf(err, "error encountered") } stringOut := string(out) diff --git a/docker/docker_test.go b/docker/docker_test.go new file mode 100644 index 000000000..fe089f55c --- /dev/null +++ b/docker/docker_test.go @@ -0,0 +1,10 @@ +package docker + +import "testing" + +func TestExecVersion(t *testing.T) { + err := Exec("version") + if err != nil { + t.Error(err) + } +}