| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- package config
- import (
- "context"
- "encoding/base64"
- "encoding/json"
- "fmt"
- "io/ioutil"
- "net/url"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
- "github.com/docker/cli/cli/config/configfile"
- "github.com/docker/cli/cli/config/types"
- "github.com/fatih/color"
- api "github.com/porter-dev/porter/api/client"
- "github.com/porter-dev/porter/cli/cmd/github"
- )
- func SetDockerConfig(client *api.Client) error {
- pID := GetCLIConfig().Project
- // get all registries that should be added
- regToAdd := make([]string, 0)
- // get the list of namespaces
- resp, err := client.ListRegistries(
- context.Background(),
- pID,
- )
- if err != nil {
- return err
- }
- registries := *resp
- for _, registry := range registries {
- if registry.URL != "" {
- rURL := registry.URL
- if !strings.Contains(rURL, "http") {
- rURL = "http://" + rURL
- }
- // strip the protocol
- regURL, err := url.Parse(rURL)
- if err != nil {
- continue
- }
- regToAdd = append(regToAdd, regURL.Host)
- }
- }
- // create a docker dir if it does not exist
- dockerDir := filepath.Join(home, ".docker")
- if _, err := os.Stat(dockerDir); os.IsNotExist(err) {
- err = os.Mkdir(dockerDir, 0o700)
- if err != nil {
- return err
- }
- }
- dockerConfigFile := filepath.Join(home, ".docker", "config.json")
- // determine if configfile exists
- if _, err := os.Stat(dockerConfigFile); os.IsNotExist(err) {
- // if it does not exist, create it
- err := ioutil.WriteFile(dockerConfigFile, []byte("{}"), 0o700)
- if err != nil {
- return err
- }
- }
- // read the file bytes
- configBytes, err := ioutil.ReadFile(dockerConfigFile)
- if err != nil {
- return err
- }
- // check if the docker credential helper exists
- if !commandExists("docker-credential-porter") {
- err := downloadCredMatchingRelease()
- if err != nil {
- color.New(color.FgRed).Println("Failed to download credential helper binary:", err.Error())
- os.Exit(1)
- }
- }
- // otherwise, check the version flag of the binary
- cmdVersionCred := exec.Command("docker-credential-porter", "--version")
- writer := &VersionWriter{}
- cmdVersionCred.Stdout = writer
- err = cmdVersionCred.Run()
- if err != nil || writer.Version != Version {
- err := downloadCredMatchingRelease()
- if err != nil {
- color.New(color.FgRed).Println("Failed to download credential helper binary:", err.Error())
- os.Exit(1)
- }
- }
- configFile := &configfile.ConfigFile{
- Filename: dockerConfigFile,
- }
- err = json.Unmarshal(configBytes, GetCLIConfig())
- if err != nil {
- return err
- }
- if configFile.CredentialHelpers == nil {
- configFile.CredentialHelpers = make(map[string]string)
- }
- if configFile.AuthConfigs == nil {
- configFile.AuthConfigs = make(map[string]types.AuthConfig)
- }
- for _, regURL := range regToAdd {
- // if this is a dockerhub registry, see if an auth config has already been generated
- // for index.docker.io
- if strings.Contains(regURL, "index.docker.io") {
- isAuthenticated := false
- for key := range configFile.AuthConfigs {
- if key == "https://index.docker.io/v1/" {
- isAuthenticated = true
- }
- }
- if !isAuthenticated {
- // get a dockerhub token from the Porter API
- tokenResp, err := client.GetDockerhubAuthorizationToken(context.Background(), GetCLIConfig().Project)
- if err != nil {
- return err
- }
- decodedToken, err := base64.StdEncoding.DecodeString(tokenResp.Token)
- if err != nil {
- return fmt.Errorf("Invalid token: %v", err)
- }
- parts := strings.SplitN(string(decodedToken), ":", 2)
- if len(parts) < 2 {
- return fmt.Errorf("Invalid token: expected two parts, got %d", len(parts))
- }
- configFile.AuthConfigs["https://index.docker.io/v1/"] = types.AuthConfig{
- Auth: tokenResp.Token,
- Username: parts[0],
- Password: parts[1],
- }
- // since we're using token-based auth, unset the credstore
- configFile.CredentialsStore = ""
- }
- } else {
- configFile.CredentialHelpers[regURL] = "porter"
- }
- }
- return configFile.Save()
- }
- func commandExists(cmd string) bool {
- _, err := exec.LookPath(cmd)
- return err == nil
- }
- func downloadCredMatchingRelease() error {
- // download the porter cred helper
- z := &github.ZIPReleaseGetter{
- AssetName: "docker-credential-porter",
- AssetFolderDest: "/usr/local/bin",
- ZipFolderDest: filepath.Join(home, ".porter"),
- ZipName: "docker-credential-porter_latest.zip",
- EntityID: "porter-dev",
- RepoName: "porter",
- IsPlatformDependent: true,
- Downloader: &github.ZIPDownloader{
- ZipFolderDest: filepath.Join(home, ".porter"),
- AssetFolderDest: "/usr/local/bin",
- ZipName: "docker-credential-porter_latest.zip",
- },
- }
- return z.GetRelease(Version)
- }
|