diff --git a/orm/orm_client/ormcli/cmscli.py b/orm/orm_client/ormcli/cmscli.py index ce5f531f..87ee1a98 100644 --- a/orm/orm_client/ormcli/cmscli.py +++ b/orm/orm_client/ormcli/cmscli.py @@ -367,6 +367,32 @@ def add_to_parser(service_sub): parser_unassign_group_role.add_argument( '--domain', type=str, help='domain name') + # groups - add default users + parser_add_group_default_users = subparsers.add_parser( + 'add_group_default_users', + help='[<"X-RANGER-Client" ' + 'header>] ' + '') + parser_add_group_default_users.add_argument( + 'client', **cli_common.ORM_CLIENT_KWARGS) + parser_add_group_default_users.add_argument( + 'groupid', type=str, help='') + parser_add_group_default_users.add_argument( + 'datafile', type=argparse.FileType('r'), + help='') + + # groups - delete default user + parser_delete_group_default_user = \ + subparsers.add_parser('delete_group_default_user', + help='[<"X-RANGER-Client" header>] ') + parser_delete_group_default_user.add_argument( + 'client', **cli_common.ORM_CLIENT_KWARGS) + parser_delete_group_default_user.add_argument( + 'groupid', type=str, help='') + parser_delete_group_default_user.add_argument( + 'userid', type=str, help='') + return parser @@ -472,6 +498,12 @@ def cmd_details(args): args.role, assignment_type, assignment_value) + elif args.subcmd == 'add_group_default_users': + return requests.post, 'groups/%s/users' % args.groupid + elif args.subcmd == 'delete_group_default_user': + return requests.delete, 'groups/%s/users/%s' % ( + args.groupid, + args.userid) def get_token(timeout, args, host): diff --git a/orm/services/customer_manager/cms_rest/controllers/v1/orm/group/roles.py b/orm/services/customer_manager/cms_rest/controllers/v1/orm/group/roles.py index 595d2d31..5f306509 100644 --- a/orm/services/customer_manager/cms_rest/controllers/v1/orm/group/roles.py +++ b/orm/services/customer_manager/cms_rest/controllers/v1/orm/group/roles.py @@ -25,7 +25,7 @@ class RoleController(rest.RestController): def post(self, group_id, role_assignments): LOG.info("RoleController - Assign Roles to group id {0} " "roles: {1}".format(group_id, str(role_assignments))) - authentication.authorize(request, 'groups:assign_region') + authentication.authorize(request, 'groups:assign_role') try: group_logic = GroupLogic() result = group_logic.assign_roles(group_id, @@ -43,7 +43,6 @@ class RoleController(rest.RestController): except DBDuplicateEntry as exception: LOG.log_exception( "DBDuplicateEntry - Group Roles already assigned.", exception) - print exception.message raise err_utils.get_error( request.transaction_id, status_code=409, @@ -75,7 +74,7 @@ class RoleController(rest.RestController): group_id, role_name, assignment_type, assignment_value)) - authentication.authorize(request, 'groups:unassign_region') + authentication.authorize(request, 'groups:unassign_role') try: group_logic = GroupLogic() group_logic.unassign_roles(group_id, diff --git a/orm/services/customer_manager/cms_rest/controllers/v1/orm/group/root.py b/orm/services/customer_manager/cms_rest/controllers/v1/orm/group/root.py index f36198f3..7a2f8d38 100755 --- a/orm/services/customer_manager/cms_rest/controllers/v1/orm/group/root.py +++ b/orm/services/customer_manager/cms_rest/controllers/v1/orm/group/root.py @@ -4,12 +4,12 @@ from wsmeext.pecan import wsexpose from orm.common.orm_common.utils import api_error_utils as err_utils from orm.common.orm_common.utils import utils -from orm.services.customer_manager.cms_rest.controllers.v1.orm.customer.users \ - import DefaultUserController from orm.services.customer_manager.cms_rest.controllers.v1.orm.group.regions \ import RegionController from orm.services.customer_manager.cms_rest.controllers.v1.orm.group.roles \ import RoleController +from orm.services.customer_manager.cms_rest.controllers.v1.orm.group.users \ + import UserController from orm.services.customer_manager.cms_rest.logger import get_logger from orm.services.customer_manager.cms_rest.logic.error_base import ErrorStatus from orm.services.customer_manager.cms_rest.logic.group_logic import GroupLogic @@ -23,7 +23,7 @@ LOG = get_logger(__name__) class GroupController(rest.RestController): roles = RoleController() regions = RegionController() - users = DefaultUserController() + users = UserController() @wsexpose(Group, str, rest_content_types='json') def get(self, group_uuid): diff --git a/orm/services/customer_manager/cms_rest/controllers/v1/orm/group/users.py b/orm/services/customer_manager/cms_rest/controllers/v1/orm/group/users.py new file mode 100644 index 00000000..7c62ab4d --- /dev/null +++ b/orm/services/customer_manager/cms_rest/controllers/v1/orm/group/users.py @@ -0,0 +1,108 @@ +from oslo_db.exception import DBDuplicateEntry +from pecan import request, rest +from wsmeext.pecan import wsexpose + +from orm.common.orm_common.utils import api_error_utils as err_utils +from orm.common.orm_common.utils import utils +from orm.services.customer_manager.cms_rest.logger import get_logger +from orm.services.customer_manager.cms_rest.logic.error_base import ErrorStatus +from orm.services.customer_manager.cms_rest.logic.group_logic import GroupLogic +from orm.services.customer_manager.cms_rest.model.GroupModels import \ + User, UserResultWrapper +from orm.services.customer_manager.cms_rest.utils import authentication + +LOG = get_logger(__name__) + + +class UserController(rest.RestController): + + @wsexpose([str], str, rest_content_types='json') + def get(self, group_id): + return ["This is groups user controller ", "group id: " + group_id] + + @wsexpose(UserResultWrapper, str, body=[User], + rest_content_types='json', status_code=200) + def post(self, group_id, users): + LOG.info("UserController - Add users to group id {0} " + "users: {1}".format(group_id, users)) + authentication.authorize(request, 'groups:add_default_user') + try: + group_logic = GroupLogic() + result = group_logic.add_default_users(group_id, + users, + request.transaction_id) + + LOG.info("UserController - Users added: " + str(result)) + + event_details = 'Group {} - users assigned.'.format(group_id) + utils.audit_trail('added group users', + request.transaction_id, + request.headers, + group_id, + event_details=event_details) + + except DBDuplicateEntry as exception: + LOG.log_exception( + "DBDuplicateEntry - Group users already assigned.", exception) + print exception.message + raise err_utils.get_error( + request.transaction_id, + status_code=409, + message='Duplicate Entry - Group users already assigned.', + error_details=exception.message) + + except ErrorStatus as exception: + LOG.log_exception( + "ErrorStatus - Failed to add users", exception) + raise err_utils.get_error(request.transaction_id, + message=exception.message, + status_code=exception.status_code) + except Exception as exception: + LOG.log_exception( + "Exception - Failed in add default users", exception) + raise err_utils.get_error(request.transaction_id, + status_code=500, + error_details=str(exception)) + + return result + + @wsexpose(None, str, str, status_code=204) + def delete(self, group_id, user): + + requester = request.headers.get('X-RANGER-Requester') + is_rds_client_request = requester == 'rds_resource_service_proxy' + LOG.info("Remove users from group id: {0} user: {1} ".format( + group_id, user)) + + authentication.authorize(request, 'groups:delete_default_user') + try: + group_logic = GroupLogic() + group_logic.delete_default_user(group_id, + user, + request.transaction_id) + + LOG.info("UserController - Remove user from group finished") + + event_details = 'Group {} users unassigned'.format(group_id) + utils.audit_trail('delete group user', + request.transaction_id, + request.headers, + group_id, + event_details=event_details) + + except ValueError as exception: + raise err_utils.get_error(request.transaction_id, + message=exception.message, + status_code=404) + except ErrorStatus as exception: + LOG.log_exception("ErrorStatus - Failed to delete user from group", + exception) + raise err_utils.get_error(request.transaction_id, + message=exception.message, + status_code=exception.status_code) + except Exception as exception: + LOG.log_exception("Exception - Failed in delete default user", + exception) + raise err_utils.get_error(request.transaction_id, + status_code=500, + error_details=str(exception)) diff --git a/orm/services/customer_manager/cms_rest/data/data_manager.py b/orm/services/customer_manager/cms_rest/data/data_manager.py index 544e18c5..b63b5c52 100755 --- a/orm/services/customer_manager/cms_rest/data/data_manager.py +++ b/orm/services/customer_manager/cms_rest/data/data_manager.py @@ -14,10 +14,12 @@ from orm.services.customer_manager.cms_rest.data.sql_alchemy.\ groups_region_record import GroupsRegionRecord from orm.services.customer_manager.cms_rest.data.sql_alchemy.\ groups_role_record import GroupsRoleRecord +from orm.services.customer_manager.cms_rest.data.sql_alchemy.\ + groups_user_record import GroupsUserRecord from orm.services.customer_manager.cms_rest.data.sql_alchemy.models \ import (CmsRole, CmsUser, Customer, CustomerRegion, Groups, GroupsCustomerRole, GroupsDomainRole, GroupsRegion, - GroupsRole, Quota, + GroupsRole, GroupsUser, Quota, QuotaFieldDetail, Region, UserRole) from orm.services.customer_manager.cms_rest.data.sql_alchemy.user_role_record \ @@ -183,6 +185,13 @@ class DataManager(object): self.session) return self.groups_domain_role_record + elif (record_name == "GroupsUser" or + record_name == "groups_user"): + if not hasattr(self, "groups_user_record"): + self.groups_user_record = GroupsUserRecord( + self.session) + return self.groups_user_record + return None def add_user(self, user): @@ -254,7 +263,7 @@ class DataManager(object): sql_group = Groups( uuid=uuid, name=group.name, - domain_name=group.domain_name, + domain_name=group.domain, enabled=group.enabled, description=group.description ) @@ -377,8 +386,8 @@ class DataManager(object): self.flush() return groups_domain_role - def add_groups_role_on_project(self, - group_id, role_id, region_id, customer_id): + def add_groups_role_on_customer(self, + group_id, role_id, region_id, customer_id): self.add_groups_role(role_id, group_id) groups_customer_role = GroupsCustomerRole(role_id=role_id, @@ -389,6 +398,18 @@ class DataManager(object): self.flush() return groups_customer_role + def add_groups_user(self, + group_id, user_id, region_id, domain): + + groups_user = GroupsUser(user_id=user_id, + group_id=group_id, + domain_name=domain, + region_id=region_id) + + self.session.add(groups_user) + self.flush() + return groups_user + @classmethod def get_dict_from_quota(cls, quota, quota_type): types = { diff --git a/orm/services/customer_manager/cms_rest/data/sql_alchemy/groups_user_record.py b/orm/services/customer_manager/cms_rest/data/sql_alchemy/groups_user_record.py new file mode 100644 index 00000000..754ad971 --- /dev/null +++ b/orm/services/customer_manager/cms_rest/data/sql_alchemy/groups_user_record.py @@ -0,0 +1,120 @@ +from orm.services.customer_manager.cms_rest.data.sql_alchemy.cms_user_record \ + import CmsUserRecord +from orm.services.customer_manager.cms_rest.data.sql_alchemy.models \ + import GroupsUser +from orm.services.customer_manager.cms_rest.data.sql_alchemy.region_record \ + import RegionRecord +from orm.services.customer_manager.cms_rest.logger import get_logger + +LOG = get_logger(__name__) + + +class GroupsUserRecord: + def __init__(self, session): + + # thie model uses for the parameters for any acceess methods - not + # as instance of record in the table + self.__groups_user = GroupsUser() + self.__TableName = "groups_user" + + if (session): + self.session = session + + def setDBSession(self, session): + self.session = session + + @property + def groups_user(self): + return self.__groups_user + + @groups_user.setter + def groups_user(self): + self.__groups_user = GroupsUser() + + def insert(self, groups_user): + try: + self.session.add(groups_user) + except Exception as exception: + LOG.log_exception( + "Failed to insert groups_user" + str(groups_user), exception) + raise + + def get_groups_user_keys(self, + user_name, + group_uuid, + region_name, + domain_name): + region_record = RegionRecord(self.session) + region_id = region_record.get_region_id_from_name(region_name) + + if region_id is None: + raise ValueError( + 'region with the region name {0} not found'.format( + region_name)) + + user_record = CmsUserRecord(self.session) + user_id = user_record.get_cms_user_id_from_name(user_name) + + if user_id is None: + raise ValueError( + 'user with the user name {0} not found'.format( + user_name)) + try: + group = self.session.query(GroupsUser).filter( + and_( + GroupsUser.group_id == group_uuid, + GroupsUser.domain_name == domain_name, + GroupsUser.region_id == region_id, + GroupsUser.user_id == user_id)) + return group.first() + + except Exception as exception: + message = "Failed to get groups user by primary keys: " \ + " group_uuid:%s domain:%s region:%s user_name: %s" \ + % group_uuid, domain_name, region_name, user_name + LOG.log_exception(message, exception) + raise + + def get_users_for_group(self, group_uuid): + groups_users = [] + + try: + query = self.session.query(GroupsUser).filter( + GroupsUser.group_id == group_uuid) + + for groups_user in query.all(): + groups_users.append(groups_user) + return groups_users + + except Exception as exception: + message = "Failed to get users for group: %s" % (group_uuid) + LOG.log_exception(message, exception) + raise + + def remove_user_from_group(self, + group_uuid, + region_id, + domain_name, + user_name): + + user_record = CmsUserRecord(self.session) + user_id = user_record.get_cms_user_id_from_name(user_name) + + cmd = 'DELETE FROM groups_user WHERE group_id = %s and \ + region_id = %s and domain_name = %s and user_id = %s' + result = self.session.connection().execute(cmd, + (group_uuid, + region_id, + domain_name, + user_id)) + self.session.flush() + + if result.rowcount == 0: + LOG.warn('user with user name {0} not found'.format( + user_name)) + raise ValueError( + 'user with user name {0} not found'.format( + user_name)) + + LOG.debug("num records deleted: " + str(result.rowcount)) + return result diff --git a/orm/services/customer_manager/cms_rest/data/sql_alchemy/models.py b/orm/services/customer_manager/cms_rest/data/sql_alchemy/models.py index b9a51300..d1655fbb 100755 --- a/orm/services/customer_manager/cms_rest/data/sql_alchemy/models.py +++ b/orm/services/customer_manager/cms_rest/data/sql_alchemy/models.py @@ -121,7 +121,7 @@ class Groups(Base, CMSBaseModel): uuid=uuid, regions=regions, enabled=enabled, - domain_name=domain_name) + domain=domain_name) return result ''' @@ -303,7 +303,8 @@ class GroupsUser(Base, CMSBaseModel): region_id = Column(Integer, ForeignKey('groups_region.region_id'), primary_key=True, nullable=False, index=True) - domain_name = Column(String(64), nullable=True) + domain_name = Column(String(64), ForeignKey('cms_domain.name'), + nullable=False) user = relationship("CmsUser", viewonly=True) groups = relationship("Groups", viewonly=True) diff --git a/orm/services/customer_manager/cms_rest/etc/policy.json b/orm/services/customer_manager/cms_rest/etc/policy.json index 8a53688f..568c4f8e 100755 --- a/orm/services/customer_manager/cms_rest/etc/policy.json +++ b/orm/services/customer_manager/cms_rest/etc/policy.json @@ -45,5 +45,7 @@ "groups:add_region": "rule:admin_or_support_or_creator", "groups:delete_region": "rule:admin_or_creator", "groups:assign_role": "rule:admin_or_support_or_creator", - "groups:unassign_role": "rule:admin_or_creator" + "groups:unassign_role": "rule:admin_or_creator", + "groups:add_default_user": "rule:admin_or_support", + "groups:delete_default_user": "rule:admin" } diff --git a/orm/services/customer_manager/cms_rest/logic/group_logic.py b/orm/services/customer_manager/cms_rest/logic/group_logic.py index 244708b2..4a0bafc0 100755 --- a/orm/services/customer_manager/cms_rest/logic/group_logic.py +++ b/orm/services/customer_manager/cms_rest/logic/group_logic.py @@ -13,9 +13,10 @@ from orm.services.customer_manager.cms_rest.logic.error_base import ( DuplicateEntryError, ErrorStatus, NotFound) from orm.services.customer_manager.cms_rest.model.GroupModels import ( GroupResultWrapper, - RoleResultWrapper, GroupSummary, - GroupSummaryResponse) + GroupSummaryResponse, + RoleResultWrapper, + UserResultWrapper) from orm.services.customer_manager.cms_rest.rds_proxy import RdsProxy @@ -55,6 +56,28 @@ class GroupLogic(object): ' already associated with group') raise ex + def add_default_users(self, + group_uuid, + users, + transaction_id): + LOG.info("Add default users: group: {} user: {} ".format( + group_uuid, users)) + + users_result = [{'id': user.id, + 'domain': user.domain} for user in users] + user_result_wrapper = build_response(group_uuid, + transaction_id, + 'add_default_users', + users=users_result) + return user_result_wrapper + + def delete_default_user(self, + group_uuid, + user, + transaction_id): + LOG.info("Delete default user: group: {} user: {} ".format( + group_uuid, user)) + def assign_roles(self, group_uuid, role_assignments, @@ -75,20 +98,20 @@ class GroupLogic(object): for group_region in groups_regions: region_id = group_region.region_id - if role_assignment.domain_name: + if role_assignment.domain: datamanager.add_groups_role_on_domain( group_uuid, role_id, region_id, - role_assignment.domain_name) - elif role_assignment.project: - project_id = datamanager.get_customer_id_by_uuid( - role_assignment.project) - datamanager.add_groups_role_on_project( + role_assignment.domain) + elif role_assignment.customer: + customer_id = datamanager.get_customer_id_by_uuid( + role_assignment.customer) + datamanager.add_groups_role_on_customer( group_uuid, role_id, region_id, - project_id) + customer_id) datamanager.flush() group = group_record.read_group_by_uuid(group_uuid) @@ -98,8 +121,8 @@ class GroupLogic(object): RdsProxy.send_group_dict(group_dict, transaction_id, "PUT") roles = [{'roles': role_assignment.roles, - 'domain': role_assignment.domain_name, - 'project': role_assignment.project} + 'domain': role_assignment.domain, + 'customer': role_assignment.customer} for role_assignment in role_assignments] role_result_wrapper = build_response(group_uuid, transaction_id, @@ -447,7 +470,7 @@ class GroupLogic(object): raise -def build_response(group_uuid, transaction_id, context, roles=[]): +def build_response(group_uuid, transaction_id, context, roles=[], users=[]): """this function generate th group action response JSON :param group_uuid: :param transaction_id: @@ -463,22 +486,22 @@ def build_response(group_uuid, transaction_id, context, roles=[]): if context == 'create_group': base_link = base_link + group_uuid - group_result_wrapper = GroupResultWrapper( - transaction_id=transaction_id, - id=group_uuid, - updated=None, - created=timestamp, - links={'self': base_link}) - - return group_result_wrapper + return GroupResultWrapper(transaction_id=transaction_id, + id=group_uuid, + updated=None, + created=timestamp, + links={'self': base_link}) elif context == 'role_assignment': - role_result_wrapper = RoleResultWrapper( - transaction_id=transaction_id, - roles=roles, - links={'self': base_link}, - created=timestamp) + return RoleResultWrapper(transaction_id=transaction_id, + roles=roles, + links={'self': base_link}, + created=timestamp) - return role_result_wrapper + elif context == 'add_default_users': + return UserResultWrapper(transaction_id=transaction_id, + users=users, + links={'self': base_link}, + created=timestamp) else: return None diff --git a/orm/services/customer_manager/cms_rest/model/GroupModels.py b/orm/services/customer_manager/cms_rest/model/GroupModels.py index 1d752cc9..d63c2a08 100755 --- a/orm/services/customer_manager/cms_rest/model/GroupModels.py +++ b/orm/services/customer_manager/cms_rest/model/GroupModels.py @@ -37,18 +37,18 @@ class Region(Model): class RoleAssignment(Model): roles = wsme.wsattr([str], mandatory=True) - project = wsme.wsattr(wsme.types.text, mandatory=False) - domain_name = wsme.wsattr(wsme.types.text, mandatory=False) + customer = wsme.wsattr(wsme.types.text, mandatory=False) + domain = wsme.wsattr(wsme.types.text, mandatory=False) - def __init__(self, status="", domain="", project="", roles=[]): - self.domain_name = domain - self.project = project + def __init__(self, domain="", customer="", roles=[]): + self.domain = domain + self.customer = customer self.roles = roles def validate_model(self): - if self.project and self.domain_name: + if self.customer and self.domain: raise ErrorStatus(400, - "Found both project and domain_name tag used. " + "Found both customer and domain tag used. " "Only one can be specified for role assignment.") if len(set(self.roles)) != len(self.roles): @@ -56,19 +56,74 @@ class RoleAssignment(Model): "Duplicate role in roles tag found ") +class User(Model): + id = wsme.wsattr(wsme.types.text, mandatory=True) + domain = wsme.wsattr(wsme.types.text, mandatory=True) + + def __init__(self, id="", domain=""): + self.id = id + self.domain = domain + + +class UserUsers(Model): + users = wsme.wsattr([str], mandatory=True) + + def __init__(self, user=""): + self.users = users + + def validate_model(self): + # check no duplicate users in dictonary list + # if len(set(self.users)) != len(self.users) and + # len(set(self.domain)) != len(self.users): + # raise ErrorStatus(400, "Duplicate regions found") + + # Remove the below return once implementation is done + return None + + +class UserRegions(Model): + name = wsme.wsattr(wsme.types.text, mandatory=False) + type = wsme.wsattr(wsme.types.text, default="single", mandatory=False) + users = wsme.wsattr([UserUsers], mandatory=False) + + def __init__(self, name="", type="", users=[]): + self.name = name + self.type = type + self.users = users + + +class UserAssignment(Model): + userUsers = wsme.wsattr([UserUsers], mandatory=True) + userRegions = wsme.wsattr([UserRegions], mandatory=True) + + def __init__(self, status="", userUsers=None, userRegions=""): + self.userUsers = userUsers + self.userRegions = userRegions + + def validate_model(self): + + if not userUsers and not userRegions: + raise ErrorStatus(400, "Either regions or users" + "is required. ") + + # check no duplicate users in dictonary list + # for userRegion in userRegions: + # if dups found issue 400 duplicate region error + + class Group(Model): """group entity with all it's related data """ description = wsme.wsattr(wsme.types.text, mandatory=True) name = wsme.wsattr(wsme.types.text, mandatory=True) status = wsme.wsattr(wsme.types.text, mandatory=False) - domain_name = wsme.wsattr(wsme.types.text, mandatory=True) + domain = wsme.wsattr(wsme.types.text, mandatory=True) uuid = wsme.wsattr(wsme.types.text, mandatory=False) enabled = wsme.wsattr(bool, mandatory=True) regions = wsme.wsattr([Region], mandatory=False) def __init__(self, description="", name="", enabled=False, - regions=[], status="", domain_name='default', uuid=None): + regions=[], status="", domain='default', uuid=None): """Create a new Group. :param description: Server name @@ -77,7 +132,7 @@ class Group(Model): self.description = description self.name = name self.status = status - self.domain_name = domain_name + self.domain = domain self.enabled = enabled self.regions = regions if uuid is not None: @@ -148,13 +203,13 @@ class GroupSummary(Model): name = wsme.wsattr(wsme.types.text) id = wsme.wsattr(wsme.types.text) description = wsme.wsattr(wsme.types.text) - domain_name = wsme.wsattr(wsme.types.text) + domain = wsme.wsattr(wsme.types.text) enabled = wsme.wsattr(bool, mandatory=True) status = wsme.wsattr(wtypes.text, mandatory=True) regions = wsme.wsattr([str], mandatory=True) def __init__(self, name='', id='', description='', - status="", enabled=True, domain_name='default', regions=[]): + status="", enabled=True, domain='default', regions=[]): Model.__init__(self) self.name = name @@ -162,7 +217,7 @@ class GroupSummary(Model): self.description = description self.enabled = enabled self.status = status - self.domain_name = domain_name + self.domain = domain self.regions = regions @staticmethod @@ -175,7 +230,7 @@ class GroupSummary(Model): group.name = sql_group.name group.description = sql_group.description group.enabled = bool(sql_group.enabled) - group.domain_name = sql_group.domain_name + group.domain = sql_group.domain_name group.regions = regions return group @@ -215,16 +270,16 @@ class RegionResultWrapper(Model): class RoleResult(Model): roles = wsme.wsattr([str], mandatory=True) - project = wsme.wsattr(wsme.types.text, mandatory=False) - domain_name = wsme.wsattr(wsme.types.text, mandatory=False) + customer = wsme.wsattr(wsme.types.text, mandatory=False) + domain = wsme.wsattr(wsme.types.text, mandatory=False) - def __init__(self, roles, project="", domain=""): + def __init__(self, roles, customer="", domain=""): Model.__init__(self) self.roles = roles - if project: - self.project = project + if customer: + self.customer = customer if domain: - self.domain_name = domain + self.domain = domain class RoleResultWrapper(Model): @@ -235,9 +290,34 @@ class RoleResultWrapper(Model): def __init__(self, transaction_id, roles, links, created): roles_result = [RoleResult(role['roles'], - project=role['project'], + customer=role['customer'], domain=role['domain']) for role in roles] self.roles = roles_result self.transaction_id = transaction_id self.links = links self.created = created + + +class UserResult(Model): + id = wsme.wsattr(wsme.types.text, mandatory=True) + domain = wsme.wsattr(wsme.types.text, mandatory=True) + + def __init__(self, id="", domain=""): + Model.__init__(self) + self.id = id + self.domain = domain + + +class UserResultWrapper(Model): + transaction_id = wsme.wsattr(wsme.types.text, mandatory=True) + users = wsme.wsattr([UserResult], mandatory=True) + links = wsme.wsattr({str: str}, mandatory=True) + created = wsme.wsattr(wsme.types.text, mandatory=True) + + def __init__(self, transaction_id, users, links, created): + users_result = [UserResult(id=user['id'], + domain=user['domain']) for user in users] + self.users = users_result + self.transaction_id = transaction_id + self.links = links + self.created = created diff --git a/orm/services/customer_manager/scripts/db_scripts/ranger_cms_create_db.sql b/orm/services/customer_manager/scripts/db_scripts/ranger_cms_create_db.sql index 470ea0ae..3c21aa9c 100755 --- a/orm/services/customer_manager/scripts/db_scripts/ranger_cms_create_db.sql +++ b/orm/services/customer_manager/scripts/db_scripts/ranger_cms_create_db.sql @@ -140,11 +140,12 @@ create table if not exists groups_user group_id varchar(64) not null, region_id integer not null, user_id integer not null, - domain_name varchar(64), + domain_name varchar(64) not null, primary key (group_id, region_id, user_id), foreign key (`user_id`) references `cms_user` (`id`) ON DELETE CASCADE, foreign key (`group_id`) references `groups` (`uuid`) ON DELETE CASCADE ON UPDATE NO ACTION, foreign key (`region_id`) references `groups_region` (`region_id`) ON UPDATE NO ACTION, + foreign key (`domain_name`) references `cms_domain` (`name`) ON DELETE CASCADE ON UPDATE NO ACTION, index group_id (group_id), index region_id (region_id), index user_id (user_id)); diff --git a/orm/services/resource_distributor/rds/services/yaml_group_builder.py b/orm/services/resource_distributor/rds/services/yaml_group_builder.py index 04b95e2c..d8a57f3a 100755 --- a/orm/services/resource_distributor/rds/services/yaml_group_builder.py +++ b/orm/services/resource_distributor/rds/services/yaml_group_builder.py @@ -38,10 +38,28 @@ def yamlbuilder(alldata, region): } } - if "groups_roles" in jsondata and len(jsondata["groups_roles"]) > 0: + if "groups_users" in jsondata and len(jsondata["groups_users"]) > 0: + template_name = '{}_user_assignments'.format(group_name) + users = [] - template_name = "{}-Role-Assignment".format(group_name) + for user in jsondata['groups_users']: + users.append({ + "name": user["user_name"], + "user_domain": user["domain_name"] + }) + + resources["resources"][template_name] = { + 'type': 'OS::Keystone::GroupUserAssignment\n', + 'properties': { + 'group': "{get_resource: %s}" % group_name, + 'group_domain': "%s" % jsondata['domain_name'], + } + } + + if "groups_roles" in jsondata and len(jsondata["groups_roles"]) > 0: + template_name = "{}_role_assignments".format(group_name) roles = [] + for customer_role in jsondata["groups_customer_roles"]: roles.append({ "role": customer_role["role_name"], diff --git a/orm/tests/unit/cms/test_group_logic.py b/orm/tests/unit/cms/test_group_logic.py index c8ec0bda..52b62eda 100644 --- a/orm/tests/unit/cms/test_group_logic.py +++ b/orm/tests/unit/cms/test_group_logic.py @@ -194,14 +194,14 @@ class TestGroupLogic(FunctionalTest): assert record_mock.read_group_by_uuid.called assert record_mock.get_regions_for_group.called - def test_assign_roles_to_group_on_project_success(self): + def test_assign_roles_to_group_on_customer_success(self): roles_assginments = [models.RoleAssignment( - roles=['a_role'], project='project')] + roles=['a_role'], customer='customer')] logic = group_logic.GroupLogic() logic.assign_roles('group_uuid', roles_assginments, 'some_trans_id') - assert data_manager_mock.add_groups_role_on_project.called + assert data_manager_mock.add_groups_role_on_customer.called assert data_manager_mock.get_customer_id_by_uuid.called assert data_manager_mock.commit.called assert data_manager_mock.get_role_id_by_name.called @@ -222,12 +222,12 @@ class TestGroupLogic(FunctionalTest): assert data_manager_mock.rollback.called - def test_assign_roles_to_group_on_project_error(self): + def test_assign_roles_to_group_on_customer_error(self): global mock_returns_error mock_returns_error = True roles_assginments = [models.RoleAssignment( - roles=['a_role'], project='project')] + roles=['a_role'], customer='customer')] logic = group_logic.GroupLogic() self.assertRaises(SystemError, logic.assign_roles, 'group_uuid', @@ -249,7 +249,7 @@ class TestGroupLogic(FunctionalTest): assert data_manager_mock.commit.called assert data_manager_mock.get_role_id_by_name.called - def test_unassign_roles_from_group_on_project_success(self): + def test_unassign_roles_from_group_on_customer_success(self): logic = group_logic.GroupLogic() logic.unassign_roles('group_uuid', 'role', 'customer', 'customer_id', 'some_trans_id') @@ -292,7 +292,7 @@ class TestGroupLogic(FunctionalTest): assert data_manager_mock.rollback.called assert data_manager_mock.get_role_id_by_name.called - def test_unassign_roles_from_group_on_project_error(self): + def test_unassign_roles_from_group_on_customer_error(self): global mock_returns_error mock_returns_error = True @@ -386,7 +386,7 @@ def get_mock_datamanager(): # mock for assign roles data_manager_mock.add_groups_role_on_domain.side_effect = \ SystemError() - data_manager_mock.add_groups_role_on_project.side_effect = \ + data_manager_mock.add_groups_role_on_customer.side_effect = \ SystemError() record_mock.get_regions_for_group.return_value = [ sql_models.GroupsRegion(region_id=1, group_id="group_id")] diff --git a/orm/tests/unit/cms/test_groups.py b/orm/tests/unit/cms/test_groups.py index b9e323eb..ea3fa07e 100644 --- a/orm/tests/unit/cms/test_groups.py +++ b/orm/tests/unit/cms/test_groups.py @@ -199,7 +199,7 @@ GROUP_JSON = { "description": "Group description", "enabled": True, "name": "myGroup", - "domain_name": "default", + "domain": "default", "regions": [ { "name": "SAN1", @@ -211,7 +211,7 @@ GROUP_JSON = { RET_GROUP_JSON = { "description": "Group description", "name": "myName", - "domain_name": "default", + "domain": "default", "enabled": True, "regions": [GroupModels.Region()] } diff --git a/orm/tests/unit/cms/test_groups_role.py b/orm/tests/unit/cms/test_groups_role.py index 7da0e3cf..656f95e3 100644 --- a/orm/tests/unit/cms/test_groups_role.py +++ b/orm/tests/unit/cms/test_groups_role.py @@ -159,7 +159,7 @@ class ResponseMock: GROUPS_ROLE_JSON = [ { - "project": "project-id", + "customer": "customer-id", "roles": [ "role1", "role2" diff --git a/orm/tests/unit/cms/test_groups_users.py b/orm/tests/unit/cms/test_groups_users.py new file mode 100644 index 00000000..2f70a78f --- /dev/null +++ b/orm/tests/unit/cms/test_groups_users.py @@ -0,0 +1,151 @@ +import mock +import requests +from wsme.exc import ClientSideError + +from orm.services.customer_manager.cms_rest.controllers.v1.orm.group \ + import users +from orm.services.customer_manager.cms_rest.logic.error_base import ErrorStatus +from orm.services.customer_manager.cms_rest.model import GroupModels +from orm.tests.unit.cms import FunctionalTest + +group_logic_mock = None + + +class TestGroupsUserController(FunctionalTest): + def setUp(self): + FunctionalTest.setUp(self) + + users.authentication = mock.MagicMock() + + users.GroupLogic = get_mock_group_logic + users.GroupLogic.return_error = 0 + + users.utils = mock.MagicMock() + users.utils.audit_trail.return_value = None + + users.err_utils = mock.MagicMock() + + def tearDown(self): + FunctionalTest.tearDown(self) + + def test_add_default_users(self): + # given + requests.post = mock.MagicMock(return_value=ResponseMock(200)) + + # when + response = self.app.post_json('/v1/orm/groups/{group id}/users/', + GROUPS_USER_JSON) + + # assert + self.assertEqual(response.status_int, 200) + self.assertTrue(group_logic_mock.add_default_users.called) + + def test_add_default_users_fail(self): + # given + requests.post = mock.MagicMock() + + users.GroupLogic.return_error = 1 + users.err_utils.get_error = mock.MagicMock( + return_value=ClientSideError("blabla", 500)) + # when + response = self.app.post_json('/v1/orm/groups/{group id}/users/', + GROUPS_USER_JSON, + expect_errors=True) + # assert + self.assertEqual(response.status_int, 500) + + def test_add_default_users_fail_bad_request(self): + # given + requests.post = mock.MagicMock() + + users.GroupLogic.return_error = 2 + users.err_utils.get_error = mock.MagicMock( + return_value=ClientSideError("blabla", 404)) + # when + response = self.app.post_json('/v1/orm/groups/{group id}/users/', + GROUPS_USER_JSON, + expect_errors=True) + + # assert + self.assertEqual(response.status_int, 404) + + def test_delete_default_user(self): + # given + requests.delete = mock.MagicMock(return_value=ResponseMock(200)) + + # when + response = self.app.delete('/v1/orm/groups/{group id}/users/{user_id}') + + # assert + self.assertEqual(response.status_int, 204) + # uncomment below line when delete_default_user is implemented + # self.assertTrue(users.utils.audit_trail.called) + self.assertTrue(group_logic_mock.delete_default_user.called) + + def test_delete_default_user_fail(self): + # given + requests.delete = mock.MagicMock() + + users.GroupLogic.return_error = 1 + users.err_utils.get_error = mock.MagicMock( + return_value=ClientSideError("blabla", 500)) + + # when + response = self.app.delete('/v1/orm/groups/{group id}/users/{user_id}', + expect_errors=True) + + # assert + self.assertEqual(response.status_int, 500) + + def test_delete_default_user_fail_bad_request(self): + # given + requests.delete = mock.MagicMock() + + users.GroupLogic.return_error = 2 + users.err_utils.get_error = mock.MagicMock( + return_value=ClientSideError("blabla", 404)) + + # when + response = self.app.delete('/v1/orm/groups/{group id}/users/{user_id}', + expect_errors=True) + + # assert + self.assertEqual(response.status_int, 404) + + +def get_mock_group_logic(): + global group_logic_mock + group_logic_mock = mock.MagicMock() + + if users.GroupLogic.return_error == 0: + res = GroupModels.UserResultWrapper(transaction_id='1', + users=[], + links={}, + created='1') + + group_logic_mock.add_default_users.return_value = res + + elif users.GroupLogic.return_error == 1: + group_logic_mock.add_default_users.side_effect = SystemError() + group_logic_mock.delete_default_user.side_effect = SystemError() + + else: + group_logic_mock.add_default_users.side_effect = ErrorStatus( + status_code=404) + group_logic_mock.delete_default_user.side_effect = ErrorStatus( + status_code=404) + + return group_logic_mock + + +class ResponseMock: + def __init__(self, status_code=200): + self.status_code = status_code + + +GROUPS_USER_JSON = [ + { + "id": "attuser1", + "domain": "nc" + } +] diff --git a/orm/tests/unit/ormcli/test_cmscli.py b/orm/tests/unit/ormcli/test_cmscli.py index 8a78bc35..ff633c30 100755 --- a/orm/tests/unit/ormcli/test_cmscli.py +++ b/orm/tests/unit/ormcli/test_cmscli.py @@ -96,6 +96,11 @@ class CmsTests(TestCase): '&contains=%s' % (args.region, args.starts_with, args.contains)), + 'add_group_default_users': ( + requests.post, 'groups/%s/users' % args.groupid,), + 'delete_group_default_user': ( + requests.delete, 'groups/%s/users/%s' % ( + args.groupid, args.userid),), 'assign_group_roles': ( requests.post, 'groups/%s/roles' % args.groupid,) } diff --git a/ranger-tempest-plugin/ranger_tempest_plugin/schemas/group_schema.py b/ranger-tempest-plugin/ranger_tempest_plugin/schemas/group_schema.py index 05d4adf8..dcbb74e7 100644 --- a/ranger-tempest-plugin/ranger_tempest_plugin/schemas/group_schema.py +++ b/ranger-tempest-plugin/ranger_tempest_plugin/schemas/group_schema.py @@ -70,12 +70,12 @@ get_group = { 'status': _status, 'uuid': {'type': 'string'}, 'enabled': {'type': 'boolean'}, - 'domain_name': {'type': 'string'}, + 'domain': {'type': 'string'}, 'name': {'type': 'string'}, 'regions': {'type': 'array'}, 'description': {'type': 'string'} }, - 'required': ['status', 'uuid', 'enabled', 'domain_name', 'name', + 'required': ['status', 'uuid', 'enabled', 'domain', 'name', 'regions', 'description'] } } @@ -93,7 +93,7 @@ list_groups = { 'status': _status, 'description': {'type': 'string'}, 'enabled': {'type': 'boolean'}, - 'domain_name': {'type': 'string'}, + 'domain': {'type': 'string'}, 'regions': { 'type': 'array', 'items': {'type': 'string'} @@ -102,7 +102,7 @@ list_groups = { 'name': {'type': 'string'} }, 'required': ['status', 'description', 'enabled', - 'domain_name', 'regions', 'id', 'name'] + 'domain', 'regions', 'id', 'name'] } } }, @@ -120,8 +120,8 @@ _roles = { 'type': 'array', 'items': {'type': 'string'} }, - 'project': {'type': 'string'}, - 'domain_name': {'type': 'string'} + 'customer': {'type': 'string'}, + 'domain': {'type': 'string'} }, 'required': ['roles'] } diff --git a/ranger-tempest-plugin/ranger_tempest_plugin/tests/api/grp_base.py b/ranger-tempest-plugin/ranger_tempest_plugin/tests/api/grp_base.py index 3e2cbf18..a1ffa0db 100755 --- a/ranger-tempest-plugin/ranger_tempest_plugin/tests/api/grp_base.py +++ b/ranger-tempest-plugin/ranger_tempest_plugin/tests/api/grp_base.py @@ -41,7 +41,7 @@ class GrpBaseOrmTest(CmsBaseOrmTest): region['type'] = 'single' regions = [region] payload["description"] = grp_name - payload["domain_name"] = CONF.ranger.domain + payload["domain"] = CONF.ranger.domain payload["enabled"] = True if enabled else False payload["name"] = grp_name payload["regions"] = regions @@ -72,7 +72,7 @@ class GrpBaseOrmTest(CmsBaseOrmTest): - name - description - enabled - - domain_name + - domain - regions """ _, body = self.grp_client.create_group(**kwargs) diff --git a/ranger-tempest-plugin/ranger_tempest_plugin/tests/api/test_groups.py b/ranger-tempest-plugin/ranger_tempest_plugin/tests/api/test_groups.py index ba0d9468..d0d7ad74 100755 --- a/ranger-tempest-plugin/ranger_tempest_plugin/tests/api/test_groups.py +++ b/ranger-tempest-plugin/ranger_tempest_plugin/tests/api/test_groups.py @@ -133,7 +133,7 @@ class TestTempestGrp(grp_base.GrpBaseOrmTest): def test_assign_unassign_role_to_group_on_domain(self): role = { 'roles': ["admin"], - 'domain_name': CONF.ranger.domain + 'domain': CONF.ranger.domain } post_body = [role] @@ -141,13 +141,13 @@ class TestTempestGrp(grp_base.GrpBaseOrmTest): *post_body) self._wait_for_group_status(self.setup_group_id, 'Success') - self.assertEqual(body['roles'][0]['domain_name'], role['domain_name']) + self.assertEqual(body['roles'][0]['domain'], role['domain']) self.assertEqual(body['roles'][0]['roles'][0], role['roles'][0]) _, body = self.grp_client.unassign_group_role(self.setup_group_id, role['roles'][0], 'domain', - role['domain_name']) + role['domain']) self._wait_for_group_status(self.setup_group_id, 'Success') # Once the get groups role function is implemented, it will be @@ -156,10 +156,10 @@ class TestTempestGrp(grp_base.GrpBaseOrmTest): self.assertEqual(body, '') @decorators.idempotent_id('67f5e46e-9267-4cbb-84d6-ee8521370e23') - def test_assign_unassign_role_to_group_on_project(self): + def test_assign_unassign_role_to_group_on_customer(self): role = { 'roles': ["admin"], - 'project': self.setup_customer_id + 'customer': self.setup_customer_id } post_body = [role] @@ -167,13 +167,13 @@ class TestTempestGrp(grp_base.GrpBaseOrmTest): *post_body) self._wait_for_group_status(self.setup_group_id, 'Success') - self.assertEqual(body['roles'][0]['project'], role['project']) + self.assertEqual(body['roles'][0]['customer'], role['customer']) self.assertEqual(body['roles'][0]['roles'][0], role['roles'][0]) _, body = self.grp_client.unassign_group_role(self.setup_group_id, role['roles'][0], 'customer', - role['project']) + role['customer']) self._wait_for_group_status(self.setup_group_id, 'Success') # Once the get groups role function is implemented, it will be