From f03a606d1b5c4ed5bac491b12f106dc5d931f5df Mon Sep 17 00:00:00 2001 From: Martin Schuppert Date: Wed, 15 May 2024 11:23:00 +0200 Subject: [PATCH] Allow usage of OpenStackConfigGenerator without a full deployed env This change allows to just generate ansible playbooks using the OpenStackConfigGenerate without deploying controller VMs or compute baremetal nodes. This is useful e.g. for debugging purposes to just get the content from ConfigMaps/Secrets and analyse rendering issues on a different system. a) As a pre-requ create the required ConfigMaps and Secrets ConfigMaps: - heat-env-config-deploy - tripleo-deploy-config-default - tripleo-tarball-config-deploy Secrets: - git-secret (make sure to prepare the git repo, or run the OpenStackConfigGenerator with `interactive: true` and run the create_playbooks.sh manually. This allows to check the generated playbooks whithin the pod) - tripleo-passwords () b) Create the OpenStackConfigGenerator with name `default` and an `debug` section like e.g.: ~~~ apiVersion: osp-director.openstack.org/v1beta1 kind: OpenStackConfigGenerator metadata: name: default namespace: openstack spec: enableFencing: false ephemeralHeatSettings: heatEngineReplicas: 3 gitSecret: git-secret heatEnvConfigMap: heat-env-config-deploy heatEnvs: - ssl/tls-endpoints-public-dns.yaml - ssl/enable-tls.yaml - services/octavia.yaml imageURL: registry.redhat.io/.../.../openstack-tripleoclient:17.1 interactive: false tarballConfigMap: tripleo-tarball-config-deploy debug: skipWaiting: true tripleoDeployConfigOverride: tripleo-deploy-config-default openStackRelease: "17.1" ~~~ --- api/v1beta1/openstackconfiggenerator_types.go | 19 +++ api/v1beta1/zz_generated.deepcopy.go | 26 ++++ ...enstack.org_openstackconfiggenerators.yaml | 22 +++ .../openstackconfiggenerator_controller.go | 129 +++++++++++------- 4 files changed, 149 insertions(+), 47 deletions(-) diff --git a/api/v1beta1/openstackconfiggenerator_types.go b/api/v1beta1/openstackconfiggenerator_types.go index bc128845..241406dd 100644 --- a/api/v1beta1/openstackconfiggenerator_types.go +++ b/api/v1beta1/openstackconfiggenerator_types.go @@ -60,6 +60,25 @@ type OpenStackConfigGeneratorSpec struct { EnableFencing bool `json:"enableFencing"` // TripleoRoleOverride - map of TripleO role name to temporary role override to support a multi-rhel environment (valid for 17.1 only) TripleoRoleOverride map[string]TripleoRoleOverrideSpec `json:"tripleoRoleOverride,omitempty"` + // +kubebuilder:validation:Optional + Debug OpenStackConfigGeneratorAdvancedSettings `json:"debug,omitempty"` +} + +// OpenStackConfigGeneratorAdvancedSettings - +// The main intention of these parameters are for debugging purposes to generate playbooks without the need of a full deployed environment. +type OpenStackConfigGeneratorAdvancedSettings struct { + // +kubebuilder:validation:Optional + // SkipWaiting enables the user to control if the OpenStackConfigGenerator should wait for all openstackbaremetalsets and openstackvmsets + // to be Ready before start to generate the playbooks. + SkipWaiting *bool `json:"skipWaiting,omitempty"` + // +kubebuilder:validation:Optional + // TripleoDeployConfigOverride allows to point to an existing configmap which has the files which are usually generated by the operator. + // Note: the configmap must provide a tripleo parameter file named `rendered-tripleo-config.yaml` + TripleoDeployConfigOverride *string `json:"tripleoDeployConfigOverride,omitempty"` + // +kubebuilder:validation:Optional + // OpenStackRelease to overwrite OSPrelease auto detection from the OpenStackControlPlane CR + // Note: needs to be set when SkipWaiting is used + OpenStackRelease string `json:"openStackRelease,omitempty"` } // OpenStackConfigGeneratorStatus defines the observed state of OpenStackConfigGenerator diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index d6874baf..6b2e5996 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -899,6 +899,31 @@ func (in *OpenStackConfigGenerator) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OpenStackConfigGeneratorAdvancedSettings) DeepCopyInto(out *OpenStackConfigGeneratorAdvancedSettings) { + *out = *in + if in.SkipWaiting != nil { + in, out := &in.SkipWaiting, &out.SkipWaiting + *out = new(bool) + **out = **in + } + if in.TripleoDeployConfigOverride != nil { + in, out := &in.TripleoDeployConfigOverride, &out.TripleoDeployConfigOverride + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackConfigGeneratorAdvancedSettings. +func (in *OpenStackConfigGeneratorAdvancedSettings) DeepCopy() *OpenStackConfigGeneratorAdvancedSettings { + if in == nil { + return nil + } + out := new(OpenStackConfigGeneratorAdvancedSettings) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OpenStackConfigGeneratorDefaults) DeepCopyInto(out *OpenStackConfigGeneratorDefaults) { *out = *in @@ -967,6 +992,7 @@ func (in *OpenStackConfigGeneratorSpec) DeepCopyInto(out *OpenStackConfigGenerat (*out)[key] = *val.DeepCopy() } } + in.Debug.DeepCopyInto(&out.Debug) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackConfigGeneratorSpec. diff --git a/config/crd/bases/osp-director.openstack.org_openstackconfiggenerators.yaml b/config/crd/bases/osp-director.openstack.org_openstackconfiggenerators.yaml index 9c628cd8..0a218155 100644 --- a/config/crd/bases/osp-director.openstack.org_openstackconfiggenerators.yaml +++ b/config/crd/bases/osp-director.openstack.org_openstackconfiggenerators.yaml @@ -46,6 +46,28 @@ spec: description: OpenStackConfigGeneratorSpec defines the desired state of OpenStackConfigGenerator properties: + debug: + description: OpenStackConfigGeneratorAdvancedSettings - The main intention + of these parameters are for debugging purposes to generate playbooks + without the need of a full deployed environment. + properties: + openStackRelease: + description: 'OpenStackRelease to overwrite OSPrelease auto detection + from the OpenStackControlPlane CR Note: needs to be set when + SkipWaiting is used' + type: string + skipWaiting: + description: SkipWaiting enables the user to control if the OpenStackConfigGenerator + should wait for all openstackbaremetalsets and openstackvmsets + to be Ready before start to generate the playbooks. + type: boolean + tripleoDeployConfigOverride: + description: 'TripleoDeployConfigOverride allows to point to an + existing configmap which has the files which are usually generated + by the operator. Note: the configmap must provide a tripleo + parameter file named `rendered-tripleo-config.yaml`' + type: string + type: object enableFencing: description: 'EnableFencing allows the automatic creation of required heat environment files to enable fencing. Note: - Production OSP diff --git a/controllers/openstackconfiggenerator_controller.go b/controllers/openstackconfiggenerator_controller.go index d1c0a7ce..c9d25e21 100644 --- a/controllers/openstackconfiggenerator_controller.go +++ b/controllers/openstackconfiggenerator_controller.go @@ -162,48 +162,65 @@ func (r *OpenStackConfigGeneratorReconciler) Reconcile(ctx context.Context, req envVars := make(map[string]common.EnvSetter) templateParameters := make(map[string]interface{}) cmLabels := common.GetLabels(instance, openstackconfiggenerator.AppLabel, map[string]string{}) + var controlPlane ospdirectorv1beta2.OpenStackControlPlane + var OSPVersion shared.OSPVersion - // - // Get OSPVersion from OSControlPlane status - // - // unified OSPVersion from ControlPlane CR - // which means also get either 16.2 or 17.0 for upstream versions - controlPlane, ctrlResult, err := ospdirectorv1beta2.GetControlPlane(r.Client, instance) - if err != nil { - cond.Message = err.Error() - cond.Reason = shared.ControlPlaneReasonNetNotFound - cond.Type = shared.ConfigGeneratorCondTypeError - err = common.WrapErrorForObject(cond.Message, instance, err) + if instance.Spec.Debug.SkipWaiting == nil || + (instance.Spec.Debug.SkipWaiting != nil && !*instance.Spec.Debug.SkipWaiting) { + var ctrlResult reconcile.Result + // + // Get OSPVersion from OSControlPlane status + // + // unified OSPVersion from ControlPlane CR + // which means also get either 16.2 or 17.0 for upstream versions + controlPlane, ctrlResult, err = ospdirectorv1beta2.GetControlPlane(r.Client, instance) + if err != nil { + cond.Message = err.Error() + cond.Reason = shared.ControlPlaneReasonNetNotFound + cond.Type = shared.ConfigGeneratorCondTypeError + err = common.WrapErrorForObject(cond.Message, instance, err) - return ctrlResult, err - } - OSPVersion, err := shared.GetOSPVersion(string(controlPlane.Status.OSPVersion)) - if err != nil { - cond.Message = err.Error() - cond.Reason = shared.ControlPlaneReasonNotSupportedVersion - cond.Type = shared.ConfigGeneratorCondTypeError - err = common.WrapErrorForObject(cond.Message, instance, err) + return ctrlResult, err + } + OSPVersion, err = shared.GetOSPVersion(string(controlPlane.Status.OSPVersion)) + if err != nil { + cond.Message = err.Error() + cond.Reason = shared.ControlPlaneReasonNotSupportedVersion + cond.Type = shared.ConfigGeneratorCondTypeError + err = common.WrapErrorForObject(cond.Message, instance, err) - return ctrlResult, err - } + return ctrlResult, err + } - templateParameters["OSPVersion"] = OSPVersion + // + // wait for the controlplane VMs to be provisioned + // + if controlPlane.Status.ProvisioningStatus.State != shared.ProvisioningState(shared.ControlPlaneProvisioned) { + cond.Message = fmt.Sprintf("Control plane %s VMs are not yet provisioned. Requeing...", controlPlane.Name) + cond.Reason = shared.ConfigGeneratorCondReasonCMNotFound + cond.Type = shared.ConfigGeneratorCondTypeWaiting + common.LogForObject( + r, + cond.Message, + instance, + ) - // - // wait for the controlplane VMs to be provisioned - // - if controlPlane.Status.ProvisioningStatus.State != shared.ProvisioningState(shared.ControlPlaneProvisioned) { - cond.Message = fmt.Sprintf("Control plane %s VMs are not yet provisioned. Requeing...", controlPlane.Name) - cond.Reason = shared.ConfigGeneratorCondReasonCMNotFound - cond.Type = shared.ConfigGeneratorCondTypeWaiting - common.LogForObject( - r, - cond.Message, - instance, - ) + return ctrl.Result{RequeueAfter: 10 * time.Second}, nil + } + } + + if instance.Spec.Debug.OpenStackRelease != "" { + OSPVersion, err = shared.GetOSPVersion(instance.Spec.Debug.OpenStackRelease) + if err != nil { + cond.Message = err.Error() + cond.Reason = shared.ControlPlaneReasonNotSupportedVersion + cond.Type = shared.ConfigGeneratorCondTypeError + err = common.WrapErrorForObject(cond.Message, instance, err) - return ctrl.Result{RequeueAfter: 10 * time.Second}, nil + return ctrl.Result{}, err + } } + templateParameters["OSPVersion"] = OSPVersion // // check if heat-env-config (customizations provided by administrator) exist if it does not exist, requeue @@ -272,18 +289,36 @@ func (r *OpenStackConfigGeneratorReconciler) Reconcile(ctx context.Context, req // // render OOO environment, create TripleoDeployCM and read the tripleo-deploy-config CM // - tripleoDeployCM, err := r.createTripleoDeployCM( - ctx, - instance, - cond, - &envVars, - cmLabels, - OSPVersion, - &controlPlane, - tripleoTarballCM, - ) - if err != nil { - return ctrl.Result{}, err + var tripleoDeployCM *corev1.ConfigMap + if instance.Spec.Debug.TripleoDeployConfigOverride == nil || + (instance.Spec.Debug.TripleoDeployConfigOverride != nil && *instance.Spec.Debug.TripleoDeployConfigOverride == "") { + tripleoDeployCM, err = r.createTripleoDeployCM( + ctx, + instance, + cond, + &envVars, + cmLabels, + OSPVersion, + &controlPlane, + tripleoTarballCM, + ) + if err != nil { + return ctrl.Result{}, err + } + } else { + tripleoDeployCM, _, err = common.GetConfigMapAndHashWithName(ctx, r, *instance.Spec.Debug.TripleoDeployConfigOverride, instance.Namespace) + if err != nil { + if k8s_errors.IsNotFound(err) { + cond.Message = "TripleoDeployConfigOverride config map not found, requeuing and waiting. Requeing..." + cond.Reason = shared.ConfigGeneratorCondReasonCMNotFound + cond.Type = shared.ConfigGeneratorCondTypeWaiting + err = common.WrapErrorForObject(cond.Message, instance, err) + + return ctrl.Result{RequeueAfter: 10 * time.Second}, err + } + // Error reading the object - requeue the request. + return ctrl.Result{}, err + } } tripleoDeployFiles := tripleoDeployCM.Data