diff --git a/api/v1beta1/ibmpowervsimage_types.go b/api/v1beta1/ibmpowervsimage_types.go index a408f24e44..2c2985109c 100644 --- a/api/v1beta1/ibmpowervsimage_types.go +++ b/api/v1beta1/ibmpowervsimage_types.go @@ -53,6 +53,12 @@ type IBMPowerVSImageSpec struct { // +kubebuilder:validation:Enum=tier1;tier3 // +optional StorageType string `json:"storageType,omitempty"` + + // DeletePolicy defines the policy used to identify images to delete when deleting associated cluster. + // +kubebuilder:default=delete + // +kubebuilder:validation:Enum=delete;retain + // +optional + DeletePolicy string `json:"deletePolicy,omitempty"` } // IBMPowerVSImageStatus defines the observed state of IBMPowerVSImage diff --git a/api/v1beta1/types.go b/api/v1beta1/types.go index d42d53ae2f..25215c0da9 100644 --- a/api/v1beta1/types.go +++ b/api/v1beta1/types.go @@ -16,6 +16,11 @@ limitations under the License. package v1beta1 +const ( + // DeletePolicyLabel is the label set on ibmpowervsimage to identify images to delete when deleting associated cluster. + DeletePolicyLabel = "infrastructure.cluster.x-k8s.io/delete-policy" +) + // PowerVSInstanceState describes the state of an IBM Power VS instance. type PowerVSInstanceState string diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_ibmpowervsimages.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_ibmpowervsimages.yaml index 229dedb8b4..658edff34c 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_ibmpowervsimages.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_ibmpowervsimages.yaml @@ -52,6 +52,14 @@ spec: to. minLength: 1 type: string + deletePolicy: + default: delete + description: DeletePolicy defines the policy used to identify images + to delete when deleting associated cluster. + enum: + - delete + - retain + type: string object: description: Cloud Object Storage image filename type: string diff --git a/controllers/ibmpowervscluster_controller.go b/controllers/ibmpowervscluster_controller.go index f63aa53b16..30d8dade9f 100644 --- a/controllers/ibmpowervscluster_controller.go +++ b/controllers/ibmpowervscluster_controller.go @@ -190,7 +190,7 @@ func (r *IBMPowerVSClusterReconciler) listDescendants(ctx context.Context, clust listOptions := []client.ListOption{ client.InNamespace(cluster.Namespace), - client.MatchingLabels(map[string]string{clusterv1.ClusterLabelName: cluster.Name}), + client.MatchingLabels(map[string]string{clusterv1.ClusterLabelName: cluster.Name, v1beta1.DeletePolicyLabel: "delete"}), } if err := r.Client.List(ctx, &descendants.ibmPowerVSImages, listOptions...); err != nil { diff --git a/controllers/ibmpowervsimage_controller.go b/controllers/ibmpowervsimage_controller.go index 25405127fb..716d49c4fc 100644 --- a/controllers/ibmpowervsimage_controller.go +++ b/controllers/ibmpowervsimage_controller.go @@ -66,6 +66,9 @@ func (r *IBMPowerVSImageReconciler) Reconcile(ctx context.Context, req ctrl.Requ cluster, err := util.GetClusterByName(ctx, r.Client, ibmImage.Namespace, ibmImage.Spec.ClusterName) if err != nil { + if ibmImage.Spec.DeletePolicy == "retain" { + return ctrl.Result{}, nil + } return ctrl.Result{}, err } @@ -106,6 +109,10 @@ func (r *IBMPowerVSImageReconciler) reconcile(ctx context.Context, cluster *v1be imageScope.IBMPowerVSImage.Labels[clusterv1.ClusterLabelName] = imageScope.IBMPowerVSImage.Spec.ClusterName } + if _, ok := imageScope.IBMPowerVSImage.Labels[v1beta1.DeletePolicyLabel]; !ok { + imageScope.IBMPowerVSImage.Labels[v1beta1.DeletePolicyLabel] = imageScope.IBMPowerVSImage.Spec.DeletePolicy + } + if r.shouldAdopt(*imageScope.IBMPowerVSImage) { imageScope.Info("Image Controller has not yet set OwnerRef") imageScope.IBMPowerVSImage.OwnerReferences = clusterv1util.EnsureOwnerRef(imageScope.IBMPowerVSImage.OwnerReferences, metav1.OwnerReference{ @@ -121,7 +128,7 @@ func (r *IBMPowerVSImageReconciler) reconcile(ctx context.Context, cluster *v1be job, err := imageScope.IBMPowerVSClient.GetJob(jobID) if err != nil { imageScope.Info("Unable to get job details") - return ctrl.Result{RequeueAfter: 2 * time.Minute}, err + return ctrl.Result{RequeueAfter: 1 * time.Minute}, err } switch *job.Status.State { case "completed": @@ -130,17 +137,17 @@ func (r *IBMPowerVSImageReconciler) reconcile(ctx context.Context, cluster *v1be imageScope.SetNotReady() imageScope.SetImageState(string(v1beta1.PowerVSImageStateFailed)) conditions.MarkFalse(imageScope.IBMPowerVSImage, v1beta1.ImageImportedCondition, v1beta1.ImageImportFailedReason, clusterv1.ConditionSeverityError, job.Status.Message) - return ctrl.Result{RequeueAfter: 2 * time.Minute}, fmt.Errorf("failed to import image, message: %s", job.Status.Message) + return ctrl.Result{RequeueAfter: 1 * time.Minute}, fmt.Errorf("failed to import image, message: %s", job.Status.Message) case "queued": imageScope.SetNotReady() imageScope.SetImageState(string(v1beta1.PowerVSImageStateQue)) conditions.MarkFalse(imageScope.IBMPowerVSImage, v1beta1.ImageImportedCondition, string(v1beta1.PowerVSImageStateQue), clusterv1.ConditionSeverityInfo, job.Status.Message) - return ctrl.Result{RequeueAfter: 2 * time.Minute}, nil + return ctrl.Result{RequeueAfter: 1 * time.Minute}, nil default: imageScope.SetNotReady() imageScope.SetImageState(string(v1beta1.PowerVSImageStateImporting)) conditions.MarkFalse(imageScope.IBMPowerVSImage, v1beta1.ImageImportedCondition, *job.Status.State, clusterv1.ConditionSeverityInfo, job.Status.Message) - return ctrl.Result{RequeueAfter: 2 * time.Minute}, nil + return ctrl.Result{RequeueAfter: 1 * time.Minute}, nil } }