]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: fix retention add for subvolume 55691/head
authorIvo Almeida <ialmeida@redhat.com>
Wed, 21 Feb 2024 13:02:19 +0000 (13:02 +0000)
committerIvo Almeida <ialmeida@redhat.com>
Tue, 19 Mar 2024 12:14:11 +0000 (12:14 +0000)
- Added parameters for subvolume and subvolume group when adding a new
snap schedule.
- Added call to remove retention policies when removing a snap schedule
  in case it is the last one with same path

Fixes: https://tracker.ceph.com/issues/64524
Signed-off-by: Ivo Almeida <ialmeida@redhat.com>
src/pybind/mgr/dashboard/controllers/cephfs.py
src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-snapshotschedule-form/cephfs-snapshotschedule-form.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cephfs/cephfs-snapshotschedule-list/cephfs-snapshotschedule-list.component.ts
src/pybind/mgr/dashboard/frontend/src/app/shared/api/cephfs-snapshot-schedule.service.ts
src/pybind/mgr/dashboard/openapi.yaml

index 6410a73785ecb84bad94b594c5add27bab29f3f1..4210746fbd1ffc16ec4bd16717a32d0ba126167c 100644 (file)
@@ -1029,7 +1029,9 @@ class CephFSSnapshotSchedule(RESTController):
                                                                     path,
                                                                     retention_spec_or_period,
                                                                     retention_count,
-                                                                    fs)
+                                                                    fs,
+                                                                    subvol,
+                                                                    group)
                 if error_code_retention != 0:
                     raise DashboardException(
                         f'Failed to add retention policy for path {path}: {err_retention}'
@@ -1071,7 +1073,36 @@ class CephFSSnapshotSchedule(RESTController):
 
     @RESTController.Resource('DELETE')
     def delete_snapshot(self, fs: str, path: str, schedule: str, start: str,
-                        subvol=None, group=None):
+                        retention_policy=None, subvol=None, group=None):
+        if retention_policy:
+            # check if there are other snap schedules for this exact same path
+            error_code, out, err = mgr.remote('snap_schedule', 'snap_schedule_list',
+                                              path, False, fs, subvol, group, 'plain')
+
+            if error_code != 0:
+                raise DashboardException(
+                    f'Failed to get snapshot schedule list for path {path}: {err}'
+                )
+            # only remove the retention policies if there no other snap schedules for this path
+            snapshot_schedule_list = out.split('\n')
+            if len(snapshot_schedule_list) <= 1:
+                retention_policies = retention_policy.split('|')
+                for retention in retention_policies:
+                    retention_count = retention.split('-')[0]
+                    retention_spec_or_period = retention.split('-')[1]
+                    error_code, _, err = mgr.remote('snap_schedule',
+                                                    'snap_schedule_retention_rm',
+                                                    path,
+                                                    retention_spec_or_period,
+                                                    retention_count,
+                                                    fs,
+                                                    subvol,
+                                                    group)
+                    if error_code != 0:
+                        raise DashboardException(
+                            f'Failed to remove retention policy for path {path}: {err}'
+                        )
+        # remove snap schedule
         error_code, _, err = mgr.remote('snap_schedule',
                                         'snap_schedule_rm',
                                         path,
index 0ef68f7d529c5edc1e93d7f0aa629fa1cc339154..22fa33f0fe1cbbdc87a5db31d72ed3153a731e91 100644 (file)
@@ -389,7 +389,8 @@ export class CephfsSnapshotscheduleFormComponent extends CdForm implements OnIni
               frm.get('directory').value,
               this.fsName,
               retentionList,
-              this.retentionPoliciesToRemove?.map?.((rp) => rp.retentionFrequency) || []
+              this.retentionPoliciesToRemove?.map?.((rp) => rp.retentionFrequency) || [],
+              !!this.subvolume
             )
             .pipe(
               map(({ exists, errorIndex }) => {
index f6f372dcffc4ea8658e3f9e17e9062038d338196..9a131a1e80b7c0247e10ca32c4b4d2210b870b40 100644 (file)
@@ -291,7 +291,17 @@ export class CephfsSnapshotscheduleListComponent
   }
 
   deleteSnapshotSchedule() {
-    const { path, start, fs, schedule, subvol, group } = this.selection.first();
+    const { path, start, fs, schedule, subvol, group, retention } = this.selection.first();
+    const retentionPolicy = retention
+      ?.split(/\s/gi)
+      ?.filter((r: string) => !!r)
+      ?.map((r: string) => {
+        const frequency = r.substring(r.length - 1);
+        const interval = r.substring(0, r.length - 1);
+        return `${interval}-${frequency}`;
+      })
+      ?.join('|')
+      ?.toLocaleLowerCase();
 
     this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
       itemDescription: $localize`snapshot schedule`,
@@ -305,6 +315,7 @@ export class CephfsSnapshotscheduleListComponent
             schedule,
             start,
             fs,
+            retentionPolicy,
             subvol,
             group
           })
index 93c04dc38ed953a92f41a3e6e7fa9ab4213853b4..ade935a9299a4ebf6a5defe8024b4b5c549c53e6 100644 (file)
@@ -48,10 +48,21 @@ export class CephfsSnapshotScheduleService {
     );
   }
 
-  delete({ fs, path, schedule, start, subvol, group }: Record<string, any>): Observable<any> {
+  delete({
+    fs,
+    path,
+    schedule,
+    start,
+    retentionPolicy,
+    subvol,
+    group
+  }: Record<string, any>): Observable<any> {
     let deleteUrl = `${this.baseURL}/snapshot/schedule/${fs}/${encodeURIComponent(
       path
     )}/delete_snapshot?schedule=${schedule}&start=${encodeURIComponent(start)}`;
+    if (retentionPolicy) {
+      deleteUrl += `&retention_policy=${retentionPolicy}`;
+    }
     if (subvol && group) {
       deleteUrl += `&subvol=${encodeURIComponent(subvol)}&group=${encodeURIComponent(group)}`;
     }
@@ -81,13 +92,16 @@ export class CephfsSnapshotScheduleService {
     path: string,
     fs: string,
     retentionFrequencies: string[],
-    retentionFrequenciesRemoved: string[] = []
+    retentionFrequenciesRemoved: string[] = [],
+    isSubvolume = false
   ): Observable<{ exists: boolean; errorIndex: number }> {
     return this.getSnapshotSchedule(path, fs, false).pipe(
       map((response) => {
         let errorIndex = -1;
         let exists = false;
-        const index = response.findIndex((x) => x.path === path);
+        const index = response.findIndex((x) =>
+          isSubvolume ? x.path.startsWith(path) : x.path === path
+        );
         const result = retentionFrequencies?.length
           ? intersection(
               Object.keys(response?.[index]?.retention).filter(
index f3d4f3607f333da82b487be2c6acd89952c2b818..5244d4a983b26cb66c87d98a5e411d5169728fd9 100644 (file)
@@ -2081,6 +2081,11 @@ paths:
         required: true
         schema:
           type: string
+      - allowEmptyValue: true
+        in: query
+        name: retention_policy
+        schema:
+          type: string
       - allowEmptyValue: true
         in: query
         name: subvol