From fe943d24d649ff891a516446ecdc7bd9c1c428a6 Mon Sep 17 00:00:00 2001 From: Mara Sophie Grosch Date: Mon, 24 Oct 2022 13:26:12 +0200 Subject: [PATCH] Extend containerd registry mirror config containerd can be configured for multiple registry mirrors per registry, this extends machine-controller to configure mirrors for registries other than docker.io, reusing the existing command line flag. Signed-off-by: Mara Sophie Grosch --- pkg/containerruntime/config.go | 32 ++++--- pkg/containerruntime/config_test.go | 134 ++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 10 deletions(-) create mode 100644 pkg/containerruntime/config_test.go diff --git a/pkg/containerruntime/config.go b/pkg/containerruntime/config.go index 551befbb6..90bce0306 100644 --- a/pkg/containerruntime/config.go +++ b/pkg/containerruntime/config.go @@ -21,6 +21,7 @@ import ( "encoding/json" "fmt" "net/url" + "regexp" "strings" corev1 "k8s.io/api/core/v1" @@ -45,11 +46,25 @@ func BuildConfig(opts Opts) (Config, error) { } } - var registryMirrors []string + // we want to match e.g. docker.io=registry.docker-cn.com, having docker.io as the first + // match group and registry.docker-cn.com as the second one. + registryMirrorRegexp := regexp.MustCompile(`^([a-zA-Z0-9\.-]+)=(.*)`) + + if opts.ContainerdRegistryMirrors == nil { + opts.ContainerdRegistryMirrors = make(RegistryMirrorsFlags) + } + for _, mirror := range strings.Split(opts.RegistryMirrors, ",") { if trimmedMirror := strings.TrimSpace(mirror); trimmedMirror != "" { - if !strings.HasPrefix(mirror, "http") { - trimmedMirror = "https://" + mirror + registry := "docker.io" + + if matches := registryMirrorRegexp.FindStringSubmatch(trimmedMirror); matches != nil { + registry = matches[1] + trimmedMirror = matches[2] + } + + if !strings.HasPrefix(trimmedMirror, "http") { + trimmedMirror = "https://" + trimmedMirror } _, err := url.Parse(trimmedMirror) @@ -57,15 +72,12 @@ func BuildConfig(opts Opts) (Config, error) { return Config{}, fmt.Errorf("incorrect mirror provided: %w", err) } - registryMirrors = append(registryMirrors, trimmedMirror) - } - } + if opts.ContainerdRegistryMirrors[registry] == nil { + opts.ContainerdRegistryMirrors[registry] = make([]string, 0, 1) + } - if len(registryMirrors) > 0 { - if opts.ContainerdRegistryMirrors == nil { - opts.ContainerdRegistryMirrors = make(RegistryMirrorsFlags) + opts.ContainerdRegistryMirrors[registry] = append(opts.ContainerdRegistryMirrors[registry], trimmedMirror) } - opts.ContainerdRegistryMirrors["docker.io"] = registryMirrors } // Only validate registry credential here diff --git a/pkg/containerruntime/config_test.go b/pkg/containerruntime/config_test.go new file mode 100644 index 000000000..4ee6ecd79 --- /dev/null +++ b/pkg/containerruntime/config_test.go @@ -0,0 +1,134 @@ +/* +Copyright 2022 The Machine Controller Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package containerruntime + +import ( + "errors" + "fmt" + "testing" +) + +func TestContainerdRegistryMirror(t *testing.T) { + type testCase struct { + desc string + flag string + expectedMirrors map[string][]string + expectedError error + } + + testCases := []testCase{ + { + desc: "no registry mirrors set", + flag: "", + expectedMirrors: map[string][]string{}, + expectedError: nil, + }, + + { + desc: "registry mirror without name and protocol", + flag: "registry-v1.docker.io", + expectedMirrors: map[string][]string{ + "docker.io": {"https://registry-v1.docker.io"}, + }, + expectedError: nil, + }, + { + desc: "multiple registry mirrors without name, with and without protocol", + flag: "registry-v1.docker.io,http://registry.docker-cn.com", + expectedMirrors: map[string][]string{ + "docker.io": { + "https://registry-v1.docker.io", + "http://registry.docker-cn.com", + }, + }, + expectedError: nil, + }, + + { + desc: "registry mirror with name and without protocol", + flag: "quay.io=my-quay-io-mirror.example.com", + expectedMirrors: map[string][]string{ + "quay.io": {"https://my-quay-io-mirror.example.com"}, + }, + expectedError: nil, + }, + { + desc: "registry mirror with name and protocol", + flag: "quay.io=http://my-quay-io-mirror.example.com", + expectedMirrors: map[string][]string{ + "quay.io": {"http://my-quay-io-mirror.example.com"}, + }, + expectedError: nil, + }, + { + desc: "multiple registry mirrors with same name", + flag: "quay.io=http://my-quay-io-mirror.example.com,quay.io=example.net", + expectedMirrors: map[string][]string{ + "quay.io": { + "http://my-quay-io-mirror.example.com", + "https://example.net", + }, + }, + expectedError: nil, + }, + + { + desc: "complex example", + flag: "quay.io=http://my-quay-io-mirror.example.com,quay.io=example.net," + + "registry-v1.docker.io,http://registry.docker-cn.com," + + "ghcr.io=http://foo/bar", + expectedMirrors: map[string][]string{ + "quay.io": { + "http://my-quay-io-mirror.example.com", + "https://example.net", + }, + "docker.io": { + "https://registry-v1.docker.io", + "http://registry.docker-cn.com", + }, + "ghcr.io": { + "http://foo/bar", + }, + }, + expectedError: nil, + }, + } + + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + opts := Opts{ + ContainerRuntime: containerdName, + RegistryMirrors: tc.flag, + } + + config, err := BuildConfig(opts) + if tc.expectedError != nil { + if !errors.Is(err, tc.expectedError) { + t.Errorf("expected error %q but got %q", tc.expectedError, err) + } + } + + if err != nil { + t.Errorf("expected success but got error: %q", err) + } + + if fmt.Sprint(config.RegistryMirrors) != fmt.Sprint(tc.expectedMirrors) { + t.Errorf("expected to get %v instead got: %v", tc.expectedMirrors, config.RegistryMirrors) + } + }) + } +}