diff --git a/rally/plugins/openstack/context/keystone/users.py b/rally/plugins/openstack/context/keystone/users.py index 2896c02e..09818ec2 100644 --- a/rally/plugins/openstack/context/keystone/users.py +++ b/rally/plugins/openstack/context/keystone/users.py @@ -253,7 +253,6 @@ class UserGenerator(UserContextMixin, context.Context): clients, name_generator=self.generate_random_name) client = cache["client"] user = client.create_user(username, password=password, - email="%s@email.me" % username, project_id=tenant_id, domain_name=user_dom, default_role=default_role) diff --git a/rally/plugins/openstack/scenarios/ceilometer/events.py b/rally/plugins/openstack/scenarios/ceilometer/events.py index 27c348c2..b5b98dc6 100644 --- a/rally/plugins/openstack/scenarios/ceilometer/events.py +++ b/rally/plugins/openstack/scenarios/ceilometer/events.py @@ -12,17 +12,18 @@ # License for the specific language governing permissions and limitations # under the License. +""" +Scenarios for Ceilometer Events API. +""" + from rally import consts from rally import exceptions from rally.plugins.openstack import scenario from rally.plugins.openstack.scenarios.ceilometer import utils as cutils -from rally.plugins.openstack.scenarios.keystone import utils as kutils +from rally.plugins.openstack.scenarios.keystone import basic as kbasic from rally.task import validation -"""Scenarios for Ceilometer Events API.""" - - # NOTE(idegtiarov): to work with event we need to create it, there are # no other way except emit suitable notification from one of services, # for example create new user in keystone. @@ -34,7 +35,7 @@ from rally.task import validation "cleanup": ["ceilometer"]}, name="CeilometerEvents.create_user_and_list_events") class CeilometerEventsCreateUserAndListEvents(cutils.CeilometerScenario, - kutils.KeystoneScenario): + kbasic.KeystoneBasic): def run(self): """Create user and fetch all events. @@ -42,7 +43,7 @@ class CeilometerEventsCreateUserAndListEvents(cutils.CeilometerScenario, This scenario creates user to store new event and fetches list of all events using GET /v2/events. """ - self._user_create() + self.admin_keystone.create_user() events = self._list_events() if not events: raise exceptions.RallyException( @@ -57,7 +58,7 @@ class CeilometerEventsCreateUserAndListEvents(cutils.CeilometerScenario, "cleanup": ["ceilometer"]}, name="CeilometerEvents.create_user_and_list_event_types") class CeilometerEventsCreateUserAndListEventTypes(cutils.CeilometerScenario, - kutils.KeystoneScenario): + kbasic.KeystoneBasic): def run(self): """Create user and fetch all event types. @@ -65,7 +66,7 @@ class CeilometerEventsCreateUserAndListEventTypes(cutils.CeilometerScenario, This scenario creates user to store new event and fetches list of all events types using GET /v2/event_types. """ - self._user_create() + self.admin_keystone.create_user() event_types = self._list_event_types() if not event_types: raise exceptions.RallyException( @@ -80,7 +81,7 @@ class CeilometerEventsCreateUserAndListEventTypes(cutils.CeilometerScenario, "cleanup": ["ceilometer"]}, name="CeilometerEvents.create_user_and_get_event") class CeilometerEventsCreateUserAndGetEvent(cutils.CeilometerScenario, - kutils.KeystoneScenario): + kbasic.KeystoneBasic): def run(self): """Create user and gets event. @@ -88,7 +89,7 @@ class CeilometerEventsCreateUserAndGetEvent(cutils.CeilometerScenario, This scenario creates user to store new event and fetches one event using GET /v2/events/. """ - self._user_create() + self.admin_keystone.create_user() events = self._list_events() if not events: raise exceptions.RallyException( diff --git a/rally/plugins/openstack/scenarios/ceilometer/traits.py b/rally/plugins/openstack/scenarios/ceilometer/traits.py index 2ccf4890..8c3dc8d6 100644 --- a/rally/plugins/openstack/scenarios/ceilometer/traits.py +++ b/rally/plugins/openstack/scenarios/ceilometer/traits.py @@ -15,7 +15,7 @@ from rally import consts from rally.plugins.openstack import scenario from rally.plugins.openstack.scenarios.ceilometer import utils as cutils -from rally.plugins.openstack.scenarios.keystone import utils as kutils +from rally.plugins.openstack.scenarios.keystone import basic as kbasic from rally.task import validation @@ -33,7 +33,7 @@ from rally.task import validation "cleanup": ["ceilometer"]}, name="CeilometerTraits.create_user_and_list_traits") class CreateUserAndListTraits(cutils.CeilometerScenario, - kutils.KeystoneScenario): + kbasic.KeystoneBasic): def run(self): """Create user and fetch all event traits. @@ -42,7 +42,7 @@ class CreateUserAndListTraits(cutils.CeilometerScenario, fetches list of all traits for certain event type and trait name using GET /v2/event_types//traits/. """ - self._user_create() + self.admin_keystone.create_user() event = self._list_events()[0] trait_name = event.traits[0]["name"] self._list_event_traits(event_type=event.event_type, @@ -57,7 +57,7 @@ class CreateUserAndListTraits(cutils.CeilometerScenario, name="CeilometerTraits.create_user_and" "_list_trait_descriptions") class CreateUserAndListTraitDescriptions( - cutils.CeilometerScenario, kutils.KeystoneScenario): + cutils.CeilometerScenario, kbasic.KeystoneBasic): def run(self): """Create user and fetch all trait descriptions. @@ -66,6 +66,6 @@ class CreateUserAndListTraitDescriptions( fetches list of all traits for certain event type using GET /v2/event_types//traits. """ - self._user_create() + self.admin_keystone.create_user() event = self._list_events()[0] self._list_event_trait_descriptions(event_type=event.event_type) \ No newline at end of file diff --git a/rally/plugins/openstack/scenarios/keystone/basic.py b/rally/plugins/openstack/scenarios/keystone/basic.py index 1cb56594..2a985ad7 100644 --- a/rally/plugins/openstack/scenarios/keystone/basic.py +++ b/rally/plugins/openstack/scenarios/keystone/basic.py @@ -19,14 +19,29 @@ Benchmark scenarios for Keystone. from rally.common import logging from rally.plugins.openstack import scenario -from rally.plugins.openstack.scenarios.keystone import utils as kutils +from rally.plugins.openstack.services.identity import identity from rally.task import validation +class KeystoneBasic(scenario.OpenStackScenario): + """Base class for Keystone scenarios with initialized service object.""" + + def __init__(self, context=None, admin_clients=None, clients=None): + super(KeystoneBasic, self).__init__(context, admin_clients, clients) + if hasattr(self, "_admin_clients"): + self.admin_keystone = identity.Identity( + self._admin_clients, name_generator=self.generate_random_name, + atomic_inst=self.atomic_actions()) + if hasattr(self, "_clients"): + self.keystone = identity.Identity( + self._clients, name_generator=self.generate_random_name, + atomic_inst=self.atomic_actions()) + + @validation.required_openstack(admin=True) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_user") -class CreateUser(kutils.KeystoneScenario): +class CreateUser(KeystoneBasic): @logging.log_deprecated_args( "The 'name_length' argument to create_user is ignored", @@ -37,13 +52,13 @@ class CreateUser(kutils.KeystoneScenario): :param kwargs: Other optional parameters to create users like "tenant_id", "enabled". """ - self._user_create(**kwargs) + self.admin_keystone.create_user(**kwargs) @validation.required_openstack(admin=True) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_delete_user") -class CreateDeleteUser(kutils.KeystoneScenario): +class CreateDeleteUser(KeystoneBasic): @logging.log_deprecated_args( "The 'name_length' argument to create_delete_user is ignored", @@ -54,14 +69,14 @@ class CreateDeleteUser(kutils.KeystoneScenario): :param kwargs: Other optional parameters to create users like "tenant_id", "enabled". """ - user = self._user_create(**kwargs) - self._resource_delete(user) + user = self.admin_keystone.create_user(**kwargs) + self.admin_keystone.delete_user(user.id) @validation.required_openstack(admin=True) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_user_set_enabled_and_delete") -class CreateUserSetEnabledAndDelete(kutils.KeystoneScenario): +class CreateUserSetEnabledAndDelete(KeystoneBasic): def run(self, enabled=True, **kwargs): """Create a keystone user, enable or disable it, and delete it. @@ -71,16 +86,15 @@ class CreateUserSetEnabledAndDelete(kutils.KeystoneScenario): value, and then it will be toggled. :param kwargs: Other optional parameters to create user. """ - user = self._user_create(enabled=enabled, **kwargs) - self._update_user_enabled(user, not enabled) - self._resource_delete(user) + user = self.admin_keystone.create_user(enabled=enabled, **kwargs) + self.admin_keystone.update_user(user.id, enabled=(not enabled)) + self.admin_keystone.delete_user(user.id) @validation.required_openstack(admin=True) -@validation.required_api_versions(component="keystone", versions=[2.0]) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_tenant") -class CreateTenant(kutils.KeystoneScenario): +class CreateTenant(KeystoneBasic): @logging.log_deprecated_args( "The 'name_length' argument to create_tenant is ignored", @@ -90,33 +104,26 @@ class CreateTenant(kutils.KeystoneScenario): :param kwargs: Other optional parameters """ - self._tenant_create(**kwargs) + self.admin_keystone.create_project(**kwargs) @validation.required_openstack(admin=True) @validation.required_api_versions(component="keystone", versions=[2.0]) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.authenticate_user_and_validate_token") -class AuthenticateUserAndValidateToken(kutils.KeystoneScenario): +class AuthenticateUserAndValidateToken(KeystoneBasic): def run(self): """Authenticate and validate a keystone token.""" - name = self.context["user"]["credential"].username - password = self.context["user"]["credential"].password - tenant_id = self.context["tenant"]["id"] - tenant_name = self.context["tenant"]["name"] - - token = self._authenticate_token(name, password, tenant_id, - tenant_name, atomic_action=False) - self._token_validate(token.id) + token = self.admin_keystone.fetch_token() + self.admin_keystone.validate_token(token) @validation.number("users_per_tenant", minval=1) @validation.required_openstack(admin=True) -@validation.required_api_versions(component="keystone", versions=[2.0]) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_tenant_with_users") -class CreateTenantWithUsers(kutils.KeystoneScenario): +class CreateTenantWithUsers(KeystoneBasic): @logging.log_deprecated_args( "The 'name_length' argument to create_tenant_with_users is ignored", @@ -128,14 +135,15 @@ class CreateTenantWithUsers(kutils.KeystoneScenario): :param kwargs: Other optional parameters for tenant creation :returns: keystone tenant instance """ - tenant = self._tenant_create(**kwargs) - self._users_create(tenant, users_per_tenant=users_per_tenant) + tenant = self.admin_keystone.create_project(**kwargs) + self.admin_keystone.create_users(tenant.id, + number_of_users=users_per_tenant) @validation.required_openstack(admin=True) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_and_list_users") -class CreateAndListUsers(kutils.KeystoneScenario): +class CreateAndListUsers(KeystoneBasic): @logging.log_deprecated_args( "The 'name_length' argument to create_and_list_users is ignored", @@ -146,15 +154,15 @@ class CreateAndListUsers(kutils.KeystoneScenario): :param kwargs: Other optional parameters to create users like "tenant_id", "enabled". """ - self._user_create(**kwargs) - self._list_users() + kwargs.pop("name", None) + self.admin_keystone.create_user(**kwargs) + self.admin_keystone.list_users() @validation.required_openstack(admin=True) -@validation.required_api_versions(component="keystone", versions=[2.0]) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_and_list_tenants") -class CreateAndListTenants(kutils.KeystoneScenario): +class CreateAndListTenants(KeystoneBasic): @logging.log_deprecated_args( "The 'name_length' argument to create_and_list_tenants is ignored", @@ -164,14 +172,14 @@ class CreateAndListTenants(kutils.KeystoneScenario): :param kwargs: Other optional parameters """ - self._tenant_create(**kwargs) - self._list_tenants() + self.admin_keystone.create_project(**kwargs) + self.admin_keystone.list_projects() @validation.required_openstack(admin=True, users=True) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.add_and_remove_user_role") -class AddAndRemoveUserRole(kutils.KeystoneScenario): +class AddAndRemoveUserRole(KeystoneBasic): def run(self): """Create a user role add to a user and disassociate.""" @@ -187,7 +195,7 @@ class AddAndRemoveUserRole(kutils.KeystoneScenario): @validation.required_openstack(admin=True) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_and_delete_role") -class CreateAndDeleteRole(kutils.KeystoneScenario): +class CreateAndDeleteRole(KeystoneBasic): def run(self): """Create a user role and delete it.""" @@ -198,7 +206,7 @@ class CreateAndDeleteRole(kutils.KeystoneScenario): @validation.required_openstack(admin=True, users=True) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_add_and_list_user_roles") -class CreateAddAndListUserRoles(kutils.KeystoneScenario): +class CreateAddAndListUserRoles(KeystoneBasic): def run(self): """Create user role, add it and list user roles for given user.""" @@ -211,10 +219,9 @@ class CreateAddAndListUserRoles(kutils.KeystoneScenario): @validation.required_openstack(admin=True) -@validation.required_api_versions(component="keystone", versions=[2.0]) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.get_entities") -class GetEntities(kutils.KeystoneScenario): +class GetEntities(KeystoneBasic): def run(self, service_name="keystone"): """Get instance of a tenant, user, role and service by id's. @@ -230,23 +237,23 @@ class GetEntities(kutils.KeystoneScenario): None, to create an ephemeral service and get it by ID. """ - tenant = self._tenant_create() - user = self._user_create() + project = self.admin_keystone.create_project() + user = self.admin_keystone.create_user(project_id=project.id) role = self.admin_keystone.create_role() - self._get_tenant(tenant.id) - self._get_user(user.id) - self._get_role(role.id) + self.admin_keystone.get_project(project.id) + self.admin_keystone.get_user(user.id) + self.admin_keystone.get_role(role.id) if service_name is None: - service = self._service_create() + service = self.admin_keystone.create_service() else: - service = self._get_service_by_name(service_name) - self._get_service(service.id) + service = self.admin_keystone.get_service_by_name(service_name) + self.admin_keystone.get_service(service.id) @validation.required_openstack(admin=True) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_and_delete_service") -class CreateAndDeleteService(kutils.KeystoneScenario): +class CreateAndDeleteService(KeystoneBasic): @logging.log_deprecated_args( "The 'name' argument to create_and_delete_service will be ignored", @@ -257,15 +264,15 @@ class CreateAndDeleteService(kutils.KeystoneScenario): :param service_type: type of the service :param description: description of the service """ - service = self._service_create(service_type, description) - self._delete_service(service.id) + service = self.admin_keystone.create_service(service_type=service_type, + description=description) + self.admin_keystone.delete_service(service.id) @validation.required_openstack(admin=True) -@validation.required_api_versions(component="keystone", versions=[2.0]) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_update_and_delete_tenant") -class CreateUpdateAndDeleteTenant(kutils.KeystoneScenario): +class CreateUpdateAndDeleteTenant(KeystoneBasic): @logging.log_deprecated_args( "The 'name_length' argument to create_update_and_delete_tenant is " @@ -275,15 +282,18 @@ class CreateUpdateAndDeleteTenant(kutils.KeystoneScenario): :param kwargs: Other optional parameters for tenant creation """ - tenant = self._tenant_create(**kwargs) - self._update_tenant(tenant) - self._resource_delete(tenant) + project = self.admin_keystone.create_project(**kwargs) + new_name = self.generate_random_name() + new_description = self.generate_random_name() + self.admin_keystone.update_project(project.id, name=new_name, + description=new_description) + self.admin_keystone.delete_project(project.id) @validation.required_openstack(admin=True) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_user_update_password") -class CreateUserUpdatePassword(kutils.KeystoneScenario): +class CreateUserUpdatePassword(KeystoneBasic): @logging.log_deprecated_args( "The 'name_length' and 'password_length' arguments to " @@ -291,15 +301,15 @@ class CreateUserUpdatePassword(kutils.KeystoneScenario): "0.1.2", ["name_length", "password_length"], once=True) def run(self, name_length=None, password_length=None): """Create user and update password for that user.""" + user = self.admin_keystone.create_user() password = self.generate_random_name() - user = self._user_create() - self._update_user_password(user.id, password) + self.admin_keystone.update_user(user.id, password=password) @validation.required_openstack(admin=True) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_and_list_services") -class CreateAndListServices(kutils.KeystoneScenario): +class CreateAndListServices(KeystoneBasic): @logging.log_deprecated_args( "The 'name' argument to create_and_list_services will be ignored", @@ -310,38 +320,42 @@ class CreateAndListServices(kutils.KeystoneScenario): :param service_type: type of the service :param description: description of the service """ - self._service_create(service_type, description) - self._list_services() + self.admin_keystone.create_service(service_type=service_type, + description=description) + self.admin_keystone.list_services() @validation.required_openstack(users=True) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_and_list_ec2credentials") -class CreateAndListEc2Credentials(kutils.KeystoneScenario): +class CreateAndListEc2Credentials(KeystoneBasic): def run(self): """Create and List all keystone ec2-credentials.""" - self._create_ec2credentials(self.context["user"]["id"], - self.context["tenant"]["id"]) - self._list_ec2credentials(self.context["user"]["id"]) + self.keystone.create_ec2credentials( + self.context["user"]["id"], + project_id=self.context["tenant"]["id"]) + self.keystone.list_ec2credentials(self.context["user"]["id"]) @validation.required_openstack(users=True) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_and_delete_ec2credential") -class CreateAndDeleteEc2Credential(kutils.KeystoneScenario): +class CreateAndDeleteEc2Credential(KeystoneBasic): def run(self): """Create and delete keystone ec2-credential.""" - creds = self._create_ec2credentials(self.context["user"]["id"], - self.context["tenant"]["id"]) - self._delete_ec2credential(self.context["user"]["id"], creds.access) + creds = self.keystone.create_ec2credentials( + self.context["user"]["id"], + project_id=self.context["tenant"]["id"]) + self.keystone.delete_ec2credential( + self.context["user"]["id"], access=creds.access) @validation.required_openstack(admin=True) @scenario.configure(context={"admin_cleanup": ["keystone"]}, name="KeystoneBasic.create_and_get_role") -class CreateAndGetRole(kutils.KeystoneScenario): +class CreateAndGetRole(KeystoneBasic): def run(self, **kwargs): """Create a user role and get it detailed information. diff --git a/rally/plugins/openstack/scenarios/keystone/utils.py b/rally/plugins/openstack/scenarios/keystone/utils.py index 49230440..30858560 100644 --- a/rally/plugins/openstack/scenarios/keystone/utils.py +++ b/rally/plugins/openstack/scenarios/keystone/utils.py @@ -15,25 +15,26 @@ import uuid +from rally.common.i18n import _LW +from rally.common import logging from rally.plugins.openstack import scenario -from rally.plugins.openstack.services.identity import identity from rally.plugins.openstack.wrappers import keystone as keystone_wrapper from rally.task import atomic +LOG = logging.getLogger(__name__) + + class KeystoneScenario(scenario.OpenStackScenario): """Base class for Keystone scenarios with basic atomic actions.""" def __init__(self, context=None, admin_clients=None, clients=None): super(KeystoneScenario, self).__init__(context, admin_clients, clients) - if hasattr(self, "_admin_clients"): - self.admin_keystone = identity.Identity( - self._admin_clients, name_generator=self.generate_random_name, - atomic_inst=self.atomic_actions()) - if hasattr(self, "_clients"): - self.keystone = identity.Identity( - self._clients, name_generator=self.generate_random_name, - atomic_inst=self.atomic_actions()) + LOG.warning(_LW( + "Class %s is deprecated since Rally 0.8.0 and will be removed " + "soon. Use " + "rally.plugins.openstack.services.identity.identity.Identity " + "instead.") % self.__class__) @atomic.action_timer("keystone.create_user") def _user_create(self, email=None, **kwargs): diff --git a/rally/plugins/openstack/services/identity/identity.py b/rally/plugins/openstack/services/identity/identity.py index 820fe62e..b6820624 100644 --- a/rally/plugins/openstack/services/identity/identity.py +++ b/rally/plugins/openstack/services/identity/identity.py @@ -42,6 +42,19 @@ class Identity(service.UnifiedOpenStackService): return self._impl.create_project(project_name, domain_name=domain_name) + @service.should_be_overridden + def update_project(self, project_id, name=None, enabled=None, + description=None): + """Update project name, enabled and description + + :param project_id: Id of project to update + :param name: project name to be set + :param enabled: enabled status of project + :param description: project description to be set + """ + self._impl.update_project(project_id, name=name, enabled=enabled, + description=description) + @service.should_be_overridden def delete_project(self, project_id): """Deletes project.""" @@ -53,29 +66,45 @@ class Identity(service.UnifiedOpenStackService): return self._impl.list_projects() @service.should_be_overridden - def create_user(self, username=None, password=None, email=None, - project_id=None, domain_name="Default", + def get_project(self, project_id): + """Get project.""" + return self._impl.get_project(project_id) + + @service.should_be_overridden + def create_user(self, username=None, password=None, project_id=None, + domain_name="Default", enabled=True, default_role="member"): """Create user. :param username: name of user :param password: user password - :param email: user's email :param project_id: user's default project :param domain_name: Name or id of domain where to create user, for those service implementations that don't support domains you should use None or 'Default' value. + :param enabled: whether the user is enabled. :param default_role: Name of role, for implementations that don't support domains this argument must be None or 'member'. """ return self._impl.create_user(username=username, password=password, - email=email, project_id=project_id, domain_name=domain_name, default_role=default_role) + @service.should_be_overridden + def create_users(self, owner_id, number_of_users, user_create_args=None): + """Create specified amount of users. + + :param owner_id: Id of tenant/project + :param number_of_users: number of users to create + :param user_create_args: additional user creation arguments + """ + return self._impl.create_users(owner_id, + number_of_users=number_of_users, + user_create_args=user_create_args) + @service.should_be_overridden def delete_user(self, user_id): """Deletes user by its id.""" @@ -86,6 +115,28 @@ class Identity(service.UnifiedOpenStackService): """List all users.""" return self._impl.list_users() + @service.should_be_overridden + def update_user(self, user_id, enabled=None, name=None, email=None, + password=None): + return self._impl.update_user(user_id, enabled=enabled, name=name, + email=email, password=password) + + @service.should_be_overridden + def get_user(self, user_id): + """Get user.""" + return self._impl.get_user(user_id) + + @service.should_be_overridden + def create_service(self, name=None, service_type=None, description=None): + """Creates keystone service with random name. + + :param name: name of service to create + :param service_type: type of the service + :param description: description of the service + """ + return self._impl.create_service(name=name, service_type=service_type, + description=description) + @service.should_be_overridden def delete_service(self, service_id): """Deletes service.""" @@ -96,6 +147,11 @@ class Identity(service.UnifiedOpenStackService): """List all services.""" return self._impl.list_services() + @service.should_be_overridden + def get_service(self, service_id): + """Get service.""" + return self._impl.get_service(service_id) + @service.should_be_overridden def create_role(self, name=None, domain_name="Default"): """Create role with specific name @@ -143,10 +199,51 @@ class Identity(service.UnifiedOpenStackService): """Get role.""" return self._impl.get_role(role_id) - @staticmethod - def _unify_service(service): - return Service(id=service.id, name=service.name) + @service.should_be_overridden + def get_service_by_name(self, name): + """List all services to find proper one.""" + return self._impl.get_service_by_name(name) - @staticmethod - def _unify_role(role): - return Role(id=role.id, name=role.name) + @service.should_be_overridden + def create_ec2credentials(self, user_id, project_id): + """Create ec2credentials. + + :param user_id: User ID for which to create credentials + :param project_id: Project ID for which to create credentials + + :returns: Created ec2-credentials object + """ + return self._impl.create_ec2credentials(user_id=user_id, + project_id=project_id) + + @service.should_be_overridden + def list_ec2credentials(self, user_id): + """List of access/secret pairs for a user_id. + + :param user_id: List all ec2-credentials for User ID + + :returns: Return ec2-credentials list + """ + return self._impl.list_ec2credentials(user_id) + + @service.should_be_overridden + def delete_ec2credential(self, user_id, access): + """Delete ec2credential. + + :param user_id: User ID for which to delete credential + :param access: access key for ec2credential to delete + """ + return self._impl.delete_ec2credential(user_id=user_id, access=access) + + @service.should_be_overridden + def fetch_token(self): + """Authenticate user token.""" + return self._impl.fetch_token() + + @service.should_be_overridden + def validate_token(self, token): + """Validate user token. + + :param token: Auth token to validate + """ + return self._impl.validate_token(token) diff --git a/rally/plugins/openstack/services/identity/keystone_common.py b/rally/plugins/openstack/services/identity/keystone_common.py new file mode 100644 index 00000000..49e6b9c7 --- /dev/null +++ b/rally/plugins/openstack/services/identity/keystone_common.py @@ -0,0 +1,192 @@ +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from rally import osclients +from rally.plugins.openstack.services.identity import identity +from rally.task import atomic + + +class UnifiedKeystoneMixin(object): + @staticmethod + def _unify_service(service): + return identity.Service(id=service.id, name=service.name) + + @staticmethod + def _unify_role(role): + return identity.Role(id=role.id, name=role.name) + + def delete_user(self, user_id): + """Deletes user by its id.""" + return self._impl.delete_user(user_id) + + def get_user(self, user_id): + """Get user.""" + return self._unify_user(self._impl.get_user(user_id)) + + def create_service(self, name=None, service_type=None, description=None): + """Creates keystone service.""" + + return self._unify_service(self._impl.create_service( + name=name, service_type=service_type, description=description)) + + def delete_service(self, service_id): + """Deletes service.""" + return self._impl.delete_service(service_id) + + def get_service(self, service_id): + """Get service.""" + return self._unify_service(self._impl.get_service(service_id)) + + def get_service_by_name(self, name): + """List all services to find proper one.""" + return self._unify_service(self._impl.get_service_by_name(name)) + + def get_role(self, role_id): + """Get role.""" + return self._unify_role(self._impl.get_role(role_id)) + + def delete_role(self, role_id): + """Deletes role.""" + return self._impl.delete_role(role_id) + + def list_ec2credentials(self, user_id): + """List of access/secret pairs for a user_id. + + :param user_id: List all ec2-credentials for User ID + + :returns: Return ec2-credentials list + """ + return self._impl.list_ec2credentials(user_id) + + def delete_ec2credential(self, user_id, access): + """Delete ec2credential. + + :param user_id: User ID for which to delete credential + :param access: access key for ec2credential to delete + """ + return self._impl.delete_ec2credential(user_id=user_id, access=access) + + def fetch_token(self): + """Authenticate user token.""" + return self._impl.fetch_token() + + def validate_token(self, token): + """Validate user token. + + :param token: Auth token to validate + """ + return self._impl.validate_token(token) + + +class KeystoneMixin(object): + + def list_users(self): + aname = "keystone_v%s.list_users" % self.version + with atomic.ActionTimer(self, aname): + return self._clients.keystone(self.version).users.list() + + def delete_user(self, user_id): + """Deletes user by its id.""" + aname = "keystone_v%s.delete_user" % self.version + with atomic.ActionTimer(self, aname): + self._clients.keystone(self.version).users.delete(user_id) + + def get_user(self, user_id): + """Get user by its id.""" + aname = "keystone_v%s.get_user" % self.version + with atomic.ActionTimer(self, aname): + return self._clients.keystone(self.version).users.get(user_id) + + def delete_service(self, service_id): + """Deletes service.""" + aname = "keystone_v%s.delete_service" % self.version + with atomic.ActionTimer(self, aname): + self._clients.keystone(self.version).services.delete(service_id) + + def list_services(self): + """List all services.""" + aname = "keystone_v%s.list_services" % self.version + with atomic.ActionTimer(self, aname): + return self._clients.keystone(self.version).services.list() + + def get_service(self, service_id): + """Get service.""" + aname = "keystone_v%s.get_services" % self.version + with atomic.ActionTimer(self, aname): + return self._clients.keystone(self.version).services.get( + service_id) + + def get_service_by_name(self, name): + """List all services to find proper one.""" + for s in self.list_services(): + if s.name == name: + return s + + def delete_role(self, role_id): + """Deletes role.""" + aname = "keystone_v%s.delete_role" % self.version + with atomic.ActionTimer(self, aname): + self._clients.keystone(self.version).roles.delete(role_id) + + def list_roles(self): + """List all roles.""" + aname = "keystone_v%s.list_roles" % self.version + with atomic.ActionTimer(self, aname): + return self._clients.keystone(self.version).roles.list() + + def get_role(self, role_id): + """Get role.""" + aname = "keystone_v%s.get_role" % self.version + with atomic.ActionTimer(self, aname): + return self._clients.keystone(self.version).roles.get(role_id) + + def list_ec2credentials(self, user_id): + """List of access/secret pairs for a user_id. + + :param user_id: List all ec2-credentials for User ID + + :returns: Return ec2-credentials list + """ + aname = "keystone_v%s.list_ec2creds" % self.version + with atomic.ActionTimer(self, aname): + return self._clients.keystone(self.version).ec2.list(user_id) + + def delete_ec2credential(self, user_id, access): + """Delete ec2credential. + + :param user_id: User ID for which to delete credential + :param access: access key for ec2credential to delete + """ + aname = "keystone_v%s.delete_ec2creds" % self.version + with atomic.ActionTimer(self, aname): + self._clients.keystone(self.version).ec2.delete(user_id=user_id, + access=access) + + def fetch_token(self): + """Authenticate user token.""" + cred = self._clients.credential + aname = "keystone_v%s.fetch_token" % self.version + with atomic.ActionTimer(self, aname): + clients = osclients.Clients(credential=cred, + api_info=self._clients.api_info) + return clients.keystone.auth_ref.auth_token + + def validate_token(self, token): + """Validate user token. + + :param token: Auth token to validate + """ + aname = "keystone_v%s.validate_token" % self.version + with atomic.ActionTimer(self, aname): + self._clients.keystone(self.version).tokens.validate(token) diff --git a/rally/plugins/openstack/services/identity/keystone_v2.py b/rally/plugins/openstack/services/identity/keystone_v2.py index 557ebf35..0c653015 100644 --- a/rally/plugins/openstack/services/identity/keystone_v2.py +++ b/rally/plugins/openstack/services/identity/keystone_v2.py @@ -12,19 +12,41 @@ # License for the specific language governing permissions and limitations # under the License. +import uuid + from rally.plugins.openstack import service from rally.plugins.openstack.services.identity import identity +from rally.plugins.openstack.services.identity import keystone_common from rally.task import atomic @service.service("keystone", service_type="identity", version="2") -class KeystoneV2Service(service.Service): +class KeystoneV2Service(service.Service, keystone_common.KeystoneMixin): @atomic.action_timer("keystone_v2.create_tenant") def create_tenant(self, tenant_name=None): tenant_name = tenant_name or self.generate_random_name() return self._clients.keystone("2").tenants.create(tenant_name) + @atomic.action_timer("keystone_v2.update_tenant") + def update_tenant(self, tenant_id, name=None, enabled=None, + description=None): + """Update tenant name and description. + + :param tenant_id: Id of tenant to update + :param name: tenant name to be set (if boolean True, random name will + be set) + :param enabled: enabled status of project + :param description: tenant description to be set (if boolean True, + random description will be set) + """ + if name is True: + name = self.generate_random_name() + if description is True: + description = self.generate_random_name() + self._clients.keystone("2").tenants.update( + tenant_id, name=name, description=description, enabled=enabled) + @atomic.action_timer("keystone_v2.delete_tenant") def delete_tenant(self, tenant_id): return self._clients.keystone("2").tenants.delete(tenant_id) @@ -33,31 +55,69 @@ class KeystoneV2Service(service.Service): def list_tenants(self): return self._clients.keystone("2").tenants.list() + @atomic.action_timer("keystone_v2.get_tenant") + def get_tenant(self, tenant_id): + """Get tenant.""" + return self._clients.keystone("2").tenants.get(tenant_id) + @atomic.action_timer("keystone_v2.create_user") - def create_user(self, username, password, email=None, tenant_id=None): + def create_user(self, username=None, password=None, email=None, + tenant_id=None, enabled=True): + username = username or self.generate_random_name() + password = password or str(uuid.uuid4()) + email = email or (username + "@rally.me") return self._clients.keystone("2").users.create(name=username, password=password, email=email, - tenant_id=tenant_id) + tenant_id=tenant_id, + enabled=enabled) - @atomic.action_timer("keystone_v2.list_users") - def list_users(self): - return self._clients.keystone("2").users.list() + @atomic.action_timer("keystone_v2.create_users") + def create_users(self, tenant_id, number_of_users, user_create_args=None): + """Create specified amount of users. - @atomic.action_timer("keystone_v2.delete_user") - def delete_user(self, user_id): - """Deletes user by its id.""" - self._clients.keystone("2").users.delete(user_id) + :param tenant_id: Id of tenant + :param number_of_users: number of users to create + :param user_create_args: additional user creation arguments + """ + users = [] + for _i in range(number_of_users): + users.append(self.create_user(tenant_id=tenant_id, + **(user_create_args or {}))) + return users - @atomic.action_timer("keystone_v2.delete_service") - def delete_service(self, service_id): - """Deletes service.""" - self._clients.keystone("2").services.delete(service_id) + @atomic.action_timer("keystone_v2.update_user") + def update_user(self, user_id, **kwargs): + allowed_args = ("name", "email", "enabled") + restricted = set(kwargs) - set(allowed_args) + if restricted: + raise NotImplementedError( + "Failed to update '%s', since Keystone V2 allows to update " + "only '%s'." % ("', '".join(restricted), + "', '".join(allowed_args))) + self._clients.keystone("2").users.update(user_id, **kwargs) - @atomic.action_timer("keystone.list_services") - def list_services(self): - """List all services.""" - return self._clients.keystone("2").services.list() + @atomic.action_timer("keystone_v2.update_user_password") + def update_user_password(self, user_id, password): + self._clients.keystone("2").users.update_password(user_id, + password=password) + + @atomic.action_timer("keystone_v2.create_service") + def create_service(self, name=None, service_type=None, description=None): + """Creates keystone service. + + :param name: name of service to create + :param service_type: type of the service + :param description: description of the service + :returns: keystone service instance + """ + name = name or self.generate_random_name() + service_type = service_type or "rally_test_type" + description = description or self.generate_random_name() + return self._clients.keystone("2").services.create( + name, + service_type=service_type, + description=description) @atomic.action_timer("keystone_v2.create_role") def create_role(self, name=None): @@ -66,14 +126,9 @@ class KeystoneV2Service(service.Service): @atomic.action_timer("keystone_v2.add_role") def add_role(self, role_id, user_id, tenant_id): - return self._clients.keystone("2").roles.add_user_role( + self._clients.keystone("2").roles.add_user_role( user=user_id, role=role_id, tenant=tenant_id) - @atomic.action_timer("keystone.delete_role") - def delete_role(self, role_id): - """Deletes role.""" - self._clients.keystone("2").roles.delete(role_id) - @atomic.action_timer("keystone_v2.list_roles") def list_roles(self): """List all roles.""" @@ -90,14 +145,22 @@ class KeystoneV2Service(service.Service): role=role_id, tenant=tenant_id) - @atomic.action_timer("keystone_v2.get_role") - def get_role(self, role_id): - """Get role.""" - return self._clients.keystone("2").roles.get(role_id) + @atomic.action_timer("keystone_v2.create_ec2creds") + def create_ec2credentials(self, user_id, tenant_id): + """Create ec2credentials. + + :param user_id: User ID for which to create credentials + :param tenant_id: Tenant ID for which to create credentials + + :returns: Created ec2-credentials object + """ + return self._clients.keystone("2").ec2.create(user_id, + tenant_id=tenant_id) @service.compat_layer(KeystoneV2Service) -class UnifiedKeystoneV2Service(identity.Identity): +class UnifiedKeystoneV2Service(keystone_common.UnifiedKeystoneMixin, + identity.Identity): """Compatibility layer for Keystone V2.""" @staticmethod @@ -128,6 +191,18 @@ class UnifiedKeystoneV2Service(identity.Identity): tenant = self._impl.create_tenant(project_name) return self._unify_tenant(tenant) + def update_project(self, project_id, name=None, enabled=None, + description=None): + """Update project name, enabled and description + + :param project_id: Id of project to update + :param name: project name to be set + :param enabled: enabled status of project + :param description: project description to be set + """ + self._impl.update_tenant(tenant_id=project_id, name=name, + enabled=enabled, description=description) + def delete_project(self, project_id): """Deletes project.""" return self._impl.delete_tenant(project_id) @@ -136,37 +211,64 @@ class UnifiedKeystoneV2Service(identity.Identity): """List all projects.""" return [self._unify_tenant(t) for t in self._impl.list_tenants()] - def create_user(self, username, password, email=None, project_id=None, - domain_name="Default", default_role="member"): + def get_project(self, project_id): + """Get project.""" + return self._unify_tenant(self._impl.get_tenant(project_id)) + + def create_user(self, username=None, password=None, project_id=None, + domain_name="Default", enabled=True, + default_role="member"): """Create user. :param username: name of user :param password: user password - :param email: user's email :param project_id: user's default project :param domain_name: Restricted for Keystone V2. Should not be set or "Default" is expected. + :param enabled: whether the user is enabled. :param default_role: Restricted for Keystone V2. Should not be set or "member" is expected. """ self._check_domain(domain_name) user = self._impl.create_user(username=username, password=password, - email=email, - tenant_id=project_id) + tenant_id=project_id, + enabled=enabled) return self._unify_user(user) - def delete_user(self, user_id): - """Deletes user by its id.""" - return self._impl.delete_user(user_id) + def create_users(self, tenant_id, number_of_users, user_create_args=None): + """Create specified amount of users. + + :param tenant_id: Id of tenant + :param number_of_users: number of users to create + :param user_create_args: additional user creation arguments + """ + if user_create_args and "domain_name" in user_create_args: + self._check_domain(user_create_args["domain_name"]) + return [self._unify_user(u) + for u in self._impl.create_users( + tenant_id=tenant_id, number_of_users=number_of_users, + user_create_args=user_create_args)] def list_users(self): """List all users.""" return [self._unify_user(u) for u in self._impl.list_users()] - def delete_service(self, service_id): - """Deletes service.""" - return self._impl.delete_service(service_id) + def update_user(self, user_id, enabled=None, name=None, email=None, + password=None): + if password is not None: + self._impl.update_user_password(user_id=user_id, password=password) + + update_args = {} + if enabled is not None: + update_args["enabled"] = enabled + if name is not None: + update_args["name"] = name + if email is not None: + update_args["email"] = email + + if update_args: + self._impl.update_user(user_id, **update_args) def list_services(self): """List all services.""" @@ -179,12 +281,8 @@ class UnifiedKeystoneV2Service(identity.Identity): def add_role(self, role_id, user_id, project_id): """Add role to user.""" - return self._unify_role(self._impl.add_role( - role_id=role_id, user_id=user_id, tenant_id=project_id)) - - def delete_role(self, role_id): - """Deletes role.""" - return self._impl.delete_role(role_id) + self._impl.add_role(role_id=role_id, user_id=user_id, + tenant_id=project_id) def revoke_role(self, role_id, user_id, project_id): """Revokes a role from a user.""" @@ -203,6 +301,13 @@ class UnifiedKeystoneV2Service(identity.Identity): roles = self._impl.list_roles() return [self._unify_role(role) for role in roles] - def get_role(self, role_id): - """Get role.""" - return self._unify_role(self._impl.get_role(role_id)) + def create_ec2credentials(self, user_id, project_id): + """Create ec2credentials. + + :param user_id: User ID for which to create credentials + :param project_id: Project ID for which to create credentials + + :returns: Created ec2-credentials object + """ + return self._impl.create_ec2credentials(user_id=user_id, + tenant_id=project_id) diff --git a/rally/plugins/openstack/services/identity/keystone_v3.py b/rally/plugins/openstack/services/identity/keystone_v3.py index f456e0b8..07382338 100644 --- a/rally/plugins/openstack/services/identity/keystone_v3.py +++ b/rally/plugins/openstack/services/identity/keystone_v3.py @@ -16,6 +16,7 @@ from rally.common import logging from rally import exceptions from rally.plugins.openstack import service from rally.plugins.openstack.services.identity import identity +from rally.plugins.openstack.services.identity import keystone_common from rally.task import atomic @@ -23,7 +24,7 @@ LOG = logging.getLogger(__name__) @service.service("keystone", service_type="identity", version="3") -class KeystoneV3Service(service.Service): +class KeystoneV3Service(service.Service, keystone_common.KeystoneMixin): def _get_domain_id(self, domain_name_or_id): from keystoneclient import exceptions as kc_exceptions @@ -49,6 +50,25 @@ class KeystoneV3Service(service.Service): return self._clients.keystone("3").projects.create(name=project_name, domain=domain_id) + @atomic.action_timer("keystone_v3.update_project") + def update_project(self, project_id, name=None, enabled=None, + description=None): + """Update tenant name and description. + + :param project_id: Id of project to update + :param name: project name to be set (if boolean True, random name will + be set) + :param enabled: enabled status of project + :param description: project description to be set (if boolean True, + random description will be set) + """ + if name is True: + name = self.generate_random_name() + if description is True: + description = self.generate_random_name() + self._clients.keystone("3").projects.update( + project_id, name=name, description=description, enabled=enabled) + @atomic.action_timer("keystone_v3.delete_project") def delete_project(self, project_id): self._clients.keystone("3").projects.delete(project_id) @@ -57,52 +77,87 @@ class KeystoneV3Service(service.Service): def list_projects(self): return self._clients.keystone("3").projects.list() + @atomic.action_timer("keystone_v3.get_project") + def get_project(self, project_id): + """Get project.""" + return self._clients.keystone("3").projects.get(project_id) + @atomic.action_timer("keystone_v3.create_user") - def create_user(self, username, password, email=None, project_id=None, - domain_name="Default", default_role="member"): + def create_user(self, username=None, password=None, project_id=None, + domain_name="Default", enabled=True, + default_role="member"): """Create user. :param username: name of user :param password: user password - :param email: user'ss email :param project_id: user's default project :param domain_name: Name or id of domain where to create project. + :param enabled: whether the user is enabled. :param default_role: user's default role """ domain_id = self._get_domain_id(domain_name) + username = username or self.generate_random_name() user = self._clients.keystone("3").users.create( name=username, password=password, default_project=project_id, - email=email, domain=domain_id) - for role in self.list_roles(): - if default_role in role.name.lower(): - self.add_role(role_id=role.id, - user_id=user.id, - project_id=project_id) - break - else: - LOG.warning("Unable to set %s role to created user." % - default_role) + domain=domain_id, enabled=enabled) + + if project_id: + # we can't setup role without project_id + for role in self.list_roles(): + if default_role in role.name.lower(): + self.add_role(role_id=role.id, + user_id=user.id, + project_id=project_id) + break + else: + LOG.warning("Unable to set %s role to created user." % + default_role) return user - @atomic.action_timer("keystone_v3.list_users") - def list_users(self): - return self._clients.keystone("3").users.list() + @atomic.action_timer("keystone_v3.create_users") + def create_users(self, project_id, number_of_users, user_create_args=None): + """Create specified amount of users. - @atomic.action_timer("keystone_v3.delete_user") - def delete_user(self, user_id): - """Deletes user by its id.""" - self._clients.keystone("3").users.delete(user_id) + :param project_id: Id of project + :param number_of_users: number of users to create + :param user_create_args: additional user creation arguments + """ + users = [] + for _i in range(number_of_users): + users.append(self.create_user(project_id=project_id, + **(user_create_args or {}))) + return users - @atomic.action_timer("keystone_v3.delete_service") - def delete_service(self, service_id): - """Deletes service.""" - self._clients.keystone("3").services.delete(service_id) + @atomic.action_timer("keystone_v3.update_user") + def update_user(self, user_id, name=None, domain_name=None, + project_id=None, password=None, email=None, + description=None, enabled=None, default_project=None): + domain = None + if domain_name: + domain = self._get_domain_id(domain_name) - @atomic.action_timer("keystone_v3.list_services") - def list_services(self): - """List all services.""" - return self._clients.keystone("3").services.list() + self._clients.keystone("3").users.update( + user_id, name=name, domain=domain, project=project_id, + password=password, email=email, description=description, + enabled=enabled, default_project=default_project) + + @atomic.action_timer("keystone_v3.create_service") + def create_service(self, name=None, service_type=None, description=None, + enabled=True): + """Creates keystone service. + + :param name: name of service to create + :param service_type: type of the service + :param description: description of the service + :param enabled: whether the service appears in the catalog + :returns: keystone service instance + """ + name = name or self.generate_random_name() + service_type = service_type or "rally_test_type" + description = description or self.generate_random_name() + return self._clients.keystone("3").services.create( + name, type=service_type, description=description, enabled=enabled) @atomic.action_timer("keystone_v3.create_role") def create_role(self, name=None, domain_name="Default"): @@ -112,14 +167,9 @@ class KeystoneV3Service(service.Service): @atomic.action_timer("keystone_v3.add_role") def add_role(self, role_id, user_id, project_id): - return self._clients.keystone("3").roles.grant(role=role_id, - user=user_id, - project=project_id) - - @atomic.action_timer("keystone_v3.delete_role") - def delete_role(self, role_id): - """Deletes role.""" - self._clients.keystone("3").roles.delete(role_id) + self._clients.keystone("3").roles.grant(role=role_id, + user=user_id, + project=project_id) @atomic.action_timer("keystone_v3.list_roles") def list_roles(self, user_id=None, project_id=None, domain_name=None): @@ -137,19 +187,27 @@ class KeystoneV3Service(service.Service): user=user_id, project=project_id) - @atomic.action_timer("keystone_v3.get_role") - def get_role(self, role_id): - """Get role.""" - return self._clients.keystone("3").roles.get(role_id) - @atomic.action_timer("keystone_v3.create_domain") def create_domain(self, name, description=None, enabled=True): return self._clients.keystone("3").domains.create( name, description=description, enabled=enabled) + @atomic.action_timer("keystone_v3.create_ec2creds") + def create_ec2credentials(self, user_id, project_id): + """Create ec2credentials. + + :param user_id: User ID for which to create credentials + :param project_id: Tenant ID for which to create credentials + + :returns: Created ec2-credentials object + """ + return self._clients.keystone("3").ec2.create(user_id, + project_id=project_id) + @service.compat_layer(KeystoneV3Service) -class UnifiedKeystoneV3Service(identity.Identity): +class UnifiedKeystoneV3Service(keystone_common.UnifiedKeystoneMixin, + identity.Identity): @staticmethod def _unify_project(project): @@ -160,7 +218,8 @@ class UnifiedKeystoneV3Service(identity.Identity): def _unify_user(user): # When user has default_project_id that is None user.default_project_id # will raise AttributeError - project_id = getattr(user, "default_project_id", None) + project_id = getattr(user, "project_id", + getattr(user, "default_project_id", None)) return identity.User(id=user.id, name=user.name, project_id=project_id, domain_id=user.domain_id) @@ -173,6 +232,18 @@ class UnifiedKeystoneV3Service(identity.Identity): project = self._impl.create_project(project_name) return self._unify_project(project) + def update_project(self, project_id, name=None, enabled=None, + description=None): + """Update project name, enabled and description + + :param project_id: Id of project to update + :param name: project name to be set + :param enabled: enabled status of project + :param description: project description to be set + """ + self._impl.update_project(project_id=project_id, name=name, + enabled=enabled, description=description) + def delete_project(self, project_id): """Deletes project.""" return self._impl.delete_project(project_id) @@ -181,33 +252,47 @@ class UnifiedKeystoneV3Service(identity.Identity): """List all projects.""" return [self._unify_project(p) for p in self._impl.list_projects()] - def create_user(self, username, password, email=None, project_id=None, - domain_name="Default", default_role="member"): + def get_project(self, project_id): + """Get project.""" + return self._unify_project(self._impl.get_project(project_id)) + + def create_user(self, username=None, password=None, project_id=None, + domain_name="Default", enabled=True, + default_role="member"): """Create user. :param username: name of user :param password: user password - :param email: user's email :param project_id: user's default project :param domain_name: Name or id of domain where to create project, + :param enabled: whether the user is enabled. :param default_role: Name of default user's role """ return self._unify_user(self._impl.create_user( - username=username, password=password, email=email, - project_id=project_id, domain_name=domain_name, - default_role=default_role)) + username=username, password=password, project_id=project_id, + domain_name=domain_name, default_role=default_role, + enabled=enabled)) - def delete_user(self, user_id): - """Deletes user by its id.""" - return self._impl.delete_user(user_id) + def create_users(self, project_id, number_of_users, user_create_args=None): + """Create specified amount of users. + + :param project_id: Id of project + :param number_of_users: number of users to create + :param user_create_args: additional user creation arguments + """ + return [self._unify_user(u) + for u in self._impl.create_users( + project_id=project_id, number_of_users=number_of_users, + user_create_args=user_create_args)] def list_users(self): """List all users.""" return [self._unify_user(u) for u in self._impl.list_users()] - def delete_service(self, service_id): - """Deletes service.""" - return self._impl.delete_service(service_id) + def update_user(self, user_id, enabled=None, name=None, email=None, + password=None): + return self._impl.update_user(user_id, enabled=enabled, name=name, + email=email, password=password) def list_services(self): """List all services.""" @@ -220,12 +305,8 @@ class UnifiedKeystoneV3Service(identity.Identity): def add_role(self, role_id, user_id, project_id): """Add role to user.""" - return self._unify_role(self._impl.add_role( - role_id=role_id, user_id=user_id, project_id=project_id)) - - def delete_role(self, role_id): - """Deletes role.""" - return self._impl.delete_role(role_id) + self._impl.add_role(role_id=role_id, user_id=user_id, + project_id=project_id) def revoke_role(self, role_id, user_id, project_id): """Revokes a role from a user.""" @@ -237,6 +318,13 @@ class UnifiedKeystoneV3Service(identity.Identity): return [self._unify_role(role) for role in self._impl.list_roles( user_id=user_id, project_id=project_id, domain_name=domain_name)] - def get_role(self, role_id): - """Get role.""" - return self._unify_role(self._impl.get_role(role_id)) + def create_ec2credentials(self, user_id, project_id): + """Create ec2credentials. + + :param user_id: User ID for which to create credentials + :param project_id: Project ID for which to create credentials + + :returns: Created ec2-credentials object + """ + return self._impl.create_ec2credentials(user_id=user_id, + project_id=project_id) diff --git a/tests/unit/plugins/openstack/scenarios/ceilometer/test_events.py b/tests/unit/plugins/openstack/scenarios/ceilometer/test_events.py index 99a8a179..8ff74d4b 100644 --- a/tests/unit/plugins/openstack/scenarios/ceilometer/test_events.py +++ b/tests/unit/plugins/openstack/scenarios/ceilometer/test_events.py @@ -21,23 +21,38 @@ from tests.unit import test class CeilometerEventsTestCase(test.ScenarioTestCase): + def setUp(self): + super(CeilometerEventsTestCase, self).setUp() + patch = mock.patch( + "rally.plugins.openstack.services.identity.identity.Identity") + self.addCleanup(patch.stop) + self.mock_identity = patch.start() + + def get_test_context(self): + context = super(CeilometerEventsTestCase, self).get_test_context() + context["admin"] = {"id": "fake_user_id", + "credential": mock.MagicMock() + } + return context + def test_list_events(self): scenario = events.CeilometerEventsCreateUserAndListEvents(self.context) - scenario._user_create = mock.MagicMock() scenario._list_events = mock.MagicMock() + scenario.run() - scenario._user_create.assert_called_once_with() + + self.mock_identity.return_value.create_user.assert_called_once_with() scenario._list_events.assert_called_once_with() def test_list_events_fails(self): scenario = events.CeilometerEventsCreateUserAndListEvents(self.context) - scenario._user_create = mock.MagicMock() scenario._list_events = mock.MagicMock(return_value=[]) self.assertRaises(exceptions.RallyException, scenario.run) - scenario._user_create.assert_called_once_with() + + self.mock_identity.return_value.create_user.assert_called_once_with() scenario._list_events.assert_called_once_with() def test_list_event_types(self): @@ -45,43 +60,44 @@ class CeilometerEventsTestCase(test.ScenarioTestCase): self.context) scenario._list_event_types = mock.MagicMock() - scenario._user_create = mock.MagicMock() + scenario.run() - scenario._user_create.assert_called_once_with() + + self.mock_identity.return_value.create_user.assert_called_once_with() scenario._list_event_types.assert_called_once_with() def test_list_event_types_fails(self): scenario = events.CeilometerEventsCreateUserAndListEventTypes( self.context) - scenario._user_create = mock.MagicMock() scenario._list_event_types = mock.MagicMock(return_value=[]) self.assertRaises(exceptions.RallyException, scenario.run) - scenario._user_create.assert_called_once_with() + + self.mock_identity.return_value.create_user.assert_called_once_with() scenario._list_event_types.assert_called_once_with() def test_get_event(self): scenario = events.CeilometerEventsCreateUserAndGetEvent(self.context) - scenario._user_create = mock.MagicMock() - scenario._list_events = mock.MagicMock() scenario._get_event = mock.MagicMock() - scenario._list_events.return_value = [mock.Mock(message_id="fake_id")] + scenario._list_events = mock.MagicMock( + return_value=[mock.Mock(message_id="fake_id")]) + scenario.run() - scenario._user_create.assert_called_once_with() + + self.mock_identity.return_value.create_user.assert_called_once_with() scenario._list_events.assert_called_with() scenario._get_event.assert_called_with(event_id="fake_id") def test_get_event_fails(self): scenario = events.CeilometerEventsCreateUserAndGetEvent(self.context) - scenario._user_create = mock.MagicMock() scenario._list_events = mock.MagicMock(return_value=[]) scenario._get_event = mock.MagicMock() self.assertRaises(exceptions.RallyException, scenario.run) - scenario._user_create.assert_called_once_with() + self.mock_identity.return_value.create_user.assert_called_once_with() scenario._list_events.assert_called_with() self.assertFalse(scenario._get_event.called) diff --git a/tests/unit/plugins/openstack/scenarios/ceilometer/test_traits.py b/tests/unit/plugins/openstack/scenarios/ceilometer/test_traits.py index 20c81e0c..35344da6 100644 --- a/tests/unit/plugins/openstack/scenarios/ceilometer/test_traits.py +++ b/tests/unit/plugins/openstack/scenarios/ceilometer/test_traits.py @@ -20,18 +20,33 @@ from tests.unit import test class CeilometerTraitsTestCase(test.ScenarioTestCase): + def setUp(self): + super(CeilometerTraitsTestCase, self).setUp() + patch = mock.patch( + "rally.plugins.openstack.services.identity.identity.Identity") + self.addCleanup(patch.stop) + self.mock_identity = patch.start() + + def get_test_context(self): + context = super(CeilometerTraitsTestCase, self).get_test_context() + context["admin"] = {"id": "fake_user_id", + "credential": mock.MagicMock() + } + return context + def test_list_traits(self): scenario = traits.CreateUserAndListTraits(self.context) - scenario._user_create = mock.MagicMock() - scenario._list_events = mock.MagicMock() scenario._list_event_traits = mock.MagicMock() - scenario._list_events.return_value = [mock.Mock( - event_type="fake_event_type", - traits=[{"name": "fake_trait_name"}]) - ] + scenario._list_events = mock.MagicMock( + return_value=[mock.Mock( + event_type="fake_event_type", + traits=[{"name": "fake_trait_name"}]) + ]) + scenario.run() - scenario._user_create.assert_called_once_with() + + self.mock_identity.return_value.create_user.assert_called_once_with() scenario._list_events.assert_called_with() scenario._list_event_traits.assert_called_once_with( event_type="fake_event_type", trait_name="fake_trait_name") @@ -40,14 +55,15 @@ class CeilometerTraitsTestCase(test.ScenarioTestCase): scenario = traits.CreateUserAndListTraitDescriptions( self.context) - scenario._user_create = mock.MagicMock() - scenario._list_events = mock.MagicMock() scenario._list_event_trait_descriptions = mock.MagicMock() - scenario._list_events.return_value = [mock.Mock( - event_type="fake_event_type") - ] + scenario._list_events = mock.MagicMock( + return_value=[mock.Mock( + event_type="fake_event_type") + ]) + scenario.run() - scenario._user_create.assert_called_once_with() + + self.mock_identity.return_value.create_user.assert_called_once_with() scenario._list_events.assert_called_with() scenario._list_event_trait_descriptions.assert_called_once_with( event_type="fake_event_type") diff --git a/tests/unit/plugins/openstack/scenarios/keystone/test_basic.py b/tests/unit/plugins/openstack/scenarios/keystone/test_basic.py index 0e11d671..0774f4e9 100755 --- a/tests/unit/plugins/openstack/scenarios/keystone/test_basic.py +++ b/tests/unit/plugins/openstack/scenarios/keystone/test_basic.py @@ -48,88 +48,91 @@ class KeystoneBasicTestCase(test.ScenarioTestCase): def test_create_user(self): scenario = basic.CreateUser(self.context) - scenario._user_create = mock.MagicMock() - scenario.run(password="tttt", tenant_id="id") - scenario._user_create.assert_called_once_with(password="tttt", - tenant_id="id") + + scenario.run(password="tttt", project_id="id") + self.mock_identity.return_value.create_user.assert_called_once_with( + password="tttt", project_id="id") def test_create_delete_user(self): - create_result = mock.MagicMock() + identity_service = self.mock_identity.return_value + + fake_email = "abcd" + fake_user = identity_service.create_user.return_value scenario = basic.CreateDeleteUser(self.context) - scenario._user_create = mock.MagicMock(return_value=create_result) - scenario._resource_delete = mock.MagicMock() - scenario.run(email="abcd", enabled=True) + scenario.run(email=fake_email, enabled=True) - scenario._user_create.assert_called_once_with(email="abcd", - enabled=True) - scenario._resource_delete.assert_called_once_with(create_result) + identity_service.create_user.assert_called_once_with( + email=fake_email, enabled=True) + identity_service.delete_user.assert_called_once_with(fake_user.id) def test_create_user_set_enabled_and_delete(self): - scenario = basic.CreateUserSetEnabledAndDelete(self.context) - scenario._user_create = mock.Mock() - scenario._update_user_enabled = mock.Mock() - scenario._resource_delete = mock.Mock() + identity_service = self.mock_identity.return_value - scenario.run(enabled=True, email="abcd") - scenario._user_create.assert_called_once_with(email="abcd", - enabled=True) - scenario._update_user_enabled.assert_called_once_with( - scenario._user_create.return_value, False) - scenario._resource_delete.assert_called_once_with( - scenario._user_create.return_value) + scenario = basic.CreateUserSetEnabledAndDelete(self.context) + + fake_email = "abcd" + fake_user = identity_service.create_user.return_value + scenario.run(enabled=True, email=fake_email) + + identity_service.create_user.assert_called_once_with( + email=fake_email, enabled=True) + identity_service.update_user.assert_called_once_with( + fake_user.id, enabled=False) + identity_service.delete_user.assert_called_once_with(fake_user.id) def test_user_authenticate_and_validate_token(self): - fake_token = mock.MagicMock() - context = self.context - scenario = basic.AuthenticateUserAndValidateToken(context) + identity_service = self.mock_identity.return_value + scenario = basic.AuthenticateUserAndValidateToken(self.context) - fake_user = context["user"]["credential"].username - fake_paswd = context["user"]["credential"].password - fake_tenant_id = context["tenant"]["id"] - fake_tenant_name = context["tenant"]["name"] + fake_token = identity_service.fetch_token.return_value - scenario._authenticate_token = mock.MagicMock(return_value=fake_token) - scenario._token_validate = mock.MagicMock() scenario.run() - scenario._authenticate_token.assert_called_once_with( - fake_user, fake_paswd, fake_tenant_id, - fake_tenant_name, atomic_action=False) - scenario._token_validate.assert_called_once_with(fake_token.id) + + identity_service.fetch_token.assert_called_once_with() + identity_service.validate_token.assert_called_once_with(fake_token) def test_create_tenant(self): scenario = basic.CreateTenant(self.context) - scenario._tenant_create = mock.MagicMock() + scenario.run(enabled=True) - scenario._tenant_create.assert_called_once_with(enabled=True) + + self.mock_identity.return_value.create_project.assert_called_once_with( + enabled=True) def test_create_tenant_with_users(self): + identity_service = self.mock_identity.return_value + + fake_project = identity_service.create_project.return_value + number_of_users = 1 + scenario = basic.CreateTenantWithUsers(self.context) - fake_tenant = mock.MagicMock() - scenario._tenant_create = mock.MagicMock(return_value=fake_tenant) - scenario._users_create = mock.MagicMock() - scenario.run(users_per_tenant=1, enabled=True) - scenario._tenant_create.assert_called_once_with(enabled=True) - scenario._users_create.assert_called_once_with(fake_tenant, - users_per_tenant=1) + + scenario.run(users_per_tenant=number_of_users, enabled=True) + + identity_service.create_project.assert_called_once_with(enabled=True) + identity_service.create_users.assert_called_once_with( + fake_project.id, number_of_users=number_of_users) def test_create_and_list_users(self): scenario = basic.CreateAndListUsers(self.context) - scenario._user_create = mock.MagicMock() - scenario._list_users = mock.MagicMock() - scenario.run(password="tttt", tenant_id="id") - scenario._user_create.assert_called_once_with(password="tttt", - tenant_id="id") - scenario._list_users.assert_called_once_with() + + passwd = "tttt" + project_id = "id" + + scenario.run(password=passwd, project_id=project_id) + self.mock_identity.return_value.create_user.assert_called_once_with( + password=passwd, project_id=project_id) + self.mock_identity.return_value.list_users.assert_called_once_with() def test_create_and_list_tenants(self): + identity_service = self.mock_identity.return_value scenario = basic.CreateAndListTenants(self.context) - scenario._tenant_create = mock.MagicMock() - scenario._list_tenants = mock.MagicMock() + scenario.run(enabled=True) - scenario._tenant_create.assert_called_once_with(enabled=True) - scenario._list_tenants.assert_called_with() + identity_service.create_project.assert_called_once_with(enabled=True) + identity_service.list_projects.assert_called_once_with() def test_assign_and_remove_user_role(self): fake_tenant = self.context["tenant"]["id"] @@ -187,116 +190,127 @@ class KeystoneBasicTestCase(test.ScenarioTestCase): @ddt.data(None, "keystone", "fooservice") def test_get_entities(self, service_name): - fake_tenant = mock.MagicMock() - fake_user = mock.MagicMock() - fake_role = mock.MagicMock() - fake_service = mock.MagicMock() + identity_service = self.mock_identity.return_value - self.mock_identity.return_value.create_role.return_value = fake_role + fake_project = identity_service.create_project.return_value + fake_user = identity_service.create_user.return_value + fake_role = identity_service.create_role.return_value + fake_service = identity_service.create_service.return_value scenario = basic.GetEntities(self.context) - scenario._tenant_create = mock.MagicMock(return_value=fake_tenant) - scenario._user_create = mock.MagicMock(return_value=fake_user) - - scenario._service_create = mock.MagicMock(return_value=fake_service) - - scenario._get_tenant = mock.MagicMock(return_value=fake_tenant) - scenario._get_user = mock.MagicMock(return_value=fake_user) - scenario._get_role = mock.MagicMock(return_value=fake_role) - scenario._get_service_by_name = mock.MagicMock( - return_value=fake_service) - scenario._get_service = mock.MagicMock(return_value=fake_service) - scenario.run(service_name) - scenario._tenant_create.assert_called_once_with() - scenario._user_create.assert_called_once_with() - self.mock_identity.return_value.create_role.assert_called_once_with() + identity_service.create_project.assert_called_once_with() + identity_service.create_user.assert_called_once_with( + project_id=fake_project.id) + identity_service.create_role.assert_called_once_with() - scenario._get_tenant.assert_called_once_with(fake_tenant.id) - scenario._get_user.assert_called_once_with(fake_user.id) - scenario._get_role.assert_called_once_with(fake_role.id) + identity_service.get_project.assert_called_once_with(fake_project.id) + identity_service.get_user.assert_called_once_with(fake_user.id) + identity_service.get_role.assert_called_once_with(fake_role.id) if service_name is None: - scenario._service_create.assert_called_once_with() - self.assertFalse(scenario._get_service_by_name.called) + identity_service.create_service.assert_called_once_with() + self.assertFalse(identity_service.get_service_by_name.called) + identity_service.get_service.assert_called_once_with( + fake_service.id) else: - scenario._get_service_by_name.assert_called_once_with(service_name) - self.assertFalse(scenario._service_create.called) - scenario._get_service.assert_called_once_with(fake_service.id) + identity_service.get_service_by_name.assert_called_once_with( + service_name) + self.assertFalse(identity_service.create_service.called) + identity_service.get_service.assert_called_once_with( + identity_service.get_service_by_name.return_value.id) def test_create_and_delete_service(self): + identity_service = self.mock_identity.return_value scenario = basic.CreateAndDeleteService(self.context) + service_type = "test_service_type" description = "test_description" - fake_service = mock.MagicMock() - scenario._service_create = mock.MagicMock(return_value=fake_service) - scenario._delete_service = mock.MagicMock() + fake_service = identity_service.create_service.return_value + scenario.run(service_type=service_type, description=description) - scenario._service_create.assert_called_once_with(service_type, - description) - scenario._delete_service.assert_called_once_with(fake_service.id) + + identity_service.create_service.assert_called_once_with( + service_type=service_type, description=description) + identity_service.delete_service.assert_called_once_with( + fake_service.id) def test_create_update_and_delete_tenant(self): + identity_service = self.mock_identity.return_value + scenario = basic.CreateUpdateAndDeleteTenant(self.context) - fake_tenant = mock.MagicMock() - scenario._tenant_create = mock.MagicMock(return_value=fake_tenant) - scenario._update_tenant = mock.MagicMock() - scenario._resource_delete = mock.MagicMock() + + gen_name = mock.MagicMock() + basic.CreateUpdateAndDeleteTenant.generate_random_name = gen_name + fake_project = identity_service.create_project.return_value + scenario.run() - scenario._update_tenant.assert_called_once_with(fake_tenant) - scenario._resource_delete.assert_called_once_with(fake_tenant) + + identity_service.create_project.assert_called_once_with() + identity_service.update_project.assert_called_once_with( + fake_project.id, description=gen_name.return_value, + name=gen_name.return_value) + identity_service.delete_project(fake_project.id) def test_create_user_update_password(self): + identity_service = self.mock_identity.return_value + scenario = basic.CreateUserUpdatePassword(self.context) + fake_password = "pswd" - fake_user = mock.MagicMock() - scenario._user_create = mock.MagicMock(return_value=fake_user) + fake_user = identity_service.create_user.return_value scenario.generate_random_name = mock.MagicMock( return_value=fake_password) - scenario._update_user_password = mock.MagicMock() scenario.run() + scenario.generate_random_name.assert_called_once_with() - scenario._user_create.assert_called_once_with() - scenario._update_user_password.assert_called_once_with(fake_user.id, - fake_password) + identity_service.create_user.assert_called_once_with() + identity_service.update_user.assert_called_once_with( + fake_user.id, password=fake_password) def test_create_and_list_services(self): + identity_service = self.mock_identity.return_value + scenario = basic.CreateAndListServices(self.context) service_type = "test_service_type" description = "test_description" - fake_service = mock.MagicMock() - scenario._service_create = mock.MagicMock(return_value=fake_service) - scenario._list_services = mock.MagicMock() + scenario.run(service_type=service_type, description=description) - scenario._service_create.assert_called_once_with(service_type, - description) - scenario._list_services.assert_called_once_with() + + identity_service.create_service.assert_called_once_with( + service_type=service_type, description=description) + identity_service.list_services.assert_called_once_with() def test_create_and_list_ec2credentials(self): - context = self.context - scenario = basic.CreateAndListEc2Credentials(context) - scenario._create_ec2credentials = mock.MagicMock() - scenario._list_ec2credentials = mock.MagicMock() + identity_service = self.mock_identity.return_value + + scenario = basic.CreateAndListEc2Credentials(self.context) + scenario.run() - scenario._create_ec2credentials.assert_called_once_with( - "fake_user_id", "fake_tenant_id") - scenario._list_ec2credentials.assert_called_with("fake_user_id") + + identity_service.create_ec2credentials.assert_called_once_with( + self.context["user"]["id"], + project_id=self.context["tenant"]["id"]) + identity_service.list_ec2credentials.assert_called_with( + self.context["user"]["id"]) def test_create_and_delete_ec2credential(self): - fake_creds = mock.MagicMock() - context = self.context - scenario = basic.CreateAndDeleteEc2Credential(context) - scenario._create_ec2credentials = mock.MagicMock( - return_value=fake_creds) - scenario._delete_ec2credential = mock.MagicMock() + identity_service = self.mock_identity.return_value + + fake_creds = identity_service.create_ec2credentials.return_value + + scenario = basic.CreateAndDeleteEc2Credential(self.context) + scenario.run() - scenario._create_ec2credentials.assert_called_once_with( - "fake_user_id", "fake_tenant_id") - scenario._delete_ec2credential.assert_called_once_with( - "fake_user_id", fake_creds.access) + + identity_service.create_ec2credentials.assert_called_once_with( + self.context["user"]["id"], + project_id=self.context["tenant"]["id"]) + identity_service.delete_ec2credential.assert_called_once_with( + self.context["user"]["id"], access=fake_creds.access) def test_add_and_remove_user_role(self): context = self.context diff --git a/tests/unit/plugins/openstack/services/identity/test_identity.py b/tests/unit/plugins/openstack/services/identity/test_identity.py index 6c837f59..a6cf088d 100644 --- a/tests/unit/plugins/openstack/services/identity/test_identity.py +++ b/tests/unit/plugins/openstack/services/identity/test_identity.py @@ -1,4 +1,3 @@ -# Copyright 2014: Mirantis Inc. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -41,6 +40,19 @@ class IdentityTestCase(test.TestCase): service._impl.create_project.assert_called_once_with( project_name, domain_name=domain_name) + def test_update_project(self): + service = self.get_service_with_fake_impl() + + project_id = "id" + project_name = "name" + description = "descr" + enabled = False + service.update_project(project_id=project_id, name=project_name, + description=description, enabled=enabled) + service._impl.update_project.assert_called_once_with( + project_id, name=project_name, description=description, + enabled=enabled) + def test_delete_project(self): service = self.get_service_with_fake_impl() project = "id" @@ -52,21 +64,37 @@ class IdentityTestCase(test.TestCase): service.list_projects() service._impl.list_projects.assert_called_once_with() + def test_get_project(self): + service = self.get_service_with_fake_impl() + project = "id" + service.get_project(project) + service._impl.get_project.assert_called_once_with(project) + def test_create_user(self): service = self.get_service_with_fake_impl() username = "username" password = "password" - email = "email" project_id = "project_id" domain_name = "domain_name" - service.create_user(username=username, password=password, email=email, + service.create_user(username=username, password=password, project_id=project_id, domain_name=domain_name) service._impl.create_user.assert_called_once_with( - username=username, password=password, email=email, - project_id=project_id, domain_name=domain_name, - default_role="member") + username=username, password=password, project_id=project_id, + domain_name=domain_name, default_role="member") + + def test_create_users(self): + service = self.get_service_with_fake_impl() + + project_id = "project_id" + n = 3 + user_create_args = {} + + service.create_users(project_id, number_of_users=n, + user_create_args=user_create_args) + service._impl.create_users.assert_called_once_with( + project_id, number_of_users=n, user_create_args=user_create_args) def test_delete_user(self): service = self.get_service_with_fake_impl() @@ -79,6 +107,38 @@ class IdentityTestCase(test.TestCase): service.list_users() service._impl.list_users.assert_called_once_with() + def test_update_user(self): + service = self.get_service_with_fake_impl() + + user_id = "id" + user_name = "name" + email = "mail" + password = "pass" + enabled = False + service.update_user(user_id, name=user_name, password=password, + email=email, enabled=enabled) + service._impl.update_user.assert_called_once_with( + user_id, name=user_name, password=password, email=email, + enabled=enabled) + + def test_get_user(self): + service = self.get_service_with_fake_impl() + user = "id" + service.get_user(user) + service._impl.get_user.assert_called_once_with(user) + + def test_create_service(self): + service = self.get_service_with_fake_impl() + + service_name = "name" + service_type = "service_type" + description = "descr" + service.create_service(service_name, service_type=service_type, + description=description) + service._impl.create_service.assert_called_once_with( + name=service_name, service_type=service_type, + description=description) + def test_delete_service(self): service = self.get_service_with_fake_impl() service_id = "id" @@ -91,6 +151,18 @@ class IdentityTestCase(test.TestCase): service.list_services() service._impl.list_services.assert_called_once_with() + def test_get_service(self): + service = self.get_service_with_fake_impl() + service_id = "id" + service.get_service(service_id) + service._impl.get_service.assert_called_once_with(service_id) + + def test_get_service_by_name(self): + service = self.get_service_with_fake_impl() + service_name = "name" + service.get_service_by_name(service_name) + service._impl.get_service_by_name.assert_called_once_with(service_name) + def test_create_role(self): service = self.get_service_with_fake_impl() @@ -144,26 +216,42 @@ class IdentityTestCase(test.TestCase): service.get_role(role) service._impl.get_role.assert_called_once_with(role) - def test__unify_service(self): - class SomeFakeService(object): - id = 123123123123123 - name = "asdfasdfasdfasdfadf" - other_var = "asdfasdfasdfasdfasdfasdfasdf" + def test_create_ec2credentials(self): + service = self.get_service_with_fake_impl() - service = self.get_service_with_fake_impl()._unify_service( - SomeFakeService()) - self.assertIsInstance(service, identity.Service) - self.assertEqual(SomeFakeService.id, service.id) - self.assertEqual(SomeFakeService.name, service.name) + user_id = "id" + project_id = "project-id" - def test__unify_role(self): - class SomeFakeRole(object): - id = 123123123123123 - name = "asdfasdfasdfasdfadf" - other_var = "asdfasdfasdfasdfasdfasdfasdf" + service.create_ec2credentials(user_id=user_id, project_id=project_id) + service._impl.create_ec2credentials.assert_called_once_with( + user_id=user_id, project_id=project_id) - role = self.get_service_with_fake_impl()._unify_role( - SomeFakeRole()) - self.assertIsInstance(role, identity.Role) - self.assertEqual(SomeFakeRole.id, role.id) - self.assertEqual(SomeFakeRole.name, role.name) + def test_list_ec2credentials(self): + service = self.get_service_with_fake_impl() + + user_id = "id" + + service.list_ec2credentials(user_id=user_id) + service._impl.list_ec2credentials.assert_called_once_with(user_id) + + def test_delete_ec2credential(self): + service = self.get_service_with_fake_impl() + + user_id = "id" + access = "access" + + service.delete_ec2credential(user_id=user_id, access=access) + service._impl.delete_ec2credential.assert_called_once_with( + user_id=user_id, access=access) + + def test_fetch_token(self): + service = self.get_service_with_fake_impl() + service.fetch_token() + service._impl.fetch_token.assert_called_once_with() + + def test_validate_token(self): + service = self.get_service_with_fake_impl() + + token = "id" + service.validate_token(token) + service._impl.validate_token.assert_called_once_with(token) diff --git a/tests/unit/plugins/openstack/services/identity/test_keystone_common.py b/tests/unit/plugins/openstack/services/identity/test_keystone_common.py new file mode 100644 index 00000000..565352c5 --- /dev/null +++ b/tests/unit/plugins/openstack/services/identity/test_keystone_common.py @@ -0,0 +1,280 @@ +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import mock + +from rally.plugins.openstack import service +from rally.plugins.openstack.services.identity import identity +from rally.plugins.openstack.services.identity import keystone_common +from tests.unit import test + + +class FullUnifiedKeystone(keystone_common.UnifiedKeystoneMixin, + service.Service): + """Implementation of UnifiedKeystoneMixin with Service base class.""" + pass + + +class UnifiedKeystoneMixinTestCase(test.TestCase): + def setUp(self): + super(UnifiedKeystoneMixinTestCase, self).setUp() + self.clients = mock.MagicMock() + self.name_generator = mock.MagicMock() + self.impl = mock.MagicMock() + self.version = "some" + self.service = FullUnifiedKeystone( + clients=self.clients, name_generator=self.name_generator) + self.service._impl = self.impl + self.service.version = self.version + + def test__unify_service(self): + class SomeFakeService(object): + id = 123123123123123 + name = "asdfasdfasdfasdfadf" + other_var = "asdfasdfasdfasdfasdfasdfasdf" + + service = self.service._unify_service(SomeFakeService()) + self.assertIsInstance(service, identity.Service) + self.assertEqual(SomeFakeService.id, service.id) + self.assertEqual(SomeFakeService.name, service.name) + + def test__unify_role(self): + class SomeFakeRole(object): + id = 123123123123123 + name = "asdfasdfasdfasdfadf" + other_var = "asdfasdfasdfasdfasdfasdfasdf" + + role = self.service._unify_role(SomeFakeRole()) + self.assertIsInstance(role, identity.Role) + self.assertEqual(SomeFakeRole.id, role.id) + self.assertEqual(SomeFakeRole.name, role.name) + + def test_delete_user(self): + user_id = "id" + + self.service.delete_user(user_id) + self.impl.delete_user.assert_called_once_with(user_id) + + def test_get_user(self): + user_id = "id" + + self.service._unify_user = mock.MagicMock() + + self.assertEqual(self.service._unify_user.return_value, + self.service.get_user(user_id)) + + self.impl.get_user.assert_called_once_with(user_id) + self.service._unify_user.assert_called_once_with( + self.impl.get_user.return_value) + + def test_create_service(self): + self.service._unify_service = mock.MagicMock() + + name = "some_Service" + service_type = "computeNextGen" + description = "we will Rock you!" + + self.assertEqual(self.service._unify_service.return_value, + self.service.create_service( + name=name, service_type=service_type, + description=description)) + + self.service._unify_service.assert_called_once_with( + self.service._impl.create_service.return_value) + self.service._impl.create_service.assert_called_once_with( + name=name, service_type=service_type, description=description) + + def test_delete_service(self): + service_id = "id" + + self.service.delete_service(service_id) + self.impl.delete_service.assert_called_once_with(service_id) + + def test_get_service(self): + service_id = "id" + + self.service._unify_service = mock.MagicMock() + + self.assertEqual(self.service._unify_service.return_value, + self.service.get_service(service_id)) + + self.impl.get_service.assert_called_once_with(service_id) + self.service._unify_service.assert_called_once_with( + self.impl.get_service.return_value) + + def test_get_service_by_name(self): + service_id = "id" + + self.service._unify_service = mock.MagicMock() + + self.assertEqual(self.service._unify_service.return_value, + self.service.get_service_by_name(service_id)) + + self.impl.get_service_by_name.assert_called_once_with(service_id) + self.service._unify_service.assert_called_once_with( + self.impl.get_service_by_name.return_value) + + def test_delete_role(self): + role_id = "id" + + self.service.delete_role(role_id) + self.impl.delete_role.assert_called_once_with(role_id) + + def test_get_role(self): + role_id = "id" + + self.service._unify_role = mock.MagicMock() + + self.assertEqual(self.service._unify_role.return_value, + self.service.get_role(role_id)) + + self.impl.get_role.assert_called_once_with(role_id) + self.service._unify_role.assert_called_once_with( + self.impl.get_role.return_value) + + def test_list_ec2credentials(self): + user_id = "id" + self.assertEqual(self.impl.list_ec2credentials.return_value, + self.service.list_ec2credentials(user_id)) + + self.impl.list_ec2credentials.assert_called_once_with(user_id) + + def test_delete_ec2credential(self): + user_id = "id" + access = mock.MagicMock() + + self.assertEqual(self.impl.delete_ec2credential.return_value, + self.service.delete_ec2credential(user_id, + access=access)) + + self.impl.delete_ec2credential.assert_called_once_with(user_id=user_id, + access=access) + + def test_fetch_token(self): + + self.assertEqual(self.impl.fetch_token.return_value, + self.service.fetch_token()) + + self.impl.fetch_token.assert_called_once_with() + + def test_validate_token(self): + token = "id" + + self.assertEqual(self.impl.validate_token.return_value, + self.service.validate_token(token)) + + self.impl.validate_token.assert_called_once_with(token) + + +class FullKeystone(service.Service, keystone_common.KeystoneMixin): + """Implementation of KeystoneMixin with Service base class.""" + pass + + +class KeystoneMixinTestCase(test.TestCase): + def setUp(self): + super(KeystoneMixinTestCase, self).setUp() + self.clients = mock.MagicMock() + self.kc = self.clients.keystone.return_value + self.name_generator = mock.MagicMock() + self.version = "some" + self.service = FullKeystone( + clients=self.clients, name_generator=self.name_generator) + self.service.version = self.version + + def test_list_users(self): + self.assertEqual(self.kc.users.list.return_value, + self.service.list_users()) + self.kc.users.list.assert_called_once_with() + + def test_delete_user(self): + user_id = "fake_id" + self.service.delete_user(user_id) + self.kc.users.delete.assert_called_once_with(user_id) + + def test_get_user(self): + user_id = "fake_id" + self.service.get_user(user_id) + self.kc.users.get.assert_called_once_with(user_id) + + def test_delete_service(self): + service_id = "fake_id" + self.service.delete_service(service_id) + self.kc.services.delete.assert_called_once_with(service_id) + + def test_list_services(self): + self.assertEqual(self.kc.services.list.return_value, + self.service.list_services()) + self.kc.services.list.assert_called_once_with() + + def test_get_service(self): + service_id = "fake_id" + self.service.get_service(service_id) + self.kc.services.get.assert_called_once_with(service_id) + + def test_get_service_by_name(self): + class FakeService(object): + def __init__(self, name): + self.name = name + service_name = "fake_name" + services = [FakeService(name="foo"), FakeService(name=service_name), + FakeService(name="bar")] + self.service.list_services = mock.MagicMock(return_value=services) + + self.assertEqual(services[1], + self.service.get_service_by_name(service_name)) + + def test_delete_role(self): + role_id = "fake_id" + self.service.delete_role(role_id) + self.kc.roles.delete.assert_called_once_with(role_id) + + def test_list_roles(self): + self.assertEqual(self.kc.roles.list.return_value, + self.service.list_roles()) + self.kc.roles.list.assert_called_once_with() + + def test_get_role(self): + role_id = "fake_id" + self.service.get_role(role_id) + self.kc.roles.get.assert_called_once_with(role_id) + + def test_list_ec2credentials(self): + user_id = "fake_id" + + self.assertEqual(self.kc.ec2.list.return_value, + self.service.list_ec2credentials(user_id)) + self.kc.ec2.list.assert_called_once_with(user_id) + + def test_delete_ec2credentials(self): + user_id = "fake_id" + access = mock.MagicMock() + + self.service.delete_ec2credential(user_id, access=access) + self.kc.ec2.delete.assert_called_once_with(user_id=user_id, + access=access) + + @mock.patch("rally.osclients.Clients") + def test_fetch_token(self, mock_clients): + expected_token = mock_clients.return_value.keystone.auth_ref.auth_token + self.assertEqual(expected_token, self.service.fetch_token()) + mock_clients.assert_called_once_with( + credential=self.clients.credential, + api_info=self.clients.api_info) + + def test_validate_token(self): + token = "some_token" + + self.service.validate_token(token) + self.kc.tokens.validate.assert_called_once_with(token) diff --git a/tests/unit/plugins/openstack/services/identity/test_keystone_v2.py b/tests/unit/plugins/openstack/services/identity/test_keystone_v2.py index 0d746f7a..6d1a118f 100644 --- a/tests/unit/plugins/openstack/services/identity/test_keystone_v2.py +++ b/tests/unit/plugins/openstack/services/identity/test_keystone_v2.py @@ -1,4 +1,3 @@ -# Copyright 2014: Mirantis Inc. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -15,6 +14,7 @@ import uuid +import ddt import mock from rally.plugins.openstack.services.identity import identity @@ -25,12 +25,15 @@ from tests.unit import test PATH = "rally.plugins.openstack.services.identity.keystone_v2" +@ddt.ddt class KeystoneV2ServiceTestCase(test.TestCase): def setUp(self): super(KeystoneV2ServiceTestCase, self).setUp() self.clients = mock.MagicMock() self.kc = self.clients.keystone.return_value - self.service = keystone_v2.KeystoneV2Service(self.clients) + self.name_generator = mock.MagicMock() + self.service = keystone_v2.KeystoneV2Service( + self.clients, name_generator=self.name_generator) def test_create_tenant(self): name = "name" @@ -39,6 +42,25 @@ class KeystoneV2ServiceTestCase(test.TestCase): self.assertEqual(tenant, self.kc.tenants.create.return_value) self.kc.tenants.create.assert_called_once_with(name) + @ddt.data({"tenant_id": "fake_id", "name": True, "enabled": True, + "description": True}, + {"tenant_id": "fake_id", "name": "some", "enabled": False, + "description": "descr"}) + @ddt.unpack + def test_update_tenant(self, tenant_id, name, enabled, description): + + self.name_generator.side_effect = ("foo", "bar") + self.service.update_tenant(tenant_id, + name=name, + description=description, + enabled=enabled) + + name = "foo" if name is True else name + description = "bar" if description is True else description + + self.kc.tenants.update.assert_called_once_with( + tenant_id, name=name, description=description, enabled=enabled) + def test_delete_tenant(self): tenant_id = "fake_id" self.service.delete_tenant(tenant_id) @@ -49,6 +71,11 @@ class KeystoneV2ServiceTestCase(test.TestCase): self.service.list_tenants()) self.kc.tenants.list.assert_called_once_with() + def test_get_tenant(self): + tenant_id = "fake_id" + self.service.get_tenant(tenant_id) + self.kc.tenants.get.assert_called_once_with(tenant_id) + def test_create_user(self): name = "name" password = "passwd" @@ -60,27 +87,56 @@ class KeystoneV2ServiceTestCase(test.TestCase): self.assertEqual(user, self.kc.users.create.return_value) self.kc.users.create.assert_called_once_with( - name=name, password=password, email=email, tenant_id=tenant_id) + name=name, password=password, email=email, tenant_id=tenant_id, + enabled=True) - def test_list_users(self): - self.assertEqual(self.kc.users.list.return_value, - self.service.list_users()) - self.kc.users.list.assert_called_once_with() + def test_create_users(self): + self.service.create_user = mock.MagicMock() - def test_delete_user(self): + n = 2 + tenant_id = "some" + self.assertEqual([self.service.create_user.return_value] * n, + self.service.create_users(number_of_users=n, + tenant_id=tenant_id)) + self.assertEqual([mock.call(tenant_id=tenant_id)] * n, + self.service.create_user.call_args_list) + + def test_update_user_with_wrong_params(self): user_id = "fake_id" - self.service.delete_user(user_id) - self.kc.users.delete.assert_called_once_with(user_id) + card_with_cvv2 = "1234 5678 9000 0000 : 666" + self.assertRaises(NotImplementedError, self.service.update_user, + user_id, card_with_cvv2=card_with_cvv2) - def test_delete_service(self): - service_id = "fake_id" - self.service.delete_service(service_id) - self.kc.services.delete.assert_called_once_with(service_id) + def test_update_user(self): + user_id = "fake_id" + name = "new name" + email = "new.name2016@example.com" + enabled = True + self.service.update_user(user_id, name=name, email=email, + enabled=enabled) + self.kc.users.update.assert_called_once_with( + user_id, name=name, email=email, enabled=enabled) - def test_list_services(self): - self.assertEqual(self.kc.services.list.return_value, - self.service.list_services()) - self.kc.services.list.assert_called_once_with() + def test_update_user_password(self): + user_id = "fake_id" + password = "qwerty123" + self.service.update_user_password(user_id, password=password) + self.kc.users.update_password.assert_called_once_with( + user_id, password=password) + + @ddt.data({"name": None, "service_type": None, "description": None}, + {"name": "some", "service_type": "st", "description": "d"}) + @ddt.unpack + def test_create_service(self, name, service_type, description): + self.assertEqual(self.kc.services.create.return_value, + self.service.create_service(name=name, + service_type=service_type, + description=description)) + name = name or self.name_generator.return_value + service_type = service_type or "rally_test_type" + description = description or self.name_generator.return_value + self.kc.services.create.assert_called_once_with( + name, service_type=service_type, description=description) def test_create_role(self): name = "some" @@ -96,11 +152,6 @@ class KeystoneV2ServiceTestCase(test.TestCase): self.kc.roles.add_user_role.assert_called_once_with( user=user_id, role=role_id, tenant=tenant_id) - def test_delete_role(self): - role_id = "fake_id" - self.service.delete_role(role_id) - self.kc.roles.delete.assert_called_once_with(role_id) - def test_list_roles(self): self.assertEqual(self.kc.roles.list.return_value, self.service.list_roles()) @@ -126,12 +177,18 @@ class KeystoneV2ServiceTestCase(test.TestCase): self.kc.roles.remove_user_role.assert_called_once_with( user=user_id, role=role_id, tenant=tenant_id) - def test_get_role(self): - role_id = "fake_id" - self.service.get_role(role_id) - self.kc.roles.get.assert_called_once_with(role_id) + def test_create_ec2credentials(self): + user_id = "fake_id" + tenant_id = "fake_id" + + self.assertEqual(self.kc.ec2.create.return_value, + self.service.create_ec2credentials( + user_id, tenant_id=tenant_id)) + self.kc.ec2.create.assert_called_once_with(user_id, + tenant_id=tenant_id) +@ddt.ddt class UnifiedKeystoneV2ServiceTestCase(test.TestCase): def setUp(self): super(UnifiedKeystoneV2ServiceTestCase, self).setUp() @@ -207,11 +264,35 @@ class UnifiedKeystoneV2ServiceTestCase(test.TestCase): self.service._impl.create_tenant.return_value) self.service._impl.create_tenant.assert_called_once_with(name) + def test_update_project(self): + tenant_id = "fake_id" + name = "name" + description = "descr" + enabled = False + + self.service.update_project(project_id=tenant_id, name=name, + description=description, enabled=enabled) + self.service._impl.update_tenant.assert_called_once_with( + tenant_id=tenant_id, name=name, description=description, + enabled=enabled) + def test_delete_project(self): tenant_id = "fake_id" self.service.delete_project(tenant_id) self.service._impl.delete_tenant.assert_called_once_with(tenant_id) + @mock.patch("%s.UnifiedKeystoneV2Service._unify_tenant" % PATH) + def test_get_project(self, + mock_unified_keystone_v2_service__unify_tenant): + mock_unify_tenant = mock_unified_keystone_v2_service__unify_tenant + tenant_id = "id" + + self.assertEqual(mock_unify_tenant.return_value, + self.service.get_project(tenant_id)) + mock_unify_tenant.assert_called_once_with( + self.service._impl.get_tenant.return_value) + self.service._impl.get_tenant.assert_called_once_with(tenant_id) + @mock.patch("%s.UnifiedKeystoneV2Service._unify_tenant" % PATH) def test_list_projects(self, mock_unified_keystone_v2_service__unify_tenant): @@ -233,23 +314,35 @@ class UnifiedKeystoneV2ServiceTestCase(test.TestCase): name = "name" password = "passwd" - email = "rally@example.com" tenant_id = "project" self.assertEqual(mock_unify_user.return_value, self.service.create_user(name, password=password, - email=email, project_id=tenant_id)) mock_check_domain.assert_called_once_with("Default") mock_unify_user.assert_called_once_with( self.service._impl.create_user.return_value) self.service._impl.create_user.assert_called_once_with( - username=name, password=password, email=email, tenant_id=tenant_id) + username=name, password=password, tenant_id=tenant_id, + enabled=True) - def test_delete_user(self): - user_id = "fake_id" - self.service.delete_user(user_id) - self.service._impl.delete_user.assert_called_once_with(user_id) + @mock.patch("%s.UnifiedKeystoneV2Service._check_domain" % PATH) + @mock.patch("%s.UnifiedKeystoneV2Service._unify_user" % PATH) + def test_create_users(self, mock_unified_keystone_v2_service__unify_user, + mock_unified_keystone_v2_service__check_domain): + mock_check_domain = mock_unified_keystone_v2_service__check_domain + + tenant_id = "project" + n = 3 + domain_name = "Default" + + self.service.create_users( + tenant_id, number_of_users=3, + user_create_args={"domain_name": domain_name}) + mock_check_domain.assert_called_once_with(domain_name) + self.service._impl.create_users.assert_called_once_with( + tenant_id=tenant_id, number_of_users=n, + user_create_args={"domain_name": domain_name}) @mock.patch("%s.UnifiedKeystoneV2Service._unify_user" % PATH) def test_list_users(self, mock_unified_keystone_v2_service__unify_user): @@ -262,10 +355,29 @@ class UnifiedKeystoneV2ServiceTestCase(test.TestCase): self.service.list_users()) mock_unify_user.assert_called_once_with(users[0]) - def test_delete_service(self): - service_id = "fake_id" - self.service.delete_service(service_id) - self.service._impl.delete_service.assert_called_once_with(service_id) + @ddt.data({"user_id": "id", "enabled": False, "name": "Fake", + "email": "badboy@example.com", "password": "pass"}, + {"user_id": "id", "enabled": None, "name": None, + "email": None, "password": None}) + @ddt.unpack + def test_update_user(self, user_id, enabled, name, email, password): + self.service.update_user(user_id, enabled=enabled, name=name, + email=email, password=password) + if password: + self.service._impl.update_user_password.assert_called_once_with( + user_id=user_id, password=password) + + args = {} + if enabled is not None: + args["enabled"] = enabled + if name is not None: + args["name"] = name + if email is not None: + args["email"] = email + + if args: + self.service._impl.update_user.assert_called_once_with( + user_id, **args) @mock.patch("%s.UnifiedKeystoneV2Service._unify_service" % PATH) def test_list_services(self, @@ -291,22 +403,17 @@ class UnifiedKeystoneV2ServiceTestCase(test.TestCase): mock_unify_role.assert_called_once_with( self.service._impl.create_role.return_value) - @mock.patch("%s.UnifiedKeystoneV2Service._unify_role" % PATH) - def test_add_role(self, mock_unified_keystone_v2_service__unify_role): - mock_unify_role = mock_unified_keystone_v2_service__unify_role + def test_add_role(self): role_id = "fake_id" user_id = "user_id" project_id = "user_id" - self.assertEqual(mock_unify_role.return_value, - self.service.add_role(role_id, user_id=user_id, - project_id=project_id)) + self.service.add_role(role_id, user_id=user_id, + project_id=project_id) self.service._impl.add_role.assert_called_once_with( user_id=user_id, role_id=role_id, tenant_id=project_id) - mock_unify_role.assert_called_once_with( - self.service._impl.add_role.return_value) def test_delete_role(self): role_id = "fake_id" @@ -358,7 +465,13 @@ class UnifiedKeystoneV2ServiceTestCase(test.TestCase): self.assertRaises(NotImplementedError, self.service.list_roles, domain_name="some") - def test_get_role(self): - role_id = "fake_id" - self.service.get_role(role_id) - self.service._impl.get_role.assert_called_once_with(role_id) + def test_create_ec2credentials(self): + user_id = "id" + tenant_id = "tenant-id" + + self.assertEqual(self.service._impl.create_ec2credentials.return_value, + self.service.create_ec2credentials( + user_id=user_id, project_id=tenant_id)) + + self.service._impl.create_ec2credentials.assert_called_once_with( + user_id=user_id, tenant_id=tenant_id) diff --git a/tests/unit/plugins/openstack/services/identity/test_keystone_v3.py b/tests/unit/plugins/openstack/services/identity/test_keystone_v3.py index 3a85228d..c1b79476 100644 --- a/tests/unit/plugins/openstack/services/identity/test_keystone_v3.py +++ b/tests/unit/plugins/openstack/services/identity/test_keystone_v3.py @@ -1,4 +1,3 @@ -# Copyright 2014: Mirantis Inc. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -15,6 +14,7 @@ import uuid +import ddt import mock from rally import exceptions @@ -26,12 +26,15 @@ from tests.unit import test PATH = "rally.plugins.openstack.services.identity.keystone_v3" +@ddt.ddt class KeystoneV3ServiceTestCase(test.TestCase): def setUp(self): super(KeystoneV3ServiceTestCase, self).setUp() self.clients = mock.MagicMock() self.kc = self.clients.keystone.return_value - self.service = keystone_v3.KeystoneV3Service(self.clients) + self.name_generator = mock.MagicMock() + self.service = keystone_v3.KeystoneV3Service( + self.clients, name_generator=self.name_generator) def test__get_domain_id_not_found(self): from keystoneclient import exceptions as kc_exceptions @@ -85,6 +88,26 @@ class KeystoneV3ServiceTestCase(test.TestCase): self.kc.projects.create.assert_called_once_with(name=name, domain=domain_id) + @ddt.data({"project_id": "fake_id", "name": True, "enabled": True, + "description": True}, + {"project_id": "fake_id", "name": "some", "enabled": False, + "description": "descr"}) + @ddt.unpack + def test_update_project(self, project_id, name, enabled, description): + + self.service.update_project(project_id, + name=name, + description=description, + enabled=enabled) + + if name is True: + name = self.name_generator.return_value + if description is True: + description = self.name_generator.return_value + + self.kc.projects.update.assert_called_once_with( + project_id, name=name, description=description, enabled=enabled) + def test_delete_project(self): project_id = "fake_id" self.service.delete_project(project_id) @@ -95,30 +118,57 @@ class KeystoneV3ServiceTestCase(test.TestCase): self.service.list_projects()) self.kc.projects.list.assert_called_once_with() + def test_get_project(self): + project_id = "fake_id" + self.service.get_project(project_id) + self.kc.projects.get.assert_called_once_with(project_id) + @mock.patch("%s.LOG" % PATH) @mock.patch("%s.KeystoneV3Service._get_domain_id" % PATH) def test_create_user(self, mock__get_domain_id, mock_log): name = "name" password = "passwd" - email = "rally@example.com" project_id = "project" domain_name = "domain" self.service.list_roles = mock.MagicMock(return_value=[]) - user = self.service.create_user(name, password=password, email=email, + user = self.service.create_user(name, password=password, project_id=project_id, domain_name=domain_name) self.assertEqual(user, self.kc.users.create.return_value) self.kc.users.create.assert_called_once_with( - name=name, password=password, email=email, - default_project=project_id, - domain=mock__get_domain_id.return_value) + name=name, password=password, default_project=project_id, + domain=mock__get_domain_id.return_value, + enabled=True) self.assertTrue(mock_log.warning.called) + @mock.patch("%s.LOG" % PATH) + @mock.patch("%s.KeystoneV3Service._get_domain_id" % PATH) + def test_create_user_without_project_id(self, mock__get_domain_id, + mock_log): + + name = "name" + password = "passwd" + domain_name = "domain" + + self.service.list_roles = mock.MagicMock(return_value=[]) + + user = self.service.create_user(name, password=password, + domain_name=domain_name) + + self.assertEqual(user, self.kc.users.create.return_value) + self.kc.users.create.assert_called_once_with( + name=name, password=password, default_project=None, + domain=mock__get_domain_id.return_value, + enabled=True) + + self.assertFalse(self.service.list_roles.called) + self.assertFalse(mock_log.warning.called) + @mock.patch("%s.LOG" % PATH) @mock.patch("%s.KeystoneV3Service._get_domain_id" % PATH) def test_create_user_and_add_role( @@ -127,7 +177,6 @@ class KeystoneV3ServiceTestCase(test.TestCase): name = "name" password = "passwd" - email = "rally@example.com" project_id = "project" domain_name = "domain" @@ -140,15 +189,15 @@ class KeystoneV3ServiceTestCase(test.TestCase): return_value=[Role("admin"), Role("member")]) self.service.add_role = mock.MagicMock() - user = self.service.create_user(name, password=password, email=email, + user = self.service.create_user(name, password=password, project_id=project_id, domain_name=domain_name) self.assertEqual(user, self.kc.users.create.return_value) self.kc.users.create.assert_called_once_with( - name=name, password=password, email=email, - default_project=project_id, - domain=mock__get_domain_id.return_value) + name=name, password=password, default_project=project_id, + domain=mock__get_domain_id.return_value, + enabled=True) self.assertFalse(mock_log.warning.called) self.service.add_role.assert_called_once_with( @@ -156,25 +205,65 @@ class KeystoneV3ServiceTestCase(test.TestCase): user_id=user.id, project_id=project_id) - def test_list_users(self): - self.assertEqual(self.kc.users.list.return_value, - self.service.list_users()) - self.kc.users.list.assert_called_once_with() + def test_create_users(self): + self.service.create_user = mock.MagicMock() - def test_delete_user(self): + n = 2 + project_id = "some" + self.assertEqual([self.service.create_user.return_value] * n, + self.service.create_users(number_of_users=n, + project_id=project_id)) + self.assertEqual([mock.call(project_id=project_id)] * n, + self.service.create_user.call_args_list) + + @ddt.data(None, "some") + def test_update_user(self, domain_name): user_id = "fake_id" - self.service.delete_user(user_id) - self.kc.users.delete.assert_called_once_with(user_id) + name = "new name" + project_id = "new project" + password = "pass" + email = "mail" + description = "n/a" + enabled = False + default_project = "some" - def test_delete_service(self): - service_id = "fake_id" - self.service.delete_service(service_id) - self.kc.services.delete.assert_called_once_with(service_id) + self.service._get_domain_id = mock.MagicMock() - def test_list_services(self): - self.assertEqual(self.kc.services.list.return_value, - self.service.list_services()) - self.kc.services.list.assert_called_once_with() + self.service.update_user(user_id, name=name, domain_name=domain_name, + project_id=project_id, password=password, + email=email, description=description, + enabled=enabled, + default_project=default_project) + + domain = None + if domain_name: + self.service._get_domain_id.assert_called_once_with(domain_name) + domain = self.service._get_domain_id.return_value + else: + self.assertFalse(self.service._get_domain_id.called) + + self.kc.users.update.assert_called_once_with( + user_id, name=name, domain=domain, project=project_id, + password=password, email=email, description=description, + enabled=enabled, default_project=default_project) + + @ddt.data({"name": None, "service_type": None, "description": None, + "enabled": True}, + {"name": "some", "service_type": "st", "description": "d", + "enabled": False}) + @ddt.unpack + def test_create_service(self, name, service_type, description, enabled): + self.assertEqual(self.kc.services.create.return_value, + self.service.create_service(name=name, + service_type=service_type, + description=description, + enabled=enabled)) + name = name or self.name_generator.return_value + service_type = service_type or "rally_test_type" + description = description or self.name_generator.return_value + self.kc.services.create.assert_called_once_with( + name, type=service_type, description=description, + enabled=enabled) @mock.patch("%s.KeystoneV3Service._get_domain_id" % PATH) def test_create_role(self, mock__get_domain_id): @@ -188,6 +277,26 @@ class KeystoneV3ServiceTestCase(test.TestCase): self.kc.roles.create.assert_called_once_with( name, domain=mock__get_domain_id.return_value) + @ddt.data({"domain_name": "domain", "user_id": "user", "project_id": "pr"}, + {"domain_name": None, "user_id": None, "project_id": None}) + @ddt.unpack + def test_list_roles(self, domain_name, user_id, project_id): + self.service._get_domain_id = mock.MagicMock() + self.assertEqual(self.kc.roles.list.return_value, + self.service.list_roles(user_id=user_id, + domain_name=domain_name, + project_id=project_id)) + domain = None + if domain_name: + self.service._get_domain_id.assert_called_once_with(domain_name) + domain = self.service._get_domain_id.return_value + else: + self.assertFalse(self.service._get_domain_id.called) + + self.kc.roles.list.assert_called_once_with(user=user_id, + domain=domain, + project=project_id) + def test_add_role(self): role_id = "fake_id" user_id = "user_id" @@ -197,17 +306,6 @@ class KeystoneV3ServiceTestCase(test.TestCase): self.kc.roles.grant.assert_called_once_with( user=user_id, role=role_id, project=project_id) - def test_delete_role(self): - role_id = "fake_id" - self.service.delete_role(role_id) - self.kc.roles.delete.assert_called_once_with(role_id) - - def test_list_roles(self): - self.assertEqual(self.kc.roles.list.return_value, - self.service.list_roles()) - self.kc.roles.list.assert_called_once_with(project=None, user=None, - domain=None) - def test_revoke_role(self): role_id = "fake_id" user_id = "user_id" @@ -233,7 +331,18 @@ class KeystoneV3ServiceTestCase(test.TestCase): self.kc.domains.create.assert_called_once_with( name, description=descr, enabled=enabled) + def test_create_ec2credentials(self): + user_id = "fake_id" + project_id = "fake_id" + self.assertEqual(self.kc.ec2.create.return_value, + self.service.create_ec2credentials( + user_id, project_id=project_id)) + self.kc.ec2.create.assert_called_once_with(user_id, + project_id=project_id) + + +@ddt.ddt class UnifiedKeystoneV3ServiceTestCase(test.TestCase): def setUp(self): super(UnifiedKeystoneV3ServiceTestCase, self).setUp() @@ -300,11 +409,35 @@ class UnifiedKeystoneV3ServiceTestCase(test.TestCase): self.service._impl.create_project.return_value) self.service._impl.create_project.assert_called_once_with(name) + def test_update_project(self): + project_id = "fake_id" + name = "name" + description = "descr" + enabled = False + + self.service.update_project(project_id=project_id, name=name, + description=description, enabled=enabled) + self.service._impl.update_project.assert_called_once_with( + project_id=project_id, name=name, description=description, + enabled=enabled) + def test_delete_project(self): project_id = "fake_id" self.service.delete_project(project_id) self.service._impl.delete_project.assert_called_once_with(project_id) + @mock.patch("%s.UnifiedKeystoneV3Service._unify_project" % PATH) + def test_get_project(self, + mock_unified_keystone_v3_service__unify_project): + mock_unify_project = mock_unified_keystone_v3_service__unify_project + project_id = "id" + + self.assertEqual(mock_unify_project.return_value, + self.service.get_project(project_id)) + mock_unify_project.assert_called_once_with( + self.service._impl.get_project.return_value) + self.service._impl.get_project.assert_called_once_with(project_id) + @mock.patch("%s.UnifiedKeystoneV3Service._unify_project" % PATH) def test_list_projects(self, mock_unified_keystone_v3_service__unify_project): @@ -323,28 +456,33 @@ class UnifiedKeystoneV3ServiceTestCase(test.TestCase): name = "name" password = "passwd" - email = "rally@example.com" project_id = "project" domain_name = "domain" default_role = "role" self.assertEqual(mock_unify_user.return_value, self.service.create_user(name, password=password, - email=email, project_id=project_id, domain_name=domain_name, default_role=default_role)) mock_unify_user.assert_called_once_with( self.service._impl.create_user.return_value) self.service._impl.create_user.assert_called_once_with( - username=name, password=password, email=email, - project_id=project_id, domain_name=domain_name, - default_role=default_role) + username=name, password=password, project_id=project_id, + domain_name=domain_name, default_role=default_role, enabled=True) - def test_delete_user(self): - user_id = "fake_id" - self.service.delete_user(user_id) - self.service._impl.delete_user.assert_called_once_with(user_id) + @mock.patch("%s.UnifiedKeystoneV3Service._unify_user" % PATH) + def test_create_users(self, mock_unified_keystone_v3_service__unify_user): + project_id = "project" + n = 3 + domain_name = "Default" + + self.service.create_users( + project_id, number_of_users=3, + user_create_args={"domain_name": domain_name}) + self.service._impl.create_users.assert_called_once_with( + project_id=project_id, number_of_users=n, + user_create_args={"domain_name": domain_name}) @mock.patch("%s.UnifiedKeystoneV3Service._unify_user" % PATH) def test_list_users(self, mock_unified_keystone_v3_service__unify_user): @@ -357,10 +495,17 @@ class UnifiedKeystoneV3ServiceTestCase(test.TestCase): self.service.list_users()) mock_unify_user.assert_called_once_with(users[0]) - def test_delete_service(self): - service_id = "fake_id" - self.service.delete_service(service_id) - self.service._impl.delete_service.assert_called_once_with(service_id) + @ddt.data({"user_id": "id", "enabled": False, "name": "Fake", + "email": "badboy@example.com", "password": "pass"}, + {"user_id": "id", "enabled": None, "name": None, + "email": None, "password": None}) + @ddt.unpack + def test_update_user(self, user_id, enabled, name, email, password): + self.service.update_user(user_id, enabled=enabled, name=name, + email=email, password=password) + self.service._impl.update_user.assert_called_once_with( + user_id, enabled=enabled, name=name, email=email, + password=password) @mock.patch("%s.UnifiedKeystoneV3Service._unify_service" % PATH) def test_list_services(self, @@ -375,26 +520,28 @@ class UnifiedKeystoneV3ServiceTestCase(test.TestCase): mock_unify_service.assert_called_once_with(services[0]) @mock.patch("%s.UnifiedKeystoneV3Service._unify_role" % PATH) - def test_add_role(self, mock_unified_keystone_v3_service__unify_role): + def test_create_role(self, mock_unified_keystone_v3_service__unify_role): mock_unify_role = mock_unified_keystone_v3_service__unify_role + name = "some" + domain = "some" + self.assertEqual(mock_unify_role.return_value, + self.service.create_role(name, domain_name=domain)) + + self.service._impl.create_role.assert_called_once_with( + name, domain_name=domain) + mock_unify_role.assert_called_once_with( + self.service._impl.create_role.return_value) + + def test_add_role(self): role_id = "fake_id" user_id = "user_id" project_id = "user_id" - self.assertEqual(mock_unify_role.return_value, - self.service.add_role(role_id, user_id=user_id, - project_id=project_id)) + self.service.add_role(role_id, user_id=user_id, project_id=project_id) self.service._impl.add_role.assert_called_once_with( user_id=user_id, role_id=role_id, project_id=project_id) - mock_unify_role.assert_called_once_with( - self.service._impl.add_role.return_value) - - def test_delete_role(self): - role_id = "fake_id" - self.service.delete_role(role_id) - self.service._impl.delete_role.assert_called_once_with(role_id) def test_revoke_role(self): role_id = "fake_id" @@ -418,7 +565,13 @@ class UnifiedKeystoneV3ServiceTestCase(test.TestCase): self.service.list_roles()) mock_unify_role.assert_called_once_with(roles[0]) - def test_get_role(self): - role_id = "fake_id" - self.service.get_role(role_id) - self.service._impl.get_role.assert_called_once_with(role_id) + def test_create_ec2credentials(self): + user_id = "id" + project_id = "project-id" + + self.assertEqual(self.service._impl.create_ec2credentials.return_value, + self.service.create_ec2credentials( + user_id=user_id, project_id=project_id)) + + self.service._impl.create_ec2credentials.assert_called_once_with( + user_id=user_id, project_id=project_id)