Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

registry: Remove dependency on Docker binary for login/logout #805

Merged
merged 4 commits into from May 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
44 changes: 21 additions & 23 deletions commands/registry.go
Expand Up @@ -17,13 +17,16 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"os"
"os/exec"
"strings"

"github.com/digitalocean/doctl"
"github.com/digitalocean/doctl/commands/displayers"
"github.com/digitalocean/doctl/do"
"github.com/digitalocean/godo"
dockerconf "github.com/docker/cli/cli/config"
configtypes "github.com/docker/cli/cli/config/types"
"github.com/spf13/cobra"
k8sapiv1 "k8s.io/api/core/v1"
k8smetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -213,11 +216,6 @@ var execCommand = exec.Command

// RunRegistryLogin logs in Docker to the registry
func RunRegistryLogin(c *CmdConfig) error {
// check if docker is installed
if _, err := exec.LookPath("docker"); err != nil {
return fmt.Errorf("unable to find the Docker CLI binary. Make sure docker is installed")
}

fmt.Printf("Logging Docker in to %s\n", c.Registry().Endpoint())

creds, err := c.Registry().DockerCredentials(&godo.RegistryDockerCredentialsRequest{
Expand Down Expand Up @@ -247,21 +245,20 @@ func RunRegistryLogin(c *CmdConfig) error {
}
user, pass := splitCreds[0], splitCreds[1]

// log in via the docker cli
args := []string{
"login", host,
"-u", user,
"--password-stdin",
authconfig := configtypes.AuthConfig{
Username: user,
Password: pass,
ServerAddress: host,
}
cmd := execCommand("docker", args...)
cmd.Stdin = strings.NewReader(pass)
cmd.Stdout = c.Out
cmd.Stderr = c.Out

err = cmd.Run()
cf := dockerconf.LoadDefaultConfigFile(os.Stderr)
dockerCreds := cf.GetCredentialsStore(authconfig.ServerAddress)
err = dockerCreds.Store(authconfig)
Comment on lines +255 to +256
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these two operations call cgo. I'm going to pull down your branch right now to check, but if so, it might make our release process more complicated since we may not be able to use Go's built-in cross compilation as part of goreleaser.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay – they do call cgo, but it seems like it does not affect our ability to use Go's usual cross compilation tools, so I think this is fine.

if err != nil {
return err
}

cf.Save()
}

return nil
Expand Down Expand Up @@ -344,16 +341,17 @@ func RunDockerConfig(c *CmdConfig) error {

// RunRegistryLogout logs Docker out of the registry
func RunRegistryLogout(c *CmdConfig) error {
// check if docker is installed
if _, err := exec.LookPath("docker"); err != nil {
return fmt.Errorf("unable to find the Docker CLI binary. Make sure docker is installed")
}
server := c.Registry().Endpoint()
fmt.Printf("Removing login credentials for %s\n", server)

cmd := execCommand("docker", "logout", c.Registry().Endpoint())
cmd.Stdout = c.Out
cmd.Stderr = c.Out
cf := dockerconf.LoadDefaultConfigFile(os.Stderr)
dockerCreds := cf.GetCredentialsStore(server)
err := dockerCreds.Erase(server)
if err != nil {
return err
}

return cmd.Run()
return nil
}

// Repository Run Commands
Expand Down
111 changes: 0 additions & 111 deletions commands/registry_test.go
Expand Up @@ -16,11 +16,7 @@ package commands
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"testing"
"time"

Expand Down Expand Up @@ -416,132 +412,25 @@ func TestRegistryKubernetesManifest(t *testing.T) {
})
}

// https://npf.io/2015/06/testing-exec-command/
func fakeExecCommand(testName string) func(string, ...string) *exec.Cmd {
return func(command string, args ...string) *exec.Cmd {
cs := []string{"-test.v", "-test.run=TestHelperProcess", "--", testName, command}
cs = append(cs, args...)
cmd := exec.Command(os.Args[0], cs...)
cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
return cmd
}
}

// this function adds a fake "docker" to PATH because the commands look
// for it but the tests fake the call through fakeExecCommand
// so the cli binary isn't needed at all
func createFakeDocker() (func(), error) {
// get the original PATH and create a temp dir
originalPath := os.Getenv("PATH")
tempDir, err := ioutil.TempDir("", "docker")
if err != nil {
return func() {}, err
}

// define this here so we can return it
// in different places
fnCleanUp := func() {
os.Setenv("PATH", originalPath)
os.RemoveAll(tempDir)
}

// create a fake executable
f, err := os.Create(filepath.Join(tempDir, "docker"))
if err != nil {
return fnCleanUp, err
}
defer f.Close()
f.Chmod(0777)

// add the temp dir to PATH
newPath := fmt.Sprintf("%s%c%s", tempDir, os.PathListSeparator, originalPath)
err = os.Setenv("PATH", newPath)

// return a function to clean up
return fnCleanUp, err
}

func TestRegistryLogin(t *testing.T) {
// create a fake docker executable in PATH so the test doesn't fail
// if Docker isn't installed
removeFakeDocker, err := createFakeDocker()
defer removeFakeDocker() // clean up even if there is an error
if err != nil {
t.Logf("couldn't create temp dir to hold the fake docker cli binary: %v", err)
}

withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
tm.registry.EXPECT().Endpoint().Return(do.RegistryHostname)
tm.registry.EXPECT().DockerCredentials(&godo.RegistryDockerCredentialsRequest{
ReadWrite: true,
}).Return(testDockerCredentials, nil)

// fake execCommand
execCommand = fakeExecCommand("login")
defer func() { execCommand = exec.Command }()

config.Out = os.Stderr
err := RunRegistryLogin(config)
assert.NoError(t, err)
})
}

func TestRegistryLogout(t *testing.T) {
// create a fake docker executable in PATH so the test doesn't fail
// if Docker isn't installed
removeFakeDocker, err := createFakeDocker()
defer removeFakeDocker() // clean up even if there is an error
if err != nil {
t.Logf("couldn't create temp dir to hold the fake docker cli binary: %v", err)
}

withTestClient(t, func(config *CmdConfig, tm *tcMocks) {
tm.registry.EXPECT().Endpoint().Return(do.RegistryHostname)

// fake execCommand
execCommand = fakeExecCommand("logout")
defer func() { execCommand = exec.Command }()

config.Out = os.Stderr
err := RunRegistryLogout(config)
assert.NoError(t, err)
})
}

func TestHelperProcess(t *testing.T) {
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
t.Log("Called TestHelperProcess() when it's not needed")
return
}

// This process is used to fake the "docker" cli command call.
if len(os.Args) < 4 {
t.Error("Invalid TestHelperProcess() call. Use fakeExecCommand() to generate the command")
return
}

switch os.Args[4] {
case "login":
// Make sure we receive the correct test credentials
// as in `testDockerCredentials`.
expectedCommand := []string{"docker", "login", "hostname", "-u", "username", "--password-stdin"}
gotCommand := os.Args[5:]

assert.Equal(t, expectedCommand, gotCommand)

stdin, err := ioutil.ReadAll(os.Stdin)
assert.NoError(t, err)

gotPassword := string(stdin)
assert.Equal(t, "password", gotPassword)

case "logout":
expected := []string{"docker", "logout", do.RegistryHostname}
got := os.Args[5:]

assert.Equal(t, expected, got)

default:
t.Error("Unknown test", os.Args[4])
}
}
7 changes: 6 additions & 1 deletion go.mod
Expand Up @@ -7,9 +7,13 @@ require (
github.com/cpuguy83/go-md2man v1.0.10 // indirect
github.com/creack/pty v1.1.7
github.com/digitalocean/godo v1.35.1
github.com/docker/cli v0.0.0-20200511172450-ab108430b268
github.com/docker/docker v17.12.0-ce-rc1.0.20200429205700-c3b3aedfa4ad+incompatible // indirect
github.com/docker/docker-credential-helpers v0.6.3 // indirect
github.com/dustin/go-humanize v1.0.0
github.com/fatih/color v1.7.0
github.com/gobwas/glob v0.2.3
github.com/gogo/protobuf v1.3.1 // indirect
github.com/golang/mock v1.4.0
github.com/golang/protobuf v1.4.0 // indirect
github.com/google/uuid v1.1.1
Expand All @@ -28,7 +32,8 @@ require (
github.com/stretchr/testify v1.4.0
golang.org/x/crypto v0.0.0-20200420201142-3c4aac89819a
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
gopkg.in/yaml.v2 v2.2.4
gopkg.in/yaml.v2 v2.2.8
gotest.tools/v3 v3.0.2 // indirect
k8s.io/api v0.17.0
k8s.io/apimachinery v0.17.0
k8s.io/client-go v0.17.0
Expand Down
19 changes: 19 additions & 0 deletions go.sum
Expand Up @@ -26,6 +26,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
Expand All @@ -40,6 +41,12 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/digitalocean/godo v1.35.1 h1:3P5timR4LTqcCafzrCgV2j83ck4aWb937ybFC7YQVFw=
github.com/digitalocean/godo v1.35.1/go.mod h1:p7dOjjtSBqCTUksqtA5Fd3uaKs9kyTq2xcz76ulEJRU=
github.com/docker/cli v0.0.0-20200511172450-ab108430b268 h1:qQcFj4AX9xSurO9U9Z+tNVbuSwm323HC1+62B848YSw=
github.com/docker/cli v0.0.0-20200511172450-ab108430b268/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/docker v17.12.0-ce-rc1.0.20200429205700-c3b3aedfa4ad+incompatible h1:3VA+ZiIkI6AbYYAP6qvflZQEm1GbAQbuN5VeTf6QEPA=
github.com/docker/docker v17.12.0-ce-rc1.0.20200429205700-c3b3aedfa4ad+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
Expand Down Expand Up @@ -69,6 +76,8 @@ github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
Expand Down Expand Up @@ -135,6 +144,7 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
Expand Down Expand Up @@ -177,7 +187,10 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand All @@ -197,6 +210,7 @@ github.com/sclevine/spec v1.3.0 h1:iTB51CYlnju5oRh0/l67fg1+RlQ2nqmFecwdvN+5TrI=
github.com/sclevine/spec v1.3.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
Expand Down Expand Up @@ -307,6 +321,7 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262 h1:qsl9y/CJx34tuA7QCPNp86JNJe4spst6Ff8MjvPUdPg=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
Expand Down Expand Up @@ -344,6 +359,10 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools/v3 v3.0.2 h1:kG1BFyqVHuQoVQiR1bWGnfz/fmHvvuiSPIV7rvl360E=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.17.0 h1:H9d/lw+VkZKEVIUc8F3wgiQ+FUXTTr21M87jXLU7yqM=
Expand Down