diff --git a/api/v1beta1/conditions_consts.go b/api/v1beta1/conditions_consts.go index 5b428a0ce..bc2491a84 100644 --- a/api/v1beta1/conditions_consts.go +++ b/api/v1beta1/conditions_consts.go @@ -45,9 +45,15 @@ const ( const ( // ImageNotReadyReason used when the image is in a queued state. ImageNotReadyReason = "ImageNotReady" + + // ImageImportFailedReason used when the image import is failed. + ImageImportFailedReason = "ImageImportFailed" ) const ( // ImageReadyCondition reports on current status of the image. Ready indicates the image is in a active state. ImageReadyCondition clusterv1.ConditionType = "ImageReady" + + // ImageImportedCondition reports on current status of the image import job. Ready indicates the import job is finished. + ImageImportedCondition clusterv1.ConditionType = "ImageImported" ) diff --git a/api/v1beta1/ibmpowervsimage_types.go b/api/v1beta1/ibmpowervsimage_types.go index 490288068..a408f24e4 100644 --- a/api/v1beta1/ibmpowervsimage_types.go +++ b/api/v1beta1/ibmpowervsimage_types.go @@ -60,7 +60,7 @@ type IBMPowerVSImageStatus struct { // Ready is true when the provider resource is ready. // +optional - Ready bool `json:"ready,omitempty"` + Ready bool `json:"ready"` // ImageID is the id of the imported image ImageID string `json:"imageID,omitempty"` @@ -69,6 +69,10 @@ type IBMPowerVSImageStatus struct { // +optional ImageState PowerVSImageState `json:"imageState,omitempty"` + // JobID is the job ID of an import operation + // +optional + JobID string `json:"jobID,omitempty"` + // Conditions defines current service state of the IBMPowerVSImage. // +optional Conditions clusterv1.Conditions `json:"conditions,omitempty"` diff --git a/api/v1beta1/types.go b/api/v1beta1/types.go index 0c1552b7d..d42d53ae2 100644 --- a/api/v1beta1/types.go +++ b/api/v1beta1/types.go @@ -40,8 +40,14 @@ var ( // PowerVSImageStateACTIVE is the string representing an image in a active state. PowerVSImageStateACTIVE = PowerVSImageState("active") - // PowerVSInstanceStateQue is the string representing an image in a queued state. - PowerVSInstanceStateQue = PowerVSImageState("queued") + // PowerVSImageStateQue is the string representing an image in a queued state. + PowerVSImageStateQue = PowerVSImageState("queued") + + // PowerVSImageStateFailed is the string representing an image in a failed state. + PowerVSImageStateFailed = PowerVSImageState("failed") + + // PowerVSImageStateImporting is the string representing an image in a failed state. + PowerVSImageStateImporting = PowerVSImageState("importing") ) // NetworkInterface holds the network interface information like subnet id. diff --git a/cloud/scope/powervs_image.go b/cloud/scope/powervs_image.go index cab181da7..b86d977fb 100644 --- a/cloud/scope/powervs_image.go +++ b/cloud/scope/powervs_image.go @@ -229,10 +229,18 @@ func (i *PowerVSImageScope) GetImageID() string { return i.IBMPowerVSImage.Status.ImageID } -func (i *PowerVSImageScope) SetImageState(status *string) { - i.IBMPowerVSImage.Status.ImageState = v1beta1.PowerVSImageState(*status) +func (i *PowerVSImageScope) SetImageState(status string) { + i.IBMPowerVSImage.Status.ImageState = v1beta1.PowerVSImageState(status) } func (i *PowerVSImageScope) GetImageState() v1beta1.PowerVSImageState { return i.IBMPowerVSImage.Status.ImageState } + +func (i *PowerVSImageScope) SetJobID(id string) { + i.IBMPowerVSImage.Status.JobID = id +} + +func (i *PowerVSImageScope) GetJobID() string { + return i.IBMPowerVSImage.Status.JobID +} 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 1cef80313..229dedb8b 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_ibmpowervsimages.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_ibmpowervsimages.yaml @@ -131,6 +131,9 @@ spec: imageState: description: ImageState is the status of the imported image type: string + jobID: + description: JobID is the job ID of an import operation + type: string ready: description: Ready is true when the provider resource is ready. type: boolean diff --git a/controllers/ibmpowervsimage_controller.go b/controllers/ibmpowervsimage_controller.go index d761eeec0..fabd6d174 100644 --- a/controllers/ibmpowervsimage_controller.go +++ b/controllers/ibmpowervsimage_controller.go @@ -18,13 +18,13 @@ package controllers import ( "context" + "fmt" "time" "github.com/IBM-Cloud/power-go-client/power/models" "github.com/go-logr/logr" "github.com/pkg/errors" - "github.com/IBM/go-sdk-core/v5/core" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -108,6 +108,33 @@ func (r *IBMPowerVSImageReconciler) reconcile(ctx context.Context, cluster *v1be return ctrl.Result{}, nil } + if jobID := imageScope.GetJobID(); jobID != "" { + job, err := imageScope.IBMPowerVSClient.GetJob(jobID) + if err != nil { + imageScope.Info("Unable to get job details") + return ctrl.Result{RequeueAfter: 2 * time.Minute}, err + } + switch *job.Status.State { + case "completed": + conditions.MarkTrue(imageScope.IBMPowerVSImage, v1beta1.ImageImportedCondition) + case "failed": + 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) + 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 + 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 + } + } + img, jobRef, err := r.getOrCreate(imageScope) if err != nil { imageScope.Error(err, "Unable to import image") @@ -115,19 +142,7 @@ func (r *IBMPowerVSImageReconciler) reconcile(ctx context.Context, cluster *v1be } if jobRef != nil { - job, err := imageScope.IBMPowerVSClient.GetJob(*jobRef.ID) - if err != nil { - imageScope.Info("Unable to get job details") - return ctrl.Result{RequeueAfter: 2 * time.Minute}, err - } - - if *job.Status.State != "completed" && *job.Status.State != "failed" { - imageScope.Info("Import job not yet finished - " + *job.Status.State) - imageScope.SetNotReady() - imageScope.SetImageState(core.StringPtr("")) - conditions.MarkFalse(imageScope.IBMPowerVSImage, v1beta1.ImageReadyCondition, v1beta1.ImageNotReadyReason, clusterv1.ConditionSeverityWarning, "") - return ctrl.Result{}, nil - } + imageScope.SetJobID(*jobRef.ID) } return reconcileImage(img, imageScope) } @@ -142,11 +157,11 @@ func reconcileImage(img *models.ImageReference, imageScope *scope.PowerVSImageSc imageScope.SetImageID(image.ImageID) imageScope.Info("ImageID - " + imageScope.GetImageID()) - imageScope.SetImageState(&image.State) + imageScope.SetImageState(image.State) imageScope.Info("ImageState - " + image.State) switch imageScope.GetImageState() { - case v1beta1.PowerVSInstanceStateQue: + case v1beta1.PowerVSImageStateQue: imageScope.Info("Image is in queued state") imageScope.SetNotReady() conditions.MarkFalse(imageScope.IBMPowerVSImage, v1beta1.ImageReadyCondition, v1beta1.ImageNotReadyReason, clusterv1.ConditionSeverityWarning, "")