summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/dashboard
diff options
context:
space:
mode:
authorNizamudeen A <nia@redhat.com>2023-10-18 08:38:21 +0200
committerNizamudeen A <nia@redhat.com>2023-11-27 13:43:41 +0100
commit5c28d78a45d87d2be6b9ea2961be42689673e252 (patch)
tree3ceebd5b875bb2191b87791c725fde5feb3c7b91 /src/pybind/mgr/dashboard
parentmgr/dashboard: support rgw roles removal (diff)
downloadceph-5c28d78a45d87d2be6b9ea2961be42689673e252.tar.xz
ceph-5c28d78a45d87d2be6b9ea2961be42689673e252.zip
mgr/dashboard: support rgw roles updating
Right now only the modification of max_session_duration is supported via the roles update command. To update, we need to use `policy modify` command which is not added in this PR. That should be done separately Refer: https://docs.ceph.com/en/latest/radosgw/role/#update-a-role Fixes: https://tracker.ceph.com/issues/63230 Signed-off-by: Nizamudeen A <nia@redhat.com>
Diffstat (limited to 'src/pybind/mgr/dashboard')
-rw-r--r--src/pybind/mgr/dashboard/controllers/_crud.py14
-rw-r--r--src/pybind/mgr/dashboard/controllers/ceph_users.py3
-rw-r--r--src/pybind/mgr/dashboard/controllers/rgw.py55
-rw-r--r--src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/roles.e2e-spec.ts14
-rw-r--r--src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/roles.po.ts26
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw.module.ts7
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/core/context/context.component.ts12
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/crud-table/crud-table.component.ts6
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/datatable.module.ts6
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/shared/forms/crud-form/helpers.ts10
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/shared/forms/crud-form/validators/rgw-role-validator.ts9
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/shared/models/crud-table-metadata.ts1
-rw-r--r--src/pybind/mgr/dashboard/openapi.yaml75
-rw-r--r--src/pybind/mgr/dashboard/services/rgw_client.py19
14 files changed, 237 insertions, 20 deletions
diff --git a/src/pybind/mgr/dashboard/controllers/_crud.py b/src/pybind/mgr/dashboard/controllers/_crud.py
index 240a2b5ab8c..d65649cadb4 100644
--- a/src/pybind/mgr/dashboard/controllers/_crud.py
+++ b/src/pybind/mgr/dashboard/controllers/_crud.py
@@ -104,6 +104,7 @@ class Validator(Enum):
RGW_ROLE_NAME = 'rgwRoleName'
RGW_ROLE_PATH = 'rgwRolePath'
FILE = 'file'
+ RGW_ROLE_SESSION_DURATION = 'rgwRoleSessionDuration'
class FormField(NamedTuple):
@@ -224,6 +225,10 @@ class Container:
properties[field.key]['title'] = field.name
field_ui_schema['key'] = field_key
field_ui_schema['readonly'] = field.readonly
+ if field.readonly:
+ field_ui_schema['templateOptions'] = {
+ 'disabled': True
+ }
field_ui_schema['help'] = f'{field.help}'
field_ui_schema['validators'] = [i.value for i in field.validators]
items.append(field_ui_schema)
@@ -307,6 +312,7 @@ class CRUDMeta(SerializableClass):
self.forms = []
self.columnKey = ''
self.detail_columns = []
+ self.resource = ''
class CRUDCollectionMethod(NamedTuple):
@@ -330,6 +336,7 @@ class CRUDEndpoint:
actions: Optional[List[TableAction]] = None,
permissions: Optional[List[str]] = None, forms: Optional[List[Form]] = None,
column_key: Optional[str] = None,
+ resource: Optional[str] = None,
meta: CRUDMeta = CRUDMeta(), get_all: Optional[CRUDCollectionMethod] = None,
create: Optional[CRUDCollectionMethod] = None,
delete: Optional[CRUDCollectionMethod] = None,
@@ -352,6 +359,7 @@ class CRUDEndpoint:
self.detail_columns = detail_columns if detail_columns is not None else []
self.extra_endpoints = extra_endpoints if extra_endpoints is not None else []
self.selection_type = selection_type
+ self.resource = resource
def __call__(self, cls: Any):
self.create_crud_class(cls)
@@ -415,6 +423,7 @@ class CRUDEndpoint:
self.generate_forms(model_key)
self.set_permissions()
self.set_column_key()
+ self.set_table_resource()
self.get_detail_columns()
selection_type = self.__class__.outer_self.selection_type
self.__class__.outer_self.meta.table.set_selection_type(selection_type)
@@ -468,6 +477,10 @@ class CRUDEndpoint:
if self.__class__.outer_self.column_key:
self.outer_self.meta.columnKey = self.__class__.outer_self.column_key
+ def set_table_resource(self):
+ if self.__class__.outer_self.resource:
+ self.outer_self.meta.resource = self.__class__.outer_self.resource
+
class_name = self.router.path.replace('/', '')
meta_class = type(f'{class_name}_CRUDClassMetadata',
(RESTController,),
@@ -478,6 +491,7 @@ class CRUDEndpoint:
'generate_forms': generate_forms,
'set_permissions': set_permissions,
'set_column_key': set_column_key,
+ 'set_table_resource': set_table_resource,
'get_detail_columns': get_detail_columns,
'outer_self': self,
})
diff --git a/src/pybind/mgr/dashboard/controllers/ceph_users.py b/src/pybind/mgr/dashboard/controllers/ceph_users.py
index e1bdc157091..022f8f36c42 100644
--- a/src/pybind/mgr/dashboard/controllers/ceph_users.py
+++ b/src/pybind/mgr/dashboard/controllers/ceph_users.py
@@ -174,7 +174,7 @@ edit_form = Form(path='/cluster/user/edit',
TableAction(name='Create', permission='create', icon=Icon.ADD.value,
routerLink='/cluster/user/create'),
TableAction(name='Edit', permission='update', icon=Icon.EDIT.value,
- click='edit'),
+ click='edit', routerLink='/cluster/user/edit'),
TableAction(name='Delete', permission='delete', icon=Icon.DESTROY.value,
click='delete', disable=True),
TableAction(name='Import', permission='create', icon=Icon.IMPORT.value,
@@ -185,6 +185,7 @@ edit_form = Form(path='/cluster/user/edit',
permissions=[Scope.CONFIG_OPT],
forms=[create_form, edit_form, import_user_form],
column_key='entity',
+ resource='user',
get_all=CRUDCollectionMethod(
func=CephUserEndpoints.user_list,
doc=EndpointDoc("Get Ceph Users")
diff --git a/src/pybind/mgr/dashboard/controllers/rgw.py b/src/pybind/mgr/dashboard/controllers/rgw.py
index fd376a53f03..bf2d9555317 100644
--- a/src/pybind/mgr/dashboard/controllers/rgw.py
+++ b/src/pybind/mgr/dashboard/controllers/rgw.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
+# pylint: disable=C0302
import json
import logging
import re
@@ -717,6 +718,15 @@ class RGWRoleEndpoints:
rgw_client.create_role(role_name, role_path, role_assume_policy_doc)
return f'Role {role_name} created successfully'
+ @staticmethod
+ def role_update(_, role_name: str, max_session_duration: str):
+ assert role_name
+ assert max_session_duration
+ # convert max_session_duration which is in hours to seconds
+ max_session_duration = int(float(max_session_duration) * 3600)
+ rgw_client = RgwClient.admin_instance()
+ rgw_client.update_role(role_name, str(max_session_duration))
+ return f'Role {role_name} updated successfully'
@staticmethod
def role_delete(_, role_name: str):
@@ -725,7 +735,18 @@ class RGWRoleEndpoints:
rgw_client.delete_role(role_name)
return f'Role {role_name} deleted successfully'
+ @staticmethod
+ def model(role_name: str):
+ assert role_name
+ rgw_client = RgwClient.admin_instance()
+ role = rgw_client.get_role(role_name)
+ model = {'role_name': '', 'max_session_duration': ''}
+ model['role_name'] = role['RoleName']
+ # convert maxsessionduration which is in seconds to hours
+ if role['MaxSessionDuration']:
+ model['max_session_duration'] = role['MaxSessionDuration'] / 3600
+ return model
# pylint: disable=C0301
@@ -735,6 +756,10 @@ assume_role_policy_help = (
'target="_blank">click here.</a>'
)
+max_session_duration_help = (
+ 'The maximum session duration (in hours) that you want to set for the specified role.This setting can have a value from 1 hour to 12 hours.' # noqa: E501
+)
+
create_container = VerticalContainer('Create Role', 'create_role', fields=[
FormField('Role name', 'role_name', validators=[Validator.RGW_ROLE_NAME]),
FormField('Path', 'role_path', validators=[Validator.RGW_ROLE_PATH]),
@@ -744,23 +769,43 @@ create_container = VerticalContainer('Create Role', 'create_role', fields=[
field_type='textarea',
validators=[Validator.JSON]),
])
-create_role_form = Form(path='/rgw/roles/create',
+
+edit_container = VerticalContainer('Edit Role', 'edit_role', fields=[
+ FormField('Role name', 'role_name', readonly=True),
+ FormField('Max Session Duration', 'max_session_duration',
+ help=max_session_duration_help,
+ validators=[Validator.RGW_ROLE_SESSION_DURATION])
+])
+
+create_role_form = Form(path='/create',
root_container=create_container,
task_info=FormTaskInfo("IAM RGW Role '{role_name}' created successfully",
['role_name']),
method_type=MethodType.POST.value)
+edit_role_form = Form(path='/edit',
+ root_container=edit_container,
+ task_info=FormTaskInfo("IAM RGW Role '{role_name}' edited successfully",
+ ['role_name']),
+ method_type=MethodType.PUT.value,
+ model_callback=RGWRoleEndpoints.model)
+
@CRUDEndpoint(
router=APIRouter('/rgw/roles', Scope.RGW),
doc=APIDoc("List of RGW roles", "RGW"),
actions=[
TableAction(name='Create', permission='create', icon=Icon.ADD.value,
+ routerLink='/rgw/roles/create'),
+ TableAction(name='Edit', permission='update', icon=Icon.EDIT.value,
+ click='edit', routerLink='/rgw/roles/edit'),
TableAction(name='Delete', permission='delete', icon=Icon.DESTROY.value,
click='delete', disable=True),
],
- forms=[create_role_form],
- permissions=[Scope.CONFIG_OPT],
+ forms=[create_role_form, edit_role_form],
+ column_key='RoleName',
+ resource='Role',
+ permissions=[Scope.RGW],
get_all=CRUDCollectionMethod(
func=RGWRoleEndpoints.role_list,
doc=EndpointDoc("List RGW roles")
@@ -769,6 +814,10 @@ create_role_form = Form(path='/rgw/roles/create',
func=RGWRoleEndpoints.role_create,
doc=EndpointDoc("Create RGW role")
),
+ edit=CRUDCollectionMethod(
+ func=RGWRoleEndpoints.role_update,
+ doc=EndpointDoc("Edit RGW role")
+ ),
delete=CRUDCollectionMethod(
func=RGWRoleEndpoints.role_delete,
doc=EndpointDoc("Delete RGW role")
diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/roles.e2e-spec.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/roles.e2e-spec.ts
index 597f7d1be88..80a8b0ec902 100644
--- a/src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/roles.e2e-spec.ts
+++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/roles.e2e-spec.ts
@@ -9,11 +9,21 @@ describe('RGW roles page', () => {
});
describe('Create, Edit & Delete rgw roles', () => {
+ const roleName = 'testRole';
+
it('should create rgw roles', () => {
roles.navigateTo('create');
- roles.create('testRole', '/', '{}');
+ roles.create(roleName, '/', '{}');
roles.navigateTo();
- roles.checkExist('testRole', true);
+ roles.checkExist(roleName, true);
+ });
+
+ it('should edit rgw role', () => {
+ roles.edit(roleName, 3);
+ });
+
+ it('should delete rgw role', () => {
+ roles.delete(roleName);
});
});
});
diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/roles.po.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/roles.po.ts
index b72ca5df9a7..717655b2f08 100644
--- a/src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/roles.po.ts
+++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/roles.po.ts
@@ -11,18 +11,36 @@ export class RolesPageHelper extends PageHelper {
columnIndex = {
roleName: 2,
path: 3,
- arn: 4
+ arn: 4,
+ createDate: 5,
+ maxSessionDuration: 6
};
@PageHelper.restrictTo(pages.create.url)
create(name: string, path: string, policyDocument: string) {
- cy.get('#formly_3_string_role_name_0').type(name);
- cy.get('#formly_3_textarea_role_assume_policy_doc_2').type(policyDocument);
- cy.get('#formly_3_string_role_path_1').type(path);
+ cy.get('[id$="string_role_name_0"]').type(name);
+ cy.get('[id$="role_assume_policy_doc_2"]').type(policyDocument);
+ cy.get('[id$="role_path_1"]').type(path);
cy.get("[aria-label='Create Role']").should('exist').click();
cy.get('cd-crud-table').should('exist');
}
+ edit(name: string, maxSessionDuration: number) {
+ this.navigateEdit(name);
+ cy.get('[id$="max_session_duration_1"]').clear().type(maxSessionDuration.toString());
+ cy.get("[aria-label='Edit Role']").should('exist').click();
+ cy.get('cd-crud-table').should('exist');
+
+ this.getTableCell(this.columnIndex.roleName, name)
+ .click()
+ .parent()
+ .find(`datatable-body-cell:nth-child(${this.columnIndex.maxSessionDuration})`)
+ .should(($elements) => {
+ const roleName = $elements.map((_, el) => el.textContent).get();
+ expect(roleName).to.include(`${maxSessionDuration} hours`);
+ });
+ }
+
@PageHelper.restrictTo(pages.index.url)
checkExist(name: string, exist: boolean) {
this.getTableCell(this.columnIndex.roleName, name).should(($elements) => {
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw.module.ts
index c16c13a81bd..f2e37af0aa7 100644
--- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw.module.ts
+++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw.module.ts
@@ -156,6 +156,13 @@ const routes: Routes = [
data: {
breadcrumbs: ActionLabels.CREATE
}
+ },
+ {
+ path: URLVerbs.EDIT,
+ component: CrudFormComponent,
+ data: {
+ breadcrumbs: ActionLabels.EDIT
+ }
}
]
},
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/context/context.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/context/context.component.ts
index e036b754438..178f230c931 100644
--- a/src/pybind/mgr/dashboard/frontend/src/app/core/context/context.component.ts
+++ b/src/pybind/mgr/dashboard/frontend/src/app/core/context/context.component.ts
@@ -24,12 +24,14 @@ export class ContextComponent implements OnInit, OnDestroy {
private subs = new Subscription();
private rgwUrlPrefix = '/rgw';
private rgwUserUrlPrefix = '/rgw/user';
+ private rgwRoleUrlPrefix = '/rgw/roles';
private rgwBuckerUrlPrefix = '/rgw/bucket';
permissions: Permissions;
featureToggleMap$: FeatureTogglesMap$;
isRgwRoute =
document.location.href.includes(this.rgwUserUrlPrefix) ||
- document.location.href.includes(this.rgwBuckerUrlPrefix);
+ document.location.href.includes(this.rgwBuckerUrlPrefix) ||
+ document.location.href.includes(this.rgwRoleUrlPrefix);
constructor(
private authStorageService: AuthStorageService,
@@ -48,9 +50,11 @@ export class ContextComponent implements OnInit, OnDestroy {
.pipe(filter((event: Event) => event instanceof NavigationEnd))
.subscribe(
() =>
- (this.isRgwRoute = [this.rgwBuckerUrlPrefix, this.rgwUserUrlPrefix].some((urlPrefix) =>
- this.router.url.startsWith(urlPrefix)
- ))
+ (this.isRgwRoute = [
+ this.rgwBuckerUrlPrefix,
+ this.rgwUserUrlPrefix,
+ this.rgwRoleUrlPrefix
+ ].some((urlPrefix) => this.router.url.startsWith(urlPrefix)))
)
);
// Set daemon list polling only when in RGW route:
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/crud-table/crud-table.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/crud-table/crud-table.component.ts
index 750152161c2..6881e373b58 100644
--- a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/crud-table/crud-table.component.ts
+++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/crud-table/crud-table.component.ts
@@ -120,7 +120,7 @@ export class CRUDTableComponent implements OnInit {
delete() {
const selectedKey = this.selection.first()[this.meta.columnKey];
this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
- itemDescription: $localize`${this.meta.columnKey}`,
+ itemDescription: $localize`${this.meta.resource}`,
itemNames: [selectedKey],
submitAction: () => {
this.taskWrapper
@@ -153,7 +153,9 @@ export class CRUDTableComponent implements OnInit {
if (this.selection.hasSelection) {
key = this.selection.first()[this.meta.columnKey];
}
- this.router.navigate(['/cluster/user/edit'], { queryParams: { key: key } });
+
+ const editAction = this.meta.actions.find((action) => action.name === 'Edit');
+ this.router.navigate([editAction.routerLink], { queryParams: { key: key } });
}
authExport() {
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/datatable.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/datatable.module.ts
index 37e94f236be..76cbbcfb3a2 100644
--- a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/datatable.module.ts
+++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/datatable.module.ts
@@ -61,7 +61,11 @@ import { CheckedTableFormComponent } from './checked-table-form/checked-table-fo
'Role path must start and finish with a slash "/".' +
' (pattern: (\u002F)|(\u002F[\u0021-\u007E]+\u002F))'
},
- { name: 'file_size', message: 'File size must not exceed 4KiB' }
+ { name: 'file_size', message: 'File size must not exceed 4KiB' },
+ {
+ name: 'rgwRoleSessionDuration',
+ message: 'This field must be a number and should be a value from 1 hour to 12 hour'
+ }
],
wrappers: [{ name: 'input-wrapper', component: FormlyInputWrapperComponent }]
}),
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/crud-form/helpers.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/crud-form/helpers.ts
index 1ea21b71081..aca9a20af09 100644
--- a/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/crud-form/helpers.ts
+++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/crud-form/helpers.ts
@@ -3,7 +3,11 @@ import { FormlyFieldConfig } from '@ngx-formly/core';
import { forEach } from 'lodash';
import { formlyAsyncFileValidator } from './validators/file-validator';
import { formlyAsyncJsonValidator } from './validators/json-validator';
-import { formlyRgwRoleNameValidator, formlyRgwRolePath } from './validators/rgw-role-validator';
+import {
+ formlyFormNumberValidator,
+ formlyRgwRoleNameValidator,
+ formlyRgwRolePath
+} from './validators/rgw-role-validator';
export function getFieldState(field: FormlyFieldConfig, uiSchema: any[] = undefined) {
const formState: any[] = uiSchema || field.options?.formState;
@@ -34,6 +38,10 @@ export function setupValidators(field: FormlyFieldConfig, uiSchema: any[]) {
validators.push(formlyAsyncFileValidator);
break;
}
+ case 'rgwRoleSessionDuration': {
+ validators.push(formlyFormNumberValidator);
+ break;
+ }
}
});
field.asyncValidators = { validation: validators };
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/crud-form/validators/rgw-role-validator.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/crud-form/validators/rgw-role-validator.ts
index a100f278bea..c994dc96407 100644
--- a/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/crud-form/validators/rgw-role-validator.ts
+++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/forms/crud-form/validators/rgw-role-validator.ts
@@ -17,3 +17,12 @@ export function formlyRgwRoleNameValidator(control: AbstractControl): Promise<an
resolve({ rgwRoleName: true });
});
}
+
+export function formlyFormNumberValidator(control: AbstractControl): Promise<any> {
+ return new Promise((resolve, _reject) => {
+ if (control.value.match('^[0-9.]+$')) {
+ if (control.value <= 12 && control.value >= 1) resolve(null);
+ }
+ resolve({ rgwRoleSessionDuration: true });
+ });
+}
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/crud-table-metadata.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/crud-table-metadata.ts
index 140fa5b5f8e..dc33e6236ae 100644
--- a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/crud-table-metadata.ts
+++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/crud-table-metadata.ts
@@ -14,4 +14,5 @@ export class CrudMetadata {
actions: CdTableAction[];
forms: any;
columnKey: string;
+ resource: string;
}
diff --git a/src/pybind/mgr/dashboard/openapi.yaml b/src/pybind/mgr/dashboard/openapi.yaml
index d35ea87e15a..453352493d4 100644
--- a/src/pybind/mgr/dashboard/openapi.yaml
+++ b/src/pybind/mgr/dashboard/openapi.yaml
@@ -9596,7 +9596,80 @@ paths:
trace.
security:
- jwt: []
- summary: Create Ceph User
+ summary: Create RGW role
+ tags:
+ - RGW
+ put:
+ parameters: []
+ requestBody:
+ content:
+ application/json:
+ schema:
+ properties:
+ max_session_duration:
+ type: string
+ role_name:
+ type: string
+ required:
+ - role_name
+ - max_session_duration
+ type: object
+ responses:
+ '200':
+ content:
+ application/vnd.ceph.api.v1.0+json:
+ type: object
+ description: Resource updated.
+ '202':
+ content:
+ application/vnd.ceph.api.v1.0+json:
+ type: object
+ description: Operation is still executing. Please check the task queue.
+ '400':
+ description: Operation exception. Please check the response body for details.
+ '401':
+ description: Unauthenticated access. Please login first.
+ '403':
+ description: Unauthorized access. Please check your permissions.
+ '500':
+ description: Unexpected error. Please check the response body for the stack
+ trace.
+ security:
+ - jwt: []
+ summary: Edit RGW role
+ tags:
+ - RGW
+ /api/rgw/roles/{role_name}:
+ delete:
+ parameters:
+ - in: path
+ name: role_name
+ required: true
+ schema:
+ type: string
+ responses:
+ '202':
+ content:
+ application/vnd.ceph.api.v1.0+json:
+ type: object
+ description: Operation is still executing. Please check the task queue.
+ '204':
+ content:
+ application/vnd.ceph.api.v1.0+json:
+ type: object
+ description: Resource deleted.
+ '400':
+ description: Operation exception. Please check the response body for details.
+ '401':
+ description: Unauthenticated access. Please login first.
+ '403':
+ description: Unauthorized access. Please check your permissions.
+ '500':
+ description: Unexpected error. Please check the response body for the stack
+ trace.
+ security:
+ - jwt: []
+ summary: Delete RGW role
tags:
- RGW
/api/rgw/site:
diff --git a/src/pybind/mgr/dashboard/services/rgw_client.py b/src/pybind/mgr/dashboard/services/rgw_client.py
index fe7b8c66898..6358d397976 100644
--- a/src/pybind/mgr/dashboard/services/rgw_client.py
+++ b/src/pybind/mgr/dashboard/services/rgw_client.py
@@ -851,7 +851,24 @@ class RgwClient(RestClient):
'Looks like the document has a wrong format.'
f' For more information about the format look at {link}')
raise DashboardException(msg=msg, component='rgw')
-
+
+ def get_role(self, role_name: str):
+ rgw_get_role_command = ['role', 'get', '--role-name', role_name]
+ code, role, _err = mgr.send_rgwadmin_command(rgw_get_role_command)
+ if code != 0:
+ raise DashboardException(msg=f'Error getting role with code {code}: {_err}',
+ component='rgw')
+ return role
+
+ def update_role(self, role_name: str, max_session_duration: str):
+ rgw_update_role_command = ['role', 'update', '--role-name',
+ role_name, '--max_session_duration', max_session_duration]
+ code, _, _err = mgr.send_rgwadmin_command(rgw_update_role_command,
+ stdout_as_json=False)
+ if code != 0:
+ raise DashboardException(msg=f'Error updating role with code {code}: {_err}',
+ component='rgw')
+
def delete_role(self, role_name: str) -> None:
rgw_delete_role_command = ['role', 'delete', '--role-name', role_name]
code, _, _err = mgr.send_rgwadmin_command(rgw_delete_role_command,