]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-form/rbd-form.component.ts
import ceph quincy 17.2.4
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / block / rbd-form / rbd-form.component.ts
index 1dc1df0dd3aba8da08c4025e85018572d3cd0df2..4fa71646215fafe9f6603309d04818892c97651b 100644 (file)
@@ -8,6 +8,7 @@ import { first, switchMap } from 'rxjs/operators';
 
 import { Pool } from '~/app/ceph/pool/pool';
 import { PoolService } from '~/app/shared/api/pool.service';
+import { RbdMirroringService } from '~/app/shared/api/rbd-mirroring.service';
 import { RbdService } from '~/app/shared/api/rbd.service';
 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
 import { Icons } from '~/app/shared/enum/icons.enum';
@@ -77,6 +78,11 @@ export class RbdFormComponent extends CdForm implements OnInit {
 
   defaultObjectSize = '4 MiB';
 
+  mirroringOptions = ['journal', 'snapshot'];
+  poolMirrorMode: string;
+  mirroring = false;
+  currentPoolName = '';
+
   objectSizes: Array<string> = [
     '4 KiB',
     '8 KiB',
@@ -93,6 +99,11 @@ export class RbdFormComponent extends CdForm implements OnInit {
     '16 MiB',
     '32 MiB'
   ];
+
+  defaultStripingUnit = '4 MiB';
+
+  defaultStripingCount = 1;
+
   action: string;
   resource: string;
   private rbdImage = new ReplaySubject(1);
@@ -109,7 +120,8 @@ export class RbdFormComponent extends CdForm implements OnInit {
     private taskWrapper: TaskWrapperService,
     private dimlessBinaryPipe: DimlessBinaryPipe,
     public actionLabels: ActionLabelsI18n,
-    private router: Router
+    private router: Router,
+    private rbdMirroringService: RbdMirroringService
   ) {
     super();
     this.routerUrl = this.router.url;
@@ -141,13 +153,6 @@ export class RbdFormComponent extends CdForm implements OnInit {
         allowDisable: true,
         initDisabled: true
       },
-      journaling: {
-        desc: $localize`Journaling (requires exclusive-lock)`,
-        requires: 'exclusive-lock',
-        allowEnable: true,
-        allowDisable: true,
-        initDisabled: true
-      },
       'fast-diff': {
         desc: $localize`Fast diff (interlocked with object-map)`,
         requires: 'object-map',
@@ -188,8 +193,13 @@ export class RbdFormComponent extends CdForm implements OnInit {
             return acc;
           }, {})
         ),
-        stripingUnit: new FormControl(null),
-        stripingCount: new FormControl(null, {
+        mirroring: new FormControl(false),
+        schedule: new FormControl('', {
+          validators: [Validators.pattern(/^([0-9]+)d|([0-9]+)h|([0-9]+)m$/)] // check schedule interval to be in format - 1d or 1h or 1m
+        }),
+        mirroringMode: new FormControl(this.mirroringOptions[0]),
+        stripingUnit: new FormControl(this.defaultStripingUnit),
+        stripingCount: new FormControl(this.defaultStripingCount, {
           updateOn: 'blur'
         })
       },
@@ -232,6 +242,48 @@ export class RbdFormComponent extends CdForm implements OnInit {
     this.gatherNeededData().subscribe(this.handleExternalData.bind(this));
   }
 
+  setExclusiveLock() {
+    if (this.mirroring && this.rbdForm.get('mirroringMode').value === 'journal') {
+      this.rbdForm.get('exclusive-lock').setValue(true);
+      this.rbdForm.get('exclusive-lock').disable();
+    } else {
+      this.rbdForm.get('exclusive-lock').enable();
+      if (this.poolMirrorMode === 'pool') {
+        this.rbdForm.get('mirroringMode').setValue(this.mirroringOptions[0]);
+      }
+    }
+  }
+
+  setMirrorMode() {
+    this.mirroring = !this.mirroring;
+    this.setExclusiveLock();
+  }
+
+  setPoolMirrorMode() {
+    this.currentPoolName =
+      this.mode === this.rbdFormMode.editing
+        ? this.response?.pool_name
+        : this.rbdForm.getValue('pool');
+    if (this.currentPoolName) {
+      this.rbdMirroringService.refresh();
+      this.rbdMirroringService.subscribeSummary((data) => {
+        const pool = data.content_data.pools.find((o: any) => o.name === this.currentPoolName);
+        this.poolMirrorMode = pool.mirror_mode;
+
+        if (pool.mirror_mode === 'disabled') {
+          this.mirroring = false;
+          this.rbdForm.get('mirroring').setValue(this.mirroring);
+          this.rbdForm.get('mirroring').disable();
+        } else if (this.mode !== this.rbdFormMode.editing) {
+          this.rbdForm.get('mirroring').enable();
+          this.mirroring = true;
+          this.rbdForm.get('mirroring').setValue(this.mirroring);
+        }
+      });
+    }
+    this.setExclusiveLock();
+  }
+
   private prepareFormForAction() {
     const url = this.routerUrl;
     if (url.startsWith('/block/rbd/edit')) {
@@ -285,6 +337,7 @@ export class RbdFormComponent extends CdForm implements OnInit {
 
   private handleExternalData(data: ExternalData) {
     this.handlePoolData(data.pools);
+    this.setPoolMirrorMode();
 
     if (data.defaultFeatures) {
       // Fetched only during creation
@@ -389,7 +442,8 @@ export class RbdFormComponent extends CdForm implements OnInit {
         objectSizeControl.value != null ? objectSizeControl.value : this.defaultObjectSize
       );
       const stripingCountControl = formGroup.get('stripingCount');
-      const stripingCount = stripingCountControl.value != null ? stripingCountControl.value : 1;
+      const stripingCount =
+        stripingCountControl.value != null ? stripingCountControl.value : this.defaultStripingCount;
       let sizeControlErrors = null;
       if (sizeControl.value === null) {
         sizeControlErrors = { required: true };
@@ -543,6 +597,16 @@ export class RbdFormComponent extends CdForm implements OnInit {
     }
     if (this.mode === this.rbdFormMode.editing) {
       this.rbdForm.get('name').setValue(response.name);
+      if (response?.mirror_mode === 'snapshot' || response.features_name.includes('journaling')) {
+        this.mirroring = true;
+        this.rbdForm.get('mirroring').setValue(this.mirroring);
+        this.rbdForm.get('mirroringMode').setValue(response?.mirror_mode);
+        this.rbdForm.get('schedule').setValue(response?.schedule_interval);
+      } else {
+        this.mirroring = false;
+        this.rbdForm.get('mirroring').setValue(this.mirroring);
+      }
+      this.setPoolMirrorMode();
     }
     this.rbdForm.get('pool').setValue(response.pool_name);
     this.onPoolChange(response.pool_name);
@@ -570,7 +634,11 @@ export class RbdFormComponent extends CdForm implements OnInit {
     request.pool_name = this.rbdForm.getValue('pool');
     request.namespace = this.rbdForm.getValue('namespace');
     request.name = this.rbdForm.getValue('name');
+    request.schedule_interval = this.rbdForm.getValue('schedule');
     request.size = this.formatter.toBytes(this.rbdForm.getValue('size'));
+    if (this.poolMirrorMode === 'image') {
+      request.mirror_mode = this.rbdForm.getValue('mirroringMode');
+    }
     this.addObjectSizeAndStripingToRequest(request);
     request.configuration = this.getDirtyConfigurationValues();
     return request;
@@ -586,6 +654,10 @@ export class RbdFormComponent extends CdForm implements OnInit {
       }
     });
 
+    if (this.mirroring && this.rbdForm.getValue('mirroringMode') === 'journal') {
+      request.features.push('journaling');
+    }
+
     /* Striping */
     request.stripe_unit = this.formatter.toBytes(this.rbdForm.getValue('stripingUnit'));
     request.stripe_count = this.rbdForm.getValue('stripingCount');
@@ -598,7 +670,9 @@ export class RbdFormComponent extends CdForm implements OnInit {
       task: new FinishedTask('rbd/create', {
         pool_name: request.pool_name,
         namespace: request.namespace,
-        image_name: request.name
+        image_name: request.name,
+        schedule_interval: request.schedule_interval,
+        start_time: request.start_time
       }),
       call: this.rbdService.create(request)
     });
@@ -607,12 +681,29 @@ export class RbdFormComponent extends CdForm implements OnInit {
   editRequest() {
     const request = new RbdFormEditRequestModel();
     request.name = this.rbdForm.getValue('name');
+    request.schedule_interval = this.rbdForm.getValue('schedule');
+    request.name = this.rbdForm.getValue('name');
     request.size = this.formatter.toBytes(this.rbdForm.getValue('size'));
     _.forIn(this.features, (feature) => {
       if (this.rbdForm.getValue(feature.key)) {
         request.features.push(feature.key);
       }
     });
+    request.enable_mirror = this.rbdForm.getValue('mirroring');
+    if (this.poolMirrorMode === 'image') {
+      if (request.enable_mirror) {
+        request.mirror_mode = this.rbdForm.getValue('mirroringMode');
+      }
+    } else {
+      if (request.enable_mirror) {
+        request.features.push('journaling');
+      } else {
+        const index = request.features.indexOf('journaling', 0);
+        if (index > -1) {
+          request.features.splice(index, 1);
+        }
+      }
+    }
     request.configuration = this.getDirtyConfigurationValues();
     return request;
   }