diff --git a/tests/integration/create_cluster/ha_hetzner/options.yaml b/tests/integration/create_cluster/ha_hetzner/options.yaml index b60ad670e4..bcc18dc8c7 100644 --- a/tests/integration/create_cluster/ha_hetzner/options.yaml +++ b/tests/integration/create_cluster/ha_hetzner/options.yaml @@ -1,6 +1,5 @@ CloudProvider: hetzner ClusterName: ha.example.com -Image: ubuntu-20.04 KubernetesVersion: v1.25.0 ControlPlaneCount: 3 NetworkCIDR: 10.0.0.0/16 diff --git a/tests/integration/create_cluster/minimal_hetzner/options.yaml b/tests/integration/create_cluster/minimal_hetzner/options.yaml index 4e69ba8949..d01c3624db 100644 --- a/tests/integration/create_cluster/minimal_hetzner/options.yaml +++ b/tests/integration/create_cluster/minimal_hetzner/options.yaml @@ -1,6 +1,5 @@ CloudProvider: hetzner ClusterName: minimal.k8s.local -Image: ubuntu-20.04 KubernetesVersion: v1.25.0 NetworkCIDR: 10.0.0.0/16 Networking: cni diff --git a/upup/pkg/fi/cloudup/new_cluster.go b/upup/pkg/fi/cloudup/new_cluster.go index d7590398fc..f4cd0ce844 100644 --- a/upup/pkg/fi/cloudup/new_cluster.go +++ b/upup/pkg/fi/cloudup/new_cluster.go @@ -444,7 +444,10 @@ func NewCluster(opt *NewClusterOptions, clientset simple.Clientset) (*NewCluster if err != nil { return nil, err } - instanceGroup.Spec.Image = defaultImage(&cluster, channel, architecture) + instanceGroup.Spec.Image, err = defaultImage(&cluster, channel, architecture) + if err != nil { + return nil, err + } } } @@ -1503,30 +1506,34 @@ func addCiliumNetwork(cluster *api.Cluster) { } // defaultImage returns the default Image, based on the cloudprovider -func defaultImage(cluster *api.Cluster, channel *api.Channel, architecture architectures.Architecture) string { +func defaultImage(cluster *api.Cluster, channel *api.Channel, architecture architectures.Architecture) (string, error) { if channel != nil { var kubernetesVersion *semver.Version if cluster.Spec.KubernetesVersion != "" { var err error kubernetesVersion, err = util.ParseKubernetesVersion(cluster.Spec.KubernetesVersion) if err != nil { - klog.Warningf("cannot parse KubernetesVersion %q in cluster", cluster.Spec.KubernetesVersion) + return "", fmt.Errorf("unable to parse kubernetes version %q", cluster.Spec.KubernetesVersion) } } - if kubernetesVersion != nil { + if channel != nil && kubernetesVersion != nil { image := channel.FindImage(cluster.Spec.GetCloudProvider(), *kubernetesVersion, architecture) if image != nil { - return image.Name + return image.Name, nil } } } switch cluster.Spec.GetCloudProvider() { case api.CloudProviderDO: - return defaultDONodeImage + return defaultDOImage, nil + case api.CloudProviderHetzner: + return defaultHetznerImage, nil + case api.CloudProviderScaleway: + return defaultScalewayImage, nil } - klog.Infof("Cannot set default Image for CloudProvider=%q", cluster.Spec.GetCloudProvider()) - return "" + + return "", fmt.Errorf("unable to determine default image for cloud provider %q and architecture %q", cluster.Spec.GetCloudProvider(), architecture) } func MachineArchitecture(cloud fi.Cloud, machineType string) (architectures.Architecture, error) { diff --git a/upup/pkg/fi/cloudup/new_cluster_test.go b/upup/pkg/fi/cloudup/new_cluster_test.go index 66f1d283e6..e163f21783 100644 --- a/upup/pkg/fi/cloudup/new_cluster_test.go +++ b/upup/pkg/fi/cloudup/new_cluster_test.go @@ -26,6 +26,7 @@ import ( api "k8s.io/kops/pkg/apis/kops" "k8s.io/kops/pkg/diff" "k8s.io/kops/upup/pkg/fi" + "k8s.io/kops/util/pkg/architectures" ) func TestRemoveSharedPrefix(t *testing.T) { @@ -334,3 +335,112 @@ func TestSetupNetworking(t *testing.T) { } } } + +func TestDefaultImage(t *testing.T) { + tests := []struct { + cluster *api.Cluster + architecture architectures.Architecture + expected string + }{ + { + cluster: &api.Cluster{ + Spec: api.ClusterSpec{ + KubernetesVersion: "v1.25.0", + CloudProvider: api.CloudProviderSpec{ + AWS: &api.AWSSpec{}, + }, + }, + }, + architecture: architectures.ArchitectureAmd64, + expected: "099720109477/ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-20221018", + }, + { + cluster: &api.Cluster{ + Spec: api.ClusterSpec{ + KubernetesVersion: "v1.25.0", + CloudProvider: api.CloudProviderSpec{ + AWS: &api.AWSSpec{}, + }, + }, + }, + architecture: architectures.ArchitectureArm64, + expected: "099720109477/ubuntu/images/hvm-ssd/ubuntu-focal-20.04-arm64-server-20221018", + }, + { + cluster: &api.Cluster{ + Spec: api.ClusterSpec{ + KubernetesVersion: "v1.25.0", + CloudProvider: api.CloudProviderSpec{ + Azure: &api.AzureSpec{}, + }, + }, + }, + architecture: architectures.ArchitectureAmd64, + expected: "Canonical:0001-com-ubuntu-server-focal:20_04-lts-gen2:20.04.202210180", + }, + { + cluster: &api.Cluster{ + Spec: api.ClusterSpec{ + KubernetesVersion: "v1.25.0", + CloudProvider: api.CloudProviderSpec{ + GCE: &api.GCESpec{}, + }, + }, + }, + architecture: architectures.ArchitectureAmd64, + expected: "ubuntu-os-cloud/ubuntu-2004-focal-v20221018", + }, + { + cluster: &api.Cluster{ + Spec: api.ClusterSpec{ + KubernetesVersion: "v1.25.0", + CloudProvider: api.CloudProviderSpec{ + DO: &api.DOSpec{}, + }, + }, + }, + architecture: architectures.ArchitectureAmd64, + expected: defaultDOImage, + }, + { + cluster: &api.Cluster{ + Spec: api.ClusterSpec{ + KubernetesVersion: "v1.25.0", + CloudProvider: api.CloudProviderSpec{ + Hetzner: &api.HetznerSpec{}, + }, + }, + }, + architecture: architectures.ArchitectureAmd64, + expected: defaultHetznerImage, + }, + { + cluster: &api.Cluster{ + Spec: api.ClusterSpec{ + KubernetesVersion: "v1.25.0", + CloudProvider: api.CloudProviderSpec{ + Scaleway: &api.ScalewaySpec{}, + }, + }, + }, + architecture: architectures.ArchitectureAmd64, + expected: defaultScalewayImage, + }, + } + + channel, err := api.LoadChannel("file://tests/channels/channel.yaml") + if err != nil { + t.Fatalf("unable to load test channel: %v", err) + } + + for _, test := range tests { + actual, err := defaultImage(test.cluster, channel, test.architecture) + if err != nil { + t.Error(err) + continue + } + if actual != test.expected { + t.Errorf("unexpected default image for cluster %s: expected=%q, actual=%q", fi.DebugAsJsonString(test.cluster.Spec), test.expected, actual) + } + } +} diff --git a/upup/pkg/fi/cloudup/populate_instancegroup_spec.go b/upup/pkg/fi/cloudup/populate_instancegroup_spec.go index d41a0d9c14..c6e73a2142 100644 --- a/upup/pkg/fi/cloudup/populate_instancegroup_spec.go +++ b/upup/pkg/fi/cloudup/populate_instancegroup_spec.go @@ -50,7 +50,9 @@ const ( defaultMasterMachineTypeAzure = "Standard_B2s" defaultMasterMachineTypeHetzner = "cx21" - defaultDONodeImage = "ubuntu-20-04-x64" + defaultDOImage = "ubuntu-20-04-x64" + defaultHetznerImage = "ubuntu-20.04" + defaultScalewayImage = "ubuntu_focal" ) // TODO: this hardcoded list can be replaced with DescribeInstanceTypes' DedicatedHostsSupported field @@ -129,9 +131,9 @@ func PopulateInstanceGroupSpec(cluster *kops.Cluster, input *kops.InstanceGroup, if err != nil { return nil, fmt.Errorf("unable to determine machine architecture for InstanceGroup %q: %v", ig.ObjectMeta.Name, err) } - ig.Spec.Image = defaultImage(cluster, channel, architecture) - if ig.Spec.Image == "" { - return nil, fmt.Errorf("unable to determine default image for InstanceGroup %s", ig.ObjectMeta.Name) + ig.Spec.Image, err = defaultImage(cluster, channel, architecture) + if err != nil { + return nil, fmt.Errorf("unable to determine default image for instance group %q: %v", ig.ObjectMeta.Name, err) } } diff --git a/upup/pkg/fi/cloudup/tests/channels/channel.yaml b/upup/pkg/fi/cloudup/tests/channels/channel.yaml new file mode 100644 index 0000000000..e5a96d2575 --- /dev/null +++ b/upup/pkg/fi/cloudup/tests/channels/channel.yaml @@ -0,0 +1,62 @@ +spec: + images: + - name: 099720109477/ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-20221018 + providerID: aws + architectureID: amd64 + kubernetesVersion: ">=1.18.0" + - name: 099720109477/ubuntu/images/hvm-ssd/ubuntu-focal-20.04-arm64-server-20221018 + providerID: aws + architectureID: arm64 + kubernetesVersion: ">=1.20.0" + - name: ubuntu-os-cloud/ubuntu-2004-focal-v20221018 + providerID: gce + architectureID: amd64 + kubernetesVersion: ">=1.18.0" + - name: Canonical:0001-com-ubuntu-server-focal:20_04-lts-gen2:20.04.202210180 + providerID: azure + architectureID: amd64 + kubernetesVersion: ">=1.20.0" + kubernetesVersions: + - range: ">=1.25.0" + recommendedVersion: 1.25.4 + requiredVersion: 1.25.0 + - range: ">=1.24.0" + recommendedVersion: 1.24.8 + requiredVersion: 1.24.0 + - range: ">=1.23.0" + recommendedVersion: 1.23.14 + requiredVersion: 1.23.0 + - range: ">=1.22.0" + recommendedVersion: 1.22.16 + requiredVersion: 1.22.0 + - range: ">=1.21.0" + recommendedVersion: 1.21.14 + requiredVersion: 1.21.0 + - range: ">=1.20.0" + recommendedVersion: 1.20.15 + requiredVersion: 1.20.0 + kopsVersions: + - range: ">=1.25.0-alpha.1" + recommendedVersion: "1.25.2" + #requiredVersion: 1.25.0 + kubernetesVersion: 1.25.4 + - range: ">=1.24.0-alpha.1" + recommendedVersion: "1.25.2" + #requiredVersion: 1.24.0 + kubernetesVersion: 1.24.8 + - range: ">=1.23.0-alpha.1" + recommendedVersion: "1.25.2" + #requiredVersion: 1.23.0 + kubernetesVersion: 1.23.14 + - range: ">=1.22.0-alpha.1" + recommendedVersion: "1.25.2" + #requiredVersion: 1.22.0 + kubernetesVersion: 1.22.16 + - range: ">=1.21.0-alpha.1" + recommendedVersion: "1.25.2" + #requiredVersion: 1.21.0 + kubernetesVersion: 1.21.14 + - range: ">=1.20.0-alpha.1" + recommendedVersion: "1.25.2" + #requiredVersion: 1.20.0 + kubernetesVersion: 1.20.15