From b833e628b21db95d8ab1a8989ae43da2a04640f8 Mon Sep 17 00:00:00 2001 From: SataQiu Date: Mon, 26 Sep 2022 19:01:22 +0800 Subject: [PATCH] kubeadm: support image repository format validation --- .../app/apis/kubeadm/validation/validation.go | 25 +++++- .../kubeadm/validation/validation_test.go | 83 +++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go index 20ed91cb1fa..bf81e25c77b 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/validation.go +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation.go @@ -24,6 +24,7 @@ import ( "strconv" "strings" + "github.com/docker/distribution/reference" "github.com/pkg/errors" "github.com/spf13/pflag" @@ -66,6 +67,7 @@ func ValidateClusterConfiguration(c *kubeadm.ClusterConfiguration) field.ErrorLi allErrs = append(allErrs, ValidateAbsolutePath(c.CertificatesDir, field.NewPath("certificatesDir"))...) allErrs = append(allErrs, ValidateFeatureGates(c.FeatureGates, field.NewPath("featureGates"))...) allErrs = append(allErrs, ValidateHostPort(c.ControlPlaneEndpoint, field.NewPath("controlPlaneEndpoint"))...) + allErrs = append(allErrs, ValidateImageRepository(c.ImageRepository, field.NewPath("imageRepository"))...) allErrs = append(allErrs, ValidateEtcd(&c.Etcd, field.NewPath("etcd"))...) allErrs = append(allErrs, componentconfigs.Validate(c)...) return allErrs @@ -282,6 +284,9 @@ func ValidateEtcd(e *kubeadm.Etcd, fldPath *field.Path) field.ErrorList { allErrs = append(allErrs, ValidateAbsolutePath(e.Local.DataDir, localPath.Child("dataDir"))...) allErrs = append(allErrs, ValidateCertSANs(e.Local.ServerCertSANs, localPath.Child("serverCertSANs"))...) allErrs = append(allErrs, ValidateCertSANs(e.Local.PeerCertSANs, localPath.Child("peerCertSANs"))...) + if len(e.Local.ImageRepository) > 0 { + allErrs = append(allErrs, ValidateImageRepository(e.Local.ImageRepository, localPath.Child("imageRepository"))...) + } } if e.External != nil { requireHTTPS := true @@ -488,13 +493,19 @@ func getClusterNodeMask(c *kubeadm.ClusterConfiguration, isIPv6 bool) (int, erro } // ValidateDNS validates the DNS object and collects all encountered errors -// TODO: Remove with v1beta2 https://github.com/kubernetes/kubeadm/issues/2459 func ValidateDNS(dns *kubeadm.DNS, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} + + // TODO: Remove with v1beta2 https://github.com/kubernetes/kubeadm/issues/2459 const kubeDNSType = "kube-dns" if dns.Type == kubeDNSType { allErrs = append(allErrs, field.Invalid(fldPath, dns.Type, fmt.Sprintf("DNS type %q is no longer supported", kubeDNSType))) } + + if len(dns.ImageRepository) > 0 { + allErrs = append(allErrs, ValidateImageRepository(dns.ImageRepository, fldPath.Child("imageRepository"))...) + } + return allErrs } @@ -638,3 +649,15 @@ func ValidateSocketPath(socket string, fldPath *field.Path) field.ErrorList { return allErrs } + +// ValidateImageRepository validates the image repository format +func ValidateImageRepository(imageRepository string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + image := fmt.Sprintf("%s/%s:%s", imageRepository, "name", "tag") + if !reference.ReferenceRegexp.MatchString(image) { + return append(allErrs, field.Invalid(fldPath, imageRepository, "invalid image repository format")) + } + + return allErrs +} diff --git a/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go b/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go index b931e6fcecd..a99a3f5b066 100644 --- a/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go +++ b/cmd/kubeadm/app/apis/kubeadm/validation/validation_test.go @@ -533,6 +533,7 @@ func TestValidateInitConfiguration(t *testing.T) { BindPort: 6443, }, ClusterConfiguration: kubeadmapi.ClusterConfiguration{ + ImageRepository: "registry.k8s.io", Etcd: kubeadmapi.Etcd{ Local: &kubeadmapi.LocalEtcd{ DataDir: "/some/path", @@ -554,6 +555,7 @@ func TestValidateInitConfiguration(t *testing.T) { BindPort: 3446, }, ClusterConfiguration: kubeadmapi.ClusterConfiguration{ + ImageRepository: "registry.k8s.io", Etcd: kubeadmapi.Etcd{ Local: &kubeadmapi.LocalEtcd{ DataDir: "/some/path", @@ -1240,3 +1242,84 @@ func TestGetClusterNodeMask(t *testing.T) { }) } } + +func TestValidateImageRepository(t *testing.T) { + var tests = []struct { + imageRepository string + expectedErrors bool + }{ + { + imageRepository: "a", + expectedErrors: false, + }, + { + imageRepository: "a.b.c", + expectedErrors: false, + }, + { + imageRepository: "a.b.c/repo", + expectedErrors: false, + }, + { + imageRepository: "a:5000", + expectedErrors: false, + }, + { + imageRepository: "a.b.c:5000", + expectedErrors: false, + }, + { + imageRepository: "a.b.c:5000/repo", + expectedErrors: false, + }, + { + imageRepository: "a/b/c", + expectedErrors: false, + }, + { + imageRepository: "127.0.0.1:5000/repo", + expectedErrors: false, + }, + { + imageRepository: "", + expectedErrors: true, + }, + { + imageRepository: `a.b/c + s`, + expectedErrors: true, + }, + { + imageRepository: " a.b.c", + expectedErrors: true, + }, + { + imageRepository: "a.b c", + expectedErrors: true, + }, + { + imageRepository: "a.b.c:5000/", + expectedErrors: true, + }, + { + imageRepository: "https://a.b.c:5000", + expectedErrors: true, + }, + { + imageRepository: "a//b/c", + expectedErrors: true, + }, + { + imageRepository: "a.b.c:5000/test:1.0", + expectedErrors: true, + }, + } + + for _, tc := range tests { + actual := ValidateImageRepository(tc.imageRepository, nil) + actualErrors := len(actual) > 0 + if actualErrors != tc.expectedErrors { + t.Errorf("case %q error:\n\t expected: %t\n\t actual: %t", tc.imageRepository, tc.expectedErrors, actualErrors) + } + } +}