mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-25 19:31:05 +00:00
Merge pull request #120 from imduffy15/docker-config-secrets
Add global registry from docker config file on woodpecker server
This commit is contained in:
commit
6feae313ec
11 changed files with 184 additions and 8 deletions
|
@ -138,6 +138,10 @@ var flags = []cli.Flag{
|
||||||
EnvVar: "DRONE_VOLUME",
|
EnvVar: "DRONE_VOLUME",
|
||||||
Name: "volume",
|
Name: "volume",
|
||||||
},
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
EnvVar: "DRONE_DOCKER_CONFIG",
|
||||||
|
Name: "docker-config",
|
||||||
|
},
|
||||||
cli.StringSliceFlag{
|
cli.StringSliceFlag{
|
||||||
EnvVar: "DRONE_ENVIRONMENT",
|
EnvVar: "DRONE_ENVIRONMENT",
|
||||||
Name: "environment",
|
Name: "environment",
|
||||||
|
|
|
@ -60,7 +60,14 @@ func setupSecretService(c *cli.Context, s store.Store) model.SecretService {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupRegistryService(c *cli.Context, s store.Store) model.RegistryService {
|
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 {
|
func setupEnvironService(c *cli.Context, s store.Store) model.EnvironService {
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -10,8 +10,10 @@ require (
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||||
github.com/dgrijalva/jwt-go v0.0.0-20150904212456-c1da56349675
|
github.com/dgrijalva/jwt-go v0.0.0-20150904212456-c1da56349675
|
||||||
github.com/dimfeld/httptreemux v5.0.1+incompatible
|
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/distribution v2.7.1+incompatible
|
||||||
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible
|
github.com/docker/docker v17.12.0-ce-rc1.0.20200309214505-aa6a9891b09c+incompatible
|
||||||
|
github.com/docker/docker-credential-helpers v0.6.3 // indirect
|
||||||
github.com/docker/go-connections v0.4.0 // indirect
|
github.com/docker/go-connections v0.4.0 // indirect
|
||||||
github.com/docker/go-units v0.4.0 // indirect
|
github.com/docker/go-units v0.4.0 // indirect
|
||||||
github.com/docker/libcompose v0.4.0
|
github.com/docker/libcompose v0.4.0
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -36,10 +36,14 @@ 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/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 h1:Qj3gVcDNoOthBAqftuD596rm4wg/adLLz5xh5CmpiCA=
|
||||||
github.com/dimfeld/httptreemux v5.0.1+incompatible/go.mod h1:rbUlSV+CCpv/SuqUTP/8Bk2O3LyUV436/yaRGkhP6Z0=
|
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/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
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/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||||
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 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 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 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||||
|
|
|
@ -31,6 +31,12 @@ type RegistryService interface {
|
||||||
RegistryDelete(*Repo, string) error
|
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.
|
// RegistryStore persists registry information to storage.
|
||||||
type RegistryStore interface {
|
type RegistryStore interface {
|
||||||
RegistryFind(*Repo, string) (*Registry, error)
|
RegistryFind(*Repo, string) (*Registry, error)
|
||||||
|
|
55
plugins/registry/combine.go
Normal file
55
plugins/registry/combine.go
Normal 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 registries []*model.Registry
|
||||||
|
for _, registry := range c.registries {
|
||||||
|
list, err := registry.RegistryList(repo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
registries = append(registries, list...)
|
||||||
|
}
|
||||||
|
return registries, 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)
|
||||||
|
}
|
|
@ -4,32 +4,32 @@ import (
|
||||||
"github.com/laszlocph/woodpecker/model"
|
"github.com/laszlocph/woodpecker/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type builtin struct {
|
type db struct {
|
||||||
store model.RegistryStore
|
store model.RegistryStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new local registry service.
|
// New returns a new local registry service.
|
||||||
func New(store model.RegistryStore) model.RegistryService {
|
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)
|
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)
|
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)
|
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)
|
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)
|
registry, err := b.RegistryFind(repo, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
1
plugins/registry/db_test.go
Normal file
1
plugins/registry/db_test.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package registry
|
96
plugins/registry/filesystem.go
Normal file
96
plugins/registry/filesystem.go
Normal 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
|
||||||
|
}
|
1
plugins/registry/filesystem_test.go
Normal file
1
plugins/registry/filesystem_test.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package registry
|
Loading…
Reference in a new issue