From a2bc9cca26580f1dfde22d73a7c4a3bb8f457577 Mon Sep 17 00:00:00 2001 From: John Gardiner Myers Date: Sun, 26 Jan 2020 17:50:20 -0800 Subject: [PATCH] Verify addon versions in BootstrapChannelBuilder --- channels/pkg/api/BUILD.bazel | 17 ++++++- channels/pkg/api/channel.go | 21 ++++++++ channels/pkg/api/channel_test.go | 50 +++++++++++++++++++ .../pkg/fi/cloudup/bootstrapchannelbuilder.go | 4 ++ 4 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 channels/pkg/api/channel_test.go diff --git a/channels/pkg/api/BUILD.bazel b/channels/pkg/api/BUILD.bazel index 099fd5a215..6417e8601c 100644 --- a/channels/pkg/api/BUILD.bazel +++ b/channels/pkg/api/BUILD.bazel @@ -1,9 +1,22 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", srcs = ["channel.go"], importpath = "k8s.io/kops/channels/pkg/api", visibility = ["//visibility:public"], - deps = ["//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library"], + deps = [ + "//vendor/github.com/blang/semver:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + ], +) + +go_test( + name = "go_default_test", + srcs = ["channel_test.go"], + embed = [":go_default_library"], + deps = [ + "//vendor/github.com/stretchr/testify/assert:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + ], ) diff --git a/channels/pkg/api/channel.go b/channels/pkg/api/channel.go index db5d600d43..9903075c63 100644 --- a/channels/pkg/api/channel.go +++ b/channels/pkg/api/channel.go @@ -17,6 +17,9 @@ limitations under the License. package api import ( + "fmt" + + "github.com/blang/semver" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -60,3 +63,21 @@ type AddonSpec struct { // switch kubernetes versions. Id string `json:"id,omitempty"` } + +func (a *Addons) Verify() error { + for _, addon := range a.Spec.Addons { + if addon != nil && addon.Version != nil && *addon.Version != "" { + name := a.ObjectMeta.Name + if addon.Name != nil { + name = *addon.Name + } + + _, err := semver.ParseTolerant(*addon.Version) + if err != nil { + return fmt.Errorf("addon %q has unparseable version %q: %v", name, *addon.Version, err) + } + } + } + + return nil +} diff --git a/channels/pkg/api/channel_test.go b/channels/pkg/api/channel_test.go new file mode 100644 index 0000000000..15f8a83d53 --- /dev/null +++ b/channels/pkg/api/channel_test.go @@ -0,0 +1,50 @@ +/* +Copyright 2020 The Kubernetes 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 api + +import ( + "testing" + + "github.com/stretchr/testify/assert" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func Test_UnparseableVersion(t *testing.T) { + addons := Addons{ + TypeMeta: v1.TypeMeta{ + Kind: "Addons", + }, + ObjectMeta: v1.ObjectMeta{ + Name: "test", + }, + Spec: AddonsSpec{ + Addons: []*AddonSpec{ + { + Name: s("testaddon"), + Version: s("1.0-kops"), + }, + }, + }, + } + + err := addons.Verify() + assert.EqualError(t, err, "addon \"testaddon\" has unparseable version \"1.0-kops\": Short version cannot contain PreRelease/Build meta data", "detected invalid version") +} + +func s(v string) *string { + return &v +} diff --git a/upup/pkg/fi/cloudup/bootstrapchannelbuilder.go b/upup/pkg/fi/cloudup/bootstrapchannelbuilder.go index 8eddab934e..d8231e2e02 100644 --- a/upup/pkg/fi/cloudup/bootstrapchannelbuilder.go +++ b/upup/pkg/fi/cloudup/bootstrapchannelbuilder.go @@ -44,6 +44,10 @@ var _ fi.ModelBuilder = &BootstrapChannelBuilder{} // Build is responsible for adding the addons to the channel func (b *BootstrapChannelBuilder) Build(c *fi.ModelBuilderContext) error { addons := b.buildAddons() + if err := addons.Verify(); err != nil { + return err + } + tasks := c.Tasks for _, a := range addons.Spec.Addons {