Add option to set individual mirrors for all logins (#122)

- also address last nits of #119

Co-authored-by: Patrick Schratz <pat-s@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/woodpecker-plugins/docker-buildx/pulls/122
Reviewed-by: Patrick Schratz <pat-s@noreply.codeberg.org>
This commit is contained in:
6543 2024-01-18 18:28:42 +00:00
parent 8367365643
commit 5d98a5da22
6 changed files with 78 additions and 46 deletions

1
.gitignore vendored
View file

@ -5,3 +5,4 @@ plugin-docker-buildx
coverage.out
CHANGELOG.md
debug.test*

View file

@ -14,7 +14,9 @@ import (
var version = "unknown"
func main() {
settings := &plugin.Settings{}
settings := &plugin.Settings{
CustomCertStore: "/etc/docker/certs.d/",
}
if _, err := os.Stat("/run/drone/env"); err == nil {
godotenv.Overload("/run/drone/env")

View file

@ -105,7 +105,7 @@ docker-build:
| `experimental` | `false` | enables docker daemon experimental mode |
| `debug` | `false` | enables verbose debug mode for the docker daemon |
| `daemon_off` | `false` | disables the startup of the docker daemon |
| `buildkit_debug` | _none_ | enables debug output of buildkit
| `buildkit_debug` | `false` | enables debug output of buildkit |
| `buildkit_config` | _none_ | sets content of the docker [buildkit TOML config](https://github.com/moby/buildkit/blob/master/docs/buildkitd.toml.md) |
| `buildkit_driveropt` | _none_ | adds one or multiple `--driver-opt` buildx arguments for the default buildkit builder instance |
| `tags_file` | _none_ | overrides the `tags` option with values in a file named `.tags`; multiple tags can be specified separated by a newline |
@ -147,6 +147,8 @@ settings:
username: a6543
password:
from_secret: docker_token
mirrors:
- "my-docker-mirror-host.local"
- registry: https://codeberg.org
username: "6543"
password:

View file

@ -179,9 +179,6 @@ func commandDaemon(daemon Daemon) *exec.Cmd {
if daemon.IPv6 {
args = append(args, "--ipv6")
}
if len(daemon.Mirror) != 0 {
args = append(args, "--registry-mirror", daemon.Mirror)
}
if len(daemon.Bip) != 0 {
args = append(args, "--bip", daemon.Bip)
}

View file

@ -40,12 +40,12 @@ type Daemon struct {
// Login defines Docker login parameters.
type Login struct {
// Generic
Registry string // Docker registry address
Username string // Docker registry username
Password string // Docker registry password
Email string // Docker registry email
Config string // Docker Auth Config
Registry string // Docker registry address
Username string // Docker registry username
Password string // Docker registry password
Email string // Docker registry email
Config string // Docker Auth Config
Mirrors []string // Docker registry mirrors
// ECR
Aws_access_key_id string `json:"aws_access_key_id"` // AWS access key id
Aws_secret_access_key string `json:"aws_secret_access_key"` // AWS secret access key
@ -93,13 +93,14 @@ type Settings struct {
AwsSecretAccessKey string `json:"aws_secret_access_key"` // AWS secret access key
// Generic
Daemon Daemon
Logins []Login
LoginsRaw string
DefaultLogin Login
Build Build
Dryrun bool
Cleanup bool
Daemon Daemon
Logins []Login
LoginsRaw string
DefaultLogin Login
Build Build
Dryrun bool
Cleanup bool
CustomCertStore string // e.g. for "/etc/docker/certs.d/<registry>/ca.crt"
}
func (l Login) anonymous() bool {
@ -128,6 +129,10 @@ func (p *Plugin) InitSettings() error {
p.EcrInit()
}
if p.settings.DefaultLogin.Registry != "" && p.settings.Daemon.Mirror != "" {
p.settings.DefaultLogin.Mirrors = []string{p.settings.Daemon.Mirror}
}
if len(p.settings.Logins) == 0 {
p.settings.Logins = []Login{p.settings.DefaultLogin}
} else if !p.settings.DefaultLogin.anonymous() {
@ -224,13 +229,13 @@ func (p *Plugin) sanitizedUserTags() []string {
}
type BuildkitConfigTOML struct {
Debug bool `toml:"debug"` // needs to be public for toml lib to use
Registry map[string]RegistryInfo `toml:"registry"`
Debug bool `toml:"debug,omitempty"` // needs to be public for toml lib to use
Registry map[string]*RegistryInfo `toml:"registry,omitempty"`
}
type RegistryInfo struct {
Mirrors []string `toml:"mirrors"`
CA []string `toml:"ca"`
Mirrors []string `toml:"mirrors,omitempty"`
CA []string `toml:"ca,omitempty"`
}
func (p *Plugin) generateBuildkitConfig() error {
@ -238,19 +243,13 @@ func (p *Plugin) generateBuildkitConfig() error {
if p.settings.Daemon.BuildkitConfig == "" {
cfg := BuildkitConfigTOML{}
cfg.Registry = map[string]RegistryInfo{}
cfg.Registry = make(map[string]*RegistryInfo)
if p.settings.Daemon.BuildkitDebug {
cfg.Debug = p.settings.Daemon.BuildkitDebug
logrus.Println("buildkit debug enabled")
}
if p.settings.Daemon.Mirror != "" {
cfg.Registry["docker.io"] = RegistryInfo{
Mirrors: []string{p.settings.Daemon.Mirror},
}
}
// use a custom CA certificate for each registry
if p.settings.Daemon.Registry != "" {
for _, login := range p.settings.Logins {
@ -263,16 +262,30 @@ func (p *Plugin) generateBuildkitConfig() error {
registry = u.Host
}
caPath := fmt.Sprintf("/etc/docker/certs.d/%s/ca.crt", registry)
// docker hub fix
if registry == "index.docker.io" {
registry = "docker.io"
}
caPath := fmt.Sprintf("%s/%s/ca.crt", p.settings.CustomCertStore, registry)
ca, err := os.Open(caPath)
if err != nil && !os.IsNotExist(err) {
logrus.Warnf("error reading %s: %v", caPath, err)
} else if err == nil {
ca.Close()
logrus.Infof("found ca file for '%s' registry", registry)
// add registry and ca path to buildkit.toml
cfg.Registry[registry] = RegistryInfo{
CA: []string{caPath},
if cfg.Registry[registry] == nil {
cfg.Registry[registry] = new(RegistryInfo)
}
cfg.Registry[registry].CA = []string{caPath}
}
if len(login.Mirrors) != 0 {
if cfg.Registry[registry] == nil {
cfg.Registry[registry] = new(RegistryInfo)
}
cfg.Registry[registry].Mirrors = login.Mirrors
}
}
}

View file

@ -1,6 +1,8 @@
package plugin
import (
"fmt"
"os"
"testing"
"codeberg.org/6543/go-yaml2json"
@ -8,7 +10,7 @@ import (
"github.com/urfave/cli/v2"
)
var defaultSettings = Settings{
var defaultTestSettings = Settings{
Daemon: Daemon{
StoragePath: "/var/lib/docker",
},
@ -22,15 +24,16 @@ var defaultSettings = Settings{
DefaultLogin: Login{
Registry: "https://index.docker.io/v1/",
},
LoginsRaw: "[]",
Cleanup: true,
LoginsRaw: "[]",
Cleanup: true,
CustomCertStore: "/etc/docker/certs.d/",
}
func TestDefaultLogin(t *testing.T) {
s := defaultSettings
s := defaultTestSettings
assert.NoError(t, newSettingsOnly(&s).Validate())
if assert.Len(t, s.Logins, 1) {
assert.EqualValues(t, defaultSettings.DefaultLogin.Registry, s.Logins[0].Registry)
assert.EqualValues(t, defaultTestSettings.DefaultLogin.Registry, s.Logins[0].Registry)
}
// only use login to auth to registrys
@ -45,11 +48,11 @@ func TestDefaultLogin(t *testing.T) {
s.LoginsRaw = string(loginsRaw)
assert.NoError(t, newSettingsOnly(&s).Validate())
if assert.Len(t, s.Logins, 2) {
assert.EqualValues(t, defaultSettings.DefaultLogin.Registry, s.Logins[0].Registry)
assert.EqualValues(t, defaultTestSettings.DefaultLogin.Registry, s.Logins[0].Registry)
}
// mixed login settings ('logins' and 'username', 'password' are used)
s = defaultSettings
s = defaultTestSettings
loginsRaw, err = yaml2json.Convert([]byte(`
- registry: https://codeberg.org
username: cb_username
@ -60,11 +63,11 @@ func TestDefaultLogin(t *testing.T) {
s.DefaultLogin.Password = "docker_password"
assert.NoError(t, newSettingsOnly(&s).Validate())
if assert.Len(t, s.Logins, 2) {
assert.EqualValues(t, defaultSettings.DefaultLogin.Registry, s.Logins[0].Registry)
assert.EqualValues(t, defaultTestSettings.DefaultLogin.Registry, s.Logins[0].Registry)
}
// ignore default registry
s = defaultSettings
s = defaultTestSettings
loginsRaw, err = yaml2json.Convert([]byte(`
- registry: https://codeberg.org
username: cb_username
@ -78,17 +81,31 @@ func TestDefaultLogin(t *testing.T) {
}
func TestWriteBuildkitConfig(t *testing.T) {
settings := defaultSettings
settings := defaultTestSettings
assert.NoError(t, newSettingsOnly(&settings).Validate())
assert.EqualValues(t, "", settings.Daemon.BuildkitConfig)
settings = defaultSettings
settings = defaultTestSettings
settings.Daemon.BuildkitDebug = true
assert.NoError(t, newSettingsOnly(&settings).Validate())
assert.EqualValues(t, "debug = true\n\n[registry]\n", settings.Daemon.BuildkitConfig)
assert.EqualValues(t, "debug = true\n", settings.Daemon.BuildkitConfig)
settings = defaultSettings
settings = defaultTestSettings
settings.Daemon.Mirror = "mirror.example.com"
assert.NoError(t, newSettingsOnly(&settings).Validate())
assert.EqualValues(t, "debug = false\n\n[registry]\n[registry.'docker.io']\nmirrors = ['mirror.example.com']\nca = []\n", settings.Daemon.BuildkitConfig)
assert.EqualValues(t, "[registry]\n[registry.'docker.io']\nmirrors = ['mirror.example.com']\n", settings.Daemon.BuildkitConfig)
settings = defaultTestSettings
settings.DefaultLogin.Registry = "codeberg.org"
tmpDir, err := os.MkdirTemp("", "go-test-*")
assert.NoError(t, err)
settings.CustomCertStore = tmpDir
defer os.RemoveAll(tmpDir)
assert.NoError(t, os.Mkdir(tmpDir+"/codeberg.org", os.ModePerm))
caFile, err := os.Create(tmpDir + "/codeberg.org/" + "ca.crt")
assert.NoError(t, err)
assert.NoError(t, caFile.Close())
assert.NoError(t, newSettingsOnly(&settings).Validate())
assert.EqualValues(t, fmt.Sprintf("[registry]\n[registry.'codeberg.org']\nca = ['%s/codeberg.org/ca.crt']\n", tmpDir), settings.Daemon.BuildkitConfig)
}