This class should be used when dealing with RBD image specs.
It allows the creation of an ImageSpec given the names of the pool, image and
namespace. Alternatively you can also create one with an already existing
image spec string.
With it you keep the access to each individual component and can also convert it
to a well formated string.
Fixes: https://tracker.ceph.com/issues/42787
Signed-off-by: Tiago Melo <tmelo@suse.com>
describe('create, edit & delete image test', () => {
const poolName = 'e2e_images_pool';
- const imageName = 'e2e_images_image';
- const newImageName = 'e2e_images_image_new';
+ const imageName = 'e2e_images#image';
+ const newImageName = 'e2e_images#image_new';
beforeAll(async () => {
await pools.navigateTo('create'); // Need pool for image testing
});
describe('move to trash, restore and purge image tests', () => {
- const poolName = 'trashpool';
- const imageName = 'trashimage';
- const newImageName = 'newtrashimage';
+ const poolName = 'trash_pool';
+ const imageName = 'trash#image';
+ const newImageName = 'newtrash#image';
beforeAll(async () => {
await pools.navigateTo('create'); // Need pool for image testing
async editImage(name, pool, newName, newSize) {
const base_url = '/#/block/rbd/edit/';
const editURL = base_url
- .concat(pool)
+ .concat(encodeURIComponent(pool))
.concat('%2F')
- .concat(name);
+ .concat(encodeURIComponent(name));
await browser.get(editURL);
await element(by.id('name')).click(); // click name box and send new name
describe('Pools page', () => {
let pools: PoolPageHelper;
- const poolName = 'pool_e2e_pool_test';
+ const poolName = 'pool_e2e_pool/test';
beforeAll(async () => {
pools = new PoolPageHelper();
import { ActivatedRouteStub } from '../../../../testing/activated-route-stub';
import { configureTestBed, i18nProviders } from '../../../../testing/unit-test-helper';
import { RbdService } from '../../../shared/api/rbd.service';
+import { ImageSpec } from '../../../shared/models/image-spec';
import { SharedModule } from '../../../shared/shared.module';
import { RbdConfigurationFormComponent } from '../rbd-configuration-form/rbd-configuration-form.component';
import { RbdFormMode } from './rbd-form-mode.enum';
it('with namespace', () => {
activatedRoute.setParams({ image_spec: 'foo%2Fbar%2Fbaz' });
- expect(rbdService.get).toHaveBeenCalledWith('foo', 'bar', 'baz');
+ expect(rbdService.get).toHaveBeenCalledWith(new ImageSpec('foo', 'bar', 'baz'));
});
it('without snapName', () => {
activatedRoute.setParams({ image_spec: 'foo%2Fbar', snap: undefined });
- expect(rbdService.get).toHaveBeenCalledWith('foo', null, 'bar');
+ expect(rbdService.get).toHaveBeenCalledWith(new ImageSpec('foo', null, 'bar'));
expect(component.snapName).toBeUndefined();
});
it('with snapName', () => {
activatedRoute.setParams({ image_spec: 'foo%2Fbar', snap: 'baz%2Fbaz' });
- expect(rbdService.get).toHaveBeenCalledWith('foo', null, 'bar');
+ expect(rbdService.get).toHaveBeenCalledWith(new ImageSpec('foo', null, 'bar'));
expect(component.snapName).toBe('baz/baz');
});
});
RbdConfigurationSourceField
} from '../../../shared/models/configuration';
import { FinishedTask } from '../../../shared/models/finished-task';
+import { ImageSpec } from '../../../shared/models/image-spec';
import { Permission } from '../../../shared/models/permissions';
import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe';
import { AuthStorageService } from '../../../shared/services/auth-storage.service';
this.mode === this.rbdFormMode.copying
) {
this.route.params.subscribe((params: { image_spec: string; snap: string }) => {
- const [poolName, namespace, rbdName] = this.rbdService.parseImageSpec(
- decodeURIComponent(params.image_spec)
- );
+ const imageSpec = ImageSpec.fromString(decodeURIComponent(params.image_spec));
if (params.snap) {
this.snapName = decodeURIComponent(params.snap);
}
- promisses[Promisse.RbdServiceGet] = this.rbdService.get(poolName, namespace, rbdName);
+ promisses[Promisse.RbdServiceGet] = this.rbdService.get(imageSpec);
});
} else {
// New image
setResponse(response: RbdFormResponseModel, snapName: string) {
this.response = response;
- const imageSpec = this.rbdService.getImageSpec(
+ const imageSpec = new ImageSpec(
response.pool_name,
response.namespace,
response.name
- );
+ ).toString();
if (this.mode === this.rbdFormMode.cloning) {
this.rbdForm.get('parent').setValue(`${imageSpec}@${snapName}`);
} else if (this.mode === this.rbdFormMode.copying) {
}
editAction(): Observable<any> {
+ const imageSpec = new ImageSpec(
+ this.response.pool_name,
+ this.response.namespace,
+ this.response.name
+ );
return this.taskWrapper.wrapTaskAroundCall({
task: new FinishedTask('rbd/edit', {
- image_spec: this.rbdService.getImageSpec(
- this.response.pool_name,
- this.response.namespace,
- this.response.name
- )
+ image_spec: imageSpec.toString()
}),
- call: this.rbdService.update(
- this.response.pool_name,
- this.response.namespace,
- this.response.name,
- this.editRequest()
- )
+ call: this.rbdService.update(imageSpec, this.editRequest())
});
}
cloneAction(): Observable<any> {
const request = this.cloneRequest();
+ const imageSpec = new ImageSpec(
+ this.response.pool_name,
+ this.response.namespace,
+ this.response.name
+ );
return this.taskWrapper.wrapTaskAroundCall({
task: new FinishedTask('rbd/clone', {
- parent_image_spec: this.rbdService.get(
- this.response.pool_name,
- this.response.namespace,
- this.response.name
- ),
+ parent_image_spec: imageSpec.toString(),
parent_snap_name: this.snapName,
child_pool_name: request.child_pool_name,
child_namespace: request.child_namespace,
child_image_name: request.child_image_name
}),
- call: this.rbdService.cloneSnapshot(
- this.response.pool_name,
- this.response.namespace,
- this.response.name,
- this.snapName,
- request
- )
+ call: this.rbdService.cloneSnapshot(imageSpec, this.snapName, request)
});
}
copyAction(): Observable<any> {
const request = this.copyRequest();
-
+ const imageSpec = new ImageSpec(
+ this.response.pool_name,
+ this.response.namespace,
+ this.response.name
+ );
return this.taskWrapper.wrapTaskAroundCall({
task: new FinishedTask('rbd/copy', {
- src_image_spec: this.rbdService.getImageSpec(
- this.response.pool_name,
- this.response.namespace,
- this.response.name
- ),
+ src_image_spec: imageSpec.toString(),
dest_pool_name: request.dest_pool_name,
dest_namespace: request.dest_namespace,
dest_image_name: request.dest_image_name
}),
- call: this.rbdService.copy(
- this.response.pool_name,
- this.response.namespace,
- this.response.name,
- request
- )
+ call: this.rbdService.copy(imageSpec, request)
});
}
import { CdTableColumn } from '../../../shared/models/cd-table-column';
import { CdTableSelection } from '../../../shared/models/cd-table-selection';
import { FinishedTask } from '../../../shared/models/finished-task';
+import { ImageSpec } from '../../../shared/models/image-spec';
import { Permission } from '../../../shared/models/permissions';
import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe';
import { DimlessPipe } from '../../../shared/pipes/dimless.pipe';
)
};
- private createRbdFromTaskImageSpec(imageSpec: string): RbdModel {
- const [poolName, namespace, rbdName] = this.rbdService.parseImageSpec(imageSpec);
- return this.createRbdFromTask(poolName, namespace, rbdName);
+ private createRbdFromTaskImageSpec(imageSpecStr: string): RbdModel {
+ const imageSpec = ImageSpec.fromString(imageSpecStr);
+ return this.createRbdFromTask(imageSpec.poolName, imageSpec.namespace, imageSpec.imageName);
}
private createRbdFromTask(pool: string, namespace: string, name: string): RbdModel {
this.permission = this.authStorageService.getPermissions().rbdImage;
const getImageUri = () =>
this.selection.first() &&
- `${encodeURIComponent(
- this.rbdService.getImageSpec(
- this.selection.first().pool_name,
- this.selection.first().namespace,
- this.selection.first().name
- )
- )}`;
+ new ImageSpec(
+ this.selection.first().pool_name,
+ this.selection.first().namespace,
+ this.selection.first().name
+ ).toStringEncoded();
const addAction: CdTableAction = {
permission: 'create',
icon: Icons.add,
let taskImageSpec: string;
switch (task.name) {
case 'rbd/copy':
- taskImageSpec = this.rbdService.getImageSpec(
+ taskImageSpec = new ImageSpec(
task.metadata['dest_pool_name'],
task.metadata['dest_namespace'],
task.metadata['dest_image_name']
- );
+ ).toString();
break;
case 'rbd/clone':
- taskImageSpec = this.rbdService.getImageSpec(
+ taskImageSpec = new ImageSpec(
task.metadata['child_pool_name'],
task.metadata['child_namespace'],
task.metadata['child_image_name']
- );
+ ).toString();
break;
case 'rbd/create':
- taskImageSpec = this.rbdService.getImageSpec(
+ taskImageSpec = new ImageSpec(
task.metadata['pool_name'],
task.metadata['namespace'],
task.metadata['image_name']
- );
+ ).toString();
break;
default:
taskImageSpec = task.metadata['image_spec'];
break;
}
return (
- taskImageSpec === this.rbdService.getImageSpec(entry.pool_name, entry.namespace, entry.name)
+ taskImageSpec === new ImageSpec(entry.pool_name, entry.namespace, entry.name).toString()
);
};
const poolName = this.selection.first().pool_name;
const namespace = this.selection.first().namespace;
const imageName = this.selection.first().name;
- const imageSpec = this.rbdService.getImageSpec(poolName, namespace, imageName);
+ const imageSpec = new ImageSpec(poolName, namespace, imageName);
this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
initialState: {
submitActionObservable: () =>
this.taskWrapper.wrapTaskAroundCall({
task: new FinishedTask('rbd/delete', {
- image_spec: imageSpec
+ image_spec: imageSpec.toString()
}),
- call: this.rbdService.delete(poolName, namespace, imageName)
+ call: this.rbdService.delete(imageSpec)
})
}
});
this.modalRef = this.modalService.show(RbdTrashMoveModalComponent, { initialState });
}
- flattenRbd(poolName, namespace, imageName) {
+ flattenRbd(imageSpec: ImageSpec) {
this.taskWrapper
.wrapTaskAroundCall({
task: new FinishedTask('rbd/flatten', {
- image_spec: this.rbdService.getImageSpec(poolName, namespace, imageName)
+ image_spec: imageSpec.toString()
}),
- call: this.rbdService.flatten(poolName, namespace, imageName)
+ call: this.rbdService.flatten(imageSpec)
})
.subscribe(undefined, undefined, () => {
this.modalRef.hide();
const namespace = this.selection.first().namespace;
const imageName = this.selection.first().name;
const parent: RbdParentModel = this.selection.first().parent;
- const parentImageSpec = this.rbdService.getImageSpec(
+ const parentImageSpec = new ImageSpec(
parent.pool_name,
parent.pool_namespace,
parent.image_name
);
+ const childImageSpec = new ImageSpec(poolName, namespace, imageName);
const initialState = {
titleText: 'RBD flatten',
bodyTpl: this.flattenTpl,
bodyData: {
parent: `${parentImageSpec}@${parent.snap_name}`,
- child: this.rbdService.getImageSpec(poolName, namespace, imageName)
+ child: childImageSpec.toString()
},
onSubmit: () => {
- this.flattenRbd(poolName, namespace, imageName);
+ this.flattenRbd(childImageSpec);
}
};
import { ActionLabelsI18n } from '../../../shared/constants/app.constants';
import { CdFormGroup } from '../../../shared/forms/cd-form-group';
import { FinishedTask } from '../../../shared/models/finished-task';
+import { ImageSpec } from '../../../shared/models/image-spec';
import { NotificationService } from '../../../shared/services/notification.service';
import { TaskManagerService } from '../../../shared/services/task-manager.service';
editAction() {
const snapshotName = this.snapshotForm.getValue('snapshotName');
+ const imageSpec = new ImageSpec(this.poolName, this.namespace, this.imageName);
const finishedTask = new FinishedTask();
finishedTask.name = 'rbd/snap/edit';
finishedTask.metadata = {
- image_spec: this.rbdService.getImageSpec(this.poolName, this.namespace, this.imageName),
+ image_spec: imageSpec.toString(),
snapshot_name: snapshotName
};
this.rbdService
- .renameSnapshot(this.poolName, this.namespace, this.imageName, this.snapName, snapshotName)
+ .renameSnapshot(imageSpec, this.snapName, snapshotName)
.toPromise()
.then(() => {
this.taskManagerService.subscribe(
createAction() {
const snapshotName = this.snapshotForm.getValue('snapshotName');
+ const imageSpec = new ImageSpec(this.poolName, this.namespace, this.imageName);
const finishedTask = new FinishedTask();
finishedTask.name = 'rbd/snap/create';
finishedTask.metadata = {
- image_spec: this.rbdService.getImageSpec(this.poolName, this.namespace, this.imageName),
+ image_spec: imageSpec.toString(),
snapshot_name: snapshotName
};
this.rbdService
- .createSnapshot(this.poolName, this.namespace, this.imageName, snapshotName)
+ .createSnapshot(imageSpec, snapshotName)
.toPromise()
.then(() => {
this.taskManagerService.subscribe(
import { CdTableSelection } from '../../../shared/models/cd-table-selection';
import { ExecutingTask } from '../../../shared/models/executing-task';
import { FinishedTask } from '../../../shared/models/finished-task';
+import { ImageSpec } from '../../../shared/models/image-spec';
import { Permission } from '../../../shared/models/permissions';
import { CdDatePipe } from '../../../shared/pipes/cd-date.pipe';
import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe';
}
ngOnChanges() {
+ const imageSpec = new ImageSpec(this.poolName, this.namespace, this.rbdName);
+
const actions = new RbdSnapshotActionsModel(this.i18n, this.actionLabels, this.featuresName);
actions.create.click = () => this.openCreateSnapshotModal();
actions.rename.click = () => this.openEditSnapshotModal();
actions.unprotect.click = () => this.toggleProtection();
const getImageUri = () =>
this.selection.first() &&
- `${encodeURIComponent(
- this.rbdService.getImageSpec(this.poolName, this.namespace, this.rbdName)
- )}/${encodeURIComponent(this.selection.first().name)}`;
+ `${imageSpec.toStringEncoded()}/${encodeURIComponent(this.selection.first().name)}`;
actions.clone.routerLink = () => `/block/rbd/clone/${getImageUri()}`;
actions.copy.routerLink = () => `/block/rbd/copy/${getImageUri()}`;
actions.rollback.click = () => this.rollbackModal();
return (
['rbd/snap/create', 'rbd/snap/delete', 'rbd/snap/edit', 'rbd/snap/rollback'].includes(
task.name
- ) &&
- this.rbdService.getImageSpec(this.poolName, this.namespace, this.rbdName) ===
- task.metadata['image_spec']
+ ) && imageSpec.toString() === task.metadata['image_spec']
);
};
const isProtected = this.selection.first().is_protected;
const finishedTask = new FinishedTask();
finishedTask.name = 'rbd/snap/edit';
+ const imageSpec = new ImageSpec(this.poolName, this.namespace, this.rbdName);
finishedTask.metadata = {
- image_spec: this.rbdService.getImageSpec(this.poolName, this.namespace, this.rbdName),
+ image_spec: imageSpec.toString(),
snapshot_name: snapshotName
};
this.rbdService
- .protectSnapshot(this.poolName, this.namespace, this.rbdName, snapshotName, !isProtected)
+ .protectSnapshot(imageSpec, snapshotName, !isProtected)
.toPromise()
.then(() => {
const executingTask = new ExecutingTask();
const finishedTask = new FinishedTask();
finishedTask.name = taskName;
finishedTask.metadata = {
- image_spec: this.rbdService.getImageSpec(this.poolName, this.namespace, this.rbdName),
+ image_spec: new ImageSpec(this.poolName, this.namespace, this.rbdName).toString(),
snapshot_name: snapshotName
};
this.rbdService[task](this.poolName, this.namespace, this.rbdName, snapshotName)
rollbackModal() {
const snapshotName = this.selection.selected[0].name;
- const imageSpec = this.rbdService.getImageSpec(this.poolName, this.namespace, this.rbdName);
+ const imageSpec = new ImageSpec(this.poolName, this.namespace, this.rbdName).toString();
const initialState = {
titleText: this.i18n('RBD snapshot rollback'),
buttonText: this.i18n('Rollback'),
import { CdTableSelection } from '../../../shared/models/cd-table-selection';
import { ExecutingTask } from '../../../shared/models/executing-task';
import { FinishedTask } from '../../../shared/models/finished-task';
+import { ImageSpec } from '../../../shared/models/image-spec';
import { Permission } from '../../../shared/models/permissions';
import { CdDatePipe } from '../../../shared/pipes/cd-date.pipe';
import { AuthStorageService } from '../../../shared/services/auth-storage.service';
];
const itemFilter = (entry, task) => {
- return (
- this.rbdService.getImageSpec(entry.pool_name, entry.namespace, entry.id) ===
- task.metadata['image_id_spec']
- );
+ const imageSpec = new ImageSpec(entry.pool_name, entry.namespace, entry.id);
+ return imageSpec.toString() === task.metadata['image_id_spec'];
};
const taskFilter = (task) => {
const namespace = this.selection.first().namespace;
const imageId = this.selection.first().id;
const expiresAt = this.selection.first().deferment_end_time;
- const imageIdSpec = this.rbdService.getImageSpec(poolName, namespace, imageId);
+ const imageIdSpec = new ImageSpec(poolName, namespace, imageId);
this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
initialState: {
submitActionObservable: () =>
this.taskWrapper.wrapTaskAroundCall({
task: new FinishedTask('rbd/trash/remove', {
- image_id_spec: imageIdSpec
+ image_id_spec: imageIdSpec.toString()
}),
- call: this.rbdService.removeTrash(poolName, namespace, imageId, true)
+ call: this.rbdService.removeTrash(imageIdSpec, true)
})
}
});
[formGroup]="moveForm"
novalidate>
<div class="modal-body">
- <p i18n>To move <kbd>{{ imageSpec }}</kbd> to trash,
+ <p i18n>To move <kbd>{{ imageSpecStr }}</kbd> to trash,
click <kbd>Move Image</kbd>. Optionally, you can pick an expiration date.</p>
<div class="form-group">
component.metaType = 'RBD';
component.poolName = 'foo';
component.imageName = 'bar';
+
+ fixture.detectChanges();
});
it('should create', () => {
});
it('should finish running ngOnInit', () => {
- fixture.detectChanges();
expect(component.pattern).toEqual('foo/bar');
});
const oldDate = moment()
.add(24, 'hour')
.toISOString();
- fixture.detectChanges();
component.moveForm.patchValue({ expiresAt: oldDate });
component.moveImage();
import { CdValidators } from '../../../shared/forms/cd-validators';
import { ExecutingTask } from '../../../shared/models/executing-task';
import { FinishedTask } from '../../../shared/models/finished-task';
+import { ImageSpec } from '../../../shared/models/image-spec';
import { TaskWrapperService } from '../../../shared/services/task-wrapper.service';
@Component({
poolName: string;
namespace: string;
imageName: string;
- imageSpec: string;
+ imageSpec: ImageSpec;
+ imageSpecStr: string;
executingTasks: ExecutingTask[];
moveForm: CdFormGroup;
}
ngOnInit() {
- this.imageSpec = this.rbdService.getImageSpec(this.poolName, this.namespace, this.imageName);
+ this.imageSpec = new ImageSpec(this.poolName, this.namespace, this.imageName);
+ this.imageSpecStr = this.imageSpec.toString();
this.pattern = `${this.poolName}/${this.imageName}`;
}
this.taskWrapper
.wrapTaskAroundCall({
task: new FinishedTask('rbd/trash/move', {
- image_spec: this.imageSpec
+ image_spec: this.imageSpecStr
}),
- call: this.rbdService.moveTrash(this.poolName, this.namespace, this.imageName, delay)
+ call: this.rbdService.moveTrash(this.imageSpec, delay)
})
.subscribe(undefined, undefined, () => {
this.modalRef.hide();
import { CdFormGroup } from '../../../shared/forms/cd-form-group';
import { ExecutingTask } from '../../../shared/models/executing-task';
import { FinishedTask } from '../../../shared/models/finished-task';
+import { ImageSpec } from '../../../shared/models/image-spec';
import { TaskWrapperService } from '../../../shared/services/task-wrapper.service';
@Component({
) {}
ngOnInit() {
- this.imageSpec = this.rbdService.getImageSpec(this.poolName, this.namespace, this.imageName);
+ this.imageSpec = new ImageSpec(this.poolName, this.namespace, this.imageName).toString();
this.restoreForm = this.fb.group({
name: this.imageName
});
restore() {
const name = this.restoreForm.getValue('name');
+ const imageSpec = new ImageSpec(this.poolName, this.namespace, this.imageId);
this.taskWrapper
.wrapTaskAroundCall({
task: new FinishedTask('rbd/trash/restore', {
- image_id_spec: this.rbdService.getImageSpec(this.poolName, this.namespace, this.imageId),
+ image_id_spec: imageSpec.toString(),
new_image_name: name
}),
- call: this.rbdService.restoreTrash(this.poolName, this.namespace, this.imageId, name)
+ call: this.rbdService.restoreTrash(imageSpec, name)
})
.subscribe(
undefined,
import { TestBed } from '@angular/core/testing';
import { configureTestBed, i18nProviders } from '../../../testing/unit-test-helper';
+import { ImageSpec } from '../models/image-spec';
import { RbdConfigurationService } from '../services/rbd-configuration.service';
import { RbdService } from './rbd.service';
});
it('should call delete', () => {
- service.delete('poolName', null, 'rbdName').subscribe();
+ service.delete(new ImageSpec('poolName', null, 'rbdName')).subscribe();
const req = httpTesting.expectOne('api/block/image/poolName%2FrbdName');
expect(req.request.method).toBe('DELETE');
});
it('should call update', () => {
- service.update('poolName', null, 'rbdName', 'foo').subscribe();
+ service.update(new ImageSpec('poolName', null, 'rbdName'), 'foo').subscribe();
const req = httpTesting.expectOne('api/block/image/poolName%2FrbdName');
expect(req.request.body).toEqual('foo');
expect(req.request.method).toBe('PUT');
});
it('should call get', () => {
- service.get('poolName', null, 'rbdName').subscribe();
+ service.get(new ImageSpec('poolName', null, 'rbdName')).subscribe();
const req = httpTesting.expectOne('api/block/image/poolName%2FrbdName');
expect(req.request.method).toBe('GET');
});
});
it('should call copy', () => {
- service.copy('poolName', null, 'rbdName', 'foo').subscribe();
+ service.copy(new ImageSpec('poolName', null, 'rbdName'), 'foo').subscribe();
const req = httpTesting.expectOne('api/block/image/poolName%2FrbdName/copy');
expect(req.request.body).toEqual('foo');
expect(req.request.method).toBe('POST');
});
it('should call flatten', () => {
- service.flatten('poolName', null, 'rbdName').subscribe();
+ service.flatten(new ImageSpec('poolName', null, 'rbdName')).subscribe();
const req = httpTesting.expectOne('api/block/image/poolName%2FrbdName/flatten');
expect(req.request.body).toEqual(null);
expect(req.request.method).toBe('POST');
});
it('should call createSnapshot', () => {
- service.createSnapshot('poolName', null, 'rbdName', 'snapshotName').subscribe();
+ service.createSnapshot(new ImageSpec('poolName', null, 'rbdName'), 'snapshotName').subscribe();
const req = httpTesting.expectOne('api/block/image/poolName%2FrbdName/snap');
expect(req.request.body).toEqual({
snapshot_name: 'snapshotName'
});
it('should call renameSnapshot', () => {
- service.renameSnapshot('poolName', null, 'rbdName', 'snapshotName', 'foo').subscribe();
+ service
+ .renameSnapshot(new ImageSpec('poolName', null, 'rbdName'), 'snapshotName', 'foo')
+ .subscribe();
const req = httpTesting.expectOne('api/block/image/poolName%2FrbdName/snap/snapshotName');
expect(req.request.body).toEqual({
new_snap_name: 'foo'
});
it('should call protectSnapshot', () => {
- service.protectSnapshot('poolName', null, 'rbdName', 'snapshotName', true).subscribe();
+ service
+ .protectSnapshot(new ImageSpec('poolName', null, 'rbdName'), 'snapshotName', true)
+ .subscribe();
const req = httpTesting.expectOne('api/block/image/poolName%2FrbdName/snap/snapshotName');
expect(req.request.body).toEqual({
is_protected: true
});
it('should call rollbackSnapshot', () => {
- service.rollbackSnapshot('poolName', null, 'rbdName', 'snapshotName').subscribe();
+ service
+ .rollbackSnapshot(new ImageSpec('poolName', null, 'rbdName'), 'snapshotName')
+ .subscribe();
const req = httpTesting.expectOne(
'api/block/image/poolName%2FrbdName/snap/snapshotName/rollback'
);
});
it('should call cloneSnapshot', () => {
- service.cloneSnapshot('poolName', null, 'rbdName', 'snapshotName', null).subscribe();
+ service
+ .cloneSnapshot(new ImageSpec('poolName', null, 'rbdName'), 'snapshotName', null)
+ .subscribe();
const req = httpTesting.expectOne('api/block/image/poolName%2FrbdName/snap/snapshotName/clone');
expect(req.request.body).toEqual(null);
expect(req.request.method).toBe('POST');
});
it('should call deleteSnapshot', () => {
- service.deleteSnapshot('poolName', null, 'rbdName', 'snapshotName').subscribe();
+ service.deleteSnapshot(new ImageSpec('poolName', null, 'rbdName'), 'snapshotName').subscribe();
const req = httpTesting.expectOne('api/block/image/poolName%2FrbdName/snap/snapshotName');
expect(req.request.method).toBe('DELETE');
});
it('should call moveTrash', () => {
- service.moveTrash('poolName', null, 'rbdName', 1).subscribe();
+ service.moveTrash(new ImageSpec('poolName', null, 'rbdName'), 1).subscribe();
const req = httpTesting.expectOne('api/block/image/poolName%2FrbdName/move_trash');
expect(req.request.method).toBe('POST');
expect(req.request.body).toEqual({ delay: 1 });
describe('should compose image spec', () => {
it('with namespace', () => {
- expect(service.getImageSpec('mypool', 'myns', 'myimage')).toBe('mypool/myns/myimage');
+ expect(new ImageSpec('mypool', 'myns', 'myimage').toString()).toBe('mypool/myns/myimage');
});
it('without namespace', () => {
- expect(service.getImageSpec('mypool', null, 'myimage')).toBe('mypool/myimage');
+ expect(new ImageSpec('mypool', null, 'myimage').toString()).toBe('mypool/myimage');
});
});
describe('should parse image spec', () => {
it('with namespace', () => {
- const [poolName, namespace, rbdName] = service.parseImageSpec('mypool/myns/myimage');
- expect(poolName).toBe('mypool');
- expect(namespace).toBe('myns');
- expect(rbdName).toBe('myimage');
+ const imageSpec = ImageSpec.fromString('mypool/myns/myimage');
+ expect(imageSpec.poolName).toBe('mypool');
+ expect(imageSpec.namespace).toBe('myns');
+ expect(imageSpec.imageName).toBe('myimage');
});
it('without namespace', () => {
- const [poolName, namespace, rbdName] = service.parseImageSpec('mypool/myimage');
- expect(poolName).toBe('mypool');
- expect(namespace).toBeNull();
- expect(rbdName).toBe('myimage');
+ const imageSpec = ImageSpec.fromString('mypool/myimage');
+ expect(imageSpec.poolName).toBe('mypool');
+ expect(imageSpec.namespace).toBeNull();
+ expect(imageSpec.imageName).toBe('myimage');
});
});
});
import { map } from 'rxjs/operators';
import { cdEncode, cdEncodeNot } from '../decorators/cd-encode';
+import { ImageSpec } from '../models/image-spec';
import { RbdConfigurationService } from '../services/rbd-configuration.service';
import { ApiModule } from './api.module';
import { RbdPool } from './rbd.model';
export class RbdService {
constructor(private http: HttpClient, private rbdConfigurationService: RbdConfigurationService) {}
- getImageSpec(poolName: string, namespace: string, rbdName: string) {
- namespace = namespace ? `${namespace}/` : '';
- return `${poolName}/${namespace}${rbdName}`;
- }
-
- parseImageSpec(@cdEncodeNot imageSpec: string) {
- const imageSpecSplited = imageSpec.split('/');
- const poolName = imageSpecSplited[0];
- const namespace = imageSpecSplited.length >= 3 ? imageSpecSplited[1] : null;
- const imageName = imageSpecSplited.length >= 3 ? imageSpecSplited[2] : imageSpecSplited[1];
- return [poolName, namespace, imageName];
- }
-
isRBDPool(pool) {
return _.indexOf(pool.application_metadata, 'rbd') !== -1 && !pool.pool_name.includes('/');
}
return this.http.post('api/block/image', rbd, { observe: 'response' });
}
- delete(poolName, namespace, rbdName) {
- const imageSpec = this.getImageSpec(poolName, namespace, rbdName);
- return this.http.delete(`api/block/image/${encodeURIComponent(imageSpec)}`, {
+ delete(imageSpec: ImageSpec) {
+ return this.http.delete(`api/block/image/${imageSpec.toStringEncoded()}`, {
observe: 'response'
});
}
- update(poolName, namespace, rbdName, rbd) {
- const imageSpec = this.getImageSpec(poolName, namespace, rbdName);
- return this.http.put(`api/block/image/${encodeURIComponent(imageSpec)}`, rbd, {
+ update(imageSpec: ImageSpec, rbd) {
+ return this.http.put(`api/block/image/${imageSpec.toStringEncoded()}`, rbd, {
observe: 'response'
});
}
- get(poolName, namespace, rbdName) {
- const imageSpec = this.getImageSpec(poolName, namespace, rbdName);
- return this.http.get(`api/block/image/${encodeURIComponent(imageSpec)}`);
+ get(imageSpec: ImageSpec) {
+ return this.http.get(`api/block/image/${imageSpec.toStringEncoded()}`);
}
list() {
);
}
- copy(poolName, namespace, rbdName, rbd) {
- const imageSpec = this.getImageSpec(poolName, namespace, rbdName);
- return this.http.post(`api/block/image/${encodeURIComponent(imageSpec)}/copy`, rbd, {
+ copy(imageSpec: ImageSpec, rbd) {
+ return this.http.post(`api/block/image/${imageSpec.toStringEncoded()}/copy`, rbd, {
observe: 'response'
});
}
- flatten(poolName, namespace, rbdName) {
- const imageSpec = this.getImageSpec(poolName, namespace, rbdName);
- return this.http.post(`api/block/image/${encodeURIComponent(imageSpec)}/flatten`, null, {
+ flatten(imageSpec: ImageSpec) {
+ return this.http.post(`api/block/image/${imageSpec.toStringEncoded()}/flatten`, null, {
observe: 'response'
});
}
return this.http.get('api/block/image/default_features');
}
- createSnapshot(poolName, namespace, rbdName, @cdEncodeNot snapshotName) {
- const imageSpec = this.getImageSpec(poolName, namespace, rbdName);
+ createSnapshot(imageSpec: ImageSpec, @cdEncodeNot snapshotName) {
const request = {
snapshot_name: snapshotName
};
- return this.http.post(`api/block/image/${encodeURIComponent(imageSpec)}/snap`, request, {
+ return this.http.post(`api/block/image/${imageSpec.toStringEncoded()}/snap`, request, {
observe: 'response'
});
}
- renameSnapshot(poolName, namespace, rbdName, snapshotName, @cdEncodeNot newSnapshotName) {
- const imageSpec = this.getImageSpec(poolName, namespace, rbdName);
+ renameSnapshot(imageSpec: ImageSpec, snapshotName, @cdEncodeNot newSnapshotName) {
const request = {
new_snap_name: newSnapshotName
};
return this.http.put(
- `api/block/image/${encodeURIComponent(imageSpec)}/snap/${snapshotName}`,
+ `api/block/image/${imageSpec.toStringEncoded()}/snap/${snapshotName}`,
request,
{
observe: 'response'
);
}
- protectSnapshot(poolName, namespace, rbdName, snapshotName, @cdEncodeNot isProtected) {
- const imageSpec = this.getImageSpec(poolName, namespace, rbdName);
+ protectSnapshot(imageSpec: ImageSpec, snapshotName, @cdEncodeNot isProtected) {
const request = {
is_protected: isProtected
};
return this.http.put(
- `api/block/image/${encodeURIComponent(imageSpec)}/snap/${snapshotName}`,
+ `api/block/image/${imageSpec.toStringEncoded()}/snap/${snapshotName}`,
request,
{
observe: 'response'
);
}
- rollbackSnapshot(poolName, namespace, rbdName, snapshotName) {
- const imageSpec = this.getImageSpec(poolName, namespace, rbdName);
+ rollbackSnapshot(imageSpec: ImageSpec, snapshotName) {
return this.http.post(
- `api/block/image/${encodeURIComponent(imageSpec)}/snap/${snapshotName}/rollback`,
+ `api/block/image/${imageSpec.toStringEncoded()}/snap/${snapshotName}/rollback`,
null,
{ observe: 'response' }
);
}
- cloneSnapshot(poolName, namespace, rbdName, snapshotName, request) {
- const imageSpec = this.getImageSpec(poolName, namespace, rbdName);
+ cloneSnapshot(imageSpec: ImageSpec, snapshotName, request) {
return this.http.post(
- `api/block/image/${encodeURIComponent(imageSpec)}/snap/${snapshotName}/clone`,
+ `api/block/image/${imageSpec.toStringEncoded()}/snap/${snapshotName}/clone`,
request,
{ observe: 'response' }
);
}
- deleteSnapshot(poolName, namespace, rbdName, snapshotName) {
- const imageSpec = this.getImageSpec(poolName, namespace, rbdName);
- return this.http.delete(
- `api/block/image/${encodeURIComponent(imageSpec)}/snap/${snapshotName}`,
- {
- observe: 'response'
- }
- );
+ deleteSnapshot(imageSpec: ImageSpec, snapshotName) {
+ return this.http.delete(`api/block/image/${imageSpec.toStringEncoded()}/snap/${snapshotName}`, {
+ observe: 'response'
+ });
}
listTrash() {
});
}
- moveTrash(poolName, namespace, rbdName, delay) {
- const imageSpec = this.getImageSpec(poolName, namespace, rbdName);
+ moveTrash(imageSpec: ImageSpec, delay) {
return this.http.post(
- `api/block/image/${encodeURIComponent(imageSpec)}/move_trash`,
+ `api/block/image/${imageSpec.toStringEncoded()}/move_trash`,
{ delay: delay },
{ observe: 'response' }
);
});
}
- restoreTrash(poolName, namespace, imageId, @cdEncodeNot newImageName) {
- const imageSpec = this.getImageSpec(poolName, namespace, imageId);
+ restoreTrash(imageSpec: ImageSpec, @cdEncodeNot newImageName: string) {
return this.http.post(
- `api/block/image/trash/${encodeURIComponent(imageSpec)}/restore`,
+ `api/block/image/trash/${imageSpec.toStringEncoded()}/restore`,
{ new_image_name: newImageName },
{ observe: 'response' }
);
}
- removeTrash(poolName, namespace, imageId, force = false) {
- const imageSpec = this.getImageSpec(poolName, namespace, imageId);
+ removeTrash(imageSpec: ImageSpec, force = false) {
return this.http.delete(
- `api/block/image/trash/${encodeURIComponent(imageSpec)}/?force=${force}`,
+ `api/block/image/trash/${imageSpec.toStringEncoded()}/?force=${force}`,
{ observe: 'response' }
);
}
--- /dev/null
+export class ImageSpec {
+ static fromString(imageSpec: string) {
+ const imageSpecSplited = imageSpec.split('/');
+
+ const poolName = imageSpecSplited[0];
+ const namespace = imageSpecSplited.length >= 3 ? imageSpecSplited[1] : null;
+ const imageName = imageSpecSplited.length >= 3 ? imageSpecSplited[2] : imageSpecSplited[1];
+
+ return new this(poolName, namespace, imageName);
+ }
+
+ constructor(public poolName: string, public namespace: string, public imageName: string) {}
+
+ private getNameSpace() {
+ return this.namespace ? `${this.namespace}/` : '';
+ }
+
+ toString() {
+ return `${this.poolName}/${this.getNameSpace()}${this.imageName}`;
+ }
+
+ toStringEncoded() {
+ return encodeURIComponent(`${this.poolName}/${this.getNameSpace()}${this.imageName}`);
+ }
+}
import { I18n } from '@ngx-translate/i18n-polyfill';
-import { RbdService } from '../api/rbd.service';
import { Components } from '../enum/components.enum';
import { FinishedTask } from '../models/finished-task';
+import { ImageSpec } from '../models/image-spec';
import { Task } from '../models/task';
export class TaskMessageOperation {
providedIn: 'root'
})
export class TaskMessageService {
- constructor(private i18n: I18n, private rbdService: RbdService) {}
+ constructor(private i18n: I18n) {}
defaultMessage = this.newTaskMessage(
new TaskMessageOperation(this.i18n('Executing'), this.i18n('execute'), this.i18n('Executed')),
id: `${metadata.image_spec}`
}),
create: (metadata) => {
- const id = this.rbdService.getImageSpec(
+ const id = new ImageSpec(
metadata.pool_name,
metadata.namespace,
metadata.image_name
- );
+ ).toString();
return this.i18n(`RBD '{{id}}'`, {
id: id
});
},
child: (metadata) => {
- const id = this.rbdService.getImageSpec(
+ const id = new ImageSpec(
metadata.child_pool_name,
metadata.child_namespace,
metadata.child_image_name
- );
+ ).toString();
return this.i18n(`RBD '{{id}}'`, {
id: id
});
},
destination: (metadata) => {
- const id = this.rbdService.getImageSpec(
+ const id = new ImageSpec(
metadata.dest_pool_name,
metadata.dest_namespace,
metadata.dest_image_name
- );
+ ).toString();
return this.i18n(`RBD '{{id}}'`, {
id: id
});