From c79457eafaa19051cab33fd7b56cd1a55db15a38 Mon Sep 17 00:00:00 2001 From: justinsb Date: Mon, 25 Nov 2024 08:10:39 -0500 Subject: [PATCH] refactor: create abstraction over cluster/instancegroup for building assets This abstraction should let us change the version on an instance group level. --- nodeup/pkg/model/containerd.go | 2 +- nodeup/pkg/model/context.go | 30 +++---- nodeup/pkg/model/kube_proxy_test.go | 4 +- pkg/apis/kops/model/features.go | 8 +- pkg/apis/kops/model/instance_group.go | 69 +++++++++++++++ pkg/apis/kops/model/kubernetes_version.go | 89 ++++++++++++++++++++ pkg/apis/kops/util/versions.go | 3 +- pkg/model/components/context.go | 7 +- pkg/nodemodel/fileassets.go | 40 +++++---- pkg/nodemodel/nodeupconfigbuilder.go | 14 +-- pkg/nodemodel/wellknownassets/cni.go | 8 +- pkg/nodemodel/wellknownassets/cni_test.go | 21 ++++- pkg/nodemodel/wellknownassets/containerd.go | 8 +- pkg/nodemodel/wellknownassets/crictl.go | 4 +- pkg/nodemodel/wellknownassets/crictl_test.go | 11 ++- pkg/nodemodel/wellknownassets/nerdctl.go | 4 +- pkg/nodemodel/wellknownassets/runc.go | 8 +- 17 files changed, 254 insertions(+), 76 deletions(-) create mode 100644 pkg/apis/kops/model/instance_group.go create mode 100644 pkg/apis/kops/model/kubernetes_version.go diff --git a/nodeup/pkg/model/containerd.go b/nodeup/pkg/model/containerd.go index 6a7bcfbf4ef2c..820eaaeab4298 100644 --- a/nodeup/pkg/model/containerd.go +++ b/nodeup/pkg/model/containerd.go @@ -177,7 +177,7 @@ func (b *ContainerdBuilder) installContainerd(c *fi.NodeupModelBuilderContext) e return nil } -func (b *ContainerdBuilder) buildSystemdService(sv semver.Version) *nodetasks.Service { +func (b *ContainerdBuilder) buildSystemdService(containerdVersion semver.Version) *nodetasks.Service { // Based on https://github.com/containerd/containerd/blob/master/containerd.service manifest := &systemd.Manifest{} diff --git a/nodeup/pkg/model/context.go b/nodeup/pkg/model/context.go index 93f49da257db0..a2ba934870202 100644 --- a/nodeup/pkg/model/context.go +++ b/nodeup/pkg/model/context.go @@ -27,12 +27,10 @@ import ( awsconfig "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" - "github.com/blang/semver/v4" hcloudmetadata "github.com/hetznercloud/hcloud-go/hcloud/metadata" "k8s.io/klog/v2" "k8s.io/kops/pkg/apis/kops" - "k8s.io/kops/pkg/apis/kops/model" - "k8s.io/kops/pkg/apis/kops/util" + kopsmodel "k8s.io/kops/pkg/apis/kops/model" "k8s.io/kops/pkg/apis/nodeup" "k8s.io/kops/pkg/systemd" "k8s.io/kops/upup/pkg/fi" @@ -74,7 +72,7 @@ type NodeupModelContext struct { // usesNoneDNS is true if the cluster runs with dns=none (which uses fixed IPs, for example a load balancer, instead of DNS) usesNoneDNS bool - kubernetesVersion semver.Version + kubernetesVersion *kopsmodel.KubernetesVersion bootstrapCerts map[string]*nodetasks.BootstrapCert bootstrapKeypairIDs map[string]string @@ -86,11 +84,11 @@ type NodeupModelContext struct { // Init completes initialization of the object, for example pre-parsing the kubernetes version func (c *NodeupModelContext) Init() error { - k8sVersion, err := util.ParseKubernetesVersion(c.NodeupConfig.KubernetesVersion) - if err != nil || k8sVersion == nil { - return fmt.Errorf("unable to parse KubernetesVersion %q", c.NodeupConfig.KubernetesVersion) + k8sVersion, err := kopsmodel.ParseKubernetesVersion(c.NodeupConfig.KubernetesVersion) + if err != nil { + return fmt.Errorf("unable to parse KubernetesVersion %q: %w", c.NodeupConfig.KubernetesVersion, err) } - c.kubernetesVersion = *k8sVersion + c.kubernetesVersion = k8sVersion c.bootstrapCerts = map[string]*nodetasks.BootstrapCert{} c.bootstrapKeypairIDs = map[string]string{} @@ -303,20 +301,20 @@ func (c *NodeupModelContext) RemapImage(image string) string { return image } -// IsKubernetesGTE checks if the version is greater-than-or-equal +// IsKubernetesGTE checks if the kubernetes version is greater-than-or-equal-to version func (c *NodeupModelContext) IsKubernetesGTE(version string) bool { - if c.kubernetesVersion.Major == 0 { + if c.kubernetesVersion == nil { klog.Fatalf("kubernetesVersion not set (%s); Init not called", c.kubernetesVersion) } - return util.IsKubernetesGTE(version, c.kubernetesVersion) + return c.kubernetesVersion.IsGTE(version) } -// IsKubernetesLT checks if the version is less-than +// IsKubernetesLT checks if the kubernetes version is less-than version func (c *NodeupModelContext) IsKubernetesLT(version string) bool { - if c.kubernetesVersion.Major == 0 { + if c.kubernetesVersion == nil { klog.Fatalf("kubernetesVersion not set (%s); Init not called", c.kubernetesVersion) } - return !c.IsKubernetesGTE(version) + return c.kubernetesVersion.IsLT(version) } // UseVolumeMounts is used to check if we have volume mounts enabled as we need to @@ -327,11 +325,11 @@ func (c *NodeupModelContext) UseVolumeMounts() bool { // UseChallengeCallback is true if we should use a callback challenge during node provisioning with kops-controller. func (c *NodeupModelContext) UseChallengeCallback(cloudProvider kops.CloudProviderID) bool { - return model.UseChallengeCallback(cloudProvider) + return kopsmodel.UseChallengeCallback(cloudProvider) } func (c *NodeupModelContext) UseExternalKubeletCredentialProvider() bool { - return model.UseExternalKubeletCredentialProvider(c.kubernetesVersion, c.CloudProvider()) + return kopsmodel.UseExternalKubeletCredentialProvider(c.kubernetesVersion, c.CloudProvider()) } // UsesSecondaryIP checks if the CNI in use attaches secondary interfaces to the host. diff --git a/nodeup/pkg/model/kube_proxy_test.go b/nodeup/pkg/model/kube_proxy_test.go index baff90595acfd..5e40cac6583bb 100644 --- a/nodeup/pkg/model/kube_proxy_test.go +++ b/nodeup/pkg/model/kube_proxy_test.go @@ -21,13 +21,13 @@ import ( "testing" "k8s.io/kops/pkg/apis/kops" + kopsmodel "k8s.io/kops/pkg/apis/kops/model" "k8s.io/kops/pkg/apis/nodeup" "k8s.io/kops/pkg/flagbuilder" "k8s.io/kops/upup/pkg/fi" "k8s.io/kops/util/pkg/architectures" "k8s.io/kops/util/pkg/exec" - "github.com/blang/semver/v4" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -70,7 +70,7 @@ func TestKubeProxyBuilder_buildPod(t *testing.T) { fields{ &NodeupModelContext{ NodeupConfig: nodeupConfig, - kubernetesVersion: semver.Version{Major: 1, Minor: 20}, + kubernetesVersion: kopsmodel.MustParseKubernetesVersion("1.20"), }, }, &v1.Pod{ diff --git a/pkg/apis/kops/model/features.go b/pkg/apis/kops/model/features.go index 5cd039f063d84..0062a96462d70 100644 --- a/pkg/apis/kops/model/features.go +++ b/pkg/apis/kops/model/features.go @@ -17,9 +17,7 @@ limitations under the License. package model import ( - "github.com/blang/semver/v4" "k8s.io/kops/pkg/apis/kops" - "k8s.io/kops/pkg/apis/kops/util" ) // UseChallengeCallback is true if we should use a callback challenge during node provisioning with kops-controller. @@ -70,12 +68,12 @@ func UseCiliumEtcd(cluster *kops.Cluster) bool { } // Configures a Kubelet Credential Provider if Kubernetes is newer than a specific version -func UseExternalKubeletCredentialProvider(k8sVersion semver.Version, cloudProvider kops.CloudProviderID) bool { +func UseExternalKubeletCredentialProvider(k8sVersion *KubernetesVersion, cloudProvider kops.CloudProviderID) bool { switch cloudProvider { case kops.CloudProviderGCE: - return util.IsKubernetesGTE("1.29", k8sVersion) + return k8sVersion.IsGTE("1.29") case kops.CloudProviderAWS: - return util.IsKubernetesGTE("1.27", k8sVersion) + return k8sVersion.IsGTE("1.27") default: return false } diff --git a/pkg/apis/kops/model/instance_group.go b/pkg/apis/kops/model/instance_group.go new file mode 100644 index 0000000000000..32215d2559ea6 --- /dev/null +++ b/pkg/apis/kops/model/instance_group.go @@ -0,0 +1,69 @@ +/* +Copyright 2024 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 model + +import ( + "fmt" + + "k8s.io/kops/pkg/apis/kops" +) + +// InstanceGroup is a subset of the full Cluster and InstanceGroup functionality, +// that gives us some abstraction over the raw types. +type InstanceGroup interface { + // KubernetesVersion returns the Kubernetes version for the instance group + KubernetesVersion() *KubernetesVersion + + // GetCloudProvider returns the cloud provider for the instance group + GetCloudProvider() kops.CloudProviderID + + // ClusterSpec returns the cluster spec for the instance group. + // If possible, prefer abstracted methods over accessing this data directly. + ClusterSpec() *kops.ClusterSpec +} + +// ForInstanceGroup creates an InstanceGroup model for the given cluster and instance group. +func ForInstanceGroup(cluster *kops.Cluster, ig *kops.InstanceGroup) (InstanceGroup, error) { + kubernetesVersionString := cluster.Spec.KubernetesVersion + kubernetesVersion, err := ParseKubernetesVersion(kubernetesVersionString) + if err != nil { + return nil, fmt.Errorf("error parsing Kubernetes version %q: %v", kubernetesVersionString, err) + } + + return &instanceGroupModel{cluster: cluster, ig: ig, kubernetesVersion: kubernetesVersion}, nil +} + +// instanceGroupModel is a concrete implementation of InstanceGroup. +type instanceGroupModel struct { + cluster *kops.Cluster + ig *kops.InstanceGroup + kubernetesVersion *KubernetesVersion +} + +var _ InstanceGroup = &instanceGroupModel{} + +func (m *instanceGroupModel) KubernetesVersion() *KubernetesVersion { + return m.kubernetesVersion +} + +func (m *instanceGroupModel) GetCloudProvider() kops.CloudProviderID { + return m.cluster.GetCloudProvider() +} + +func (m *instanceGroupModel) ClusterSpec() *kops.ClusterSpec { + return &m.cluster.Spec +} diff --git a/pkg/apis/kops/model/kubernetes_version.go b/pkg/apis/kops/model/kubernetes_version.go new file mode 100644 index 0000000000000..3672aa19d3463 --- /dev/null +++ b/pkg/apis/kops/model/kubernetes_version.go @@ -0,0 +1,89 @@ +/* +Copyright 2024 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 model + +import ( + "fmt" + "strings" + + "github.com/blang/semver/v4" + "k8s.io/kops/pkg/apis/kops/util" +) + +// KubernetesVersion is a wrapper over semver functionality, +// that offers some functionality particularly useful for kubernetes version semantics. +type KubernetesVersion struct { + versionString string + version semver.Version +} + +// ParseKubernetesVersion parses a Kubernetes version string and returns a KubernetesVersion object. +func ParseKubernetesVersion(versionString string) (*KubernetesVersion, error) { + parsedVersion, err := util.ParseKubernetesVersion(versionString) + if err != nil { + return nil, fmt.Errorf("error parsing version %q: %v", versionString, err) + } + + return &KubernetesVersion{versionString: versionString, version: *parsedVersion}, nil +} + +// MustParseKubernetesVersion parses a Kubernetes version string and panics if it fails. +func MustParseKubernetesVersion(versionString string) *KubernetesVersion { + kubernetesVersion, err := ParseKubernetesVersion(versionString) + if err != nil || kubernetesVersion == nil { + panic(err) + } + return kubernetesVersion +} + +func (v *KubernetesVersion) String() string { + return v.versionString +} + +// IsBaseURL checks if the version string is a URL, rather than a version identifier. +// URLs are typically used for CI builds and during development. +func IsBaseURL(kubernetesVersion string) bool { + return strings.HasPrefix(kubernetesVersion, "http:") || strings.HasPrefix(kubernetesVersion, "https:") || strings.HasPrefix(kubernetesVersion, "memfs:") +} + +// IsBaseURL checks if the version string is a URL, rather than a version identifier. +// URLs are typically used for CI builds and during development. +func (v *KubernetesVersion) IsBaseURL() bool { + return IsBaseURL(v.versionString) +} + +// IsGTE checks if the version is greater than or equal (>=) to the specified version. +// It panics if the kubernetes version in the cluster is invalid, or if the version is invalid. +func (v *KubernetesVersion) IsGTE(version string) bool { + parsedVersion, err := util.ParseKubernetesVersion(version) + if err != nil || parsedVersion == nil { + panic(fmt.Sprintf("error parsing version %q: %v", version, err)) + } + + // Ignore Pre & Build fields + clusterVersion := v.version + clusterVersion.Pre = nil + clusterVersion.Build = nil + + return clusterVersion.GTE(*parsedVersion) +} + +// IsLT checks if the version is strictly less (<) than the specified version. +// It panics if the kubernetes version in the cluster is invalid, or if the version is invalid. +func (v *KubernetesVersion) IsLT(version string) bool { + return !v.IsGTE(version) +} diff --git a/pkg/apis/kops/util/versions.go b/pkg/apis/kops/util/versions.go index 7b70e200822f8..76569d590962d 100644 --- a/pkg/apis/kops/util/versions.go +++ b/pkg/apis/kops/util/versions.go @@ -46,8 +46,7 @@ func ParseKubernetesVersion(version string) (*semver.Version, error) { return &sv, nil } -// TODO: Convert to our own KubernetesVersion type? - +// Deprecated: prefer using KubernetesVersion.IsGTE() func IsKubernetesGTE(version string, k8sVersion semver.Version) bool { parsedVersion, err := ParseKubernetesVersion(version) if err != nil { diff --git a/pkg/model/components/context.go b/pkg/model/components/context.go index 1218a66496f27..f2cc1dc3b46c3 100644 --- a/pkg/model/components/context.go +++ b/pkg/model/components/context.go @@ -24,6 +24,7 @@ import ( "strings" "k8s.io/kops/pkg/apis/kops" + kopsmodel "k8s.io/kops/pkg/apis/kops/model" "k8s.io/kops/pkg/apis/kops/util" "k8s.io/kops/pkg/assets" "k8s.io/kops/pkg/k8sversion" @@ -89,10 +90,6 @@ func WellKnownServiceIP(networkingSpec *kops.NetworkingSpec, id int) (net.IP, er return nil, fmt.Errorf("unexpected IP address type for ServiceClusterIPRange: %s", networkingSpec.ServiceClusterIPRange) } -func IsBaseURL(kubernetesVersion string) bool { - return strings.HasPrefix(kubernetesVersion, "http:") || strings.HasPrefix(kubernetesVersion, "https:") || strings.HasPrefix(kubernetesVersion, "memfs:") -} - // Image returns the docker image name for the specified component func Image(component string, clusterSpec *kops.ClusterSpec, assetsBuilder *assets.AssetBuilder) (string, error) { if assetsBuilder == nil { @@ -106,7 +103,7 @@ func Image(component string, clusterSpec *kops.ClusterSpec, assetsBuilder *asset imageName := component - if !IsBaseURL(clusterSpec.KubernetesVersion) { + if !kopsmodel.IsBaseURL(clusterSpec.KubernetesVersion) { image := "registry.k8s.io/" + imageName + ":" + "v" + kubernetesVersion.String() image, err := assetsBuilder.RemapImage(image) diff --git a/pkg/nodemodel/fileassets.go b/pkg/nodemodel/fileassets.go index 33a72c36f2e47..e3c74b7d59774 100644 --- a/pkg/nodemodel/fileassets.go +++ b/pkg/nodemodel/fileassets.go @@ -24,9 +24,7 @@ import ( "k8s.io/kops/pkg/apis/kops" "k8s.io/kops/pkg/apis/kops/model" - "k8s.io/kops/pkg/apis/kops/util" "k8s.io/kops/pkg/assets" - "k8s.io/kops/pkg/model/components" "k8s.io/kops/pkg/nodemodel/wellknownassets" "k8s.io/kops/upup/pkg/fi" "k8s.io/kops/util/pkg/architectures" @@ -40,12 +38,14 @@ type KubernetesFileAssets struct { } // BuildKubernetesFileAssets returns the Kubernetes file assets for the given cluster -func BuildKubernetesFileAssets(cluster *kops.Cluster, assetBuilder *assets.AssetBuilder) (*KubernetesFileAssets, error) { +func BuildKubernetesFileAssets(ig model.InstanceGroup, assetBuilder *assets.AssetBuilder) (*KubernetesFileAssets, error) { + kubernetesVersion := ig.KubernetesVersion() + var baseURL string - if components.IsBaseURL(cluster.Spec.KubernetesVersion) { - baseURL = cluster.Spec.KubernetesVersion + if kubernetesVersion.IsBaseURL() { + baseURL = kubernetesVersion.String() } else { - baseURL = "https://dl.k8s.io/release/v" + cluster.Spec.KubernetesVersion + baseURL = "https://dl.k8s.io/release/v" + kubernetesVersion.String() } kubernetesAssets := make(map[architectures.Architecture][]*assets.MirroredAsset) @@ -57,7 +57,7 @@ func BuildKubernetesFileAssets(cluster *kops.Cluster, assetBuilder *assets.Asset fmt.Sprintf("/bin/linux/%s/kubectl", arch), } - if needsMounterAsset(cluster) { + if needsMounterAsset(ig) { k8sAssetsNames = append(k8sAssetsNames, fmt.Sprintf("/bin/linux/%s/mounter", arch)) } @@ -75,13 +75,11 @@ func BuildKubernetesFileAssets(cluster *kops.Cluster, assetBuilder *assets.Asset kubernetesAssets[arch] = append(kubernetesAssets[arch], assets.BuildMirroredAsset(asset)) } - kubernetesVersion, _ := util.ParseKubernetesVersion(cluster.Spec.KubernetesVersion) - - cloudProvider := cluster.GetCloudProvider() - if ok := model.UseExternalKubeletCredentialProvider(*kubernetesVersion, cloudProvider); ok { + cloudProvider := ig.GetCloudProvider() + if ok := model.UseExternalKubeletCredentialProvider(kubernetesVersion, cloudProvider); ok { switch cloudProvider { case kops.CloudProviderGCE: - binaryLocation := cluster.Spec.CloudProvider.GCE.BinariesLocation + binaryLocation := ig.ClusterSpec().CloudProvider.GCE.BinariesLocation if binaryLocation == nil { binaryLocation = fi.PtrTo("https://storage.googleapis.com/k8s-staging-cloud-provider-gcp/auth-provider-gcp") } @@ -107,7 +105,7 @@ func BuildKubernetesFileAssets(cluster *kops.Cluster, assetBuilder *assets.Asset kubernetesAssets[arch] = append(kubernetesAssets[arch], assets.BuildMirroredAsset(asset)) case kops.CloudProviderAWS: - binaryLocation := cluster.Spec.CloudProvider.AWS.BinariesLocation + binaryLocation := ig.ClusterSpec().CloudProvider.AWS.BinariesLocation if binaryLocation == nil { binaryLocation = fi.PtrTo("https://artifacts.k8s.io/binaries/cloud-provider-aws/v1.27.1") } @@ -125,15 +123,15 @@ func BuildKubernetesFileAssets(cluster *kops.Cluster, assetBuilder *assets.Asset } { - cniAsset, err := wellknownassets.FindCNIAssets(cluster, assetBuilder, arch) + cniAsset, err := wellknownassets.FindCNIAssets(ig, assetBuilder, arch) if err != nil { return nil, err } kubernetesAssets[arch] = append(kubernetesAssets[arch], assets.BuildMirroredAsset(cniAsset)) } - if cluster.Spec.Containerd == nil || !cluster.Spec.Containerd.SkipInstall { - containerdAsset, err := wellknownassets.FindContainerdAsset(cluster, assetBuilder, arch) + if ig.ClusterSpec().Containerd == nil || !ig.ClusterSpec().Containerd.SkipInstall { + containerdAsset, err := wellknownassets.FindContainerdAsset(ig, assetBuilder, arch) if err != nil { return nil, err } @@ -141,14 +139,14 @@ func BuildKubernetesFileAssets(cluster *kops.Cluster, assetBuilder *assets.Asset kubernetesAssets[arch] = append(kubernetesAssets[arch], assets.BuildMirroredAsset(containerdAsset)) } - runcAsset, err := wellknownassets.FindRuncAsset(cluster, assetBuilder, arch) + runcAsset, err := wellknownassets.FindRuncAsset(ig, assetBuilder, arch) if err != nil { return nil, err } if runcAsset != nil { kubernetesAssets[arch] = append(kubernetesAssets[arch], assets.BuildMirroredAsset(runcAsset)) } - nerdctlAsset, err := wellknownassets.FindNerdctlAsset(cluster, assetBuilder, arch) + nerdctlAsset, err := wellknownassets.FindNerdctlAsset(ig, assetBuilder, arch) if err != nil { return nil, err } @@ -157,7 +155,7 @@ func BuildKubernetesFileAssets(cluster *kops.Cluster, assetBuilder *assets.Asset } } - crictlAsset, err := wellknownassets.FindCrictlAsset(cluster, assetBuilder, arch) + crictlAsset, err := wellknownassets.FindCrictlAsset(ig, assetBuilder, arch) if err != nil { return nil, err } @@ -194,9 +192,9 @@ func BuildNodeUpAssets(ctx context.Context, assetBuilder *assets.AssetBuilder) ( // needsMounterAsset checks if we need the mounter program // This is only needed currently on ContainerOS i.e. GCE, but we don't have a nice way to detect it yet -func needsMounterAsset(c *kops.Cluster) bool { +func needsMounterAsset(ig model.InstanceGroup) bool { // TODO: Do real detection of ContainerOS (but this has to work with image names, and maybe even forked images) - switch c.GetCloudProvider() { + switch ig.GetCloudProvider() { case kops.CloudProviderGCE: return true default: diff --git a/pkg/nodemodel/nodeupconfigbuilder.go b/pkg/nodemodel/nodeupconfigbuilder.go index f0b74d9ea0e84..7f0ee4126dc05 100644 --- a/pkg/nodemodel/nodeupconfigbuilder.go +++ b/pkg/nodemodel/nodeupconfigbuilder.go @@ -28,11 +28,10 @@ import ( "strings" "k8s.io/kops/pkg/apis/kops" - apiModel "k8s.io/kops/pkg/apis/kops/model" + kopsmodel "k8s.io/kops/pkg/apis/kops/model" "k8s.io/kops/pkg/apis/nodeup" "k8s.io/kops/pkg/assets" "k8s.io/kops/pkg/model" - "k8s.io/kops/pkg/model/components" "k8s.io/kops/pkg/nodemodel/wellknownassets" "k8s.io/kops/pkg/wellknownports" "k8s.io/kops/pkg/wellknownservices" @@ -93,7 +92,7 @@ func NewNodeUpConfigBuilder(cluster *kops.Cluster, assetBuilder *assets.AssetBui isAPIServer := role == kops.InstanceGroupRoleAPIServer images[role] = make(map[architectures.Architecture][]*nodeup.Image) - if components.IsBaseURL(cluster.Spec.KubernetesVersion) { + if kopsmodel.IsBaseURL(cluster.Spec.KubernetesVersion) { // When using a custom version, we want to preload the images over http components := []string{"kube-proxy"} if isMaster { @@ -220,7 +219,12 @@ func (n *nodeUpConfigBuilder) BuildConfig(ig *kops.InstanceGroup, wellKnownAddre config, bootConfig := nodeup.NewConfig(cluster, ig) - kubernetesAssets, err := BuildKubernetesFileAssets(cluster, n.assetBuilder) + igModel, err := kopsmodel.ForInstanceGroup(cluster, ig) + if err != nil { + return nil, nil, fmt.Errorf("building instance group model: %w", err) + } + + kubernetesAssets, err := BuildKubernetesFileAssets(igModel, n.assetBuilder) if err != nil { return nil, nil, err } @@ -371,7 +375,7 @@ func (n *nodeUpConfigBuilder) BuildConfig(ig *kops.InstanceGroup, wellKnownAddre } } - useConfigServer := apiModel.UseKopsControllerForNodeConfig(cluster) && !ig.HasAPIServer() + useConfigServer := kopsmodel.UseKopsControllerForNodeConfig(cluster) && !ig.HasAPIServer() if useConfigServer { hosts := []string{"kops-controller.internal." + cluster.ObjectMeta.Name} if len(bootConfig.APIServerIPs) > 0 { diff --git a/pkg/nodemodel/wellknownassets/cni.go b/pkg/nodemodel/wellknownassets/cni.go index 58addeb1b6804..4b61fc7784a9b 100644 --- a/pkg/nodemodel/wellknownassets/cni.go +++ b/pkg/nodemodel/wellknownassets/cni.go @@ -22,7 +22,7 @@ import ( "os" "k8s.io/klog/v2" - kopsapi "k8s.io/kops/pkg/apis/kops" + "k8s.io/kops/pkg/apis/kops/model" "k8s.io/kops/pkg/assets" "k8s.io/kops/util/pkg/architectures" "k8s.io/kops/util/pkg/hashing" @@ -47,7 +47,7 @@ const ( ENV_VAR_CNI_ASSET_HASH = "CNI_ASSET_HASH_STRING" ) -func FindCNIAssets(c *kopsapi.Cluster, assetBuilder *assets.AssetBuilder, arch architectures.Architecture) (*assets.FileAsset, error) { +func FindCNIAssets(ig model.InstanceGroup, assetBuilder *assets.AssetBuilder, arch architectures.Architecture) (*assets.FileAsset, error) { // Override CNI packages from env vars cniAssetURL := os.Getenv(ENV_VAR_CNI_ASSET_URL) cniAssetHash := os.Getenv(ENV_VAR_CNI_ASSET_HASH) @@ -76,14 +76,14 @@ func FindCNIAssets(c *kopsapi.Cluster, assetBuilder *assets.AssetBuilder, arch a switch arch { case architectures.ArchitectureAmd64: - if c.IsKubernetesLT("1.27") { + if ig.KubernetesVersion().IsLT("1.27") { cniAssetURL = defaultCNIAssetAmd64K8s_22 } else { cniAssetURL = defaultCNIAssetAmd64K8s_27 } klog.V(2).Infof("Adding default ARM64 CNI plugin binaries asset: %s", cniAssetURL) case architectures.ArchitectureArm64: - if c.IsKubernetesLT("1.27") { + if ig.KubernetesVersion().IsLT("1.27") { cniAssetURL = defaultCNIAssetArm64K8s_22 } else { cniAssetURL = defaultCNIAssetArm64K8s_27 diff --git a/pkg/nodemodel/wellknownassets/cni_test.go b/pkg/nodemodel/wellknownassets/cni_test.go index 9425fa008ea42..071e8da7bbf35 100644 --- a/pkg/nodemodel/wellknownassets/cni_test.go +++ b/pkg/nodemodel/wellknownassets/cni_test.go @@ -20,6 +20,7 @@ import ( "testing" api "k8s.io/kops/pkg/apis/kops" + kopsmodel "k8s.io/kops/pkg/apis/kops/model" "k8s.io/kops/pkg/assets" "k8s.io/kops/util/pkg/architectures" "k8s.io/kops/util/pkg/vfs" @@ -35,8 +36,16 @@ func Test_FindCNIAssetFromEnvironmentVariable(t *testing.T) { cluster := &api.Cluster{} cluster.Spec.KubernetesVersion = "v1.18.0" + ig := &api.InstanceGroup{} + assetBuilder := assets.NewAssetBuilder(vfs.Context, cluster.Spec.Assets, cluster.Spec.KubernetesVersion, false) - asset, err := FindCNIAssets(cluster, assetBuilder, architectures.ArchitectureAmd64) + + igModel, err := kopsmodel.ForInstanceGroup(cluster, ig) + if err != nil { + t.Fatalf("building instance group model: %v", err) + } + + asset, err := FindCNIAssets(igModel, assetBuilder, architectures.ArchitectureAmd64) if err != nil { t.Fatalf("Unable to parse CNI version: %v", err) } @@ -57,8 +66,16 @@ func Test_FindCNIAssetFromDefaults122(t *testing.T) { cluster := &api.Cluster{} cluster.Spec.KubernetesVersion = "v1.22.0" + ig := &api.InstanceGroup{} + + igModel, err := kopsmodel.ForInstanceGroup(cluster, ig) + if err != nil { + t.Fatalf("building instance group model: %v", err) + } + assetBuilder := assets.NewAssetBuilder(vfs.Context, cluster.Spec.Assets, cluster.Spec.KubernetesVersion, false) - asset, err := FindCNIAssets(cluster, assetBuilder, architectures.ArchitectureAmd64) + + asset, err := FindCNIAssets(igModel, assetBuilder, architectures.ArchitectureAmd64) if err != nil { t.Fatalf("Unable to parse CNI version: %s", err) } diff --git a/pkg/nodemodel/wellknownassets/containerd.go b/pkg/nodemodel/wellknownassets/containerd.go index 8c0e7c2cf5f94..2529b88722df2 100644 --- a/pkg/nodemodel/wellknownassets/containerd.go +++ b/pkg/nodemodel/wellknownassets/containerd.go @@ -22,7 +22,7 @@ import ( "github.com/blang/semver/v4" - "k8s.io/kops/pkg/apis/kops" + "k8s.io/kops/pkg/apis/kops/model" "k8s.io/kops/pkg/assets" "k8s.io/kops/upup/pkg/fi" "k8s.io/kops/util/pkg/architectures" @@ -37,11 +37,11 @@ const ( containerdBundleUrlAmd64 = "https://github.com/containerd/containerd/releases/download/v%s/cri-containerd-cni-%s-linux-amd64.tar.gz" ) -func FindContainerdAsset(c *kops.Cluster, assetBuilder *assets.AssetBuilder, arch architectures.Architecture) (*assets.FileAsset, error) { - if c.Spec.Containerd == nil { +func FindContainerdAsset(ig model.InstanceGroup, assetBuilder *assets.AssetBuilder, arch architectures.Architecture) (*assets.FileAsset, error) { + containerd := ig.ClusterSpec().Containerd + if containerd == nil { return nil, fmt.Errorf("unable to find containerd config") } - containerd := c.Spec.Containerd canonicalURL := "" knownHash := "" diff --git a/pkg/nodemodel/wellknownassets/crictl.go b/pkg/nodemodel/wellknownassets/crictl.go index 0edaa94e57463..b12a996094797 100644 --- a/pkg/nodemodel/wellknownassets/crictl.go +++ b/pkg/nodemodel/wellknownassets/crictl.go @@ -20,7 +20,7 @@ import ( "fmt" "net/url" - "k8s.io/kops/pkg/apis/kops" + "k8s.io/kops/pkg/apis/kops/model" "k8s.io/kops/pkg/assets" "k8s.io/kops/util/pkg/architectures" ) @@ -30,7 +30,7 @@ const ( crictlAssetUrlArm64 = "https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.29.0/crictl-v1.29.0-linux-arm64.tar.gz" ) -func FindCrictlAsset(c *kops.Cluster, assetBuilder *assets.AssetBuilder, arch architectures.Architecture) (*assets.FileAsset, error) { +func FindCrictlAsset(ig model.InstanceGroup, assetBuilder *assets.AssetBuilder, arch architectures.Architecture) (*assets.FileAsset, error) { var assetURL string switch arch { case architectures.ArchitectureAmd64: diff --git a/pkg/nodemodel/wellknownassets/crictl_test.go b/pkg/nodemodel/wellknownassets/crictl_test.go index 0977f6ccb7a4e..30ca2997ebae7 100644 --- a/pkg/nodemodel/wellknownassets/crictl_test.go +++ b/pkg/nodemodel/wellknownassets/crictl_test.go @@ -20,6 +20,7 @@ import ( "testing" "k8s.io/kops/pkg/apis/kops" + kopsmodel "k8s.io/kops/pkg/apis/kops/model" "k8s.io/kops/pkg/assets" "k8s.io/kops/util/pkg/architectures" "k8s.io/kops/util/pkg/vfs" @@ -32,8 +33,16 @@ func Test_FindCrictlVersionHash(t *testing.T) { cluster := &kops.Cluster{} cluster.Spec.KubernetesVersion = "v1.29.0" + ig := &kops.InstanceGroup{} + + igModel, err := kopsmodel.ForInstanceGroup(cluster, ig) + if err != nil { + t.Fatalf("building instance group model: %v", err) + } + assetBuilder := assets.NewAssetBuilder(vfs.Context, cluster.Spec.Assets, cluster.Spec.KubernetesVersion, false) - crictlAsset, err := FindCrictlAsset(cluster, assetBuilder, architectures.ArchitectureAmd64) + + crictlAsset, err := FindCrictlAsset(igModel, assetBuilder, architectures.ArchitectureAmd64) if err != nil { t.Errorf("Unable to parse crictl version %s", err) } diff --git a/pkg/nodemodel/wellknownassets/nerdctl.go b/pkg/nodemodel/wellknownassets/nerdctl.go index e002009f27c1b..206af9c816f24 100644 --- a/pkg/nodemodel/wellknownassets/nerdctl.go +++ b/pkg/nodemodel/wellknownassets/nerdctl.go @@ -19,7 +19,7 @@ package wellknownassets import ( "fmt" - "k8s.io/kops/pkg/apis/kops" + "k8s.io/kops/pkg/apis/kops/model" "k8s.io/kops/pkg/assets" "k8s.io/kops/util/pkg/architectures" ) @@ -31,7 +31,7 @@ const ( nerdctlAssetHashArm64 = "d8df47708ca57b9cd7f498055126ba7dcfc811d9ba43aae1830c93a09e70e22d" ) -func FindNerdctlAsset(c *kops.Cluster, assetBuilder *assets.AssetBuilder, arch architectures.Architecture) (*assets.FileAsset, error) { +func FindNerdctlAsset(ig model.InstanceGroup, assetBuilder *assets.AssetBuilder, arch architectures.Architecture) (*assets.FileAsset, error) { var assetURL, assetHash string switch arch { case architectures.ArchitectureAmd64: diff --git a/pkg/nodemodel/wellknownassets/runc.go b/pkg/nodemodel/wellknownassets/runc.go index c5683281d7d78..9e433e766ffb3 100644 --- a/pkg/nodemodel/wellknownassets/runc.go +++ b/pkg/nodemodel/wellknownassets/runc.go @@ -21,7 +21,7 @@ import ( "github.com/blang/semver/v4" - "k8s.io/kops/pkg/apis/kops" + "k8s.io/kops/pkg/apis/kops/model" "k8s.io/kops/pkg/assets" "k8s.io/kops/upup/pkg/fi" "k8s.io/kops/util/pkg/architectures" @@ -32,11 +32,11 @@ const ( runcVersionUrlArm64 = "https://github.com/opencontainers/runc/releases/download/v%s/runc.arm64" ) -func FindRuncAsset(c *kops.Cluster, assetBuilder *assets.AssetBuilder, arch architectures.Architecture) (*assets.FileAsset, error) { - if c.Spec.Containerd == nil { +func FindRuncAsset(ig model.InstanceGroup, assetBuilder *assets.AssetBuilder, arch architectures.Architecture) (*assets.FileAsset, error) { + containerd := ig.ClusterSpec().Containerd + if containerd == nil { return nil, fmt.Errorf("unable to find containerd config") } - containerd := c.Spec.Containerd containerdVersion, err := semver.ParseTolerant(fi.ValueOf(containerd.Version)) if err != nil {