From 1556c2a6dc50751867f32cd9975b019db982db12 Mon Sep 17 00:00:00 2001 From: Bharath Nallapeta Date: Thu, 28 Nov 2024 16:39:27 +0530 Subject: [PATCH] Fix a golangci-lint issue: unparam namespace Signed-off-by: Bharath Nallapeta --- cmd/main.go | 2 + config/dev/openstack-credentials.yaml | 8 +- go.mod | 1 + go.sum | 2 + .../clusterdeployment_controller.go | 24 +- internal/credspropagation/azure.go | 3 +- internal/credspropagation/common.go | 17 +- internal/credspropagation/openstack.go | 226 +++++++++++++++--- internal/credspropagation/vsphere.go | 6 +- 9 files changed, 232 insertions(+), 57 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 03ee5f50..84c9944c 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -28,6 +28,7 @@ import ( clientgoscheme "k8s.io/client-go/kubernetes/scheme" _ "k8s.io/client-go/plugin/pkg/client/auth" capz "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" + capo "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1" capv "sigs.k8s.io/cluster-api-provider-vsphere/apis/v1beta1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/healthz" @@ -57,6 +58,7 @@ func init() { utilruntime.Must(sveltosv1beta1.AddToScheme(scheme)) utilruntime.Must(capz.AddToScheme(scheme)) utilruntime.Must(capv.AddToScheme(scheme)) + utilruntime.Must(capo.AddToScheme(scheme)) // +kubebuilder:scaffold:scheme } diff --git a/config/dev/openstack-credentials.yaml b/config/dev/openstack-credentials.yaml index 5664e953..ebeb7029 100644 --- a/config/dev/openstack-credentials.yaml +++ b/config/dev/openstack-credentials.yaml @@ -10,14 +10,12 @@ stringData: openstack: auth: auth_url: ${OS_AUTH_URL} - username: ${OS_USERNAME} - password: ${OS_PASSWORD} - project_id: ${OS_PROJECT_ID} - project_name: ${OS_PROJECT_NAME} - user_domain_name: ${OS_USER_DOMAIN_NAME} + application_credential_id: ${OS_APPLICATION_CREDENTIAL_ID} + application_credential_secret: ${OS_APPLICATION_CREDENTIAL_SECRET} region_name: ${OS_REGION_NAME} interface: ${OS_INTERFACE} identity_api_version: ${OS_IDENTITY_API_VERSION} + auth_type: ${OS_AUTH_TYPE} --- apiVersion: hmc.mirantis.com/v1alpha1 kind: Credential diff --git a/go.mod b/go.mod index a087df64..bfb20676 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( sigs.k8s.io/cluster-api v1.9.3 sigs.k8s.io/cluster-api-operator v0.14.0 sigs.k8s.io/cluster-api-provider-azure v1.17.2 + sigs.k8s.io/cluster-api-provider-openstack v0.11.3 sigs.k8s.io/cluster-api-provider-vsphere v1.12.0 sigs.k8s.io/controller-runtime v0.19.3 sigs.k8s.io/yaml v1.4.0 diff --git a/go.sum b/go.sum index 92fa1ef3..22fab400 100644 --- a/go.sum +++ b/go.sum @@ -684,6 +684,8 @@ sigs.k8s.io/cluster-api-operator v0.14.0 h1:0QgO6+XGrNNJnNHKBwvQD5v6w+EaH3Z0RL1n sigs.k8s.io/cluster-api-operator v0.14.0/go.mod h1:euShpVN6HyxXas28HkrYxhCPVDW1UV6ljbRBAeCxp8Y= sigs.k8s.io/cluster-api-provider-azure v1.17.2 h1:uS9ggE/bryI0hiOWHBa56nYHkWmsPZW3bzYeAddL4vM= sigs.k8s.io/cluster-api-provider-azure v1.17.2/go.mod h1:ohdf0TYutOn5vKsXpNVeZUVfUSNIwNhfF6wDjbiqPI0= +sigs.k8s.io/cluster-api-provider-openstack v0.11.3 h1:ZJ3G+m11bgaD227EuFjuFsFC95MRzJm9JbDIte0xwII= +sigs.k8s.io/cluster-api-provider-openstack v0.11.3/go.mod h1:0rH6yksLcuwWK/SoSoCOJi4A0kOSL3qrA+qvDVZ9NjU= sigs.k8s.io/cluster-api-provider-vsphere v1.12.0 h1:9ze+1JSdLAGiLklsnORvj/vs2XpR9jyVmkT0Dwo1nuc= sigs.k8s.io/cluster-api-provider-vsphere v1.12.0/go.mod h1:2y9fsZQ3qjT1kL6IXiOUVcyV0n8DLBQGvyPnId9xRzk= sigs.k8s.io/controller-runtime v0.19.3 h1:XO2GvC9OPftRst6xWCpTgBZO04S2cbp0Qqkj8bX1sPw= diff --git a/internal/controller/clusterdeployment_controller.go b/internal/controller/clusterdeployment_controller.go index 9b53326f..deb50d7d 100644 --- a/internal/controller/clusterdeployment_controller.go +++ b/internal/controller/clusterdeployment_controller.go @@ -312,8 +312,9 @@ func (r *ClusterDeploymentReconciler) updateCluster(ctx context.Context, mc *hmc }, ChartRef: clusterTpl.Status.ChartRef, } - if clusterTpl.Spec.Helm.ChartSpec != nil { - hrReconcileOpts.ReconcileInterval = &clusterTpl.Spec.Helm.ChartSpec.Interval.Duration + reconcileInterval := clusterTpl.Spec.Helm.ChartSpec.Interval.Duration + if reconcileInterval != 0 { + hrReconcileOpts.ReconcileInterval = &reconcileInterval } hr, _, err := helm.ReconcileHelmRelease(ctx, r.Client, mc.Name, mc.Namespace, hrReconcileOpts) @@ -354,11 +355,9 @@ func (r *ClusterDeploymentReconciler) updateCluster(ctx context.Context, mc *hmc return ctrl.Result{RequeueAfter: DefaultRequeueInterval}, nil } - if mc.Spec.PropagateCredentials { - if err := r.reconcileCredentialPropagation(ctx, mc); err != nil { - l.Error(err, "failed to reconcile credentials propagation") - return ctrl.Result{}, err - } + if err := r.reconcileCredentialPropagation(ctx, mc, cred); err != nil { + l.Error(err, "failed to reconcile credentials propagation") + return ctrl.Result{}, err } return ctrl.Result{}, nil @@ -497,9 +496,11 @@ func validateReleaseWithValues(ctx context.Context, actionConfig *action.Configu if err != nil { return err } - _, err = install.RunWithContext(ctx, hcChart, vals) - return err + if err != nil { + return err + } + return nil } // updateStatus updates the status for the ClusterDeployment object. @@ -696,7 +697,7 @@ func (r *ClusterDeploymentReconciler) objectsAvailable(ctx context.Context, name return len(itemsList.Items) != 0, nil } -func (r *ClusterDeploymentReconciler) reconcileCredentialPropagation(ctx context.Context, clusterDeployment *hmc.ClusterDeployment) error { +func (r *ClusterDeploymentReconciler) reconcileCredentialPropagation(ctx context.Context, clusterDeployment *hmc.ClusterDeployment, credential *hmc.Credential) error { l := ctrl.LoggerFrom(ctx) l.Info("Reconciling CCM credentials propagation") @@ -715,8 +716,9 @@ func (r *ClusterDeploymentReconciler) reconcileCredentialPropagation(ctx context propnCfg := &credspropagation.PropagationCfg{ Client: r.Client, - ClusterDeployment: clusterDeployment, + IdentityRef: credential.Spec.IdentityRef, KubeconfSecret: kubeconfSecret, + ClusterDeployment: clusterDeployment, SystemNamespace: r.SystemNamespace, } diff --git a/internal/credspropagation/azure.go b/internal/credspropagation/azure.go index 53abb495..c8129151 100644 --- a/internal/credspropagation/azure.go +++ b/internal/credspropagation/azure.go @@ -20,7 +20,6 @@ import ( "fmt" corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" capz "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -94,7 +93,7 @@ func generateAzureCCMSecret(azureCluster *capz.AzureCluster, azureClIdty *capz.A "cloud-config": azureJSON, } - return makeSecret("azure-cloud-provider", metav1.NamespaceSystem, secretData), nil + return makeSecret("azure-cloud-provider", secretData), nil } func getAzureSubnetData(azureCluster *capz.AzureCluster) (subnetName, secGroup, routeTable string) { diff --git a/internal/credspropagation/common.go b/internal/credspropagation/common.go index ed33d11c..7b754d61 100644 --- a/internal/credspropagation/common.go +++ b/internal/credspropagation/common.go @@ -30,8 +30,9 @@ import ( type PropagationCfg struct { Client client.Client - ClusterDeployment *hmc.ClusterDeployment KubeconfSecret *corev1.Secret + IdentityRef *corev1.ObjectReference + ClusterDeployment *hmc.ClusterDeployment SystemNamespace string } @@ -53,11 +54,11 @@ func applyCCMConfigs(ctx context.Context, kubeconfSecret *corev1.Secret, objects return nil } -func makeSecret(name, namespace string, data map[string][]byte) *corev1.Secret { +func makeSecret(name string, data map[string][]byte) *corev1.Secret { s := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: name, - Namespace: namespace, + Namespace: metav1.NamespaceSystem, }, Data: data, } @@ -65,11 +66,11 @@ func makeSecret(name, namespace string, data map[string][]byte) *corev1.Secret { return s } -func makeConfigMap(name, namespace string, data map[string]string) *corev1.ConfigMap { +func makeConfigMap(name string, data map[string]string) *corev1.ConfigMap { c := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: name, - Namespace: namespace, + Namespace: metav1.NamespaceSystem, }, Data: data, } @@ -86,7 +87,11 @@ func makeClientFromSecret(kubeconfSecret *corev1.Secret) (client.Client, error) if err != nil { return nil, err } - return client.New(restConfig, client.Options{ + cl, err := client.New(restConfig, client.Options{ Scheme: scheme, }) + if err != nil { + return nil, err + } + return cl, nil } diff --git a/internal/credspropagation/openstack.go b/internal/credspropagation/openstack.go index bdb0a2f9..418b0e7e 100644 --- a/internal/credspropagation/openstack.go +++ b/internal/credspropagation/openstack.go @@ -15,62 +15,228 @@ package credspropagation import ( + "bytes" "context" + "errors" "fmt" + texttemplate "text/template" - hmc "github.com/Mirantis/hmc/api/v1alpha1" + "gopkg.in/yaml.v3" corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + capo "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1" "sigs.k8s.io/controller-runtime/pkg/client" ) +type ( + cloudConfFields struct { + AuthURL string + ApplicationCredentialID string + ApplicationCredentialName string + ApplicationCredentialSecret string + Username string + Password string + RegionName string + FloatingNetworkID string + PublicNetworkName string + } + + cloudsYaml struct { + Clouds map[string]cloud `yaml:"clouds"` + } + + cloud struct { + Auth auth `yaml:"auth"` + RegionName string `yaml:"region_name"` + } + + auth struct { + AuthURL string `yaml:"auth_url"` + ApplicationCredentialID string `yaml:"application_credential_id"` + ApplicationCredentialName string `yaml:"application_credential_name"` + ApplicationCredentialSecret string `yaml:"application_credential_secret"` + Username string `yaml:"username"` + Password string `yaml:"password"` + ProjectDomainName string `yaml:"project_domain_name"` + } +) + +// PropagateOpenStackSecrets propagates OpenStack secrets func PropagateOpenStackSecrets(ctx context.Context, cfg *PropagationCfg) error { - openstackManagedCluster := &hmc.ManagedCluster{} + if cfg == nil { + return errors.New("PropagationCfg is nil") + } + // Fetch the OpenStackCluster resource + openstackCluster := &capo.OpenStackCluster{} if err := cfg.Client.Get(ctx, client.ObjectKey{ - Name: cfg.ManagedCluster.Name, - Namespace: cfg.ManagedCluster.Namespace, - }, openstackManagedCluster); err != nil { - return fmt.Errorf("failed to get ManagedCluster %s: %w", cfg.ManagedCluster.Name, err) + Name: cfg.ClusterDeployment.Name, + Namespace: cfg.ClusterDeployment.Namespace, + }, openstackCluster); err != nil { + return fmt.Errorf("unable to get OpenStackCluster %s/%s: %w", + cfg.ClusterDeployment.Namespace, cfg.ClusterDeployment.Name, err) } - openstackCredential := &hmc.Credential{} - if err := cfg.Client.Get(ctx, client.ObjectKey{ - Name: openstackManagedCluster.Spec.Credential, - Namespace: openstackManagedCluster.Namespace, - }, openstackCredential); err != nil { - return fmt.Errorf("failed to get OpenStackCredential %s: %w", cfg.ManagedCluster.Spec.Credential, err) + // Extract cloudName from the OpenStackCluster resource + cloudName := openstackCluster.Spec.IdentityRef.CloudName + if cloudName == "" { + return errors.New("cloudName is not specified in OpenStackCluster.spec.identityRef.cloudName") + } + + // Fetch the OpenStack secret + openstackSecret, err := fetchOpenStackSecret(ctx, cfg) + if err != nil { + return fmt.Errorf("failed to fetch OpenStack secret: %w", err) } - // Fetch the secret containing OpenStack credentials + // Generate the CCM secret using the extracted cloudName + ccmSecret, err := generateOpenStackCCMSecret(ctx, cfg, openstackSecret, cloudName) + if err != nil { + return fmt.Errorf("failed to generate CCM secret: %w", err) + } + + // Apply the CCM configuration + if err := applyCCMConfigs(ctx, cfg.KubeconfSecret, ccmSecret); err != nil { + return fmt.Errorf("failed to apply CCM configuration: %w", err) + } + + return nil +} + +// Fetch the OpenStack secret +func fetchOpenStackSecret(ctx context.Context, cfg *PropagationCfg) (*corev1.Secret, error) { openstackSecret := &corev1.Secret{} - openstackSecretName := openstackCredential.Spec.IdentityRef.Name - openstackSecretNamespace := openstackCredential.Spec.IdentityRef.Namespace if err := cfg.Client.Get(ctx, client.ObjectKey{ - Name: openstackSecretName, - Namespace: openstackSecretNamespace, + Name: cfg.IdentityRef.Name, + Namespace: cfg.IdentityRef.Namespace, }, openstackSecret); err != nil { - return fmt.Errorf("failed to get OpenStack secret %s: %w", openstackSecretName, err) + return nil, fmt.Errorf("failed to get OpenStack secret %s/%s: %w", + cfg.IdentityRef.Namespace, cfg.IdentityRef.Name, err) } + return openstackSecret, nil +} + +// Generate the CCM secret from the OpenStack secret +func generateOpenStackCCMSecret(ctx context.Context, cfg *PropagationCfg, openstackSecret *corev1.Secret, cloudName string) (*corev1.Secret, error) { + const cloudConfTemplate = ` +[Global] +auth-url="{{ .AuthURL }}" +{{- if .ApplicationCredentialID }} +application-credential-id="{{ .ApplicationCredentialID }}" +{{- end }} +{{- if .ApplicationCredentialName }} +application-credential-name="{{ .ApplicationCredentialName }}" +{{- end }} +{{- if .ApplicationCredentialSecret }} +application-credential-secret="{{ .ApplicationCredentialSecret }}" +{{- end }} +{{- if and (not .ApplicationCredentialID) (not .ApplicationCredentialSecret) }} +username="{{ .Username }}" +password="{{ .Password }}" +{{- end }} +region="{{ .RegionName }}" - // Generate CCM secret - ccmSecret, err := generateOpenStackCCMSecret(openstackSecret) +[LoadBalancer] +{{- if .FloatingNetworkID }} +floating-network-id="{{ .FloatingNetworkID }}" +{{- end }} + +[Network] +{{- if .PublicNetworkName }} +public-network-name="{{ .PublicNetworkName }}" +{{- end }} +` + + // Parse the clouds.yaml content + cloudsYamlData, ok := openstackSecret.Data["clouds.yaml"] + if !ok { + return nil, errors.New("missing clouds.yaml in OpenStack secret") + } + + parsedCloudsYaml, err := parseCloudsYaml(cloudsYamlData) if err != nil { - return fmt.Errorf("failed to generate OpenStack CCM secret: %s", err) + return nil, fmt.Errorf("failed to parse clouds.yaml: %w", err) } - // Apply CCM config - if err := applyCCMConfigs(ctx, cfg.KubeconfSecret, ccmSecret); err != nil { - return fmt.Errorf("failed to apply OpenStack CCM secret: %s", err) + // Extract cloudConfFields using the provided cloudName + fields, err := extractCloudConfFields(parsedCloudsYaml, cloudName) + if err != nil { + return nil, fmt.Errorf("failed to extract cloud.conf fields: %w", err) } - return nil + // Fetch external network details from OpenStackCluster + externalNetwork, err := fetchExternalNetwork(ctx, cfg) + if err != nil { + return nil, fmt.Errorf("failed to fetch external network details: %w", err) + } + if externalNetwork == nil || externalNetwork.ID == "" || externalNetwork.Name == "" { + return nil, errors.New("external network details are incomplete") + } + fields.FloatingNetworkID = externalNetwork.ID + fields.PublicNetworkName = externalNetwork.Name + + // Render the cloud.conf secret + return renderCloudConf(cloudConfTemplate, fields) +} + +// Parse the clouds.yaml content into structured types +func parseCloudsYaml(data []byte) (*cloudsYaml, error) { + var parsed cloudsYaml + if err := yaml.Unmarshal(data, &parsed); err != nil { + return nil, fmt.Errorf("failed to parse clouds.yaml: %w", err) + } + return &parsed, nil } -func generateOpenStackCCMSecret(openstackSecret *corev1.Secret) (*corev1.Secret, error) { - // Use the data from the fetched secret +// Extract fields required for the cloud.conf file +func extractCloudConfFields(cloudsYaml *cloudsYaml, cloudName string) (cloudConfFields, error) { + var fields cloudConfFields + + cloud, exists := cloudsYaml.Clouds[cloudName] + if !exists { + return fields, fmt.Errorf("cloud '%s' not found in clouds.yaml", cloudName) + } + + auth := cloud.Auth + fields = cloudConfFields{ + AuthURL: auth.AuthURL, + ApplicationCredentialID: auth.ApplicationCredentialID, + ApplicationCredentialName: auth.ApplicationCredentialName, + ApplicationCredentialSecret: auth.ApplicationCredentialSecret, + Username: auth.Username, + Password: auth.Password, + RegionName: cloud.RegionName, + } + + return fields, nil +} + +// Fetch external network details from OpenStackCluster +func fetchExternalNetwork(ctx context.Context, cfg *PropagationCfg) (*capo.NetworkStatus, error) { + openstackCluster := &capo.OpenStackCluster{} + if err := cfg.Client.Get(ctx, client.ObjectKey{ + Name: cfg.ClusterDeployment.Name, + Namespace: cfg.ClusterDeployment.Namespace, + }, openstackCluster); err != nil { + return nil, fmt.Errorf("unable to get OpenStackCluster %s/%s: %w", + cfg.ClusterDeployment.Namespace, cfg.ClusterDeployment.Name, err) + } + return openstackCluster.Status.ExternalNetwork, nil +} + +// Render cloud.conf using the template and fields +func renderCloudConf(templateStr string, fields cloudConfFields) (*corev1.Secret, error) { + tmpl, err := texttemplate.New("cloudConf").Parse(templateStr) + if err != nil { + return nil, fmt.Errorf("failed to parse cloud.conf template: %w", err) + } + + var buf bytes.Buffer + if err := tmpl.Execute(&buf, fields); err != nil { + return nil, fmt.Errorf("failed to render cloud.conf template: %w", err) + } + secretData := map[string][]byte{ - "clouds.yaml": openstackSecret.Data["clouds.yaml"], + "cloud.conf": buf.Bytes(), } - return makeSecret("openstack-cloud-config", metav1.NamespaceSystem, secretData), nil + return makeSecret("openstack-cloud-config", secretData), nil } diff --git a/internal/credspropagation/vsphere.go b/internal/credspropagation/vsphere.go index f9f3e5ab..a4cf3b2f 100644 --- a/internal/credspropagation/vsphere.go +++ b/internal/credspropagation/vsphere.go @@ -119,8 +119,8 @@ func generateVSphereCCMConfigs(vCl *capv.VSphereCluster, vScrt *corev1.Secret, v cmData := map[string]string{ "vsphere.conf": string(ccmCfgYaml), } - return makeSecret(secretName, metav1.NamespaceSystem, secretData), - makeConfigMap("cloud-config", metav1.NamespaceSystem, cmData), + return makeSecret(secretName, secretData), + makeConfigMap("cloud-config", cmData), nil } @@ -161,5 +161,5 @@ datacenters = "{{ .Datacenter }}" "csi-vsphere.conf": buf.Bytes(), } - return makeSecret("vcenter-config-secret", metav1.NamespaceSystem, secretData), nil + return makeSecret("vcenter-config-secret", secretData), nil }