Skip to content
This repository was archived by the owner on Dec 16, 2025. It is now read-only.

Commit 43d1ee5

Browse files
committed
Handle image statuses
Signed-off-by: Matej Feder <[email protected]>
1 parent e0ca13f commit 43d1ee5

File tree

3 files changed

+49
-70
lines changed

3 files changed

+49
-70
lines changed

api/v1alpha1/conditions_const.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,4 @@ const (
7575

7676
// IssueWithOpenStackImageReason is used when image has an issue.
7777
IssueWithOpenStackImageReason = "IssueWithOpenStackImage"
78-
79-
// OpenStackImageIsDeactivatedReason is used when image is deactivated.
80-
OpenStackImageIsDeactivatedReason = "OpenStackImageDeactivated"
81-
82-
// OpenStackImageIsDeletingReason is used when image is being deleted.
83-
OpenStackImageIsDeletingReason = "OpenStackImageGettingDeleted"
84-
85-
// OpenStackImageIsQueuedReason is used when image is queued.
86-
OpenStackImageIsQueuedReason = "OpenStackImageIsQueued"
8778
)

internal/controller/openstackclusterstackrelease_controller.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,11 @@ type NodeImages struct {
5858
}
5959

6060
const (
61-
metadataFileName = "metadata.yaml"
62-
nodeImagesFileName = "node-images.yaml"
63-
maxNameLength = 63
61+
metadataFileName = "metadata.yaml"
62+
nodeImagesFileName = "node-images.yaml"
63+
maxNameLength = 63
64+
waitForOpenStackNodeImageReleasesBecomeReady = 30 * time.Second
65+
reconcileOpenStackNodeImageReleases = 3 * time.Minute
6466
)
6567

6668
//+kubebuilder:rbac:groups=infrastructure.clusterstack.x-k8s.io,resources=openstackclusterstackreleases,verbs=get;list;watch;create;update;patch;delete
@@ -174,7 +176,7 @@ func (r *OpenStackClusterStackReleaseReconciler) Reconcile(ctx context.Context,
174176
"OpenStackNodeImageReleases not ready yet",
175177
)
176178
openstackclusterstackrelease.Status.Ready = false
177-
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
179+
return ctrl.Result{RequeueAfter: waitForOpenStackNodeImageReleasesBecomeReady}, nil
178180
}
179181
for _, openStackNodeImageRelease := range ownedOpenStackNodeImageReleases {
180182
if openStackNodeImageRelease.Status.Ready {
@@ -187,14 +189,15 @@ func (r *OpenStackClusterStackReleaseReconciler) Reconcile(ctx context.Context,
187189
"OpenStackNodeImageReleases not ready yet",
188190
)
189191
openstackclusterstackrelease.Status.Ready = false
190-
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
192+
return ctrl.Result{RequeueAfter: waitForOpenStackNodeImageReleasesBecomeReady}, nil
191193
}
192194

193195
logger.Info("OpenStackClusterStackRelease **ready**")
194196
conditions.MarkTrue(openstackclusterstackrelease, apiv1alpha1.OpenStackNodeImageReleasesReadyCondition)
195197
openstackclusterstackrelease.Status.Ready = true
196198

197-
return ctrl.Result{}, nil
199+
// Requeue to ensure the OpenStackNodeImageReleases are still ready
200+
return ctrl.Result{Requeue: true, RequeueAfter: reconcileOpenStackNodeImageReleases}, nil
198201
}
199202

200203
func (r *OpenStackClusterStackReleaseReconciler) getOrCreateOpenStackNodeImageRelease(ctx context.Context, openstackclusterstackrelease *apiv1alpha1.OpenStackClusterStackRelease, osnirName string, openStackNodeImage *apiv1alpha1.OpenStackNodeImage, ownerRef *metav1.OwnerReference) error {

internal/controller/openstacknodeimagerelease_controller.go

Lines changed: 40 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ type OpenStackNodeImageReleaseReconciler struct {
4949
}
5050

5151
const (
52-
cloudsSecretKey = "clouds.yaml"
52+
cloudsSecretKey = "clouds.yaml"
53+
waitForImageBecomeActive = 30 * time.Second
54+
reconcileImage = 3 * time.Minute
5355
)
5456

5557
//+kubebuilder:rbac:groups=infrastructure.clusterstack.x-k8s.io,resources=openstacknodeimagereleases,verbs=get;list;watch;create;update;patch;delete
@@ -188,69 +190,52 @@ func (r *OpenStackNodeImageReleaseReconciler) Reconcile(ctx context.Context, req
188190

189191
// TODO: Add timeout logic - import start time could be taken from OpenStackImageNotImportedYetReason condition, or somehow better
190192

191-
switch image.Status { //nolint:exhaustive
193+
// Manage image statuses according to the guidelines outlined in https://docs.openstack.org/glance/stein/user/statuses.html.
194+
switch image.Status {
192195
case images.ImageStatusActive:
193-
logger.Info("OpenStackNodeImageRelease **ready** - image is **active**.", "name", openstacknodeimagerelease.Spec.Image.CreateOpts.Name, "ID", imageID)
196+
logger.Info("OpenStackNodeImageRelease **ready** - image is **ACTIVE**.", "name", openstacknodeimagerelease.Spec.Image.CreateOpts.Name, "ID", imageID)
194197
conditions.MarkTrue(openstacknodeimagerelease, apiv1alpha1.OpenStackImageReadyCondition)
195198
openstacknodeimagerelease.Status.Ready = true
196199

197-
// requeue after 2 minutes to make sure the presence of the image
198-
return ctrl.Result{Requeue: true, RequeueAfter: 2 * time.Minute}, nil
199-
200-
case images.ImageStatusImporting, images.ImageStatusSaving:
201-
202-
logger.Info("OpenStackNodeImageRelease **not ready** yet - image is currently being imported by Glance.", "name", openstacknodeimagerelease.Spec.Image.CreateOpts.Name, "ID", imageID)
203-
conditions.MarkFalse(openstacknodeimagerelease, apiv1alpha1.OpenStackImageReadyCondition, apiv1alpha1.OpenStackImageNotImportedYetReason, clusterv1beta1.ConditionSeverityInfo, "image not imported yet")
204-
openstacknodeimagerelease.Status.Ready = false
205-
206-
// wait for image - requeue after 30sec
207-
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
208-
209-
case images.ImageStatusDeactivated:
210-
211-
logger.Info("OpenStackNodeImageRelease **not ready** yet - image is deactivated.", "name", openstacknodeimagerelease.Spec.Image.CreateOpts.Name, "ID", imageID)
212-
conditions.MarkFalse(openstacknodeimagerelease, apiv1alpha1.OpenStackImageReadyCondition, apiv1alpha1.OpenStackImageIsDeactivatedReason, clusterv1beta1.ConditionSeverityWarning, "image is deactivated")
213-
openstacknodeimagerelease.Status.Ready = false
214-
215-
// TODO: Should we make function to activate deactivated image or just tell user to activate it manually?
216-
// wait for image - requeue after 30sec
217-
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
218-
219-
case images.ImageStatusKilled:
220-
221-
logger.Info("OpenStackNodeImageRelease **error** - image is not readable.", "name", openstacknodeimagerelease.Spec.Image.CreateOpts.Name, "ID", imageID)
222-
conditions.MarkFalse(openstacknodeimagerelease, apiv1alpha1.OpenStackImageReadyCondition, apiv1alpha1.IssueWithOpenStackImageReason, clusterv1beta1.ConditionSeverityError, "image is not readable")
223-
openstacknodeimagerelease.Status.Ready = false
224-
225-
// TODO: Image is broken and needs to be deleted?
226-
// wait for image - requeue after 30sec
227-
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
228-
229-
case images.ImageStatusPendingDelete, images.ImageStatusDeleted:
230-
231-
logger.Info("OpenStackNodeImageRelease **deleting** - image is being deleted.", "name", openstacknodeimagerelease.Spec.Image.CreateOpts.Name, "ID", imageID)
232-
conditions.MarkFalse(openstacknodeimagerelease, apiv1alpha1.OpenStackImageReadyCondition, apiv1alpha1.OpenStackImageIsDeletingReason, clusterv1beta1.ConditionSeverityInfo, "deleting image")
200+
case images.ImageStatusDeactivated, images.ImageStatusKilled:
201+
// These statuses are unexpected. Hence we set a failure for them. See the explanation below:
202+
// `deactivated`: image is not allowed to use to any non-admin user
203+
// `killed`: an error occurred during the uploading of an image’s data, and that the image is not readable (via v1 API)
204+
err = fmt.Errorf("image status %s is unexpected", image.Status)
205+
conditions.MarkFalse(openstacknodeimagerelease,
206+
apiv1alpha1.OpenStackImageReadyCondition,
207+
apiv1alpha1.IssueWithOpenStackImageReason,
208+
clusterv1beta1.ConditionSeverityError,
209+
err.Error(),
210+
)
233211
openstacknodeimagerelease.Status.Ready = false
234-
235-
// wait for image - requeue after 30sec
236-
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
237-
238-
case images.ImageStatusQueued:
239-
240-
logger.Info("OpenStackNodeImageRelease **not ready** - image is queued.", "name", openstacknodeimagerelease.Spec.Image.CreateOpts.Name, "ID", imageID)
241-
conditions.MarkFalse(openstacknodeimagerelease, apiv1alpha1.OpenStackImageReadyCondition, apiv1alpha1.OpenStackImageIsQueuedReason, clusterv1beta1.ConditionSeverityInfo, "image is queued")
212+
return ctrl.Result{}, err
213+
214+
case images.ImageStatusQueued, images.ImageStatusSaving, images.ImageStatusDeleted, images.ImageStatusPendingDelete, images.ImageStatusImporting:
215+
// The other statuses are expected. See the explanation below:
216+
// - `deleted`, `pending_delete`: The image has been deleted and will be removed soon, hence we can create and import the image in the next reconciliation loop.
217+
// - `importing`, `uploading`, `saving`, and `queued`: The image is in the process of being uploaded or imported via upload to Glance or the Glance image import API (performed by this reconciliation loop). Therefore, let's wait for it.
218+
logger.Info("OpenStackNodeImageRelease **not ready** yet - waiting for image to become ACTIVE", "name", openstacknodeimagerelease.Spec.Image.CreateOpts.Name, "ID", imageID, "status", image.Status)
219+
conditions.MarkFalse(openstacknodeimagerelease, apiv1alpha1.OpenStackImageReadyCondition, apiv1alpha1.OpenStackImageNotImportedYetReason, clusterv1beta1.ConditionSeverityInfo, "waiting for image to become ACTIVE")
242220
openstacknodeimagerelease.Status.Ready = false
221+
// Wait for image
222+
return ctrl.Result{RequeueAfter: waitForImageBecomeActive}, nil
243223

244-
// wait for image - requeue after 30sec
245-
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
246-
247-
// TODO: Choose what is default case for image.status
248224
default:
249-
logger.Info("OpenStackNodeImageRelease **handling for image status not defined yet** - requeue", "name", openstacknodeimagerelease.Spec.Image.CreateOpts.Name, "ID", imageID, "status", image.Status)
250-
251-
// wait for image - requeue after 30sec
252-
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
225+
// An unknown state - set failure
226+
err = fmt.Errorf("image status %s is unknown", image.Status)
227+
conditions.MarkFalse(openstacknodeimagerelease,
228+
apiv1alpha1.OpenStackImageReadyCondition,
229+
apiv1alpha1.IssueWithOpenStackImageReason,
230+
clusterv1beta1.ConditionSeverityError,
231+
err.Error(),
232+
)
233+
openstacknodeimagerelease.Status.Ready = false
234+
return ctrl.Result{}, err
253235
}
236+
237+
// Requeue to ensure the image's presence
238+
return ctrl.Result{Requeue: true, RequeueAfter: reconcileImage}, nil
254239
}
255240

256241
func (r *OpenStackNodeImageReleaseReconciler) getCloudFromSecret(ctx context.Context, secretNamespace, secretName, cloudName string) (clientconfig.Cloud, error) {

0 commit comments

Comments
 (0)