diff --git a/pkg/controller/infrastructure/actuator_delete.go b/pkg/controller/infrastructure/actuator_delete.go index 199b154c1..2cdd306d6 100644 --- a/pkg/controller/infrastructure/actuator_delete.go +++ b/pkg/controller/infrastructure/actuator_delete.go @@ -38,8 +38,18 @@ func (a *actuator) delete(ctx context.Context, infra *extensionsv1alpha1.Infrast return err } + infraStatus, err := transcoder.DecodeInfrastructureStatusFromInfrastructure(infra) + if err != nil { + return err + } + client := apis.GetClientForToken(string(actuatorConfig.token)) + err = ensurer.EnsureSSHPublicKeyDeleted(ctx, client, infraStatus.SSHFingerprint) + if err != nil { + return err + } + err = ensurer.EnsureNetworksDeleted(ctx, client, infra.Namespace, actuatorConfig.infraConfig.Networks) if err != nil { return err diff --git a/pkg/controller/infrastructure/actuator_reconcile.go b/pkg/controller/infrastructure/actuator_reconcile.go index 1bfecdbda..e00fb3a11 100644 --- a/pkg/controller/infrastructure/actuator_reconcile.go +++ b/pkg/controller/infrastructure/actuator_reconcile.go @@ -43,7 +43,7 @@ func (a *actuator) reconcile(ctx context.Context, infra *extensionsv1alpha1.Infr client := apis.GetClientForToken(string(actuatorConfig.token)) - err = ensurer.EnsureSSHPublicKey(ctx, client, infra.Spec.SSHPublicKey) + sshFingerprint, err := ensurer.EnsureSSHPublicKey(ctx, client, infra.Spec.SSHPublicKey) if err != nil { return err } @@ -58,6 +58,7 @@ func (a *actuator) reconcile(ctx context.Context, infra *extensionsv1alpha1.Infr APIVersion: v1alpha1.SchemeGroupVersion.String(), Kind: "InfrastructureStatus", }, + SSHFingerprint: sshFingerprint, } if "" != infraConfig.FloatingPoolName { diff --git a/pkg/controller/infrastructure/ensurer/ssh_public_key.go b/pkg/controller/infrastructure/ensurer/ssh_public_key.go index 49e53fb55..9fa2e1d45 100644 --- a/pkg/controller/infrastructure/ensurer/ssh_public_key.go +++ b/pkg/controller/infrastructure/ensurer/ssh_public_key.go @@ -19,23 +19,44 @@ package ensurer import ( "context" + "crypto/md5" + "encoding/base64" + "encoding/hex" "fmt" + "strings" - "github.com/23technologies/gardener-extension-provider-hcloud/pkg/hcloud/apis/transcoder" "github.com/hetznercloud/hcloud-go/hcloud" ) -func EnsureSSHPublicKey(ctx context.Context, client *hcloud.Client, publicKey []byte) error { - fingerprint, err := transcoder.DecodeSSHFingerprintFromPublicKey(publicKey) - if nil != err { - return err +func EnsureSSHPublicKey(ctx context.Context, client *hcloud.Client, publicKey []byte) (string, error) { + if len(publicKey) == 0 { + return "", fmt.Errorf("SSH public key given is empty") + } + + publicKeyData := strings.SplitN(string(publicKey), " ", 3) + if len(publicKeyData) < 2 { + return "", fmt.Errorf("SSH public key has invalid format") + } + + publicKey, err := base64.StdEncoding.DecodeString(publicKeyData[1]) + if err != nil { + return "", err } + publicKeyMD5 := md5.Sum(publicKey) + fingerprintArray := make([]string, len(publicKeyMD5)) + + for i, c := range publicKeyMD5 { + fingerprintArray[i] = hex.EncodeToString([]byte{c}) + } + + fingerprint := strings.Join(fingerprintArray, ":") + labels := map[string]string{ "hcloud.provider.extensions.gardener.cloud/role": "infrastructure-ssh-v1" } sshKey, _, err := client.SSHKey.GetByFingerprint(ctx, fingerprint) if nil != err { - return err + return "", err } else if sshKey == nil { opts := hcloud.SSHKeyCreateOpts{ Name: fmt.Sprintf("infrastructure-ssh-%s", fingerprint), @@ -44,6 +65,20 @@ func EnsureSSHPublicKey(ctx context.Context, client *hcloud.Client, publicKey [] } _, _, err := client.SSHKey.Create(ctx, opts) + if nil != err { + return "", err + } + } + + return fingerprint, nil +} + +func EnsureSSHPublicKeyDeleted(ctx context.Context, client *hcloud.Client, fingerprint string) error { + sshKey, _, err := client.SSHKey.GetByFingerprint(ctx, fingerprint) + if nil != err { + return err + } else if sshKey != nil { + _, err := client.SSHKey.Delete(ctx, sshKey) if nil != err { return err } diff --git a/pkg/controller/worker/machines.go b/pkg/controller/worker/machines.go index ee33876e5..0ea6a7580 100644 --- a/pkg/controller/worker/machines.go +++ b/pkg/controller/worker/machines.go @@ -60,6 +60,7 @@ func (w *workerDelegate) DeployMachineClasses(ctx context.Context) error { return err } } + return w.seedChartApplier.Apply(ctx, filepath.Join(hcloud.InternalChartsPath, "machineclass"), w.worker.Namespace, "machineclass", kubernetes.Values(map[string]interface{}{"machineClasses": w.machineClasses})) } @@ -110,11 +111,6 @@ func (w *workerDelegate) generateMachineConfig(ctx context.Context) error { return err } - sshFingerprint, err := transcoder.DecodeSSHFingerprintFromPublicKey(w.worker.Spec.SSHPublicKey) - if err != nil { - return err - } - if len(w.worker.Spec.Pools) == 0 { return fmt.Errorf("missing pool") } @@ -137,18 +133,18 @@ func (w *workerDelegate) generateMachineConfig(ctx context.Context) error { for _, zone := range pool.Zones { secretMap := map[string]interface{}{ - "userData": string(pool.UserData), + "userData": pool.UserData, } for key, value := range machineClassSecretData { - secretMap[key] = string(value) + secretMap[key] = value } machineClassSpec := map[string]interface{}{ "cluster": w.worker.Namespace, "zone": zone, "imageName": string(imageName), - "sshFingerprint": sshFingerprint, + "sshFingerprint": infraStatus.SSHFingerprint, "machineType": string(pool.MachineType), "networkName": fmt.Sprintf("%s-workers", w.worker.Namespace), "tags": map[string]string{ diff --git a/pkg/hcloud/apis/config/v1alpha1/zz_generated.conversion.go b/pkg/hcloud/apis/config/v1alpha1/zz_generated.conversion.go index b480d0d01..6d289cb41 100644 --- a/pkg/hcloud/apis/config/v1alpha1/zz_generated.conversion.go +++ b/pkg/hcloud/apis/config/v1alpha1/zz_generated.conversion.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/pkg/hcloud/apis/config/v1alpha1/zz_generated.deepcopy.go b/pkg/hcloud/apis/config/v1alpha1/zz_generated.deepcopy.go index 76416c95a..4f9af8d1d 100644 --- a/pkg/hcloud/apis/config/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/hcloud/apis/config/v1alpha1/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/pkg/hcloud/apis/config/v1alpha1/zz_generated.defaults.go b/pkg/hcloud/apis/config/v1alpha1/zz_generated.defaults.go index 95e01b69d..fe2d0232f 100644 --- a/pkg/hcloud/apis/config/v1alpha1/zz_generated.defaults.go +++ b/pkg/hcloud/apis/config/v1alpha1/zz_generated.defaults.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/pkg/hcloud/apis/config/zz_generated.deepcopy.go b/pkg/hcloud/apis/config/zz_generated.deepcopy.go index 6e05db7b3..d5840b7d0 100644 --- a/pkg/hcloud/apis/config/zz_generated.deepcopy.go +++ b/pkg/hcloud/apis/config/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/pkg/hcloud/apis/mock/worker.go b/pkg/hcloud/apis/mock/worker.go index fcd73c5ef..bc5466067 100644 --- a/pkg/hcloud/apis/mock/worker.go +++ b/pkg/hcloud/apis/mock/worker.go @@ -18,6 +18,7 @@ limitations under the License. package mock import ( + "fmt" "net/http" "regexp" "strconv" @@ -31,9 +32,10 @@ import ( ) const ( - TestWorkerInfrastructureProviderStatus = `{ + TestWorkerInfrastructureProviderStatusTemplate = `{ "apiVersion": "hcloud.provider.extensions.gardener.cloud/v1alpha1", "kind": "InfrastructureStatus", + "sshFingerprint": %q, "floatingPoolName": "MY-FLOATING-POOL" }` TestWorkerMachineImageName = "ubuntu" @@ -59,7 +61,7 @@ func NewWorker() *v1alpha1.Worker { }, Region: TestRegion, InfrastructureProviderStatus: &runtime.RawExtension{ - Raw: []byte(TestWorkerInfrastructureProviderStatus), + Raw: []byte(fmt.Sprintf(TestWorkerInfrastructureProviderStatusTemplate, TestSSHFingerprint)), }, Pools: []v1alpha1.WorkerPool{ { diff --git a/pkg/hcloud/apis/transcoder/infrastructure.go b/pkg/hcloud/apis/transcoder/infrastructure.go index f329a1a9c..b66e01a6e 100644 --- a/pkg/hcloud/apis/transcoder/infrastructure.go +++ b/pkg/hcloud/apis/transcoder/infrastructure.go @@ -89,3 +89,12 @@ func DecodeInfrastructureStatus(infra *runtime.RawExtension) (*apis.Infrastructu return infraStatus, nil } + +func DecodeInfrastructureStatusFromInfrastructure(infra *v1alpha1.Infrastructure) (*apis.InfrastructureStatus, error) { + infraStatus, err := DecodeInfrastructureStatus(infra.Status.ProviderStatus) + if err != nil { + return nil, err + } + + return infraStatus, nil +} diff --git a/pkg/hcloud/apis/types_infrastructure.go b/pkg/hcloud/apis/types_infrastructure.go index ef5ed72f0..7af3219e8 100644 --- a/pkg/hcloud/apis/types_infrastructure.go +++ b/pkg/hcloud/apis/types_infrastructure.go @@ -43,6 +43,8 @@ type Networks struct { // InfrastructureStatus contains information about created infrastructure resources. type InfrastructureStatus struct { metav1.TypeMeta `json:",inline"` + // SSHFingerprint contains the SSH fingerprint. + SSHFingerprint string `json:"sshFingerprint,omitempty"` // FloatingPoolName contains the FloatingPoolName name in which LoadBalancer FIPs should be created. // +optional diff --git a/pkg/hcloud/apis/v1alpha1/types_infrastructure.go b/pkg/hcloud/apis/v1alpha1/types_infrastructure.go index ed5867358..7a7f97dbb 100644 --- a/pkg/hcloud/apis/v1alpha1/types_infrastructure.go +++ b/pkg/hcloud/apis/v1alpha1/types_infrastructure.go @@ -44,6 +44,8 @@ type Networks struct { // InfrastructureStatus contains information about created infrastructure resources. type InfrastructureStatus struct { metav1.TypeMeta `json:",inline"` + // SSHFingerprint contains the SSH fingerprint. + SSHFingerprint string `json:"sshFingerprint,omitempty"` // FloatingPoolName contains the FloatingPoolName name in which LoadBalancer FIPs should be created. // +optional diff --git a/pkg/hcloud/apis/v1alpha1/zz_generated.conversion.go b/pkg/hcloud/apis/v1alpha1/zz_generated.conversion.go index 1cdf53815..309bf0aaf 100644 --- a/pkg/hcloud/apis/v1alpha1/zz_generated.conversion.go +++ b/pkg/hcloud/apis/v1alpha1/zz_generated.conversion.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* @@ -333,6 +334,7 @@ func Convert_apis_InfrastructureConfig_To_v1alpha1_InfrastructureConfig(in *apis } func autoConvert_v1alpha1_InfrastructureStatus_To_apis_InfrastructureStatus(in *InfrastructureStatus, out *apis.InfrastructureStatus, s conversion.Scope) error { + out.SSHFingerprint = in.SSHFingerprint out.FloatingPoolName = in.FloatingPoolName out.NetworkIDs = (*apis.NetworkIDs)(unsafe.Pointer(in.NetworkIDs)) return nil @@ -344,6 +346,7 @@ func Convert_v1alpha1_InfrastructureStatus_To_apis_InfrastructureStatus(in *Infr } func autoConvert_apis_InfrastructureStatus_To_v1alpha1_InfrastructureStatus(in *apis.InfrastructureStatus, out *InfrastructureStatus, s conversion.Scope) error { + out.SSHFingerprint = in.SSHFingerprint out.FloatingPoolName = in.FloatingPoolName out.NetworkIDs = (*NetworkIDs)(unsafe.Pointer(in.NetworkIDs)) return nil diff --git a/pkg/hcloud/apis/v1alpha1/zz_generated.deepcopy.go b/pkg/hcloud/apis/v1alpha1/zz_generated.deepcopy.go index 904a0d3e8..77fe0a48c 100644 --- a/pkg/hcloud/apis/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/hcloud/apis/v1alpha1/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/pkg/hcloud/apis/v1alpha1/zz_generated.defaults.go b/pkg/hcloud/apis/v1alpha1/zz_generated.defaults.go index 95e01b69d..fe2d0232f 100644 --- a/pkg/hcloud/apis/v1alpha1/zz_generated.defaults.go +++ b/pkg/hcloud/apis/v1alpha1/zz_generated.defaults.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/pkg/hcloud/apis/zz_generated.deepcopy.go b/pkg/hcloud/apis/zz_generated.deepcopy.go index bb85b3989..b8b3cc078 100644 --- a/pkg/hcloud/apis/zz_generated.deepcopy.go +++ b/pkg/hcloud/apis/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /*