Commit b5143db6 authored by Kamil Trzciński's avatar Kamil Trzciński 🔴

Discover auth configuration more docker-way (source taken from Docker app)

parent 7c3e0912
v 0.6.0 (unreleased)
- Fetch docker auth from ~/.docker/config.json or ~/.dockercfg
v 0.5.2
- Fixed CentOS6 service script
- Fixed documentation
......
......@@ -17,7 +17,6 @@ import (
"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
"gitlab.com/gitlab-org/gitlab-ci-multi-runner/executors"
"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
"path"
)
type DockerExecutor struct {
......@@ -44,43 +43,33 @@ func (s *DockerExecutor) getServiceVariables() []string {
return variables
}
func (s *DockerExecutor) newAuthConfigurationsFromConfigJson() (*docker.AuthConfigurations, error) {
func (s *DockerExecutor) getAuthConfig(imageName string) (docker.AuthConfiguration, error) {
user, err := u.Current()
if s.Shell.User != nil {
user, err = u.Lookup(*s.Shell.User)
}
if err != nil {
return nil, err
}
p := path.Join(user.HomeDir, ".docker", "config.json")
r, err := os.Open(p)
if err != nil {
return nil, err
return docker.AuthConfiguration{}, err
}
defer r.Close()
return docker.NewAuthConfigurations(r)
}
indexName, _ := helpers.SplitDockerImageName(imageName)
func (s *DockerExecutor) getAuthConfig(registry *string) (docker.AuthConfiguration, error) {
authConfigs, err := docker.NewAuthConfigurationsFromDockerCfg()
authConfigs, err := helpers.ReadDockerAuthConfigs(user.HomeDir)
if err != nil {
authConfigs, err = s.newAuthConfigurationsFromConfigJson()
if err != nil {
return docker.AuthConfiguration{}, err
// ignore doesn't exist errors
if os.IsNotExist(err) {
err = nil
}
return docker.AuthConfiguration{}, err
}
authRegistry := helpers.StringOrDefault(registry, "docker.io")
for authKey, authConfig := range authConfigs.Configs {
if strings.Contains(authKey, authRegistry) {
return authConfig, nil
}
authConfig := helpers.ResolveDockerAuthConfig(indexName, authConfigs)
if authConfig != nil {
s.Debugln("Using", authConfig.Username, "to connect to", authConfig.ServerAddress, "in order to resolve", imageName, "...")
return *authConfig, nil
}
s.Warningln("No credentials found for", authRegistry, "in the docker config files")
return docker.AuthConfiguration{}, nil
return docker.AuthConfiguration{}, fmt.Errorf("No credentials found for %v", indexName)
}
func (s *DockerExecutor) getDockerImage(imageName string) (*docker.Image, error) {
......@@ -95,9 +84,9 @@ func (s *DockerExecutor) getDockerImage(imageName string) (*docker.Image, error)
Repository: imageName,
}
authConfig, err := s.getAuthConfig(helpers.ExtractRegistry(imageName))
authConfig, err := s.getAuthConfig(imageName)
if err != nil {
s.Warningln(err)
s.Debugln(err)
}
err = s.client.PullImage(pullImageOptions, authConfig)
......
......@@ -2,15 +2,80 @@ package helpers
import (
"strings"
"path"
"github.com/fsouza/go-dockerclient"
"os"
"io"
)
func ExtractRegistry(imageName string) *string {
// IndexName is the name of the index
const DefaultDockerRegistry = "docker.io"
nameParts := strings.Split(imageName, "/")
// splitReposName breaks a reposName into an index name and remote name
func SplitDockerImageName(reposName string) (string, string) {
nameParts := strings.SplitN(reposName, "/", 2)
var indexName, remoteName string
if len(nameParts) == 1 || (!strings.Contains(nameParts[0], ".") &&
!strings.Contains(nameParts[0], ":") && nameParts[0] != "localhost") {
// This is a Docker Index repos (ex: samalba/hipache or ubuntu)
// 'docker.io'
indexName = DefaultDockerRegistry
remoteName = reposName
} else {
indexName = nameParts[0]
remoteName = nameParts[1]
}
if indexName == "index."+DefaultDockerRegistry {
indexName = DefaultDockerRegistry
}
return indexName, remoteName
}
func ReadDockerAuthConfigs(homeDir string) (*docker.AuthConfigurations, error) {
var r io.Reader
var err error
p := path.Join(homeDir, ".docker", "config.json")
r, err = os.Open(p)
if err != nil {
p := path.Join(homeDir, ".dockercfg")
r, err = os.Open(p)
if err != nil {
return nil, err
}
}
return docker.NewAuthConfigurations(r)
}
// Taken from: https://github.com/docker/docker/blob/master/registry/auth.go
func ResolveDockerAuthConfig(indexName string, configs *docker.AuthConfigurations) *docker.AuthConfiguration {
if configs == nil {
return nil
}
convertToHostname := func(url string) string {
stripped := url
if strings.HasPrefix(url, "http://") {
stripped = strings.Replace(url, "http://", "", 1)
} else if strings.HasPrefix(url, "https://") {
stripped = strings.Replace(url, "https://", "", 1)
}
nameParts := strings.SplitN(stripped, "/", 2)
if nameParts[0] == "index."+DefaultDockerRegistry {
return DefaultDockerRegistry
}
return nameParts[0]
}
if len(nameParts) == 3 {
return &nameParts[0]
// Maybe they have a legacy config file, we will iterate the keys converting
// them to the new format and testing
for registry, authConfig := range configs.Configs {
if indexName == convertToHostname(registry) {
return &authConfig
}
}
// When all else fails, return an empty auth config
return nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment