From: Naman Munet Date: Thu, 27 Feb 2025 08:14:54 +0000 (+0530) Subject: mgr/dashboard: Use admin ops API for rgw accounts X-Git-Tag: v20.3.0~281^2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=78d0a26b7c986c46fa88127630f3585134731ff8;p=ceph.git mgr/dashboard: Use admin ops API for rgw accounts Fixes: https://tracker.ceph.com/issues/69487 Signed-off-by: Naman Munet --- diff --git a/src/pybind/mgr/dashboard/controllers/rgw_iam.py b/src/pybind/mgr/dashboard/controllers/rgw_iam.py index d9a87dc56b81c..3be4ffcee0282 100644 --- a/src/pybind/mgr/dashboard/controllers/rgw_iam.py +++ b/src/pybind/mgr/dashboard/controllers/rgw_iam.py @@ -1,5 +1,6 @@ from typing import Optional +from ..controllers.rgw import RgwRESTController from ..security import Scope from ..services.rgw_iam import RgwAccounts from ..tools import str_to_bool @@ -8,7 +9,7 @@ from . import APIDoc, APIRouter, EndpointDoc, RESTController, allow_empty_body @APIRouter('rgw/accounts', Scope.RGW) @APIDoc("RGW User Accounts API", "RgwUserAccounts") -class RgwUserAccountsController(RESTController): +class RgwUserAccountsController(RgwRESTController): @EndpointDoc("Update RGW account info", parameters={'account_name': (str, 'Account name'), 'email': (str, 'Email'), @@ -17,12 +18,13 @@ class RgwUserAccountsController(RESTController): 'max_users': (int, 'Max users'), 'max_roles': (int, 'Max roles'), 'max_group': (int, 'Max groups'), - 'max_access_keys': (int, 'Max access keys')}) + 'max_access_keys': (int, 'Max access keys'), + 'daemon_name': (str, 'Name of the daemon')}) @allow_empty_body def create(self, account_name: str, tenant: Optional[str] = None, email: Optional[str] = None, max_buckets: Optional[int] = None, max_users: Optional[int] = None, max_roles: Optional[int] = None, - max_group: Optional[int] = None, + max_group: Optional[int] = None, daemon_name=None, max_access_keys: Optional[int] = None): """ Create an account @@ -31,11 +33,26 @@ class RgwUserAccountsController(RESTController): :return: Returns account resource. :rtype: Dict[str, Any] """ - return RgwAccounts.create_account(account_name, tenant, email, - max_buckets, max_users, max_roles, - max_group, max_access_keys) + params = {'name': account_name} + if tenant: + params['tenant'] = tenant + if email: + params['email'] = email + if max_buckets: + params['max-buckets'] = str(max_buckets) + if max_users: + params['max-users'] = str(max_users) + if max_roles: + params['max-roles'] = str(max_roles) + if max_group: + params['max-group'] = str(max_group) + if max_access_keys: + params['max-access-keys'] = str(max_access_keys) - def list(self, detailed: bool = False): + result = self.proxy(daemon_name, 'POST', 'account', params) + return result + + def list(self, daemon_name=None, detailed: bool = False): """ List all account ids or all detailed account info based on the 'detailed' query parameter. @@ -43,26 +60,37 @@ class RgwUserAccountsController(RESTController): - If detailed=False, returns only account ids. """ detailed = str_to_bool(detailed) - return RgwAccounts.get_accounts(detailed) + account_list = RgwAccounts.get_accounts() + detailed_account_list = [] + if detailed: + for account in account_list: + detailed_account_list.append(self.get_account(account, daemon_name)) + return detailed_account_list + return account_list @EndpointDoc("Get RGW Account by id", - parameters={'account_id': (str, 'Account id')}) - def get(self, account_id: str): + parameters={'account_id': (str, 'Account id'), + 'daemon_name': (str, 'Name of the daemon')}) + def get(self, account_id: str, daemon_name=None): """ Get an account by account id """ - return RgwAccounts.get_account(account_id) + return self.get_account(account_id, daemon_name) + + def get_account(self, account_id, daemon_name=None) -> dict: + return self.proxy(daemon_name, 'GET', 'account', {'id': account_id}) @EndpointDoc("Delete RGW Account", - parameters={'account_id': (str, 'Account id')}) - def delete(self, account_id): + parameters={'account_id': (str, 'Account id'), + 'daemon_name': (str, 'Name of the daemon')}) + def delete(self, account_id, daemon_name=None): """ Removes an account :param account_id: account identifier :return: None. """ - return RgwAccounts.delete_account(account_id) + return self.proxy(daemon_name, 'DELETE', 'account', {'id': account_id}, json_response=False) @EndpointDoc("Update RGW account info", parameters={'account_id': (str, 'Account id'), @@ -73,13 +101,14 @@ class RgwUserAccountsController(RESTController): 'max_users': (int, 'Max users'), 'max_roles': (int, 'Max roles'), 'max_group': (int, 'Max groups'), - 'max_access_keys': (int, 'Max access keys')}) + 'max_access_keys': (int, 'Max access keys'), + 'daemon_name': (str, 'Name of the daemon')}) @allow_empty_body def set(self, account_id: str, account_name: str, email: Optional[str] = None, tenant: Optional[str] = None, max_buckets: Optional[int] = None, max_users: Optional[int] = None, max_roles: Optional[int] = None, max_group: Optional[int] = None, - max_access_keys: Optional[int] = None): + max_access_keys: Optional[int] = None, daemon_name=None): """ Modifies an account @@ -87,9 +116,26 @@ class RgwUserAccountsController(RESTController): :return: Returns modified account resource. :rtype: Dict[str, Any] """ - return RgwAccounts.modify_account(account_id, account_name, email, tenant, - max_buckets, max_users, max_roles, - max_group, max_access_keys) + + params = {'id': account_id} + if account_name: + params['name'] = account_name + if tenant: + params['tenant'] = tenant + if email: + params['email'] = email + if max_buckets: + params['max-buckets'] = str(max_buckets) + if max_users: + params['max-users'] = str(max_users) + if max_roles: + params['max-roles'] = str(max_roles) + if max_group: + params['max-group'] = str(max_group) + if max_access_keys: + params['max-access-keys'] = str(max_access_keys) + + return self.proxy(daemon_name, 'PUT', 'account', params) @EndpointDoc("Set RGW Account/Bucket quota", parameters={'account_id': (str, 'Account id'), diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-user-accounts.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-user-accounts.service.spec.ts index 8a3fd3f012015..40d146b41b8f6 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-user-accounts.service.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-user-accounts.service.spec.ts @@ -3,6 +3,7 @@ import { TestBed } from '@angular/core/testing'; import { RgwUserAccountsService } from './rgw-user-accounts.service'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; import { Account } from '~/app/ceph/rgw/models/rgw-user-accounts'; +import { RgwHelper } from '~/testing/unit-test-helper'; const mockAccountData: Account[] = [ { @@ -68,6 +69,7 @@ describe('RgwUserAccountsService', () => { }); service = TestBed.inject(RgwUserAccountsService); httpTesting = TestBed.inject(HttpTestingController); + RgwHelper.selectDaemon(); }); it('should be created', () => { @@ -76,8 +78,56 @@ describe('RgwUserAccountsService', () => { it('should fetch detailed list of accounts', () => { service.list(true).subscribe(); - const req = httpTesting.expectOne('api/rgw/accounts?detailed=true'); + const req = httpTesting.expectOne( + `api/rgw/accounts?${RgwHelper.DAEMON_QUERY_PARAM}&detailed=true` + ); expect(req.request.method).toBe('GET'); req.flush(mockAccountData); }); + + it('should fetch single account detail', () => { + service.get('RGW80617806988089685').subscribe(); + const req = httpTesting.expectOne( + `api/rgw/accounts/get?${RgwHelper.DAEMON_QUERY_PARAM}&account_id=RGW80617806988089685` + ); + expect(req.request.method).toBe('GET'); + req.flush(mockAccountData[0]); + }); + + it('should call create method', () => { + service.create(mockAccountData[0]).subscribe(); + const req = httpTesting.expectOne(`api/rgw/accounts?${RgwHelper.DAEMON_QUERY_PARAM}`); + expect(req.request.method).toBe('POST'); + req.flush(mockAccountData[0]); + }); + + it('should call modify method', () => { + service.modify(mockAccountData[0]).subscribe(); + const req = httpTesting.expectOne(`api/rgw/accounts/set?${RgwHelper.DAEMON_QUERY_PARAM}`); + expect(req.request.method).toBe('PUT'); + req.flush(mockAccountData[0]); + }); + + it('should call remove method', () => { + service.remove('RGW12444466134482748').subscribe(); + const req = httpTesting.expectOne( + `api/rgw/accounts/RGW12444466134482748?${RgwHelper.DAEMON_QUERY_PARAM}` + ); + expect(req.request.method).toBe('DELETE'); + req.flush(null); + }); + + it('should call setQuota method', () => { + service + .setQuota('RGW12444466134482748', { + quota_type: 'bucket', + max_size: '10MB', + max_objects: '1000', + enabled: true + }) + .subscribe(); + const req = httpTesting.expectOne(`api/rgw/accounts/RGW12444466134482748/quota`); + expect(req.request.method).toBe('PUT'); + req.flush(null); + }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-user-accounts.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-user-accounts.service.ts index bd407357c6120..b5035fd344a6d 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-user-accounts.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-user-accounts.service.ts @@ -1,6 +1,8 @@ import { HttpClient, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; +import { RgwDaemonService } from './rgw-daemon.service'; +import { Account } from '~/app/ceph/rgw/models/rgw-user-accounts'; @Injectable({ providedIn: 'root' @@ -8,34 +10,42 @@ import { Observable } from 'rxjs'; export class RgwUserAccountsService { private url = 'api/rgw/accounts'; - constructor(private http: HttpClient) {} + constructor(private http: HttpClient, private rgwDaemonService: RgwDaemonService) {} list(detailed?: boolean): Observable { - let params = new HttpParams(); - if (detailed) { - params = params.append('detailed', detailed); - } - return this.http.get(this.url, { params }); + return this.rgwDaemonService.request((params: HttpParams) => { + if (detailed) { + params = params.append('detailed', detailed); + } + return this.http.get(this.url, { params }); + }); } get(account_id: string): Observable { - let params = new HttpParams(); - if (account_id) { - params = params.append('account_id', account_id); - } - return this.http.get(`${this.url}/get`, { params }); + return this.rgwDaemonService.request((params: HttpParams) => { + if (account_id) { + params = params.append('account_id', account_id); + } + return this.http.get(`${this.url}/get`, { params }); + }); } - create(payload: any): Observable { - return this.http.post(this.url, payload); + create(payload: Partial): Observable { + return this.rgwDaemonService.request((params: HttpParams) => { + return this.http.post(this.url, payload, { params: params }); + }); } - modify(payload: any): Observable { - return this.http.put(`${this.url}/set`, payload); + modify(payload: Partial): Observable { + return this.rgwDaemonService.request((params: HttpParams) => { + return this.http.put(`${this.url}/set`, payload, { params: params }); + }); } remove(accountId: string) { - return this.http.delete(`${this.url}/${accountId}`); + return this.rgwDaemonService.request((params: HttpParams) => { + return this.http.delete(`${this.url}/${accountId}`, { params: params }); + }); } setQuota( diff --git a/src/pybind/mgr/dashboard/openapi.yaml b/src/pybind/mgr/dashboard/openapi.yaml index e1e5fab12dfa1..5ea9e10d9fa73 100755 --- a/src/pybind/mgr/dashboard/openapi.yaml +++ b/src/pybind/mgr/dashboard/openapi.yaml @@ -11040,6 +11040,11 @@ paths: \ detailed account info.\n - If detailed=False, returns only account\ \ ids.\n " parameters: + - allowEmptyValue: true + in: query + name: daemon_name + schema: + type: string - default: false in: query name: detailed @@ -11077,6 +11082,9 @@ paths: account_name: description: Account name type: string + daemon_name: + description: Name of the daemon + type: string email: description: Email type: string @@ -11137,6 +11145,12 @@ paths: required: true schema: type: string + - allowEmptyValue: true + description: Name of the daemon + in: query + name: daemon_name + schema: + type: string responses: '202': content: @@ -11171,6 +11185,12 @@ paths: required: true schema: type: string + - allowEmptyValue: true + description: Name of the daemon + in: query + name: daemon_name + schema: + type: string responses: '200': content: @@ -11210,6 +11230,9 @@ paths: account_name: description: Account name type: string + daemon_name: + description: Name of the daemon + type: string email: description: Email type: string diff --git a/src/pybind/mgr/dashboard/services/rgw_iam.py b/src/pybind/mgr/dashboard/services/rgw_iam.py index 88730dd96a1d6..31cefd3a026ca 100644 --- a/src/pybind/mgr/dashboard/services/rgw_iam.py +++ b/src/pybind/mgr/dashboard/services/rgw_iam.py @@ -1,5 +1,5 @@ from subprocess import SubprocessError -from typing import List, Optional +from typing import List from .. import mgr from ..exceptions import DashboardException @@ -21,66 +21,9 @@ class RgwAccounts: raise DashboardException(e, component='rgw') @classmethod - def get_accounts(cls, detailed: bool = False): - """ - Query account Id's, optionally returning full details. - - :param detailed: Boolean to indicate if full account details are required. - """ + def get_accounts(cls): get_accounts_cmd = ['account', 'list'] - account_list = cls.send_rgw_cmd(get_accounts_cmd) - detailed_account_list = [] - if detailed: - for account in account_list: - detailed_account_list.append(cls.get_account(account)) - return detailed_account_list - return account_list - - @classmethod - def get_account(cls, account_id: str): - get_account_cmd = ['account', 'get', '--account-id', account_id] - return cls.send_rgw_cmd(get_account_cmd) - - @classmethod - def create_account(cls, account_name: str, tenant: Optional[str] = None, - email: Optional[str] = None, max_buckets: Optional[int] = None, - max_users: Optional[int] = None, max_roles: Optional[int] = None, - max_group: Optional[int] = None, max_access_keys: Optional[int] = None): - create_accounts_cmd = ['account', 'create'] - - create_accounts_cmd += cls.get_common_args_list(account_name, email, - tenant, max_buckets, - max_users, max_roles, - max_group, max_access_keys) - - return cls.send_rgw_cmd(create_accounts_cmd) - - @classmethod - def modify_account(cls, account_id: str, account_name: str, - email: Optional[str] = None, tenant: Optional[str] = None, - max_buckets: Optional[int] = None, max_users: Optional[int] = None, - max_roles: Optional[int] = None, max_group: Optional[int] = None, - max_access_keys: Optional[int] = None): - modify_accounts_cmd = ['account', 'modify', '--account-id', account_id] - - modify_accounts_cmd += cls.get_common_args_list(account_name, email, - tenant, max_buckets, - max_users, max_roles, - max_group, max_access_keys) - - return cls.send_rgw_cmd(modify_accounts_cmd) - - @classmethod - def delete_account(cls, account_id: str): - modify_accounts_cmd = ['account', 'rm', '--account-id', account_id] - - return cls.send_rgw_cmd(modify_accounts_cmd) - - @classmethod - def get_account_stats(cls, account_id: str): - account_stats_cmd = ['account', 'stats', '--account-id', account_id] - - return cls.send_rgw_cmd(account_stats_cmd) + return cls.send_rgw_cmd(get_accounts_cmd) @classmethod def set_quota(cls, quota_type: str, account_id: str, max_size: str, max_objects: str, @@ -99,36 +42,3 @@ class RgwAccounts: '--account-id', account_id] return cls.send_rgw_cmd(set_quota_status_cmd) - - @classmethod - def get_common_args_list(cls, account_name: str, email: Optional[str] = None, - tenant: Optional[str] = None, max_buckets: Optional[int] = None, - max_users: Optional[int] = None, max_roles: Optional[int] = None, - max_group: Optional[int] = None, - max_access_keys: Optional[int] = None): - common_cmd_list = [] - if account_name: - common_cmd_list += ['--account-name', account_name] - - if email: - common_cmd_list += ['--email', email] - - if tenant: - common_cmd_list += ['--tenant', tenant] - - if max_buckets: - common_cmd_list += ['--max_buckets', str(max_buckets)] - - if max_users: - common_cmd_list += ['--max_users', str(max_users)] - - if max_roles: - common_cmd_list += ['--max_roles', str(max_roles)] - - if max_group: - common_cmd_list += ['--max_groups', str(max_group)] - - if max_access_keys: - common_cmd_list += ['--max_access_keys', str(max_access_keys)] - - return common_cmd_list diff --git a/src/pybind/mgr/dashboard/tests/test_rgw_iam.py b/src/pybind/mgr/dashboard/tests/test_rgw_iam.py index 90bb9ac16c872..567021910251f 100644 --- a/src/pybind/mgr/dashboard/tests/test_rgw_iam.py +++ b/src/pybind/mgr/dashboard/tests/test_rgw_iam.py @@ -1,16 +1,21 @@ -from unittest import TestCase -from unittest.mock import patch +from unittest.mock import call, patch from ..controllers.rgw_iam import RgwUserAccountsController -from ..services.rgw_iam import RgwAccounts +from ..tests import ControllerTestCase -class TestRgwUserAccountsController(TestCase): +class TestRgwUserAccountsController(ControllerTestCase): + @classmethod + def setup_server(cls): + cls.setup_controllers([RgwUserAccountsController], '/test') - @patch.object(RgwAccounts, 'create_account') - def test_create_account(self, mock_create_account): - mockReturnVal = { - "id": "RGW18661471562806836", + @patch('dashboard.controllers.rgw.RgwAccounts.get_accounts') + @patch('dashboard.controllers.rgw_iam.RgwUserAccountsController.get_account') + @patch('dashboard.controllers.rgw_iam.RgwUserAccountsController.proxy') + def test_account_list(self, mock_proxy, mock_get_account, mock_get_accounts): + mock_get_accounts.return_value = ['RGW67392003738907404'] + mock_proxy.return_value = { + "id": "RGW67392003738907404", "tenant": "", "name": "", "email": "", @@ -35,71 +40,46 @@ class TestRgwUserAccountsController(TestCase): "max_access_keys": 4 } - # Mock the return value of the create_account method - mock_create_account.return_value = mockReturnVal - - controller = RgwUserAccountsController() - result = controller.create(account_name='test_account', tenant='', - email='test@example.com', max_buckets=1000, - max_users=1000, max_roles=1000, max_group=1000, - max_access_keys=4) - - # Check if the account creation method was called with the correct parameters - mock_create_account.assert_called_with('test_account', '', 'test@example.com', - 1000, 1000, 1000, 1000, 4) - # Check the returned result - self.assertEqual(result, mockReturnVal) - - @patch.object(RgwAccounts, 'get_accounts') - def test_list_accounts(self, mock_get_accounts): - mock_return_value = [ - "RGW22222222222222222", - "RGW59378973811515857", - "RGW11111111111111111" - ] - - mock_get_accounts.return_value = mock_return_value - - controller = RgwUserAccountsController() - result = controller.list(detailed=False) + mock_get_account.side_effect = lambda account_id, daemon_name=None: { + "id": account_id, + "tenant": "", + "name": "", + "email": "", + "quota": { + "enabled": False, + "check_on_raw": False, + "max_size": -1, + "max_size_kb": 0, + "max_objects": -1 + }, + "bucket_quota": { + "enabled": False, + "check_on_raw": False, + "max_size": -1, + "max_size_kb": 0, + "max_objects": -1 + }, + "max_users": 1000, + "max_roles": 1000, + "max_groups": 1000, + "max_buckets": 1000, + "max_access_keys": 4 + } + self._get('/test/api/rgw/accounts?daemon_name=dummy-daemon') + self.assertStatus(200) + self.assertJsonBody(['RGW67392003738907404']) - mock_get_accounts.assert_called_with(False) + mock_get_accounts.assert_called_once() - self.assertEqual(result, mock_return_value) + self._get('/test/api/rgw/accounts?daemon_name=dummy-daemon&detailed=true') + self.assertStatus(200) - @patch.object(RgwAccounts, 'get_accounts') - def test_list_accounts_with_details(self, mock_get_accounts): - mock_return_value = [ + expected_detailed_response = [ { - "id": "RGW22222222222222222", + "id": "RGW67392003738907404", "tenant": "", - "name": "Account2", - "email": "account2@ceph.com", - "quota": { - "enabled": False, - "check_on_raw": False, - "max_size": -1, - "max_size_kb": 0, - "max_objects": -1 - }, - "bucket_quota": { - "enabled": False, - "check_on_raw": False, - "max_size": -1, - "max_size_kb": 0, - "max_objects": -1 - }, - "max_users": 1000, - "max_roles": 1000, - "max_groups": 1000, - "max_buckets": 1000, - "max_access_keys": 4 - }, - { - "id": "RGW11111111111111111", - "tenant": "", - "name": "Account1", - "email": "account1@ceph.com", + "name": "", + "email": "", "quota": { "enabled": False, "check_on_raw": False, @@ -121,23 +101,22 @@ class TestRgwUserAccountsController(TestCase): "max_access_keys": 4 } ] + self.assertJsonBody(expected_detailed_response) - mock_get_accounts.return_value = mock_return_value - - controller = RgwUserAccountsController() - result = controller.list(detailed=True) + mock_get_account.assert_has_calls([ + call('RGW67392003738907404', 'dummy-daemon') + ]) - mock_get_accounts.assert_called_with(True) + self._get('/test/api/rgw/accounts/RGW67392003738907404?daemon_name=dummy-daemon') + self.assertStatus(200) - self.assertEqual(result, mock_return_value) - - @patch.object(RgwAccounts, 'get_account') - def test_get_account(self, mock_get_account): - mock_return_value = { - "id": "RGW22222222222222222", + @patch('dashboard.controllers.rgw_iam.RgwUserAccountsController.proxy') + def test_create_account(self, mock_proxy): + mock_proxy.return_value = { + "id": "RGW67392003738907404", "tenant": "", - "name": "Account2", - "email": "account2@ceph.com", + "name": "jack", + "email": "", "quota": { "enabled": False, "check_on_raw": False, @@ -158,33 +137,60 @@ class TestRgwUserAccountsController(TestCase): "max_buckets": 1000, "max_access_keys": 4 } - mock_get_account.return_value = mock_return_value - - controller = RgwUserAccountsController() - result = controller.get(account_id='RGW22222222222222222') - - mock_get_account.assert_called_with('RGW22222222222222222') - self.assertEqual(result, mock_return_value) - - @patch.object(RgwAccounts, 'delete_account') - def test_delete_account(self, mock_delete_account): - mock_delete_account.return_value = None - - controller = RgwUserAccountsController() - result = controller.delete(account_id='RGW59378973811515857') - - mock_delete_account.assert_called_with('RGW59378973811515857') - - self.assertEqual(result, None) + self._post('/test/api/rgw/accounts?daemon_name=dummy-daemon', data={ + 'account_name': 'jack', + 'max_buckets': '1000', + 'max_users': '1000', + 'max_roles': '1000', + 'max_group': '1000', + 'max_access_keys': '4' + }) + + mock_proxy.assert_called_once_with( + 'dummy-daemon', 'POST', 'account', { + 'name': 'jack', + 'max-buckets': '1000', + 'max-users': '1000', + 'max-roles': '1000', + 'max-group': '1000', + 'max-access-keys': '4' + }) + + @patch('dashboard.controllers.rgw_iam.RgwUserAccountsController.get_account') + @patch('dashboard.controllers.rgw_iam.RgwUserAccountsController.proxy') + def test_get_account(self, mock_get_account, mock_proxy): + mock_proxy.return_value = { + "id": "RGW67392003738907404", + "tenant": "", + "name": "", + "email": "", + "quota": { + "enabled": False, + "check_on_raw": False, + "max_size": -1, + "max_size_kb": 0, + "max_objects": -1 + }, + "bucket_quota": { + "enabled": False, + "check_on_raw": False, + "max_size": -1, + "max_size_kb": 0, + "max_objects": -1 + }, + "max_users": 1000, + "max_roles": 1000, + "max_groups": 1000, + "max_buckets": 1000, + "max_access_keys": 4 + } - @patch.object(RgwAccounts, 'modify_account') - def test_set_account_name(self, mock_modify_account): - mock_return_value = mock_return_value = { - "id": "RGW59378973811515857", + mock_get_account.side_effect = lambda account_id, daemon_name=None: { + "id": account_id, "tenant": "", - "name": "new_account_name", - "email": "new_email@example.com", + "name": "", + "email": "", "quota": { "enabled": False, "check_on_raw": False, @@ -205,20 +211,65 @@ class TestRgwUserAccountsController(TestCase): "max_buckets": 1000, "max_access_keys": 4 } - mock_modify_account.return_value = mock_return_value + self._get('/test/api/rgw/accounts/RGW67392003738907404?daemon_name=dummy-daemon') + self.assertStatus(200) - controller = RgwUserAccountsController() - result = controller.set(account_id='RGW59378973811515857', account_name='new_account_name', - email='new_email@example.com', tenant='', max_buckets=1000, - max_users=1000, max_roles=1000, max_group=1000, max_access_keys=4) + @patch('dashboard.controllers.rgw_iam.RgwUserAccountsController.proxy') + def test_delete_account(self, mock_proxy): + mock_proxy.return_value = None - mock_modify_account.assert_called_with('RGW59378973811515857', 'new_account_name', - 'new_email@example.com', '', 1000, 1000, 1000, - 1000, 4) + self._delete('/test/api/rgw/accounts/RGW67392003738907404?daemon_name=dummy-daemon') + self.assertStatus(204) - self.assertEqual(result, mock_return_value) + @patch('dashboard.controllers.rgw_iam.RgwUserAccountsController.proxy') + def test_set_account(self, mock_proxy): + mock_proxy.return_value = { + "id": "RGW67392003738907404", + "tenant": "", + "name": "jack", + "email": "", + "quota": { + "enabled": False, + "check_on_raw": False, + "max_size": -1, + "max_size_kb": 0, + "max_objects": -1 + }, + "bucket_quota": { + "enabled": False, + "check_on_raw": False, + "max_size": -1, + "max_size_kb": 0, + "max_objects": -1 + }, + "max_users": 1000, + "max_roles": 1000, + "max_groups": 1000, + "max_buckets": 1000, + "max_access_keys": 4 + } - @patch.object(RgwAccounts, 'set_quota') + self._put('/test/api/rgw/accounts/RGW67392003738907404?daemon_name=dummy-daemon', data={ + 'account_name': 'jack', + 'max_buckets': '1000', + 'max_users': '1000', + 'max_roles': '1000', + 'max_group': '1000', + 'max_access_keys': '4' + }) + + mock_proxy.assert_called_once_with( + 'dummy-daemon', 'PUT', 'account', { + 'id': 'RGW67392003738907404', + 'name': 'jack', + 'max-buckets': '1000', + 'max-users': '1000', + 'max-roles': '1000', + 'max-group': '1000', + 'max-access-keys': '4' + }) + + @patch('dashboard.controllers.rgw_iam.RgwUserAccountsController.set_quota') def test_set_quota(self, mock_set_quota): mock_return_value = { "id": "RGW11111111111111111", @@ -249,14 +300,13 @@ class TestRgwUserAccountsController(TestCase): mock_set_quota.return_value = mock_return_value controller = RgwUserAccountsController() - result = controller.set_quota(quota_type='account', account_id='RGW11111111111111111', - max_size='10GB', max_objects='1000', enabled=True) + result = controller.set_quota('account', 'RGW11111111111111111', '10GB', '1000', True) mock_set_quota.assert_called_with('account', 'RGW11111111111111111', '10GB', '1000', True) self.assertEqual(result, mock_return_value) - @patch.object(RgwAccounts, 'set_quota_status') + @patch('dashboard.controllers.rgw_iam.RgwUserAccountsController.set_quota_status') def test_set_quota_status(self, mock_set_quota_status): mock_return_value = { "id": "RGW11111111111111111", @@ -287,9 +337,7 @@ class TestRgwUserAccountsController(TestCase): mock_set_quota_status.return_value = mock_return_value controller = RgwUserAccountsController() - result = controller.set_quota_status(quota_type='account', - account_id='RGW11111111111111111', - quota_status='enabled') + result = controller.set_quota_status('account', 'RGW11111111111111111', 'enabled') mock_set_quota_status.assert_called_with('account', 'RGW11111111111111111', 'enabled')