-
Notifications
You must be signed in to change notification settings - Fork 5.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21351 from votdev/dashboard_rgw_management
mgr/dashboard: Add RGW user and bucket management features Reviewed-by: Ricardo Dias <rdias@suse.com> Reviewed-by: Ricardo Marques <rimarques@suse.com>
- Loading branch information
Showing
48 changed files
with
3,599 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 4 additions & 0 deletions
4
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-user-capability.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export class RgwUserCapability { | ||
type: string; | ||
perm: string; | ||
} |
6 changes: 6 additions & 0 deletions
6
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-user-s3-key.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export class RgwUserS3Key { | ||
user: string; | ||
generate_key?: boolean; | ||
access_key: string; | ||
secret_key: string; | ||
} |
6 changes: 6 additions & 0 deletions
6
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-user-subuser.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export class RgwUserSubuser { | ||
id: string; | ||
permissions: string; | ||
generate_secret?: boolean; | ||
secret_key?: string; | ||
} |
4 changes: 4 additions & 0 deletions
4
src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/models/rgw-user-swift-key.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export class RgwUserSwiftKey { | ||
user: string; | ||
secret_key: string; | ||
} |
147 changes: 147 additions & 0 deletions
147
...nd/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-form/rgw-bucket-form.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
<nav aria-label="breadcrumb"> | ||
<ol class="breadcrumb"> | ||
<li class="breadcrumb-item" | ||
i18n>Object Gateway</li> | ||
<li class="breadcrumb-item"> | ||
<a routerLink="/rgw/bucket" | ||
i18n>Buckets</a> | ||
</li> | ||
<li class="breadcrumb-item active" | ||
aria-current="page" | ||
i18n> | ||
{editing, select, 1 {Edit} other {Add}} | ||
</li> | ||
</ol> | ||
</nav> | ||
|
||
<cd-loading-panel *ngIf="editing && loading && !error" | ||
i18n> | ||
Loading bucket data... | ||
</cd-loading-panel> | ||
<cd-error-panel *ngIf="editing && error" | ||
(backAction)="goToListView()" | ||
i18n> | ||
The bucket data could not be loaded. | ||
</cd-error-panel> | ||
|
||
<div class="col-sm-12 col-lg-6" | ||
*ngIf="!loading && !error"> | ||
<form name="bucketForm" | ||
class="form-horizontal" | ||
#frm="ngForm" | ||
[formGroup]="bucketForm" | ||
novalidate> | ||
<div class="panel panel-default"> | ||
<div class="panel-heading"> | ||
<h3 class="panel-title" | ||
i18n> | ||
{editing, select, 1 {Edit} other {Add}} bucket | ||
</h3> | ||
</div> | ||
<div class="panel-body"> | ||
|
||
<!-- Id --> | ||
<div class="form-group" | ||
*ngIf="editing"> | ||
<label i18n | ||
class="col-sm-3 control-label" | ||
for="id">Id</label> | ||
<div class="col-sm-9"> | ||
<input id="id" | ||
name="id" | ||
class="form-control" | ||
type="text" | ||
formControlName="id" | ||
readonly> | ||
</div> | ||
</div> | ||
|
||
<!-- Name --> | ||
<div class="form-group" | ||
[ngClass]="{'has-error': (frm.submitted || bucketForm.controls.bucket.dirty) && bucketForm.controls.bucket.invalid}"> | ||
<label i18n | ||
class="control-label col-sm-3" | ||
for="bucket">Name | ||
<span class="required" | ||
*ngIf="!editing"></span> | ||
</label> | ||
<div class="col-sm-9"> | ||
<input id="bucket" | ||
name="bucket" | ||
class="form-control" | ||
type="text" | ||
i18n-placeholder | ||
placeholder="Name..." | ||
formControlName="bucket" | ||
[readonly]="editing" | ||
autofocus> | ||
<span i18n | ||
class="help-block" | ||
*ngIf="(frm.submitted || bucketForm.controls.bucket.dirty) && bucketForm.controls.bucket.hasError('required')"> | ||
This field is required. | ||
</span> | ||
<span i18n | ||
class="help-block" | ||
*ngIf="(frm.submitted || bucketForm.controls.bucket.dirty) && bucketForm.controls.bucket.hasError('bucketNameInvalid')"> | ||
The value is not valid. | ||
</span> | ||
<span i18n | ||
class="help-block" | ||
*ngIf="(frm.submitted || bucketForm.controls.bucket.dirty) && bucketForm.controls.bucket.hasError('bucketNameExists')"> | ||
The chosen name is already in use. | ||
</span> | ||
</div> | ||
</div> | ||
|
||
<!-- Owner --> | ||
<div class="form-group" | ||
[ngClass]="{'has-error': (frm.submitted || bucketForm.controls.owner.dirty) && bucketForm.controls.owner.invalid}"> | ||
<label i18n | ||
class="control-label col-sm-3" | ||
for="owner">Owner | ||
<span class="required"></span> | ||
</label> | ||
<div class="col-sm-9"> | ||
<select id="owner" | ||
name="owner" | ||
class="form-control" | ||
formControlName="owner"> | ||
<option i18n | ||
*ngIf="owners === null" | ||
[ngValue]="null">Loading... | ||
</option> | ||
<option i18n | ||
*ngIf="owners !== null" | ||
[ngValue]="null">-- Select a user -- | ||
</option> | ||
<option *ngFor="let owner of owners" | ||
[value]="owner">{{ owner }}</option> | ||
</select> | ||
<span i18n | ||
class="help-block" | ||
*ngIf="(frm.submitted || bucketForm.controls.owner.dirty) && bucketForm.controls.owner.hasError('required')"> | ||
This field is required. | ||
</span> | ||
</div> | ||
</div> | ||
|
||
</div> | ||
<div class="panel-footer"> | ||
<div class="button-group text-right"> | ||
<cd-submit-button type="button" | ||
(submitAction)="submit()" | ||
[form]="bucketForm" | ||
i18n> | ||
{editing, select, 1 {Update} other {Add}} | ||
</cd-submit-button> | ||
<button i18n | ||
type="button" | ||
class="btn btn-sm btn-default" | ||
routerLink="/rgw/bucket"> | ||
Back | ||
</button> | ||
</div> | ||
</div> | ||
</div> | ||
</form> | ||
</div> |
Empty file.
106 changes: 106 additions & 0 deletions
106
...mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-form/rgw-bucket-form.component.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import { HttpClientTestingModule } from '@angular/common/http/testing'; | ||
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; | ||
import { FormControl, ReactiveFormsModule } from '@angular/forms'; | ||
import { RouterTestingModule } from '@angular/router/testing'; | ||
|
||
import 'rxjs/add/observable/of'; | ||
import { Observable } from 'rxjs/Observable'; | ||
|
||
import { RgwBucketService } from '../../../shared/api/rgw-bucket.service'; | ||
import { RgwUserService } from '../../../shared/api/rgw-user.service'; | ||
import { SharedModule } from '../../../shared/shared.module'; | ||
import { RgwBucketFormComponent } from './rgw-bucket-form.component'; | ||
|
||
describe('RgwBucketFormComponent', () => { | ||
let component: RgwBucketFormComponent; | ||
let fixture: ComponentFixture<RgwBucketFormComponent>; | ||
let queryResult: Array<string> = []; | ||
|
||
class MockRgwBucketService extends RgwBucketService { | ||
enumerate() { | ||
return Observable.of(queryResult); | ||
} | ||
} | ||
|
||
beforeEach(async(() => { | ||
TestBed.configureTestingModule({ | ||
declarations: [ RgwBucketFormComponent ], | ||
imports: [ | ||
HttpClientTestingModule, | ||
ReactiveFormsModule, | ||
RouterTestingModule, | ||
SharedModule | ||
], | ||
providers: [ | ||
RgwUserService, | ||
{ provide: RgwBucketService, useClass: MockRgwBucketService } | ||
] | ||
}) | ||
.compileComponents(); | ||
})); | ||
|
||
beforeEach(() => { | ||
fixture = TestBed.createComponent(RgwBucketFormComponent); | ||
component = fixture.componentInstance; | ||
fixture.detectChanges(); | ||
}); | ||
|
||
it('should create', () => { | ||
expect(component).toBeTruthy(); | ||
}); | ||
|
||
describe('bucketNameValidator', () => { | ||
it('should validate name (1/4)', () => { | ||
const validatorFn = component.bucketNameValidator(); | ||
const ctrl = new FormControl(''); | ||
const validatorPromise = validatorFn(ctrl); | ||
expect(validatorPromise instanceof Promise).toBeTruthy(); | ||
if (validatorPromise instanceof Promise) { | ||
validatorPromise.then((resp) => { | ||
expect(resp).toBe(null); | ||
}); | ||
} | ||
}); | ||
|
||
it('should validate name (2/4)', () => { | ||
const validatorFn = component.bucketNameValidator(); | ||
const ctrl = new FormControl('ab'); | ||
ctrl.markAsDirty(); | ||
const validatorPromise = validatorFn(ctrl); | ||
expect(validatorPromise instanceof Promise).toBeTruthy(); | ||
if (validatorPromise instanceof Promise) { | ||
validatorPromise.then((resp) => { | ||
expect(resp.bucketNameInvalid).toBeTruthy(); | ||
}); | ||
} | ||
}); | ||
|
||
it('should validate name (3/4)', () => { | ||
const validatorFn = component.bucketNameValidator(); | ||
const ctrl = new FormControl('abc'); | ||
ctrl.markAsDirty(); | ||
const validatorPromise = validatorFn(ctrl); | ||
expect(validatorPromise instanceof Promise).toBeTruthy(); | ||
if (validatorPromise instanceof Promise) { | ||
validatorPromise.then((resp) => { | ||
expect(resp).toBe(null); | ||
}); | ||
} | ||
}); | ||
|
||
it('should validate name (4/4)', () => { | ||
queryResult = ['abcd']; | ||
const validatorFn = component.bucketNameValidator(); | ||
const ctrl = new FormControl('abcd'); | ||
ctrl.markAsDirty(); | ||
const validatorPromise = validatorFn(ctrl); | ||
expect(validatorPromise instanceof Promise).toBeTruthy(); | ||
if (validatorPromise instanceof Promise) { | ||
validatorPromise.then((resp) => { | ||
expect(resp instanceof Object).toBeTruthy(); | ||
expect(resp.bucketNameExists).toBeTruthy(); | ||
}); | ||
} | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.