From 350fa762a4e5044a25ff4650fc85f7c9e6763f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= Date: Wed, 27 Mar 2024 12:03:29 -0400 Subject: [PATCH] incusd/recover: Handle instances last MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #646 Signed-off-by: Stéphane Graber --- cmd/incusd/api_internal_recover.go | 53 +++++++++++++++++++----------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/cmd/incusd/api_internal_recover.go b/cmd/incusd/api_internal_recover.go index 65df744df87..80ca6e5777f 100644 --- a/cmd/incusd/api_internal_recover.go +++ b/cmd/incusd/api_internal_recover.go @@ -307,6 +307,7 @@ func internalRecoverScan(ctx context.Context, s *state.State, userPools []api.St // If in import mode and no dependency errors, then re-create missing DB records. + // Create the pools themselves. for _, pool := range pools { // Create missing storage pool DB record if neeed. if pool.ID() == storagePools.PoolIDTemporary { @@ -369,10 +370,11 @@ func internalRecoverScan(ctx context.Context, s *state.State, userPools []api.St // Record this newly created pool so that defer doesn't unmount on return. pools[pool.Name()] = newPool - pool = newPool // Replace temporary pool handle with proper one from DB. } + } - // Create any missing instance, storage volume, and storage bucket records. + // Recover the storage volumes and buckets. + for _, pool := range pools { for projectName, poolVols := range poolsProjectVols[pool.Name()] { projectInfo := projects[projectName] @@ -381,7 +383,6 @@ func internalRecoverScan(ctx context.Context, s *state.State, userPools []api.St return response.SmartError(fmt.Errorf("Project %q not found", projectName)) } - profileProjectName := project.ProfileProjectFromRecord(projectInfo) customStorageProjectName := project.StorageVolumeProjectFromRecord(projectInfo, db.StoragePoolVolumeTypeCustom) // Recover unknown custom volumes (do this first before recovering instances so that any @@ -402,6 +403,36 @@ func internalRecoverScan(ctx context.Context, s *state.State, userPools []api.St revert.Add(cleanup) } + // Recover unknown buckets. + for _, poolVol := range poolVols { + // Skip non bucket volumes. + if poolVol.Bucket == nil { + continue + } + + // Import bucket. + cleanup, err := pool.ImportBucket(projectName, poolVol, nil) + if err != nil { + return response.SmartError(fmt.Errorf("Failed importing bucket %q in project %q: %w", poolVol.Bucket.Name, projectName, err)) + } + + revert.Add(cleanup) + } + } + } + + // Finally restore the instances. + for _, pool := range pools { + for projectName, poolVols := range poolsProjectVols[pool.Name()] { + projectInfo := projects[projectName] + + if projectInfo == nil { + // Shouldn't happen as we validated this above, but be sure for safety. + return response.SmartError(fmt.Errorf("Project %q not found", projectName)) + } + + profileProjectName := project.ProfileProjectFromRecord(projectInfo) + // Recover unknown instance volumes. for _, poolVol := range poolVols { if poolVol.Container == nil && (poolVol.Volume != nil || poolVol.Bucket != nil) { @@ -462,22 +493,6 @@ func internalRecoverScan(ctx context.Context, s *state.State, userPools []api.St } } } - - // Recover unknown buckets. - for _, poolVol := range poolVols { - // Skip non bucket volumes. - if poolVol.Bucket == nil { - continue - } - - // Import bucket. - cleanup, err := pool.ImportBucket(projectName, poolVol, nil) - if err != nil { - return response.SmartError(fmt.Errorf("Failed importing bucket %q in project %q: %w", poolVol.Bucket.Name, projectName, err)) - } - - revert.Add(cleanup) - } } }