diff --git a/charts/internal/machineclass/values.yaml b/charts/internal/machineclass/values.yaml index f5d837810..89abf40b1 100644 --- a/charts/internal/machineclass/values.yaml +++ b/charts/internal/machineclass/values.yaml @@ -1,34 +1,17 @@ machineClasses: - name: class-1 - region: myregion - datacenter: dc1 - #hostSystem: esxi1 - #resourcePool: pool1 - computeCluster: cluster1 - network: network1 - #switchUuid: "11 22-33 44" - folder: gardener - datastore: datastore1 - #datastoreCluster: ds-cluster - templateVM: "gardener/templates/coreos-2191.5.0" - guestId: coreos64Guest - numCpus: 2 - memory: 4096 - #memoryReservationLockedToMax: true - #extraConfig: - # sched.swap.vmxSwapEnabled: "false" - systemDisk: - size: 20 - description: An optional description for machines created by that class. - machineType: t1.small + cluster: shoot--foobar--hcloud + zone: hel1-dc2 + machineType: cx11 + imageName: ubuntu-20.04 + sshFingerprint: "00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff" + networkName: test-namespace-workers + floatingPoolName: MY-FLOATING-POOL sshKeys: - 12345-abcd567-aaf2 secret: - cloudConfig: abc - vsphereHost: "a_host" - vsphereUsername: "a_user" - vspherePassword: "a_password" - vsphereInsecureSSL: "true" + hcloudToken: base64token + userData: IyEvYmluL2Jhc2gKCmVjaG8gImhlbGxvIHdvcmxkIgo= tags: - - kubernetes.io/cluster/foo - - kubernetes.io/role/node + mcm.gardener.cloud/cluster: shoot--foobar--hcloud + mcm.gardener.cloud/role: node diff --git a/example/30-controlplane.yaml b/example/30-controlplane.yaml index 37c1f330b..9b3c9751a 100644 --- a/example/30-controlplane.yaml +++ b/example/30-controlplane.yaml @@ -25,6 +25,10 @@ spec: apiVersion: core.gardener.cloud/v1alpha1 kind: CloudProfile spec: + regions: + - name: hel1 + zones: + - name: hel1-dc2 providerConfig: apiVersion: hcloud.provider.extensions.gardener.cloud/v1alpha1 kind: CloudProfileConfig @@ -60,7 +64,7 @@ metadata: namespace: shoot--foobar--hcloud spec: type: hcloud - region: hel1-dc2 + region: hel1 secretRef: name: cloudprovider namespace: shoot--foobar--hcloud @@ -68,6 +72,7 @@ spec: apiVersion: hcloud.provider.extensions.gardener.cloud/v1alpha1 kind: ControlPlaneConfig loadBalancerProvider: hcloud + zone: hel1-dc2 cloudControllerManager: featureGates: CustomResourceValidation: true diff --git a/example/30-infrastructure.yaml b/example/30-infrastructure.yaml index fecb4d936..ca1c4ba39 100644 --- a/example/30-infrastructure.yaml +++ b/example/30-infrastructure.yaml @@ -13,7 +13,6 @@ metadata: type: Opaque data: hcloudToken: base64token - --- apiVersion: extensions.gardener.cloud/v1alpha1 kind: Cluster @@ -25,21 +24,20 @@ spec: kind: CloudProfile spec: regions: - - name: hel1-dc2 + - name: hel1 machineTypes: - name: cx11 providerConfig: apiVersion: hcloud.provider.extensions.gardener.cloud/v1alpha1 kind: CloudProfileConfig regions: - - name: hel1-dc2 + - name: hel1 machineImages: - name: ubuntu versions: - version: "20.04" machineTypes: - name: cx11 - seed: apiVersion: core.gardener.cloud/v1alpha1 kind: Seed @@ -49,7 +47,7 @@ spec: spec: kubernetes: version: 1.13.4 - region: hel1-dc2 + region: hel1 cloud: hcloud: test: foo @@ -65,7 +63,7 @@ metadata: namespace: shoot--foobar--hcloud spec: type: hcloud - region: hel1-dc2 + region: hel1 secretRef: name: cloudprovider namespace: shoot--foobar--hcloud diff --git a/example/30-worker.yaml b/example/30-worker.yaml index b577b70ff..b2ef81ce4 100644 --- a/example/30-worker.yaml +++ b/example/30-worker.yaml @@ -19,14 +19,14 @@ spec: kind: CloudProfile spec: regions: - - name: hel1-dc2 + - name: hel1 machineTypes: - name: cx11 providerConfig: apiVersion: hcloud.provider.extensions.gardener.cloud/v1alpha1 kind: CloudProfileConfig regions: - - name: hel1-dc2 + - name: hel1 machineImages: - name: ubuntu versions: @@ -43,7 +43,7 @@ spec: spec: kubernetes: version: 1.13.4 - region: hel1-dc2 + region: hel1 cloud: hcloud: test: foo @@ -60,7 +60,7 @@ metadata: gardener.cloud/operation: reconcile spec: type: hcloud - region: hel1-dc2 + region: hel1 infrastructureProviderStatus: apiVersion: hcloud.provider.extensions.gardener.cloud/v1alpha1 kind: InfrastructureStatus @@ -75,6 +75,8 @@ spec: maximum: 1 maxSurge: 1 maxUnavailable: 0 + zones: + - hel1-dc2 userData: IyEvYmluL2Jhc2gKCmVjaG8gImhlbGxvIHdvcmxkIgo= sshPublicKey: ZGF0YQo= secretRef: diff --git a/pkg/controller/controlplane/valuesprovider.go b/pkg/controller/controlplane/valuesprovider.go index 15437b0ec..bfba55873 100644 --- a/pkg/controller/controlplane/valuesprovider.go +++ b/pkg/controller/controlplane/valuesprovider.go @@ -382,20 +382,9 @@ func (vp *valuesProvider) getControlPlaneChartValues( checksums map[string]string, scaledDown bool, ) (map[string]interface{}, error) { - cloudProfileConfig, err := transcoder.DecodeCloudProfileConfigFromControllerCluster(cluster) - if err != nil { - return nil, err - } - - regionSpec := apis.FindRegionSpecForGardenerRegion(cluster.Shoot.Spec.Region, cloudProfileConfig) - if regionSpec == nil { - return nil, fmt.Errorf("Region %q not found in cloud profile config", cluster.Shoot.Spec.Region) - } - clusterID, csiClusterID := vp.calcClusterIDs(cp) - region := apis.GetRegionFromZone(regionSpec.Name) + region := apis.GetRegionFromZone(cpConfig.Zone) - // csiResizerEnabled := cloudProfileConfig.CSIResizerDisabled == nil || !*cloudProfileConfig.CSIResizerDisabled values := map[string]interface{}{ "hcloud-cloud-controller-manager": map[string]interface{}{ "replicas": extensionscontroller.GetControlPlaneReplicas(cluster, scaledDown, 1), diff --git a/pkg/controller/infrastructure/actuator.go b/pkg/controller/infrastructure/actuator.go index 142fc466e..aa1328a7b 100644 --- a/pkg/controller/infrastructure/actuator.go +++ b/pkg/controller/infrastructure/actuator.go @@ -19,7 +19,6 @@ package infrastructure import ( "context" - "fmt" "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud" "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud/apis" @@ -45,7 +44,6 @@ type actuator struct { type actuatorConfig struct { cloudProfileConfig *apis.CloudProfileConfig infraConfig *apis.InfrastructureConfig - region *apis.RegionSpec token string } @@ -68,11 +66,6 @@ func (a *actuator) getActuatorConfig(ctx context.Context, infra *extensionsv1alp return nil, err } - regionSpec := apis.FindRegionSpecForGardenerRegion(infra.Spec.Region, cloudProfileConfig) - if regionSpec == nil { - return nil, fmt.Errorf("Region %q not found in cloud profile", infra.Spec.Region) - } - secret, err := controller.GetSecretByReference(ctx, a.Client(), &infra.Spec.SecretRef) if err != nil { return nil, err @@ -88,7 +81,6 @@ func (a *actuator) getActuatorConfig(ctx context.Context, infra *extensionsv1alp config := &actuatorConfig{ cloudProfileConfig: cloudProfileConfig, infraConfig: infraConfig, - region: regionSpec, token: token, } diff --git a/pkg/controller/worker/machines.go b/pkg/controller/worker/machines.go index c2926ace3..ee33876e5 100644 --- a/pkg/controller/worker/machines.go +++ b/pkg/controller/worker/machines.go @@ -135,58 +135,60 @@ func (w *workerDelegate) generateMachineConfig(ctx context.Context) error { return errors.Wrap(err, "extracting machine values failed") } - machineClassSpec := map[string]interface{}{ - "cluster": w.worker.Namespace, - "zone": string(w.worker.Spec.Region), - "imageName": imageName, - "sshFingerprint": sshFingerprint, - "machineType": string(pool.MachineType), - "networkName": fmt.Sprintf("%s-workers", w.worker.Namespace), - "tags": map[string]string{ - "mcm.gardener.cloud/cluster": w.worker.Namespace, - "mcm.gardener.cloud/role": "node", - }, - "secret": map[string]interface{}{ + for _, zone := range pool.Zones { + secretMap := map[string]interface{}{ "userData": string(pool.UserData), - }, - } + } - if "" != infraStatus.FloatingPoolName { - machineClassSpec["floatingPoolName"] = infraStatus.FloatingPoolName - } + for key, value := range machineClassSecretData { + secretMap[key] = string(value) + } - if values.MachineTypeOptions != nil { - if len(values.MachineTypeOptions.ExtraConfig) > 0 { - machineClassSpec["extraConfig"] = values.MachineTypeOptions.ExtraConfig + machineClassSpec := map[string]interface{}{ + "cluster": w.worker.Namespace, + "zone": zone, + "imageName": string(imageName), + "sshFingerprint": sshFingerprint, + "machineType": string(pool.MachineType), + "networkName": fmt.Sprintf("%s-workers", w.worker.Namespace), + "tags": map[string]string{ + "mcm.gardener.cloud/cluster": w.worker.Namespace, + "mcm.gardener.cloud/role": "node", + }, + "secret": secretMap, } - } - var ( - deploymentName = fmt.Sprintf("%s-%s", w.worker.Namespace, pool.Name) - className = fmt.Sprintf("%s-%s", deploymentName, workerPoolHash) - ) - - machineDeployments = append(machineDeployments, worker.MachineDeployment{ - Name: deploymentName, - ClassName: className, - SecretName: className, - Minimum: pool.Minimum, - Maximum: pool.Maximum, - MaxSurge: pool.MaxSurge, - MaxUnavailable: pool.MaxUnavailable, - Labels: pool.Labels, - Annotations: pool.Annotations, - Taints: pool.Taints, - MachineConfiguration: genericworkeractuator.ReadMachineConfiguration(pool), - }) - - machineClassSpec["name"] = className - secretMap := machineClassSpec["secret"].(map[string]interface{}) - for k, v := range machineClassSecretData { - secretMap[k] = string(v) - } + if "" != infraStatus.FloatingPoolName { + machineClassSpec["floatingPoolName"] = infraStatus.FloatingPoolName + } - machineClasses = append(machineClasses, machineClassSpec) + if values.MachineTypeOptions != nil { + if len(values.MachineTypeOptions.ExtraConfig) > 0 { + machineClassSpec["extraConfig"] = values.MachineTypeOptions.ExtraConfig + } + } + + deploymentName := fmt.Sprintf("%s-%s-%s", w.worker.Namespace, pool.Name, zone) + className := fmt.Sprintf("%s-%s", deploymentName, workerPoolHash) + + machineDeployments = append(machineDeployments, worker.MachineDeployment{ + Name: deploymentName, + ClassName: className, + SecretName: className, + Minimum: pool.Minimum, + Maximum: pool.Maximum, + MaxSurge: pool.MaxSurge, + MaxUnavailable: pool.MaxUnavailable, + Labels: pool.Labels, + Annotations: pool.Annotations, + Taints: pool.Taints, + MachineConfiguration: genericworkeractuator.ReadMachineConfiguration(pool), + }) + + machineClassSpec["name"] = className + + machineClasses = append(machineClasses, machineClassSpec) + } } w.machineDeployments = machineDeployments diff --git a/pkg/hcloud/apis/mock/cluster.go b/pkg/hcloud/apis/mock/cluster.go index 49ba65655..cf023e8bf 100644 --- a/pkg/hcloud/apis/mock/cluster.go +++ b/pkg/hcloud/apis/mock/cluster.go @@ -30,12 +30,12 @@ const ( "apiVersion": "core.gardener.cloud/v1alpha1", "kind": "CloudProfile", "spec": { - "regions": [{"name": "hel1-dc2"}], + "regions": [{"name": "hel1", "zones": [{"name": "hel1-dc2"}]}], "machineTypes": [{"name": "cx11"}], "providerConfig": { "apiVersion": "hcloud.provider.extensions.gardener.cloud/v1alpha1", "kind": "CloudProfileConfig", - "regions": [{"name": "hel1-dc2"}], + "regions": [{"name": "hel1"}], "machineImages": [{"name": "ubuntu", "versions": [{"version": "20.04"}]}], "machineTypes": [{"name": "cx11"}] } @@ -51,7 +51,7 @@ const ( "spec": { "kubernetes": {"version": "1.13.4"}, "cloud": {"hcloud": {"test": "foo"}}, - "region": "hel1-dc2", + "region": "hel1", "status": { "lastOperation": {"state": "Succeeded"} } diff --git a/pkg/hcloud/apis/mock/infrastructure.go b/pkg/hcloud/apis/mock/infrastructure.go index 6199b0642..71e1e94c9 100644 --- a/pkg/hcloud/apis/mock/infrastructure.go +++ b/pkg/hcloud/apis/mock/infrastructure.go @@ -29,7 +29,8 @@ import ( const ( TestInfrastructureName = "abc" - TestInfrastructureRegion = "hel1-dc2" + TestInfrastructureRegion = "hel1" + TestInfrastructureZone = "hel1-dc2" TestInfrastructureSecretName = "cloudprovider" TestInfrastructureSpecFloatingPoolName = "MY-FLOATING-POOL" TestInfrastructureSpecProviderConfig = `{ diff --git a/pkg/hcloud/apis/types_controlplane.go b/pkg/hcloud/apis/types_controlplane.go index 9571fb3fa..b9687a61c 100644 --- a/pkg/hcloud/apis/types_controlplane.go +++ b/pkg/hcloud/apis/types_controlplane.go @@ -27,6 +27,9 @@ import ( type ControlPlaneConfig struct { metav1.TypeMeta + // Zone is the HCloud zone. + Zone string `json:"zone"` + // CloudControllerManager contains configuration settings for the cloud-controller-manager. CloudControllerManager *CloudControllerManagerConfig // LoadBalancerClasses lists the load balancer classes to be used. diff --git a/pkg/hcloud/apis/utils.go b/pkg/hcloud/apis/utils.go index 7e76bb495..dd59b9856 100644 --- a/pkg/hcloud/apis/utils.go +++ b/pkg/hcloud/apis/utils.go @@ -24,13 +24,3 @@ func GetRegionFromZone(zone string) string { zoneData := strings.SplitN(zone, "-", 2) return zoneData[0] } - -// FindRegionSpecForGardenerRegion finds a RegionSpec by name in the cloud profile config -func FindRegionSpecForGardenerRegion(name string, cloudProfileConfig *CloudProfileConfig) *RegionSpec { - for _, r := range cloudProfileConfig.Regions { - if r.Name == name { - return &r - } - } - return nil -} diff --git a/pkg/hcloud/apis/v1alpha1/types_controlplane.go b/pkg/hcloud/apis/v1alpha1/types_controlplane.go index b8d871908..9caa9f597 100644 --- a/pkg/hcloud/apis/v1alpha1/types_controlplane.go +++ b/pkg/hcloud/apis/v1alpha1/types_controlplane.go @@ -26,6 +26,9 @@ import ( type ControlPlaneConfig struct { metav1.TypeMeta `json:",inline"` + // Zone is the HCloud zone. + Zone string `json:"zone"` + // CloudControllerManager contains configuration settings for the cloud-controller-manager. // +optional CloudControllerManager *CloudControllerManagerConfig `json:"cloudControllerManager,omitempty"` diff --git a/pkg/hcloud/apis/v1alpha1/zz_generated.conversion.go b/pkg/hcloud/apis/v1alpha1/zz_generated.conversion.go index 308237c9f..1cdf53815 100644 --- a/pkg/hcloud/apis/v1alpha1/zz_generated.conversion.go +++ b/pkg/hcloud/apis/v1alpha1/zz_generated.conversion.go @@ -263,6 +263,7 @@ func Convert_apis_CloudProfileConfig_To_v1alpha1_CloudProfileConfig(in *apis.Clo } func autoConvert_v1alpha1_ControlPlaneConfig_To_apis_ControlPlaneConfig(in *ControlPlaneConfig, out *apis.ControlPlaneConfig, s conversion.Scope) error { + out.Zone = in.Zone out.CloudControllerManager = (*apis.CloudControllerManagerConfig)(unsafe.Pointer(in.CloudControllerManager)) out.LoadBalancerClasses = *(*[]apis.CPLoadBalancerClass)(unsafe.Pointer(&in.LoadBalancerClasses)) out.LoadBalancerSize = (*string)(unsafe.Pointer(in.LoadBalancerSize)) @@ -275,6 +276,7 @@ func Convert_v1alpha1_ControlPlaneConfig_To_apis_ControlPlaneConfig(in *ControlP } func autoConvert_apis_ControlPlaneConfig_To_v1alpha1_ControlPlaneConfig(in *apis.ControlPlaneConfig, out *ControlPlaneConfig, s conversion.Scope) error { + out.Zone = in.Zone out.CloudControllerManager = (*CloudControllerManagerConfig)(unsafe.Pointer(in.CloudControllerManager)) out.LoadBalancerClasses = *(*[]CPLoadBalancerClass)(unsafe.Pointer(&in.LoadBalancerClasses)) out.LoadBalancerSize = (*string)(unsafe.Pointer(in.LoadBalancerSize)) diff --git a/pkg/hcloud/apis/validation/controlplane.go b/pkg/hcloud/apis/validation/controlplane.go new file mode 100644 index 000000000..5db6dc2c4 --- /dev/null +++ b/pkg/hcloud/apis/validation/controlplane.go @@ -0,0 +1,39 @@ +/* +Copyright (c) 2021 SAP SE or an SAP affiliate company. All rights reserved. + +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 validation contains functions to validate controller specifications +package validation + +import ( + "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud/apis" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +// ValidateControlPlaneConfig validates a ControlPlaneConfig object. +func ValidateControlPlaneConfig(controlPlaneConfig *apis.ControlPlaneConfig, allowedZones, workerZones sets.String, version string, fldPath *field.Path) field.ErrorList { + allErrs := field.ErrorList{} + + if len(controlPlaneConfig.Zone) == 0 { + allErrs = append(allErrs, field.Required(fldPath.Child("zone"), "must provide the name of a zone in this region")) + } + + if !workerZones.Has(controlPlaneConfig.Zone) { + allErrs = append(allErrs, field.Invalid(fldPath.Child("zone"), controlPlaneConfig.Zone, "must be part of at least one worker zone")) + } + + return allErrs +} diff --git a/pkg/hcloud/apis/validation/shoot.go b/pkg/hcloud/apis/validation/workers.go similarity index 87% rename from pkg/hcloud/apis/validation/shoot.go rename to pkg/hcloud/apis/validation/workers.go index bf089b019..be5784d7d 100644 --- a/pkg/hcloud/apis/validation/shoot.go +++ b/pkg/hcloud/apis/validation/workers.go @@ -26,23 +26,11 @@ import ( "github.com/gardener/gardener/pkg/apis/core/validation" ) -// ValidateNetworking validates the network settings of a Shoot. -func ValidateNetworking(networking core.Networking, fldPath *field.Path) field.ErrorList { - allErrs := field.ErrorList{} - - if networking.Nodes == nil { - allErrs = append(allErrs, field.Required(fldPath.Child("nodes"), "a nodes CIDR must be provided for HCloud shoots")) - } - - return allErrs -} - // ValidateWorkers validates the workers of a Shoot. func ValidateWorkers(workers []core.Worker, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} for i, worker := range workers { - workerFldPath := fldPath.Index(i) if len(worker.Zones) == 0 { allErrs = append(allErrs, field.Required(workerFldPath.Child("zones"), "at least one zone must be configured"))