it('should show empty table in Sync Policy page', () => {
multisite.getTab('Sync Policy').click();
multisite.getDataTables().should('exist');
- multisite.getTableCount('total').should('eq', 0);
+ });
+ });
+
+ describe('create, edit & delete sync group policy', () => {
+ it('should create policy', () => {
+ multisite.navigateTo('create');
+ multisite.create('test', 'Enabled');
+ multisite.getFirstTableCell('test').should('exist');
+ });
+
+ it('should edit policy status', () => {
+ multisite.edit('test', 'Forbidden');
+ });
+
+ it('should delete policy', () => {
+ multisite.getTab('Sync Policy').click();
+ multisite.delete('test');
});
});
});
import { PageHelper } from '../page-helper.po';
+const WAIT_TIMER = 1000;
const pages = {
- index: { url: '#/rgw/multisite', id: 'cd-rgw-multisite-details' }
+ index: { url: '#/rgw/multisite', id: 'cd-rgw-multisite-details' },
+ create: { url: '#/rgw/multisite/sync-policy/create', id: 'cd-rgw-multisite-sync-policy-form' },
+ edit: { url: '#/rgw/multisite/sync-policy/edit', id: 'cd-rgw-multisite-sync-policy-form' }
};
export class MultisitePageHelper extends PageHelper {
pages = pages;
+
+ columnIndex = {
+ status: 3
+ };
+
+ @PageHelper.restrictTo(pages.create.url)
+ create(group_id: string, status: string) {
+ // Enter in group_id
+ cy.get('#group_id').type(group_id);
+ // Show Status
+ this.selectOption('status', status);
+ cy.get('#status').should('have.class', 'ng-valid');
+
+ // Click the create button and wait for policy to be made
+ cy.contains('button', 'Create Sync Policy Group').wait(WAIT_TIMER).click();
+ this.getFirstTableCell(group_id).should('exist');
+ }
+
+ @PageHelper.restrictTo(pages.index.url)
+ edit(group_id: string, status: string) {
+ cy.visit(`${pages.edit.url}/${group_id}`);
+
+ // Change the status field
+ this.selectOption('status', status);
+ cy.contains('button', 'Edit Sync Policy Group').click();
+
+ this.searchTable(group_id);
+ cy.get(`datatable-body-cell:nth-child(${this.columnIndex.status})`)
+ .find('.badge-warning')
+ .should('contain', status);
+ }
}
access_key: string;
secret_key: string;
}
+
+export enum RgwMultisiteSyncPolicyStatus {
+ ENABLED = 'enabled',
+ FORBIDDEN = 'forbidden',
+ ALLOWED = 'allowed'
+}
<nav ngbNav
#nav="ngbNav"
class="nav-tabs"
+ [(activeId)]="activeId"
(navChange)="onNavChange($event)">
<ng-container ngbNavItem="configuration">
<a ngbNavLink
rgwModuleStatus: boolean;
restartGatewayMessage = false;
rgwModuleData: string | any[] = [];
+ activeId: string;
constructor(
private modalService: ModalService,
private notificationService: NotificationService
) {
this.permission = this.authStorageService.getPermissions().rgw;
+ const activeId = this.router.getCurrentNavigation()?.extras?.state?.activeId;
+ if (activeId) {
+ this.activeId = activeId;
+ }
}
openModal(entity: any, edit = false) {
--- /dev/null
+<div class="cd-col-form">
+ <form
+ name="bucketForm"
+ #frm="ngForm"
+ [formGroup]="syncPolicyForm"
+ *cdFormLoading="loading"
+ novalidate>
+ <div class="card">
+ <div
+ i18n="form title"
+ class="card-header">
+ {{ action | titlecase }} {{ resource | upperFirst }}
+ </div>
+
+ <div class="card-body">
+ <!-- Group Id -->
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label required"
+ for="group_id"
+ i18n>Group Id</label>
+ <div class="cd-col-form-input">
+ <input
+ id="group_id"
+ name="group_id"
+ class="form-control"
+ type="text"
+ i18n-placeholder
+ placeholder="Group Id..."
+ formControlName="group_id"
+ [readonly]="editing"/>
+ <span
+ class="invalid-feedback"
+ *ngIf="syncPolicyForm.showError('group_id', frm, 'required')"
+ i18n>This field is required.</span>
+ </div>
+ </div>
+
+ <!-- Status -->
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label required"
+ for="status"
+ i18n>Status</label>
+ <div class="cd-col-form-input">
+ <select
+ id="status"
+ name="status"
+ class="form-select"
+ formControlName="status">
+ <option
+ i18n
+ value="{{syncPolicyStatus.ENABLED}}">{{syncPolicyStatus.ENABLED | upperFirst }}</option>
+ <option
+ i18n
+ value="{{syncPolicyStatus.ALLOWED}}">{{syncPolicyStatus.ALLOWED | upperFirst }}</option>
+ <option
+ i18n
+ value="{{syncPolicyStatus.FORBIDDEN}}">{{syncPolicyStatus.FORBIDDEN | upperFirst }}</option>
+ </select>
+ <span
+ class="invalid-feedback"
+ *ngIf="syncPolicyForm.showError('status', frm, 'required')"
+ i18n>This field is required.</span>
+ </div>
+ </div>
+
+ <!-- Bucket Name -->
+ <div class="form-group row">
+ <label
+ class="cd-col-form-label"
+ for="bucket_name"
+ i18n>Bucket Name</label>
+ <div class="cd-col-form-input">
+ <input
+ id="bucket_name"
+ name="bucket_name"
+ class="form-control"
+ type="text"
+ i18n-placeholder
+ placeholder="Bucket Name..."
+ formControlName="bucket_name"
+ [readonly]="editing"
+ [ngbTypeahead]="bucketDataSource"/>
+ <span
+ class="invalid-feedback"
+ *ngIf="syncPolicyForm.showError('bucket_name', frm, 'bucketNameNotAllowed')"
+ i18n>The bucket with chosen name does not exist.</span>
+ </div>
+ </div>
+ </div>
+
+ <div class="card-footer">
+ <cd-form-button-panel
+ (submitActionEvent)="submit()"
+ [form]="syncPolicyForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"></cd-form-button-panel>
+ </div>
+ </div>
+ </form>
+</div>
--- /dev/null
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { RgwMultisiteSyncPolicyFormComponent } from './rgw-multisite-sync-policy-form.component';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { ToastrModule } from 'ngx-toastr';
+import { ReactiveFormsModule } from '@angular/forms';
+import { PipesModule } from '~/app/shared/pipes/pipes.module';
+import { ComponentsModule } from '~/app/shared/components/components.module';
+import { RouterTestingModule } from '@angular/router/testing';
+
+describe('RgwMultisiteSyncPolicyFormComponent', () => {
+ let component: RgwMultisiteSyncPolicyFormComponent;
+ let fixture: ComponentFixture<RgwMultisiteSyncPolicyFormComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [RgwMultisiteSyncPolicyFormComponent],
+ imports: [
+ HttpClientTestingModule,
+ ReactiveFormsModule,
+ ToastrModule.forRoot(),
+ PipesModule,
+ ComponentsModule,
+ RouterTestingModule
+ ],
+ providers: []
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(RgwMultisiteSyncPolicyFormComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
--- /dev/null
+import { Component, OnInit } from '@angular/core';
+import { AbstractControl, AsyncValidatorFn, ValidationErrors, Validators } from '@angular/forms';
+import { ActivatedRoute, Router } from '@angular/router';
+import { Observable, timer as observableTimer, of } from 'rxjs';
+import {
+ catchError,
+ debounceTime,
+ distinctUntilChanged,
+ map,
+ mergeMap,
+ switchMapTo
+} from 'rxjs/operators';
+import { RgwBucketService } from '~/app/shared/api/rgw-bucket.service';
+import { RgwMultisiteService } from '~/app/shared/api/rgw-multisite.service';
+import { ActionLabelsI18n, URLVerbs } from '~/app/shared/constants/app.constants';
+import { NotificationType } from '~/app/shared/enum/notification-type.enum';
+import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
+import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
+import { NotificationService } from '~/app/shared/services/notification.service';
+import { RgwMultisiteSyncPolicyStatus } from '../models/rgw-multisite';
+import { CdForm } from '~/app/shared/forms/cd-form';
+import _ from 'lodash';
+
+@Component({
+ selector: 'cd-rgw-multisite-sync-policy-form',
+ templateUrl: './rgw-multisite-sync-policy-form.component.html',
+ styleUrls: ['./rgw-multisite-sync-policy-form.component.scss']
+})
+export class RgwMultisiteSyncPolicyFormComponent extends CdForm implements OnInit {
+ syncPolicyForm: CdFormGroup;
+ editing = false;
+ action: string;
+ resource: string;
+ syncPolicyStatus = RgwMultisiteSyncPolicyStatus;
+
+ bucketDataSource = (text$: Observable<string>) => {
+ return text$.pipe(
+ debounceTime(200),
+ distinctUntilChanged(),
+ mergeMap((token: string) => this.getBucketTypeahead(token))
+ );
+ };
+
+ constructor(
+ private router: Router,
+ private route: ActivatedRoute,
+ public actionLabels: ActionLabelsI18n,
+ private fb: CdFormBuilder,
+ private rgwMultisiteService: RgwMultisiteService,
+ private notificationService: NotificationService,
+ private rgwBucketService: RgwBucketService
+ ) {
+ super();
+ this.editing = this.router.url.startsWith(`/rgw/multisite/sync-policy/${URLVerbs.EDIT}`);
+ this.action = this.editing ? this.actionLabels.EDIT : this.actionLabels.CREATE;
+ this.resource = $localize`Sync Policy Group`;
+ this.createForm();
+ this.loadingReady();
+ }
+
+ ngOnInit(): void {
+ if (this.editing) {
+ this.route.paramMap.subscribe((params: any) => {
+ const groupName = params.get('groupName');
+ if (groupName) {
+ const bucketName = params.get('bucketName');
+ this.loadingStart();
+ this.rgwMultisiteService
+ .getSyncPolicyGroup(groupName, bucketName)
+ .subscribe((syncPolicy: any) => {
+ this.loadingReady();
+ if (syncPolicy) {
+ this.syncPolicyForm.patchValue({
+ group_id: syncPolicy.id,
+ status: syncPolicy.status,
+ bucket_name: bucketName
+ });
+ } else {
+ this.goToListView();
+ }
+ });
+ }
+ });
+ }
+ }
+
+ createForm() {
+ this.syncPolicyForm = this.fb.group({
+ group_id: ['', Validators.required],
+ status: [`${this.syncPolicyStatus.ENABLED}`, Validators.required],
+ bucket_name: ['', , this.bucketExistence(true)]
+ });
+ }
+
+ goToListView() {
+ // passing state in order to return to same tab on details page
+ this.router.navigate(['/rgw/multisite'], { state: { activeId: 'syncPolicy' } });
+ }
+
+ submit() {
+ if (this.syncPolicyForm.pristine) {
+ this.goToListView();
+ return;
+ }
+
+ // Ensure that no validation is pending
+ if (this.syncPolicyForm.pending) {
+ this.syncPolicyForm.setErrors({ cdSubmitButton: true });
+ return;
+ }
+
+ if (!this.editing) {
+ // Add
+ this.rgwMultisiteService.createSyncPolicyGroup(this.syncPolicyForm.value).subscribe(
+ () => {
+ this.notificationService.show(
+ NotificationType.success,
+ $localize`Created Sync Policy Group '${this.syncPolicyForm.getValue('group_id')}'`
+ );
+ this.goToListView();
+ },
+ () => {
+ // Reset the 'Submit' button.
+ this.syncPolicyForm.setErrors({ cdSubmitButton: true });
+ }
+ );
+ } else {
+ this.rgwMultisiteService.modifySyncPolicyGroup(this.syncPolicyForm.value).subscribe(
+ () => {
+ this.notificationService.show(
+ NotificationType.success,
+ $localize`Modified Sync Policy Group '${this.syncPolicyForm.getValue('group_id')}'`
+ );
+ this.goToListView();
+ },
+ () => {
+ // Reset the 'Submit' button.
+ this.syncPolicyForm.setErrors({ cdSubmitButton: true });
+ }
+ );
+ }
+ }
+
+ bucketExistence(requiredExistenceResult: boolean): AsyncValidatorFn {
+ return (control: AbstractControl): Observable<ValidationErrors | null> => {
+ if (control.dirty) {
+ return observableTimer(500).pipe(
+ switchMapTo(this.rgwBucketService.exists(control.value)),
+ map((existenceResult: boolean) =>
+ existenceResult === requiredExistenceResult ? null : { bucketNameNotAllowed: true }
+ )
+ );
+ }
+ return of(null);
+ };
+ }
+
+ private getBucketTypeahead(path: string): Observable<any> {
+ if (_.isString(path) && path !== '/' && path !== '') {
+ return this.rgwBucketService.list().pipe(
+ map((bucketList: any) =>
+ bucketList
+ .filter((bucketName: string) => bucketName.toLowerCase().includes(path))
+ .slice(0, 15)
+ ),
+ catchError(() => of([$localize`Error while retrieving bucket names.`]))
+ );
+ } else {
+ return of([]);
+ }
+ }
+}
- <legend i18n>
- Multisite Sync Policy
- <cd-help-text>
- Multisite bucket-granularity sync policy provides fine grained control of data movement between buckets in different zones.
- </cd-help-text>
- </legend>
- <cd-table #table
- [data]="syncPolicyData"
- [columns]="columns"
- columnMode="flex"
- selectionType="single"
- [searchableObjects]="true"
- [hasDetails]="false"
- [serverSide]="false"
- [count]="0"
- [maxLimit]="25"
- [toolHeader]="true">
- </cd-table>
+<legend i18n>
+ Multisite Sync Policy
+ <cd-help-text>
+ Multisite bucket-granularity sync policy provides fine grained control of data movement between
+ buckets in different zones.
+ </cd-help-text>
+</legend>
+<cd-table
+ #table
+ [autoReload]="false"
+ [data]="syncPolicyData"
+ [columns]="columns"
+ identifier="uniqueId"
+ [forceIdentifier]="true"
+ columnMode="flex"
+ selectionType="multiClick"
+ [searchableObjects]="true"
+ [hasDetails]="false"
+ [serverSide]="false"
+ [count]="0"
+ [maxLimit]="25"
+ [toolHeader]="true"
+ (fetchData)="getPolicyList($event)"
+ (updateSelection)="updateSelection($event)">
+ <div class="table-actions btn-toolbar">
+ <cd-table-actions
+ [permission]="permission"
+ [selection]="selection"
+ class="btn-group"
+ [tableActions]="tableActions">
+ </cd-table-actions>
+ </div>
+</cd-table>
+
+<ng-template #deleteTpl>
+ <cd-alert-panel type="danger"
+ i18n>
+ Are you sure you want to delete these policy groups?
+ </cd-alert-panel>
+</ng-template>
import { RgwMultisiteSyncPolicyComponent } from './rgw-multisite-sync-policy.component';
import { HttpClientModule } from '@angular/common/http';
import { TitleCasePipe } from '@angular/common';
+import { ToastrModule } from 'ngx-toastr';
+import { PipesModule } from '~/app/shared/pipes/pipes.module';
describe('RgwMultisiteSyncPolicyComponent', () => {
let component: RgwMultisiteSyncPolicyComponent;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [RgwMultisiteSyncPolicyComponent],
- imports: [HttpClientModule],
+ imports: [HttpClientModule, ToastrModule.forRoot(), PipesModule],
providers: [TitleCasePipe]
}).compileComponents();
import { TitleCasePipe } from '@angular/common';
-import { Component, OnInit } from '@angular/core';
+import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { forkJoin as observableForkJoin, Observable, Subscriber } from 'rxjs';
import { RgwMultisiteService } from '~/app/shared/api/rgw-multisite.service';
+import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
+import { TableComponent } from '~/app/shared/datatable/table/table.component';
import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
+import { Icons } from '~/app/shared/enum/icons.enum';
+import { CdTableAction } from '~/app/shared/models/cd-table-action';
import { CdTableColumn } from '~/app/shared/models/cd-table-column';
+import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context';
+import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
+import { FinishedTask } from '~/app/shared/models/finished-task';
+import { Permission } from '~/app/shared/models/permissions';
+import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
+import { ModalService } from '~/app/shared/services/modal.service';
+import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
+import { URLBuilderService } from '~/app/shared/services/url-builder.service';
+
+const BASE_URL = 'rgw/multisite/sync-policy';
@Component({
selector: 'cd-rgw-multisite-sync-policy',
templateUrl: './rgw-multisite-sync-policy.component.html',
- styleUrls: ['./rgw-multisite-sync-policy.component.scss']
+ styleUrls: ['./rgw-multisite-sync-policy.component.scss'],
+ providers: [{ provide: URLBuilderService, useValue: new URLBuilderService(BASE_URL) }]
})
export class RgwMultisiteSyncPolicyComponent implements OnInit {
+ @ViewChild(TableComponent, { static: true })
+ table: TableComponent;
+ @ViewChild('deleteTpl', { static: true })
+ deleteTpl: TemplateRef<any>;
+
columns: Array<CdTableColumn> = [];
syncPolicyData: any = [];
+ tableActions: CdTableAction[];
+ selection = new CdTableSelection();
+ permission: Permission;
constructor(
private rgwMultisiteService: RgwMultisiteService,
- private titleCasePipe: TitleCasePipe
+ private titleCasePipe: TitleCasePipe,
+ private actionLabels: ActionLabelsI18n,
+ private urlBuilder: URLBuilderService,
+ private authStorageService: AuthStorageService,
+ private modalService: ModalService,
+ private taskWrapper: TaskWrapperService
) {}
ngOnInit(): void {
+ this.permission = this.authStorageService.getPermissions().rgw;
this.columns = [
+ {
+ prop: 'uniqueId',
+ isHidden: true
+ },
{
name: $localize`Group Name`,
prop: 'groupName',
flexGrow: 1
}
];
-
- this.rgwMultisiteService
- .getSyncPolicy('', '', true)
- .subscribe((allSyncPolicyData: Array<Object>) => {
- if (allSyncPolicyData && allSyncPolicyData.length > 0) {
- allSyncPolicyData.forEach((policy) => {
- this.syncPolicyData.push({
- groupName: policy['id'],
- status: policy['status'],
- bucket: policy['bucketName'],
- zonegroup: ''
- });
- });
- this.syncPolicyData = [...this.syncPolicyData];
+ const getSyncGroupName = () => {
+ if (this.selection.first() && this.selection.first().groupName) {
+ if (this.selection.first().bucket) {
+ return `${encodeURIComponent(this.selection.first().groupName)}/${encodeURIComponent(
+ this.selection.first().bucket
+ )}`;
}
+ return `${encodeURIComponent(this.selection.first().groupName)}`;
+ }
+ return '';
+ };
+ const addAction: CdTableAction = {
+ permission: 'create',
+ icon: Icons.add,
+ routerLink: () => this.urlBuilder.getCreate(),
+ name: this.actionLabels.CREATE,
+ canBePrimary: (selection: CdTableSelection) => !selection.hasSelection
+ };
+ const editAction: CdTableAction = {
+ permission: 'update',
+ icon: Icons.edit,
+ routerLink: () => this.urlBuilder.getEdit(getSyncGroupName()),
+ name: this.actionLabels.EDIT
+ };
+ const deleteAction: CdTableAction = {
+ permission: 'delete',
+ icon: Icons.destroy,
+ click: () => this.deleteAction(),
+ disable: () => !this.selection.hasSelection,
+ name: this.actionLabels.DELETE,
+ canBePrimary: (selection: CdTableSelection) => selection.hasMultiSelection
+ };
+ this.tableActions = [addAction, editAction, deleteAction];
+ }
+
+ transformSyncPolicyData(allSyncPolicyData: any) {
+ if (allSyncPolicyData && allSyncPolicyData.length > 0) {
+ allSyncPolicyData.forEach((policy: any) => {
+ this.syncPolicyData.push({
+ uniqueId: policy['id'] + (policy['bucketName'] ? policy['bucketName'] : ''),
+ groupName: policy['id'],
+ status: policy['status'],
+ bucket: policy['bucketName'],
+ zonegroup: ''
+ });
});
+ this.syncPolicyData = [...this.syncPolicyData];
+ }
+ }
+
+ updateSelection(selection: CdTableSelection) {
+ this.selection = selection;
+ }
+
+ getPolicyList(context: CdTableFetchDataContext) {
+ this.rgwMultisiteService.getSyncPolicy('', '', true).subscribe(
+ (resp: object[]) => {
+ this.syncPolicyData = [];
+ this.transformSyncPolicyData(resp);
+ },
+ () => {
+ context.error();
+ }
+ );
+ }
+
+ deleteAction() {
+ const groupNames = this.selection.selected.map((policy: any) => policy.groupName);
+ this.modalService.show(CriticalConfirmationModalComponent, {
+ itemDescription: this.selection.hasSingleSelection
+ ? $localize`Policy Group`
+ : $localize`Policy Groups`,
+ itemNames: groupNames,
+ bodyTemplate: this.deleteTpl,
+ submitActionObservable: () => {
+ return new Observable((observer: Subscriber<any>) => {
+ this.taskWrapper
+ .wrapTaskAroundCall({
+ task: new FinishedTask('rgw/multisite/sync-policy/delete', {
+ group_names: groupNames
+ }),
+ call: observableForkJoin(
+ this.selection.selected.map((policy: any) => {
+ return this.rgwMultisiteService.removeSyncPolicyGroup(
+ policy.groupName,
+ policy.bucket
+ );
+ })
+ )
+ })
+ .subscribe({
+ error: (error: any) => {
+ // Forward the error to the observer.
+ observer.error(error);
+ // Reload the data table content because some deletions might
+ // have been executed successfully in the meanwhile.
+ this.table.refreshBtn();
+ },
+ complete: () => {
+ // Notify the observer that we are done.
+ observer.complete();
+ // Reload the data table content.
+ this.table.refreshBtn();
+ }
+ });
+ });
+ }
+ });
}
}
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RouterModule, Routes } from '@angular/router';
-import { NgbNavModule, NgbPopoverModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
+import {
+ NgbNavModule,
+ NgbPopoverModule,
+ NgbTooltipModule,
+ NgbTypeaheadModule
+} from '@ng-bootstrap/ng-bootstrap';
import { NgxPipeFunctionModule } from 'ngx-pipe-function';
import { ActionLabels, URLVerbs } from '~/app/shared/constants/app.constants';
import { NfsListComponent } from '../nfs/nfs-list/nfs-list.component';
import { NfsFormComponent } from '../nfs/nfs-form/nfs-form.component';
import { RgwMultisiteSyncPolicyComponent } from './rgw-multisite-sync-policy/rgw-multisite-sync-policy.component';
+import { RgwMultisiteSyncPolicyFormComponent } from './rgw-multisite-sync-policy-form/rgw-multisite-sync-policy-form.component';
@NgModule({
imports: [
NgxPipeFunctionModule,
TreeModule,
DataTableModule,
- DashboardV3Module
+ DashboardV3Module,
+ NgbTypeaheadModule
],
exports: [
RgwDaemonListComponent,
RgwSyncMetadataInfoComponent,
RgwSyncDataInfoComponent,
BucketTagModalComponent,
- RgwMultisiteSyncPolicyComponent
+ RgwMultisiteSyncPolicyComponent,
+ RgwMultisiteSyncPolicyFormComponent
],
providers: [TitleCasePipe]
})
{
path: 'multisite',
data: { breadcrumbs: 'Multi-site' },
- children: [{ path: '', component: RgwMultisiteDetailsComponent }]
+ children: [
+ { path: '', component: RgwMultisiteDetailsComponent },
+ {
+ path: `sync-policy/${URLVerbs.CREATE}`,
+ component: RgwMultisiteSyncPolicyFormComponent,
+ data: { breadcrumbs: `${ActionLabels.CREATE} Sync Policy` }
+ },
+ {
+ path: `sync-policy/${URLVerbs.EDIT}/:groupName`,
+ component: RgwMultisiteSyncPolicyFormComponent,
+ data: { breadcrumbs: `${ActionLabels.EDIT} Sync Policy` }
+ },
+ {
+ path: `sync-policy/${URLVerbs.EDIT}/:groupName/:bucketName`,
+ component: RgwMultisiteSyncPolicyFormComponent,
+ data: { breadcrumbs: `${ActionLabels.EDIT} Sync Policy` }
+ }
+ ]
},
{
path: 'nfs',
expect(req.request.method).toBe('GET');
req.flush(mockSyncPolicyData);
});
+
+ it('should create Sync Policy Group w/o bucket_name', () => {
+ const postData = { group_id: 'test', status: 'enabled' };
+ service.createSyncPolicyGroup(postData).subscribe();
+ const req = httpTesting.expectOne('api/rgw/multisite/sync-policy-group');
+ expect(req.request.method).toBe('POST');
+ expect(req.request.body).toEqual(postData);
+ req.flush(null);
+ });
+
+ it('should create Sync Policy Group with bucket_name', () => {
+ const postData = { group_id: 'test', status: 'enabled', bucket_name: 'test' };
+ service.createSyncPolicyGroup(postData).subscribe();
+ const req = httpTesting.expectOne('api/rgw/multisite/sync-policy-group');
+ expect(req.request.method).toBe('POST');
+ expect(req.request.body).toEqual(postData);
+ req.flush(null);
+ });
+
+ it('should modify Sync Policy Group', () => {
+ const postData = { group_id: 'test', status: 'enabled', bucket_name: 'test' };
+ service.modifySyncPolicyGroup(postData).subscribe();
+ const req = httpTesting.expectOne('api/rgw/multisite/sync-policy-group');
+ expect(req.request.method).toBe('PUT');
+ expect(req.request.body).toEqual(postData);
+ req.flush(null);
+ });
+
+ it('should remove Sync Policy Group', () => {
+ const group_id = 'test';
+ service.removeSyncPolicyGroup(group_id).subscribe();
+ const req = httpTesting.expectOne('api/rgw/multisite/sync-policy-group/' + group_id);
+ expect(req.request.method).toBe('DELETE');
+ req.flush(null);
+ });
+
+ it('should fetch the sync policy group with given group_id and bucket_name', () => {
+ service.getSyncPolicyGroup('test', 'test').subscribe();
+ const req = httpTesting.expectOne('api/rgw/multisite/sync-policy-group/test?bucket_name=test');
+ expect(req.request.method).toBe('GET');
+ req.flush(mockSyncPolicyData[1]);
+ });
});
params = params.append('all_policy', fetchAllPolicy);
return this.http.get(`${this.url}/sync-policy`, { params });
}
+
+ getSyncPolicyGroup(group_id: string, bucket_name?: string) {
+ let params = new HttpParams();
+ if (bucket_name) {
+ params = params.append('bucket_name', bucket_name);
+ }
+ return this.http.get(`${this.url}/sync-policy-group/${group_id}`, { params });
+ }
+
+ createSyncPolicyGroup(payload: { group_id: string; status: string; bucket_name?: string }) {
+ return this.http.post(`${this.url}/sync-policy-group`, payload);
+ }
+
+ modifySyncPolicyGroup(payload: { group_id: string; status: string; bucket_name?: string }) {
+ return this.http.put(`${this.url}/sync-policy-group`, payload);
+ }
+
+ removeSyncPolicyGroup(group_id: string, bucket_name?: string) {
+ let params = new HttpParams();
+ if (bucket_name) {
+ params = params.append('bucket_name', bucket_name);
+ }
+ return this.http.delete(`${this.url}/sync-policy-group/${group_id}`, { params });
+ }
}
metadata.bucket_names.length > 1 ? 'selected buckets' : metadata.bucket_names[0]
}`;
}),
+ 'rgw/multisite/sync-policy/delete': this.newTaskMessage(
+ this.commonOperations.delete,
+ (metadata) => {
+ return $localize`${
+ metadata.group_names.length > 1
+ ? 'selected policy groups'
+ : `policy group '${metadata.group_names[0]}'`
+ }`;
+ }
+ ),
// iSCSI target tasks
'iscsi/target/create': this.newTaskMessage(this.commonOperations.create, (metadata) =>
this.iscsiTarget(metadata)