Add global registry from docker config file on woodpecker server

This commit is contained in:
Ian 2020-05-19 13:44:16 +01:00
parent 581f08b54b
commit de010dfb39
11 changed files with 188 additions and 9 deletions

View file

@ -133,6 +133,10 @@ var flags = []cli.Flag{
EnvVar: "DRONE_VOLUME",
Name: "volume",
},
cli.StringFlag{
EnvVar: "DRONE_DOCKER_CONFIG",
Name: "docker-config",
},
cli.StringSliceFlag{
EnvVar: "DRONE_ENVIRONMENT",
Name: "environment",

View file

@ -60,7 +60,14 @@ func setupSecretService(c *cli.Context, s store.Store) model.SecretService {
}
func setupRegistryService(c *cli.Context, s store.Store) model.RegistryService {
return registry.New(s)
if c.String("docker-config") != "" {
return registry.Combined(
registry.New(s),
registry.Filesystem(c.String("docker-config")),
)
} else {
return registry.New(s)
}
}
func setupEnvironService(c *cli.Context, s store.Store) model.EnvironService {

4
go.mod
View file

@ -10,8 +10,10 @@ require (
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/dgrijalva/jwt-go v0.0.0-20150904212456-c1da56349675
github.com/dimfeld/httptreemux v5.0.1+incompatible
github.com/docker/cli v0.0.0-20200303215952-eb310fca4956
github.com/docker/distribution v2.7.1+incompatible
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible
github.com/docker/docker v1.13.1
github.com/docker/docker-credential-helpers v0.6.3 // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/docker/libcompose v0.4.0

7
go.sum
View file

@ -36,10 +36,17 @@ github.com/dgrijalva/jwt-go v0.0.0-20150904212456-c1da56349675 h1:MIkcjohFTgoQVD
github.com/dgrijalva/jwt-go v0.0.0-20150904212456-c1da56349675/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dimfeld/httptreemux v5.0.1+incompatible h1:Qj3gVcDNoOthBAqftuD596rm4wg/adLLz5xh5CmpiCA=
github.com/dimfeld/httptreemux v5.0.1+incompatible/go.mod h1:rbUlSV+CCpv/SuqUTP/8Bk2O3LyUV436/yaRGkhP6Z0=
github.com/docker/cli v0.0.0-20200303215952-eb310fca4956 h1:5/ZRsUbguX7xFNLlbxVQY/yhD3Psy+vylKZrNme5BJs=
github.com/docker/cli v0.0.0-20200303215952-eb310fca4956/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli v17.12.1-ce-rc2+incompatible h1:ESUycEAqvFuLglAHkUW66rCc2djYtd3i1x231svLq9o=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo=
github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible h1:G2hY8RD7jB9QaSmcb8mYEIg8QbEvVAB7se8+lXHZHfg=
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+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/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=

View file

@ -31,6 +31,12 @@ type RegistryService interface {
RegistryDelete(*Repo, string) error
}
// RegistryService defines a service for managing registries.
type ReadOnlyRegistryService interface {
RegistryFind(*Repo, string) (*Registry, error)
RegistryList(*Repo) ([]*Registry, error)
}
// RegistryStore persists registry information to storage.
type RegistryStore interface {
RegistryFind(*Repo, string) (*Registry, error)

View file

@ -0,0 +1,55 @@
package registry
import (
"github.com/laszlocph/woodpecker/model"
)
type combined struct {
registries []model.ReadOnlyRegistryService
dbRegistry model.RegistryService
}
func Combined(dbRegistry model.RegistryService, registries ...model.ReadOnlyRegistryService) model.RegistryService {
registries = append(registries, dbRegistry)
return &combined{
registries: registries,
dbRegistry: dbRegistry,
}
}
func (c combined) RegistryFind(repo *model.Repo, name string) (*model.Registry, error) {
for _, registry := range c.registries {
res, err := registry.RegistryFind(repo, name)
if err != nil {
return nil, err
}
if res != nil {
return res, nil
}
}
return nil, nil
}
func (c combined) RegistryList(repo *model.Repo) ([]*model.Registry, error) {
var registeries []*model.Registry
for _, registory := range c.registries {
list, err := registory.RegistryList(repo)
if err != nil {
return nil, err
}
registeries = append(registeries, list...)
}
return registeries, nil
}
func (c combined) RegistryCreate(repo *model.Repo, registry *model.Registry) error {
return c.dbRegistry.RegistryCreate(repo, registry)
}
func (c combined) RegistryUpdate(repo *model.Repo, registry *model.Registry) error {
return c.dbRegistry.RegistryUpdate(repo, registry)
}
func (c combined) RegistryDelete(repo *model.Repo, name string) error {
return c.dbRegistry.RegistryDelete(repo, name)
}

View file

@ -4,32 +4,32 @@ import (
"github.com/laszlocph/woodpecker/model"
)
type builtin struct {
type db struct {
store model.RegistryStore
}
// New returns a new local registry service.
func New(store model.RegistryStore) model.RegistryService {
return &builtin{store}
return &db{store}
}
func (b *builtin) RegistryFind(repo *model.Repo, name string) (*model.Registry, error) {
func (b *db) RegistryFind(repo *model.Repo, name string) (*model.Registry, error) {
return b.store.RegistryFind(repo, name)
}
func (b *builtin) RegistryList(repo *model.Repo) ([]*model.Registry, error) {
func (b *db) RegistryList(repo *model.Repo) ([]*model.Registry, error) {
return b.store.RegistryList(repo)
}
func (b *builtin) RegistryCreate(repo *model.Repo, in *model.Registry) error {
func (b *db) RegistryCreate(repo *model.Repo, in *model.Registry) error {
return b.store.RegistryCreate(in)
}
func (b *builtin) RegistryUpdate(repo *model.Repo, in *model.Registry) error {
func (b *db) RegistryUpdate(repo *model.Repo, in *model.Registry) error {
return b.store.RegistryUpdate(in)
}
func (b *builtin) RegistryDelete(repo *model.Repo, addr string) error {
func (b *db) RegistryDelete(repo *model.Repo, addr string) error {
registry, err := b.RegistryFind(repo, addr)
if err != nil {
return err

View file

@ -0,0 +1 @@
package registry

View file

@ -0,0 +1,96 @@
package registry
import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/config/types"
"github.com/laszlocph/woodpecker/model"
"os"
"strings"
)
type filesystem struct {
path string
}
func Filesystem(path string) model.ReadOnlyRegistryService {
return &filesystem{path}
}
func parseDockerConfig(path string) ([]*model.Registry, error) {
if path == "" {
return nil, nil
}
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
configFile := configfile.ConfigFile{
AuthConfigs: make(map[string]types.AuthConfig),
}
if err := json.NewDecoder(f).Decode(&configFile); err != nil {
return nil, err
}
for addr, ac := range configFile.AuthConfigs {
if ac.Auth != "" {
ac.Username, ac.Password, err = decodeAuth(ac.Auth)
if err != nil {
return nil, err
}
ac.Auth = ""
ac.ServerAddress = addr
configFile.AuthConfigs[addr] = ac
}
}
auths := []*model.Registry{}
for key, auth := range configFile.AuthConfigs {
auths = append(auths, &model.Registry{
Address: key,
Username: auth.Username,
Password: auth.Password,
})
}
return auths, nil
}
func (b *filesystem) RegistryFind(*model.Repo, string) (*model.Registry, error) {
return nil, nil
}
func (b *filesystem) RegistryList(*model.Repo) ([]*model.Registry, error) {
return parseDockerConfig(b.path)
}
// decodeAuth decodes a base64 encoded string and returns username and password
func decodeAuth(authStr string) (string, string, error) {
if authStr == "" {
return "", "", nil
}
decLen := base64.StdEncoding.DecodedLen(len(authStr))
decoded := make([]byte, decLen)
authByte := []byte(authStr)
n, err := base64.StdEncoding.Decode(decoded, authByte)
if err != nil {
return "", "", err
}
if n > decLen {
return "", "", fmt.Errorf("Something went wrong decoding auth config")
}
arr := strings.SplitN(string(decoded), ":", 2)
if len(arr) != 2 {
return "", "", fmt.Errorf("Invalid auth configuration file")
}
password := strings.Trim(arr[1], "\x00")
return arr[0], password, nil
}

View file

@ -0,0 +1 @@
package registry