From 151fff766c822414b8586ac4291d71f84340736b Mon Sep 17 00:00:00 2001 From: Nizamudeen A Date: Wed, 24 May 2023 22:14:24 +0530 Subject: [PATCH] mgr/dashboard: fix the rgw roles page Fixes: https://tracker.ceph.com/issues/61421 Signed-off-by: Nizamudeen A (cherry picked from commit b27e15902cc8262a496a4c9c10c607c09b14a527) Conflicts: src/pybind/mgr/dashboard/controllers/rgw.py - Remove `CreatePermission` import because its not yet there in reef src/pybind/mgr/dashboard/openapi.yaml - generate a new spec --- src/pybind/mgr/dashboard/controllers/_crud.py | 5 + .../mgr/dashboard/controllers/ceph_users.py | 8 +- src/pybind/mgr/dashboard/controllers/rgw.py | 13 +- .../cypress/e2e/rgw/roles.e2e-spec.ts | 19 +++ .../frontend/cypress/e2e/rgw/roles.po.ts | 37 +++++ .../frontend/src/app/ceph/rgw/rgw.module.ts | 2 +- src/pybind/mgr/dashboard/openapi.yaml | 130 +++++++++--------- 7 files changed, 135 insertions(+), 79 deletions(-) create mode 100644 src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/roles.e2e-spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/roles.po.ts diff --git a/src/pybind/mgr/dashboard/controllers/_crud.py b/src/pybind/mgr/dashboard/controllers/_crud.py index 20152e900da..4a57ac06cc5 100644 --- a/src/pybind/mgr/dashboard/controllers/_crud.py +++ b/src/pybind/mgr/dashboard/controllers/_crud.py @@ -14,6 +14,11 @@ class SecretStr(str): pass +class MethodType(Enum): + POST = 'post' + PUT = 'put' + + def isnamedtuple(o): return isinstance(o, tuple) and hasattr(o, '_asdict') and hasattr(o, '_fields') diff --git a/src/pybind/mgr/dashboard/controllers/ceph_users.py b/src/pybind/mgr/dashboard/controllers/ceph_users.py index a4593144739..e1bdc157091 100644 --- a/src/pybind/mgr/dashboard/controllers/ceph_users.py +++ b/src/pybind/mgr/dashboard/controllers/ceph_users.py @@ -1,5 +1,4 @@ import logging -from enum import Enum from errno import EINVAL from typing import List, NamedTuple, Optional @@ -9,7 +8,7 @@ from ..services.ceph_service import CephService, SendCommandError from . import APIDoc, APIRouter, CRUDCollectionMethod, CRUDEndpoint, \ EndpointDoc, RESTController, SecretStr from ._crud import ArrayHorizontalContainer, CRUDMeta, Form, FormField, \ - FormTaskInfo, Icon, SelectionType, TableAction, Validator, \ + FormTaskInfo, Icon, MethodType, SelectionType, TableAction, Validator, \ VerticalContainer logger = logging.getLogger("controllers.ceph_users") @@ -27,11 +26,6 @@ class Cap(NamedTuple): cap: str -class MethodType(Enum): - POST = 'post' - PUT = 'put' - - class CephUserEndpoints: @staticmethod def _run_auth_command(command: str, *args, **kwargs): diff --git a/src/pybind/mgr/dashboard/controllers/rgw.py b/src/pybind/mgr/dashboard/controllers/rgw.py index 36282654c5d..b29e424206e 100644 --- a/src/pybind/mgr/dashboard/controllers/rgw.py +++ b/src/pybind/mgr/dashboard/controllers/rgw.py @@ -16,8 +16,8 @@ from ..tools import json_str_to_object, str_to_bool from . import APIDoc, APIRouter, BaseController, CRUDCollectionMethod, \ CRUDEndpoint, Endpoint, EndpointDoc, ReadPermission, RESTController, \ UIRouter, allow_empty_body -from ._crud import CRUDMeta, Form, FormField, FormTaskInfo, Icon, TableAction, \ - Validator, VerticalContainer +from ._crud import CRUDMeta, Form, FormField, FormTaskInfo, Icon, MethodType, \ + TableAction, Validator, VerticalContainer from ._version import APIVersion logger = logging.getLogger("controllers.rgw") @@ -642,18 +642,19 @@ create_container = VerticalContainer('Create Role', 'create_role', fields=[ field_type='textarea', validators=[Validator.JSON]), ]) -create_role_form = Form(path='/rgw/user/roles/create', +create_role_form = Form(path='/rgw/roles/create', root_container=create_container, task_info=FormTaskInfo("IAM RGW Role '{role_name}' created successfully", - ['role_name'])) + ['role_name']), + method_type=MethodType.POST.value) @CRUDEndpoint( - router=APIRouter('/rgw/user/roles', Scope.RGW), + 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/user/roles/create') + routerLink='/rgw/roles/create') ], forms=[create_role_form], permissions=[Scope.CONFIG_OPT], 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 new file mode 100644 index 00000000000..597f7d1be88 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/roles.e2e-spec.ts @@ -0,0 +1,19 @@ +import { RolesPageHelper } from './roles.po'; + +describe('RGW roles page', () => { + const roles = new RolesPageHelper(); + + beforeEach(() => { + cy.login(); + roles.navigateTo(); + }); + + describe('Create, Edit & Delete rgw roles', () => { + it('should create rgw roles', () => { + roles.navigateTo('create'); + roles.create('testRole', '/', '{}'); + roles.navigateTo(); + roles.checkExist('testRole', true); + }); + }); +}); 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 new file mode 100644 index 00000000000..b72ca5df9a7 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/rgw/roles.po.ts @@ -0,0 +1,37 @@ +import { PageHelper } from '../page-helper.po'; + +const pages = { + index: { url: '#/rgw/roles', id: 'cd-crud-table' }, + create: { url: '#/rgw/roles/create', id: 'cd-crud-form' } +}; + +export class RolesPageHelper extends PageHelper { + pages = pages; + + columnIndex = { + roleName: 2, + path: 3, + arn: 4 + }; + + @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("[aria-label='Create Role']").should('exist').click(); + cy.get('cd-crud-table').should('exist'); + } + + @PageHelper.restrictTo(pages.index.url) + checkExist(name: string, exist: boolean) { + this.getTableCell(this.columnIndex.roleName, name).should(($elements) => { + const roleName = $elements.map((_, el) => el.textContent).get(); + if (exist) { + expect(roleName).to.include(name); + } else { + expect(roleName).to.not.include(name); + } + }); + } +} 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 3a8ad6f6fc7..d9fbd2b6d2e 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 @@ -93,7 +93,7 @@ const routes: Routes = [ path: 'roles', data: { breadcrumbs: 'Roles', - resource: 'api.rgw.user.roles@1.0', + resource: 'api.rgw.roles@1.0', tabs: [ { name: 'Users', diff --git a/src/pybind/mgr/dashboard/openapi.yaml b/src/pybind/mgr/dashboard/openapi.yaml index 196ad1d93a4..c289fe6edd3 100644 --- a/src/pybind/mgr/dashboard/openapi.yaml +++ b/src/pybind/mgr/dashboard/openapi.yaml @@ -8310,6 +8310,71 @@ paths: - jwt: [] tags: - RgwDaemon + /api/rgw/roles: + get: + parameters: [] + responses: + '200': + content: + application/vnd.ceph.api.v1.0+json: + type: object + description: OK + '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: List RGW roles + tags: + - RGW + post: + parameters: [] + requestBody: + content: + application/json: + schema: + properties: + role_assume_policy_doc: + default: '' + type: string + role_name: + default: '' + type: string + role_path: + default: '' + type: string + type: object + responses: + '201': + content: + application/vnd.ceph.api.v1.0+json: + type: object + description: Resource created. + '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: Create Ceph User + tags: + - RGW /api/rgw/site: get: parameters: @@ -8459,71 +8524,6 @@ paths: - jwt: [] tags: - RgwUser - /api/rgw/user/roles: - get: - parameters: [] - responses: - '200': - content: - application/vnd.ceph.api.v1.0+json: - type: object - description: OK - '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: List RGW roles - tags: - - RGW - post: - parameters: [] - requestBody: - content: - application/json: - schema: - properties: - role_assume_policy_doc: - default: '' - type: string - role_name: - default: '' - type: string - role_path: - default: '' - type: string - type: object - responses: - '201': - content: - application/vnd.ceph.api.v1.0+json: - type: object - description: Resource created. - '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: Create Ceph User - tags: - - RGW /api/rgw/user/{uid}: delete: parameters: -- 2.39.5