diff --git a/cmd/kops/create_cluster.go b/cmd/kops/create_cluster.go index 164005a0d87e3..f0208013f9596 100644 --- a/cmd/kops/create_cluster.go +++ b/cmd/kops/create_cluster.go @@ -68,6 +68,7 @@ type CreateClusterOptions struct { ControlPlaneVolumeSize int32 NodeVolumeSize int32 + ControlPlaneVolumeType string ContainerRuntime string OutDir string DisableSubnetTags bool @@ -301,6 +302,8 @@ func NewCmdCreateCluster(f *util.Factory, out io.Writer) *cobra.Command { cmd.Flags().Int32Var(&options.ControlPlaneVolumeSize, "control-plane-volume-size", options.ControlPlaneVolumeSize, "Instance volume size (in GB) for control-plane nodes") cmd.Flags().Int32Var(&options.NodeVolumeSize, "node-volume-size", options.NodeVolumeSize, "Instance volume size (in GB) for worker nodes") + cmd.Flags().StringVar(&options.ControlPlaneVolumeType, "control-plane-volume-type", options.ControlPlaneVolumeType, "Instance volume type for control-plane nodes") + cmd.Flags().StringVar(&options.NetworkID, "vpc", options.NetworkID, "Shared Network or VPC to use") cmd.Flags().MarkDeprecated("vpc", "use --network-id instead") cmd.RegisterFlagCompletionFunc("vpc", completeNetworkID) @@ -616,6 +619,15 @@ func RunCreateCluster(ctx context.Context, f *util.Factory, out io.Writer, c *Cr } } + if c.ControlPlaneVolumeType != "" { + for _, group := range controlPlanes { + if group.Spec.RootVolume == nil { + group.Spec.RootVolume = &api.InstanceRootVolumeSpec{} + } + group.Spec.RootVolume.Type = fi.PtrTo(c.ControlPlaneVolumeType) + } + } + if c.NodeVolumeSize != 0 { for _, group := range nodes { if group.Spec.RootVolume == nil { diff --git a/cmd/kops/create_cluster_integration_test.go b/cmd/kops/create_cluster_integration_test.go index 5f5723da7ec73..b24a1272a9124 100644 --- a/cmd/kops/create_cluster_integration_test.go +++ b/cmd/kops/create_cluster_integration_test.go @@ -81,6 +81,11 @@ func TestCreateClusterCilium(t *testing.T) { runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/cilium-eni", "v1alpha2") } +// TestCreateClusterVolumeType tests the control plane volume type flag +func TestCreateClusterVolumeType(t *testing.T) { + runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/volume_type", "v1alpha2") +} + // TestCreateClusterOverride tests the override flag func TestCreateClusterOverride(t *testing.T) { runCreateClusterIntegrationTest(t, "../../tests/integration/create_cluster/overrides", "v1alpha2") diff --git a/pkg/apis/kops/validation/instancegroup.go b/pkg/apis/kops/validation/instancegroup.go index 6bdf949d8f448..3a66cbb70637b 100644 --- a/pkg/apis/kops/validation/instancegroup.go +++ b/pkg/apis/kops/validation/instancegroup.go @@ -287,6 +287,7 @@ func CrossValidateInstanceGroup(g *kops.InstanceGroup, cluster *kops.Cluster, cl allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "warmPool", "minSize"), warmPool.MinSize, "warm pool minSize cannot be negative")) } } + //TODO: Add RootVolume validation for other cloud providers ex. GCE if g.Spec.Containerd != nil { allErrs = append(allErrs, validateContainerdConfig(cluster, g.Spec.Containerd, field.NewPath("spec", "containerd"), false)...) @@ -312,6 +313,10 @@ func ValidateControlPlaneInstanceGroup(g *kops.InstanceGroup, cluster *kops.Clus return allErrs } +func validateRootVolumeType(g *kops.InstanceGroup) { + +} + var validUserDataTypes = []string{ "text/x-include-once-url", "text/x-include-url", diff --git a/tests/integration/create_cluster/volume_type/expected-v1alpha2.yaml b/tests/integration/create_cluster/volume_type/expected-v1alpha2.yaml new file mode 100644 index 0000000000000..b1a049c8b49db --- /dev/null +++ b/tests/integration/create_cluster/volume_type/expected-v1alpha2.yaml @@ -0,0 +1,99 @@ +apiVersion: kops.k8s.io/v1alpha2 +kind: Cluster +metadata: + creationTimestamp: "2017-01-01T00:00:00Z" + name: volume-types.example.com +spec: + api: + loadBalancer: + type: Public + authorization: + rbac: {} + channel: stable + cloudConfig: {} + cloudProvider: gce + configBase: memfs://tests/volume-types.example.com + etcdClusters: + - cpuRequest: 200m + etcdMembers: + - instanceGroup: control-plane-us-test1-a + name: a + manager: + backupRetentionDays: 90 + memoryRequest: 100Mi + name: main + - cpuRequest: 100m + etcdMembers: + - instanceGroup: control-plane-us-test1-a + name: a + manager: + backupRetentionDays: 90 + memoryRequest: 100Mi + name: events + iam: + allowContainerRegistry: true + legacy: false + kubelet: + anonymousAuth: false + kubernetesApiAccess: + - 0.0.0.0/0 + - ::/0 + kubernetesVersion: v1.32.0 + networking: + cni: {} + nonMasqueradeCIDR: 100.64.0.0/10 + project: testproject + sshAccess: + - 0.0.0.0/0 + - ::/0 + subnets: + - cidr: 10.0.16.0/20 + name: us-test1 + region: us-test1 + type: Public + topology: + dns: + type: None + +--- + +apiVersion: kops.k8s.io/v1alpha2 +kind: InstanceGroup +metadata: + creationTimestamp: "2017-01-01T00:00:00Z" + labels: + kops.k8s.io/cluster: volume-types.example.com + name: control-plane-us-test1-a +spec: + image: ubuntu-os-cloud/ubuntu-2404-noble-amd64-v20250606 + machineType: e2-medium + maxSize: 1 + minSize: 1 + role: Master + rootVolumeSize: 32 + rootVolumeType: pd-balanced + subnets: + - us-test1 + zones: + - us-test1-a + +--- + +apiVersion: kops.k8s.io/v1alpha2 +kind: InstanceGroup +metadata: + creationTimestamp: "2017-01-01T00:00:00Z" + labels: + kops.k8s.io/cluster: volume-types.example.com + name: nodes-us-test1-a +spec: + image: ubuntu-os-cloud/ubuntu-2404-noble-amd64-v20250606 + machineType: e2-medium + maxSize: 1 + minSize: 1 + role: Node + rootVolumeSize: 64 + subnets: + - us-test1 + zones: + - us-test1-a diff --git a/tests/integration/create_cluster/volume_type/options.yaml b/tests/integration/create_cluster/volume_type/options.yaml new file mode 100644 index 0000000000000..c762cc89af5e1 --- /dev/null +++ b/tests/integration/create_cluster/volume_type/options.yaml @@ -0,0 +1,10 @@ +ClusterName: volume-types.example.com +Zones: +- us-test1-a +CloudProvider: gce +Networking: cni +Project: testproject +KubernetesVersion: v1.32.0 +ControlPlaneVolumeSize: 32 +ControlPlaneVolumeType: pd-balanced +NodeVolumeSize: 64 \ No newline at end of file