-
Notifications
You must be signed in to change notification settings - Fork 6
Add checks to see rbd image existence along with store entry #840
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -269,14 +269,10 @@ func (r *ImageReconciler) deleteImageSnapshots(ctx context.Context, log logr.Log | |
| return fmt.Errorf("failed to create snapshot clone: %w", err) | ||
| } | ||
|
|
||
| isSnapshotExist, err := snapshotExists(log, ioCtx, ImageIDToRBDID(snapName), snapName) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to check if snapshot exists: %w", err) | ||
| } | ||
| if isSnapshotExist { | ||
| log.V(2).Info("Snapshot of cloned image is already created") | ||
| if isSnapshotExist, err := snapshotExists(log, ioCtx, ImageIDToRBDID(snapName), snapName); err == nil && isSnapshotExist { | ||
| continue | ||
| } | ||
|
|
||
| log.V(2).Info("Create snapshot of cloned image", "clonedImageId", snapName) | ||
| if err := createSnapshot(log, ioCtx, snapName, ImageIDToRBDID(snapName)); err != nil { | ||
| return fmt.Errorf("failed to create snapshot of cloned image: %w", err) | ||
|
|
@@ -742,7 +738,6 @@ func (r *ImageReconciler) createImageFromSnapshot(ctx context.Context, log logr. | |
| } | ||
|
|
||
| log.V(1).Info("snapshot not found", "snapshotID", snapshotRef) | ||
|
|
||
| return false, nil | ||
| } | ||
|
|
||
|
|
@@ -751,6 +746,24 @@ func (r *ImageReconciler) createImageFromSnapshot(ctx context.Context, log logr. | |
| return false, nil | ||
| } | ||
|
|
||
| if image.Spec.Image != "" { | ||
| log.V(2).Info("Check if snapshot rbd image already exist") | ||
| imageExists, err := isRbdImageExisting(ioCtx, SnapshotIDToRBDID(snapshotRef)) | ||
| if err != nil { | ||
| return false, fmt.Errorf("failed to check snapshot rbd image existence: %w", err) | ||
| } | ||
| log.V(1).Info("Checked snapshot rbd image existence", "imageExists", imageExists) | ||
|
|
||
| if !imageExists && snapshot.Status.State == providerapi.SnapshotStateReady { | ||
| log.V(1).Info("Snapshot rbd image does not exist. Mark snapshot as failed to trigger rbd image creation in next reconciliation loop") | ||
| snapshot.Status.State = providerapi.SnapshotStateFailed | ||
| if _, err := r.snapshots.Update(ctx, snapshot); store.IgnoreErrNotFound(err) != nil { | ||
| return false, fmt.Errorf("failed to update snapshot to trigger rbd image creation: %w", err) | ||
| } | ||
| return false, nil | ||
| } | ||
| } | ||
kasabe28 marked this conversation as resolved.
Show resolved
Hide resolved
Comment on lines
+749
to
+765
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Drive parent-image existence checks from At Line 749, the check only runs when 💡 Proposed fix- if image.Spec.Image != "" {
+ parentName, snapName, err := getSnapshotSourceDetails(snapshot)
+ if err != nil {
+ return false, fmt.Errorf("failed to get snapshot source details: %w", err)
+ }
+
+ if snapshot.Source.IronCoreImage != "" || snapshot.Source.VolumeImageID != "" {
log.V(2).Info("Check if snapshot rbd image already exist")
- imageExists, err := isRbdImageExisting(ioCtx, SnapshotIDToRBDID(snapshotRef))
+ imageExists, err := isRbdImageExisting(ioCtx, parentName)
if err != nil {
return false, fmt.Errorf("failed to check snapshot rbd image existence: %w", err)
}
log.V(1).Info("Checked snapshot rbd image existence", "imageExists", imageExists)
if !imageExists && snapshot.Status.State == providerapi.SnapshotStateReady {
log.V(1).Info("Snapshot rbd image does not exist. Mark snapshot as failed to trigger rbd image creation in next reconciliation loop")
snapshot.Status.State = providerapi.SnapshotStateFailed
if _, err := r.snapshots.Update(ctx, snapshot); store.IgnoreErrNotFound(err) != nil {
return false, fmt.Errorf("failed to update snapshot to trigger rbd image creation: %w", err)
}
return false, nil
}
}
-
- parentName, snapName, err := getSnapshotSourceDetails(snapshot)
- if err != nil {
- return false, fmt.Errorf("failed to get snapshot source details: %w", err)
- }🤖 Prompt for AI Agents |
||
|
|
||
| parentName, snapName, err := getSnapshotSourceDetails(snapshot) | ||
| if err != nil { | ||
| return false, fmt.Errorf("failed to get snapshot source details: %w", err) | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -249,21 +249,35 @@ func (r *SnapshotReconciler) reconcileSnapshot(ctx context.Context, id string) e | |||||||||||||||||
| return nil | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| // SnapshotStatePopulated is no longer actively used. It has been replaced by SnapshotStateReady. | ||||||||||||||||||
| // This block will transition any snapshots that are in SnapshotStatePopulated to SnapshotStateReady. | ||||||||||||||||||
| if snapshot.Status.State == providerapi.SnapshotStatePopulated { | ||||||||||||||||||
| log.V(1).Info("Snapshot already populated") | ||||||||||||||||||
| snapshot.Status.State = providerapi.SnapshotStateReady | ||||||||||||||||||
| if _, err = r.store.Update(ctx, snapshot); err != nil { | ||||||||||||||||||
| return fmt.Errorf("failed to update snapshot: %w", err) | ||||||||||||||||||
| imageExists := false | ||||||||||||||||||
| if snapshot.Source.IronCoreImage != "" { | ||||||||||||||||||
| log.V(2).Info("Check if snapshot image already exist") | ||||||||||||||||||
| imageExists, err = isRbdImageExisting(ioCtx, SnapshotIDToRBDID(snapshot.ID)) | ||||||||||||||||||
| if err != nil { | ||||||||||||||||||
| return fmt.Errorf("failed to check if snapshot exists: %w", err) | ||||||||||||||||||
| } | ||||||||||||||||||
| log.V(1).Info("Checked snapshot rbd image existence", "imageExists", imageExists) | ||||||||||||||||||
| } else if snapshot.Source.VolumeImageID != "" { | ||||||||||||||||||
| imageExists = true | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| if imageExists { | ||||||||||||||||||
| // SnapshotStatePopulated is no longer actively used. It has been replaced by SnapshotStateReady. | ||||||||||||||||||
| // This block will transition any snapshots that are in SnapshotStatePopulated to SnapshotStateReady. | ||||||||||||||||||
| if snapshot.Status.State == providerapi.SnapshotStatePopulated { | ||||||||||||||||||
| log.V(1).Info("Snapshot already populated") | ||||||||||||||||||
| snapshot.Status.State = providerapi.SnapshotStateReady | ||||||||||||||||||
| if _, err = r.store.Update(ctx, snapshot); err != nil { | ||||||||||||||||||
| return fmt.Errorf("failed to update snapshot: %w", err) | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| return nil | ||||||||||||||||||
| } | ||||||||||||||||||
| return nil | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| if snapshot.Status.State == providerapi.SnapshotStateReady { | ||||||||||||||||||
| log.V(1).Info("Snapshot is ready") | ||||||||||||||||||
| return nil | ||||||||||||||||||
| if snapshot.Status.State == providerapi.SnapshotStateReady { | ||||||||||||||||||
| log.V(1).Info("Snapshot is ready") | ||||||||||||||||||
| return nil | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| if !slices.Contains(snapshot.Finalizers, SnapshotFinalizer) { | ||||||||||||||||||
|
|
@@ -325,20 +339,24 @@ func (r *SnapshotReconciler) reconcileIroncoreImageSnapshot(ctx context.Context, | |||||||||||||||||
| } | ||||||||||||||||||
| log.V(2).Info("Configured pool", "pool", r.pool) | ||||||||||||||||||
|
|
||||||||||||||||||
| imageName := SnapshotIDToRBDID(snapshot.ID) | ||||||||||||||||||
| rbdImageID := SnapshotIDToRBDID(snapshot.ID) | ||||||||||||||||||
| roundedSize := round.OffBytes(snapshotSize) | ||||||||||||||||||
| if err = librbd.CreateImage(ioCtx, imageName, roundedSize, options); err != nil { | ||||||||||||||||||
| return fmt.Errorf("failed to create os rbd image: %w", err) | ||||||||||||||||||
| } | ||||||||||||||||||
| log.V(2).Info("Created rbd image", "bytes", roundedSize) | ||||||||||||||||||
|
|
||||||||||||||||||
| if err := r.prepareSnapshotContent(log, ioCtx, imageName, rc); err != nil { | ||||||||||||||||||
| return fmt.Errorf("failed to prepare snapshot content: %w", err) | ||||||||||||||||||
| rbdImg, err := openImage(ioCtx, rbdImageID) | ||||||||||||||||||
| if errors.Is(err, librbd.ErrNotFound) { | ||||||||||||||||||
| if err = librbd.CreateImage(ioCtx, rbdImageID, roundedSize, options); err != nil { | ||||||||||||||||||
| return fmt.Errorf("failed to create os rbd image: %w", err) | ||||||||||||||||||
| } | ||||||||||||||||||
| log.V(2).Info("Created rbd image", "bytes", roundedSize) | ||||||||||||||||||
| rbdImg, err = openImage(ioCtx, rbdImageID) | ||||||||||||||||||
| } | ||||||||||||||||||
| if err != nil { | ||||||||||||||||||
| return err | ||||||||||||||||||
| } | ||||||||||||||||||
| defer closeImage(log, rbdImg) | ||||||||||||||||||
|
|
||||||||||||||||||
| log.V(2).Info("Create ironcore image snapshot", "ImageID", imageName) | ||||||||||||||||||
| if err := createSnapshot(log, ioCtx, ImageSnapshotVersion, imageName); err != nil { | ||||||||||||||||||
| return fmt.Errorf("failed to create ironcore image snapshot: %w", err) | ||||||||||||||||||
| if err := r.prepareSnapshotContent(log, ioCtx, rbdImg, rc); err != nil { | ||||||||||||||||||
| return fmt.Errorf("failed to prepare snapshot content: %w", err) | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| snapshot.Status.Digest = digest | ||||||||||||||||||
|
|
@@ -355,6 +373,10 @@ func (r *SnapshotReconciler) reconcileVolumeImageSnapshot(ctx context.Context, l | |||||||||||||||||
| return nil | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| if isSnapshotExist, err := snapshotExists(log, ioCtx, img.GetID(), snapshot.ID); err == nil && isSnapshotExist { | ||||||||||||||||||
| return nil | ||||||||||||||||||
| } | ||||||||||||||||||
|
Comment on lines
+376
to
+378
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use the RBD image name ( At Line 376, 💡 Proposed fix- if isSnapshotExist, err := snapshotExists(log, ioCtx, img.GetID(), snapshot.ID); err == nil && isSnapshotExist {
- return nil
- }
+ if isSnapshotExist, err := snapshotExists(log, ioCtx, ImageIDToRBDID(img.ID), snapshot.ID); err != nil {
+ return fmt.Errorf("failed to check volume snapshot existence: %w", err)
+ } else if isSnapshotExist {
+ return nil
+ }🤖 Prompt for AI Agents |
||||||||||||||||||
|
|
||||||||||||||||||
| log.V(2).Info("Create volume image snapshot", "ImageID", img.ID) | ||||||||||||||||||
| if err := createSnapshot(log, ioCtx, snapshot.ID, ImageIDToRBDID(img.ID)); err != nil { | ||||||||||||||||||
| return fmt.Errorf("failed to create volume image snapshot: %w", err) | ||||||||||||||||||
|
|
@@ -393,18 +415,22 @@ func (r *SnapshotReconciler) openIroncoreImageSource(ctx context.Context, imageR | |||||||||||||||||
| return content, uint64(rootFS.Descriptor().Size), img.Descriptor().Digest.String(), nil | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| func (r *SnapshotReconciler) prepareSnapshotContent(log logr.Logger, ioCtx *rados.IOContext, imageName string, rc io.ReadCloser) error { | ||||||||||||||||||
| rbdImg, err := openImage(ioCtx, imageName) | ||||||||||||||||||
| if err != nil { | ||||||||||||||||||
| return err | ||||||||||||||||||
| func (r *SnapshotReconciler) prepareSnapshotContent(log logr.Logger, ioCtx *rados.IOContext, rbdImg *librbd.Image, rc io.ReadCloser) error { | ||||||||||||||||||
| rbdImageID := rbdImg.GetName() | ||||||||||||||||||
| if isSnapshotExist, err := snapshotExists(log, ioCtx, rbdImageID, ImageSnapshotVersion); err == nil && isSnapshotExist { | ||||||||||||||||||
| return nil | ||||||||||||||||||
| } | ||||||||||||||||||
|
Comment on lines
+420
to
422
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not continue when At Line 420, a non-nil error is ignored, and reconciliation proceeds to populate/create snapshot. If this check fails transiently, you can perform unnecessary writes and hit avoidable failures. 💡 Proposed fix- if isSnapshotExist, err := snapshotExists(log, ioCtx, rbdImageID, ImageSnapshotVersion); err == nil && isSnapshotExist {
- return nil
- }
+ if isSnapshotExist, err := snapshotExists(log, ioCtx, rbdImageID, ImageSnapshotVersion); err != nil {
+ return fmt.Errorf("failed to check ironcore snapshot existence: %w", err)
+ } else if isSnapshotExist {
+ return nil
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||
| defer closeImage(log, rbdImg) | ||||||||||||||||||
|
|
||||||||||||||||||
| if err := r.populateImage(log, rbdImg, rc); err != nil { | ||||||||||||||||||
| return fmt.Errorf("failed to populate os image: %w", err) | ||||||||||||||||||
| } | ||||||||||||||||||
| log.V(2).Info("Populated os image on rbd image") | ||||||||||||||||||
|
|
||||||||||||||||||
| log.V(2).Info("Create ironcore image snapshot", "ImageID", rbdImageID) | ||||||||||||||||||
| if err := createSnapshot(log, ioCtx, ImageSnapshotVersion, rbdImageID); err != nil { | ||||||||||||||||||
| return fmt.Errorf("failed to create ironcore image snapshot: %w", err) | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| return nil | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Propagate
snapshotExistserrors in cleanup flow.At Line 272, errors are ignored and execution continues. If Ceph lookup fails, the code may attempt snapshot creation/removal decisions on incomplete information.
💡 Proposed fix
🤖 Prompt for AI Agents