From bc52473d21b4363a70d77410611a7097e4c9930d Mon Sep 17 00:00:00 2001 From: Volker Theile Date: Fri, 24 Aug 2018 16:54:34 +0200 Subject: [PATCH] Auto-create a name for RBD image snapshots. Signed-off-by: Volker Theile --- .../rbd-snapshot-form.component.ts | 10 +++++- .../rbd-snapshot-list.component.spec.ts | 31 +++++++++++++++++-- .../rbd-snapshot-list.component.ts | 14 +++++++-- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-form/rbd-snapshot-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-form/rbd-snapshot-form.component.ts index eea9dee561d..c606e875502 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-form/rbd-snapshot-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-form/rbd-snapshot-form.component.ts @@ -50,7 +50,15 @@ export class RbdSnapshotFormComponent implements OnInit { setSnapName(snapName) { this.snapName = snapName; this.snapshotForm.get('snapshotName').setValue(snapName); - this.editing = true; + } + + /** + * Set the 'editing' flag. If set to TRUE, the modal dialog is in + * 'Edit' mode, otherwise in 'Create' mode. + * @param {boolean} editing + */ + setEditing(editing: boolean = true) { + this.editing = editing; } editAction() { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.spec.ts index a2afd1e58f1..514f458483e 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.spec.ts @@ -3,8 +3,8 @@ import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testin import { RouterTestingModule } from '@angular/router/testing'; import { ToastModule } from 'ng2-toastr'; -import { BsModalRef, ModalModule } from 'ngx-bootstrap'; -import { throwError as observableThrowError } from 'rxjs'; +import { BsModalRef, BsModalService } from 'ngx-bootstrap'; +import { Subject, throwError as observableThrowError } from 'rxjs'; import { configureTestBed } from '../../../../testing/unit-test-helper'; import { ApiModule } from '../../../shared/api/api.module'; @@ -41,7 +41,6 @@ describe('RbdSnapshotListComponent', () => { imports: [ DataTableModule, ComponentsModule, - ModalModule.forRoot(), ToastModule.forRoot(), ServicesModule, ApiModule, @@ -172,4 +171,30 @@ describe('RbdSnapshotListComponent', () => { expectImageTasks(component.snapshots[2], 'Rolling back'); }); }); + + describe('snapshot modal dialog', () => { + beforeEach(() => { + component.poolName = 'pool01'; + component.rbdName = 'image01'; + spyOn(TestBed.get(BsModalService), 'show').and.callFake((content) => { + const ref = new BsModalRef(); + ref.content = new content(); + ref.content.onSubmit = new Subject(); + return ref; + }); + }); + + it('should display old snapshot name', () => { + component.openSnapshotModal('rbd/snap/edit', 'oldname'); + expect(component.modalRef.content.snapName).toBe('oldname'); + expect(component.modalRef.content.editing).toBeTruthy(); + }); + + it('should display suggested snapshot name', () => { + component.openSnapshotModal('rbd/snap/create'); + expect(component.modalRef.content.snapName).toMatch( + RegExp(`^${component.rbdName}-\\d+T\\d+Z\$`) + ); + }); + }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.ts index 14b1168bae7..09bfdaea5f9 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-list.component.ts @@ -1,6 +1,7 @@ import { Component, Input, OnChanges, OnInit, TemplateRef, ViewChild } from '@angular/core'; import * as _ from 'lodash'; +import * as moment from 'moment'; import { BsModalRef, BsModalService } from 'ngx-bootstrap'; import { of } from 'rxjs'; @@ -139,13 +140,20 @@ export class RbdSnapshotListComponent implements OnInit, OnChanges { ); } - private openSnapshotModal(taskName: string, oldSnapshotName: string = null) { + private openSnapshotModal(taskName: string, snapName: string = null) { this.modalRef = this.modalService.show(RbdSnapshotFormComponent); this.modalRef.content.poolName = this.poolName; this.modalRef.content.imageName = this.rbdName; - if (oldSnapshotName) { - this.modalRef.content.setSnapName(this.selection.first().name); + if (snapName) { + this.modalRef.content.setEditing(); + } else { + // Auto-create a name for the snapshot: _ + // https://en.wikipedia.org/wiki/ISO_8601 + snapName = `${this.rbdName}-${moment() + .utc() + .format('YYYYMMDD[T]HHmmss[Z]')}`; } + this.modalRef.content.setSnapName(snapName); this.modalRef.content.onSubmit.subscribe((snapshotName: string) => { const executingTask = new ExecutingTask(); executingTask.name = taskName; -- 2.39.5