Skip to content

Commit 7789fcc

Browse files
authored
Merge pull request ceph#58114 from rhcs-dashboard/add-configuration-page-rgw
mgr/dashboard: add a new configuration page in side nav bar Object > Configuration Reviewed-by: Ankush Behl <[email protected]> Reviewed-by: Nizamudeen A <[email protected]>
2 parents 74a58e0 + 75a4fe9 commit 7789fcc

21 files changed

+772
-253
lines changed

src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/buckets.e2e-spec.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,6 @@ describe('RGW buckets page', () => {
3131
buckets.delete(bucket_name);
3232
});
3333

34-
it('should check default encryption is SSE-S3', () => {
35-
buckets.navigateTo('create');
36-
buckets.checkForDefaultEncryption();
37-
});
38-
3934
it('should create bucket with object locking enabled', () => {
4035
buckets.navigateTo('create');
4136
buckets.create(bucket_name, BucketsPageHelper.USERS[0], true);

src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/buckets.po.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,6 @@ export class BucketsPageHelper extends PageHelper {
5050
this.getFirstTableCell(name).should('exist');
5151
}
5252

53-
@PageHelper.restrictTo(pages.create.url)
54-
checkForDefaultEncryption() {
55-
cy.get("a[aria-label='click here']").click();
56-
cy.get('cd-modal').within(() => {
57-
cy.get('input[id=s3Enabled]').should('be.checked');
58-
});
59-
}
60-
6153
@PageHelper.restrictTo(pages.index.url)
6254
edit(name: string, new_owner: string, isLocking = false) {
6355
this.navigateEdit(name);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { ConfigurationPageHelper } from './configuration.po';
2+
3+
describe('RGW configuration page', () => {
4+
const configurations = new ConfigurationPageHelper();
5+
6+
beforeEach(() => {
7+
cy.login();
8+
configurations.navigateTo();
9+
});
10+
11+
describe('breadcrumb and tab tests', () => {
12+
it('should open and show breadcrumb', () => {
13+
configurations.expectBreadcrumbText('Configuration');
14+
});
15+
16+
it('should show one tab', () => {
17+
configurations.getTabsCount().should('eq', 1);
18+
});
19+
20+
it('should show Server-side Encryption Config list tab at first', () => {
21+
configurations.getTabText(0).should('eq', 'Server-side Encryption');
22+
});
23+
});
24+
25+
describe('create and edit encryption configuration', () => {
26+
it('should create configuration', () => {
27+
configurations.create('vault', 'agent', 'transit', 'https://localhost:8080');
28+
configurations.getFirstTableCell('SSE_KMS').should('exist');
29+
});
30+
31+
it('should edit configuration', () => {
32+
configurations.edit('https://localhost:9090');
33+
configurations.getDataTables().should('contain.text', 'https://localhost:9090');
34+
});
35+
});
36+
});
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { PageHelper } from '../page-helper.po';
2+
3+
export class ConfigurationPageHelper extends PageHelper {
4+
pages = {
5+
index: { url: '#/rgw/configuration', id: 'cd-rgw-configuration-page' }
6+
};
7+
8+
columnIndex = {
9+
address: 4
10+
};
11+
12+
create(provider: string, auth_method: string, secret_engine: string, address: string) {
13+
cy.contains('button', 'Create').click();
14+
this.selectKmsProvider(provider);
15+
cy.get('#kms_provider').should('have.class', 'ng-valid');
16+
this.selectAuthMethod(auth_method);
17+
cy.get('#auth_method').should('have.class', 'ng-valid');
18+
this.selectSecretEngine(secret_engine);
19+
cy.get('#secret_engine').should('have.class', 'ng-valid');
20+
cy.get('#address').type(address);
21+
cy.get('#address').should('have.class', 'ng-valid');
22+
cy.contains('button', 'Submit').click();
23+
this.getFirstTableCell('SSE_KMS').should('exist');
24+
}
25+
26+
edit(new_address: string) {
27+
this.navigateEdit('SSE_KMS', true, false);
28+
cy.get('#address').clear().type(new_address);
29+
cy.get('#address').should('have.class', 'ng-valid');
30+
cy.get('#kms_provider').should('be.disabled');
31+
cy.contains('button', 'Submit').click();
32+
this.getTableCell(this.columnIndex.address, new_address)
33+
.parent()
34+
.find(`datatable-body-cell:nth-child(${this.columnIndex.address})`)
35+
.should(($elements) => {
36+
const address = $elements.text();
37+
expect(address).to.eq(new_address);
38+
});
39+
}
40+
41+
private selectKmsProvider(provider: string) {
42+
return this.selectOption('kms_provider', provider);
43+
}
44+
45+
private selectAuthMethod(auth_method: string) {
46+
return this.selectOption('auth_method', auth_method);
47+
}
48+
49+
private selectSecretEngine(secret_engine: string) {
50+
return this.selectOption('secret_engine', secret_engine);
51+
}
52+
}
Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,37 @@
1-
export class RgwBucketEncryptionModel {
2-
kmsProviders = ['vault'];
3-
authMethods = ['token', 'agent'];
4-
secretEngines = ['kv', 'transit'];
5-
sse_s3 = 'AES256';
6-
sse_kms = 'aws:kms';
1+
enum KmsProviders {
2+
Vault = 'vault'
73
}
4+
5+
enum AuthMethods {
6+
Token = 'token',
7+
Agent = 'agent'
8+
}
9+
10+
enum SecretEngines {
11+
KV = 'kv',
12+
Transit = 'transit'
13+
}
14+
15+
enum sseS3 {
16+
SSE_S3 = 'AES256'
17+
}
18+
19+
enum sseKms {
20+
SSE_KMS = 'aws:kms'
21+
}
22+
23+
interface RgwBucketEncryptionModel {
24+
kmsProviders: KmsProviders[];
25+
authMethods: AuthMethods[];
26+
secretEngines: SecretEngines[];
27+
SSE_S3: sseS3;
28+
SSE_KMS: sseKms;
29+
}
30+
31+
export const rgwBucketEncryptionModel: RgwBucketEncryptionModel = {
32+
kmsProviders: [KmsProviders.Vault],
33+
authMethods: [AuthMethods.Token, AuthMethods.Agent],
34+
secretEngines: [SecretEngines.KV, SecretEngines.Transit],
35+
SSE_S3: sseS3.SSE_S3,
36+
SSE_KMS: sseKms.SSE_KMS
37+
};

src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-form/rgw-bucket-form.component.html

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,12 +296,11 @@
296296
name="encryption_enabled"
297297
formControlName="encryption_enabled"
298298
type="checkbox"
299-
[attr.disabled]="!kmsVaultConfig && !s3VaultConfig ? true : null"/>
299+
[attr.disabled]="!kmsConfigured && !s3Configured ? true : null"/>
300300
<cd-help-text aria-label="encryption helper">
301301
<span i18n>Enables encryption for the objects in the bucket.
302302
To enable encryption on a bucket you need to set the configuration values for SSE-S3 or SSE-KMS.
303-
To set the configuration values <a href="#/rgw/bucket/create"
304-
(click)="openConfigModal()"
303+
To set the configuration values <a href="#/rgw/configuration"
305304
aria-label="click here">Click here</a></span>
306305
</cd-help-text>
307306
</div>
@@ -317,10 +316,11 @@
317316
type="radio"
318317
name="encryption_type"
319318
value="AES256"
320-
[attr.disabled]="!s3VaultConfig ? true : null">
319+
[attr.disabled]="!s3Configured ? true : null">
321320
<label class="form-control-label"
321+
[ngClass]="{'text-muted': !s3Configured}"
322322
for="sse_S3_enabled"
323-
i18n>SSE-S3 Encryption</label>
323+
i18n>SSE-S3</label>
324324
</div>
325325
</div>
326326
</div>
@@ -333,9 +333,10 @@
333333
id="kms_enabled"
334334
name="encryption_type"
335335
value="aws:kms"
336-
[attr.disabled]="!kmsVaultConfig ? true : null"
336+
[attr.disabled]="!kmsConfigured ? true : null"
337337
type="radio">
338338
<label class="form-control-label"
339+
[ngClass]="{'text-muted': !kmsConfigured}"
339340
for="kms_enabled"
340341
i18n>Connect to an external key management service</label>
341342
</div>

src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-form/rgw-bucket-form.component.ts

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,14 @@ import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
2525
import { CdValidators } from '~/app/shared/forms/cd-validators';
2626
import { ModalService } from '~/app/shared/services/modal.service';
2727
import { NotificationService } from '~/app/shared/services/notification.service';
28-
import { RgwBucketEncryptionModel } from '../models/rgw-bucket-encryption';
28+
import { rgwBucketEncryptionModel } from '../models/rgw-bucket-encryption';
2929
import { RgwBucketMfaDelete } from '../models/rgw-bucket-mfa-delete';
3030
import {
3131
AclPermissionsType,
3232
RgwBucketAclPermissions as aclPermission,
3333
RgwBucketAclGrantee as Grantee
3434
} from './rgw-bucket-acl-permissions.enum';
3535
import { RgwBucketVersioning } from '../models/rgw-bucket-versioning';
36-
import { RgwConfigModalComponent } from '../rgw-config-modal/rgw-config-modal.component';
3736
import { BucketTagModalComponent } from '../bucket-tag-modal/bucket-tag-modal.component';
3837
import { TextAreaJsonFormatterService } from '~/app/shared/services/text-area-json-formatter.service';
3938
import { RgwMultisiteService } from '~/app/shared/api/rgw-multisite.service';
@@ -44,8 +43,7 @@ import { TextAreaXmlFormatterService } from '~/app/shared/services/text-area-xml
4443
@Component({
4544
selector: 'cd-rgw-bucket-form',
4645
templateUrl: './rgw-bucket-form.component.html',
47-
styleUrls: ['./rgw-bucket-form.component.scss'],
48-
providers: [RgwBucketEncryptionModel]
46+
styleUrls: ['./rgw-bucket-form.component.scss']
4947
})
5048
export class RgwBucketFormComponent extends CdForm implements OnInit, AfterViewChecked {
5149
@ViewChild('bucketPolicyTextArea')
@@ -64,8 +62,8 @@ export class RgwBucketFormComponent extends CdForm implements OnInit, AfterViewC
6462
isVersioningAlreadyEnabled = false;
6563
isMfaDeleteAlreadyEnabled = false;
6664
icons = Icons;
67-
kmsVaultConfig = false;
68-
s3VaultConfig = false;
65+
kmsConfigured = false;
66+
s3Configured = false;
6967
tags: Record<string, string>[] = [];
7068
dirtyTags = false;
7169
tagConfig = [
@@ -97,7 +95,6 @@ export class RgwBucketFormComponent extends CdForm implements OnInit, AfterViewC
9795
private modalService: ModalService,
9896
private rgwUserService: RgwUserService,
9997
private notificationService: NotificationService,
100-
private rgwEncryptionModal: RgwBucketEncryptionModel,
10198
private textAreaJsonFormatterService: TextAreaJsonFormatterService,
10299
private textAreaXmlFormatterService: TextAreaXmlFormatterService,
103100
public actionLabels: ActionLabelsI18n,
@@ -187,15 +184,20 @@ export class RgwBucketFormComponent extends CdForm implements OnInit, AfterViewC
187184
)
188185
);
189186

190-
this.kmsProviders = this.rgwEncryptionModal.kmsProviders;
187+
this.kmsProviders = rgwBucketEncryptionModel.kmsProviders;
191188
this.rgwBucketService.getEncryptionConfig().subscribe((data) => {
192-
this.kmsVaultConfig = data[0];
193-
this.s3VaultConfig = data[1];
194-
if (this.kmsVaultConfig && this.s3VaultConfig) {
189+
if (data['SSE_KMS']?.length > 0) {
190+
this.kmsConfigured = true;
191+
}
192+
if (data['SSE_S3']?.length > 0) {
193+
this.s3Configured = true;
194+
}
195+
// Set the encryption type based on the configurations
196+
if (this.kmsConfigured && this.s3Configured) {
195197
this.bucketForm.get('encryption_type').setValue('');
196-
} else if (this.kmsVaultConfig) {
198+
} else if (this.kmsConfigured) {
197199
this.bucketForm.get('encryption_type').setValue('aws:kms');
198-
} else if (this.s3VaultConfig) {
200+
} else if (this.s3Configured) {
199201
this.bucketForm.get('encryption_type').setValue('AES256');
200202
} else {
201203
this.bucketForm.get('encryption_type').setValue('');
@@ -459,13 +461,6 @@ export class RgwBucketFormComponent extends CdForm implements OnInit, AfterViewC
459461
this.bucketForm.updateValueAndValidity();
460462
}
461463

462-
openConfigModal() {
463-
const modalRef = this.modalService.show(RgwConfigModalComponent, null, { size: 'lg' });
464-
modalRef.componentInstance.configForm
465-
.get('encryptionType')
466-
.setValue(this.bucketForm.getValue('encryption_type') || 'AES256');
467-
}
468-
469464
showTagModal(index?: number) {
470465
const modalRef = this.modalService.show(BucketTagModalComponent);
471466
const modalComponent = modalRef.componentInstance as BucketTagModalComponent;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<ng-container *ngIf="selection">
2+
<nav ngbNav
3+
#nav="ngbNav"
4+
id="tabset-config-details"
5+
class="nav-tabs"
6+
cdStatefulTab="config-details">
7+
<ng-container ngbNavItem="details">
8+
<a ngbNavLink
9+
i18n>Details</a>
10+
<ng-template ngbNavContent>
11+
<cd-table-key-value [data]="transformedData">
12+
</cd-table-key-value>
13+
</ng-template>
14+
</ng-container>
15+
</nav>
16+
<div [ngbNavOutlet]="nav"></div>
17+
</ng-container>

src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-config-details/rgw-config-details.component.scss

Whitespace-only changes.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { RgwConfigDetailsComponent } from './rgw-config-details.component';
4+
5+
describe('RgwConfigDetailsComponent', () => {
6+
let component: RgwConfigDetailsComponent;
7+
let fixture: ComponentFixture<RgwConfigDetailsComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
declarations: [RgwConfigDetailsComponent]
12+
}).compileComponents();
13+
14+
fixture = TestBed.createComponent(RgwConfigDetailsComponent);
15+
component = fixture.componentInstance;
16+
fixture.detectChanges();
17+
});
18+
19+
it('should create', () => {
20+
expect(component).toBeTruthy();
21+
});
22+
});

0 commit comments

Comments
 (0)