diff options
| author | James Page <james.page@ubuntu.com> | 2025-02-27 12:47:04 +0000 |
|---|---|---|
| committer | git-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com> | 2025-02-27 12:48:11 +0000 |
| commit | cadf285ef3bba5f6cb863c72568936e007bf556e (patch) | |
| tree | 9cac5298d12ec2fc915fdd7a64a1c49ec1e7fb90 | |
| parent | ba57fd4e657ceaead84ad821e6ac4b05b785c4ca (diff) | |
7.4.0-0ubuntu1 (patches unapplied)import/7.4.0-0ubuntu1ubuntu/plucky-proposedubuntu/plucky-develubuntu/plucky
Imported using git-ubuntu import.
Notes
Notes:
* New upstream release for OpenStack Epoxy.
82 files changed, 3688 insertions, 2598 deletions
@@ -6,6 +6,11 @@ Run unit tests for OpenStackClient with master branch of important libs. Takes advantage of the base tox job's install-siblings feature. + irrelevant-files: &common-irrelevant-files + - ^.*\.rst$ + - ^doc/.*$ + - ^releasenotes/.*$ + - ^\.pre-commit-config\.yaml$ required-projects: - openstack/cliff - openstack/keystoneauth @@ -81,13 +86,6 @@ # NOTE(amotoki): Some neutron features are enabled by devstack plugin neutron: https://opendev.org/openstack/neutron devstack_services: - ceilometer-acentral: false - ceilometer-acompute: false - ceilometer-alarm-evaluator: false - ceilometer-alarm-notifier: false - ceilometer-anotification: false - ceilometer-api: false - ceilometer-collector: false s-account: true s-container: true s-object: true @@ -112,6 +112,7 @@ Dmitriy Rabotyagov <noonedeadpunk@ya.ru> Dmitry Tantsur <dtantsur@protonmail.com> Dolph Mathews <dolph.mathews@gmail.com> Dongcan Ye <hellochosen@gmail.com> +Doug Goldstein <cardoe@cardoe.com> Doug Hellmann <doug.hellmann@dreamhost.com> Doug Hellmann <doug@doughellmann.com> Doug Wiegley <dwiegley@salesforce.com> @@ -128,6 +129,7 @@ Fan Zhang <zh.f@outlook.com> Fang Zhen <zhen.fang@easystack.cn> Fei Long Wang <flwang@catalyst.net.nz> Felix Yan <felixonmars@archlinux.org> +Fernando Royo <froyo@redhat.com> Flavio Percoco <flaper87@gmail.com> Florent Flament <florent.flament-ext@cloudwatt.com> Florian Streibelt <florian.streibelt@sap.com> @@ -439,6 +441,7 @@ Yi Zhao <zhaoyi@cmss.chinamobile.com> Yongli He <yongli.he@intel.com> YoonSoo LIM <msdbtjd123@naver.com> Yoonsoo Lim <msdbtjd123@naver.com> +Yosef Salmalian <flaslnm@gmail.com> Youngjun <yj.yoo@okestro.com> YuehuiLei <leiyuehui@inspur.com> Yunpeng Li <yunpeng.li@live.cn> @@ -1,10 +1,64 @@ CHANGES ======= +7.4.0 +----- + +* Fix credential creation + +7.3.1 +----- + +* [Neutron] Fix the "port show" command for trunk details +* [Neutron] Support \`\`uplink-status-propagation-updatable\`\` extension +* handle 'router create --flavor' option +* [Neutron] "uplink-status-propagation" enabled by default + +7.3.0 +----- + +* Add "qinq-vlan" and "no-qinq-vlan" params to the "network create" cmd +* Temporary ignore "is\_vlan\_qinq" column in the output +* Identity: Deprecate \`--region None\` in limits/registered limits +* Get "security\_groups" when port list +* Show final image state after image create +* Identity: Migrate 'role' commands to SDK +* Add the trunk subports information to the port list command +* Fix: Volume backup restore output +* identity: Migrate 'trust' commands to SDK +* tests: Stop setting attributes on class +* Adopt sdk\_fakes for compute.test\_server\_volume +* Adopt sdk\_fakes for compute.test\_server\_group +* Adopt sdk\_fakes for compute.test\_hypervisor +* Adopt sdk\_fakes for compute.test\_usage +* Adopt sdk\_fakes for compute.test\_service +* Adopt sdk\_fakes for compute.test\_keypair +* Adopt sdk\_fakes for compute.test\_console +* Adopt sdk\_fakes for compute.aggregate +* identity: Migrate 'service provider' commands to SDK +* quota: Catch correct exception type for Compute quotas +* tests: Add functional test for adding, removing SGs +* compute: Workaround bug #2089821 +* network: Make better use of argparse +* compute: Add server create --no-security-group option +* Remove ceilometer service overrides +* identity: Migrate \`region\` commands to SDK +* reno: Update master for unmaintained/2023.1 +* identity: Migrate 'credential' commands to SDK +* Replace deprecated datetime.utcnow() +* requirements: Remove unused test deps +* Skip tips jobs on pre-commit config update +* common: Use correct argument for volume limits +* Add "trusted" attribute to the "port" +* Fix ignored --user-domain in role assignment list +* Show Created At column for volume backups in v3 +* remove project from network flavor profile + 7.2.1 ----- * clientmanager: Check for 'block-storage' service type +* Fix volume backup show by name 7.2.0 ----- @@ -1,152 +1,10 @@ -Metadata-Version: 1.2 +Metadata-Version: 2.1 Name: python-openstackclient -Version: 7.2.1 +Version: 7.4.0 Summary: OpenStack Command-line Client Home-page: https://docs.openstack.org/python-openstackclient/latest/ Author: OpenStack Author-email: openstack-discuss@lists.openstack.org -License: UNKNOWN -Description: ======================== - Team and repository tags - ======================== - - .. image:: https://governance.openstack.org/tc/badges/python-openstackclient.svg - :target: https://governance.openstack.org/tc/reference/tags/index.html - - .. Change things from this point on - - =============== - OpenStackClient - =============== - - .. image:: https://img.shields.io/pypi/v/python-openstackclient.svg - :target: https://pypi.org/project/python-openstackclient/ - :alt: Latest Version - - OpenStackClient (aka OSC) is a command-line client for OpenStack that brings - the command set for Compute, Identity, Image, Network, Object Store and Block - Storage APIs together in a single shell with a uniform command structure. - - The primary goal is to provide a unified shell command structure and a common - language to describe operations in OpenStack. - - * `PyPi`_ - package installation - * `Online Documentation`_ - * `Launchpad project`_ - bugs and feature requests - * `Blueprints`_ - feature specifications (historical only) - * `Source`_ - * `Developer`_ - getting started as a developer - * `Contributing`_ - contributing code - * `Testing`_ - testing code - * IRC: #openstack-sdks on OFTC (irc.oftc.net) - * License: Apache 2.0 - - .. _PyPi: https://pypi.org/project/python-openstackclient - .. _Online Documentation: https://docs.openstack.org/python-openstackclient/latest/ - .. _Blueprints: https://blueprints.launchpad.net/python-openstackclient - .. _`Launchpad project`: https://bugs.launchpad.net/python-openstackclient - .. _Source: https://opendev.org/openstack/python-openstackclient - .. _Developer: https://docs.openstack.org/project-team-guide/project-setup/python.html - .. _Contributing: https://docs.openstack.org/infra/manual/developers.html - .. _Testing: https://docs.openstack.org/python-openstackclient/latest/contributor/developing.html#testing - .. _Release Notes: https://docs.openstack.org/releasenotes/python-openstackclient - - Getting Started - =============== - - OpenStack Client can be installed from PyPI using pip:: - - pip install python-openstackclient - - There are a few variants on getting help. A list of global options and supported - commands is shown with ``--help``:: - - openstack --help - - There is also a ``help`` command that can be used to get help text for a specific - command:: - - openstack help - openstack help server create - - If you want to make changes to the OpenStackClient for testing and contribution, - make any changes and then run:: - - python setup.py develop - - or:: - - pip install -e . - - Configuration - ============= - - The CLI is configured via environment variables and command-line - options as listed in https://docs.openstack.org/python-openstackclient/latest/cli/authentication.html. - - Authentication using username/password is most commonly used: - - - For a local user, your configuration will look like the one below:: - - export OS_AUTH_URL=<url-to-openstack-identity> - export OS_IDENTITY_API_VERSION=3 - export OS_PROJECT_NAME=<project-name> - export OS_PROJECT_DOMAIN_NAME=<project-domain-name> - export OS_USERNAME=<username> - export OS_USER_DOMAIN_NAME=<user-domain-name> - export OS_PASSWORD=<password> # (optional) - - The corresponding command-line options look very similar:: - - --os-auth-url <url> - --os-identity-api-version 3 - --os-project-name <project-name> - --os-project-domain-name <project-domain-name> - --os-username <username> - --os-user-domain-name <user-domain-name> - [--os-password <password>] - - - For a federated user, your configuration will look the so:: - - export OS_PROJECT_NAME=<project-name> - export OS_PROJECT_DOMAIN_NAME=<project-domain-name> - export OS_AUTH_URL=<url-to-openstack-identity> - export OS_IDENTITY_API_VERSION=3 - export OS_AUTH_PLUGIN=openid - export OS_AUTH_TYPE=v3oidcpassword - export OS_USERNAME=<username-in-idp> - export OS_PASSWORD=<password-in-idp> - export OS_IDENTITY_PROVIDER=<the-desired-idp-in-keystone> - export OS_CLIENT_ID=<the-client-id-configured-in-the-idp> - export OS_CLIENT_SECRET=<the-client-secred-configured-in-the-idp> - export OS_OPENID_SCOPE=<the-scopes-of-desired-attributes-to-claim-from-idp> - export OS_PROTOCOL=<the-protocol-used-in-the-apache2-oidc-proxy> - export OS_ACCESS_TOKEN_TYPE=<the-access-token-type-used-by-your-idp> - export OS_DISCOVERY_ENDPOINT=<the-well-known-endpoint-of-the-idp> - - The corresponding command-line options look very similar:: - - --os-project-name <project-name> - --os-project-domain-name <project-domain-name> - --os-auth-url <url-to-openstack-identity> - --os-identity-api-version 3 - --os-auth-plugin openid - --os-auth-type v3oidcpassword - --os-username <username-in-idp> - --os-password <password-in-idp> - --os-identity-provider <the-desired-idp-in-keystone> - --os-client-id <the-client-id-configured-in-the-idp> - --os-client-secret <the-client-secred-configured-in-the-idp> - --os-openid-scope <the-scopes-of-desired-attributes-to-claim-from-idp> - --os-protocol <the-protocol-used-in-the-apache2-oidc-proxy> - --os-access-token-type <the-access-token-type-used-by-your-idp> - --os-discovery-endpoint <the-well-known-endpoint-of-the-idp> - - If a password is not provided above (in plaintext), you will be interactively - prompted to provide one securely. - - -Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators @@ -159,3 +17,155 @@ Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Requires-Python: >=3.9 +License-File: LICENSE +Requires-Dist: pbr!=2.1.0,>=2.0.0 +Requires-Dist: cryptography>=2.7 +Requires-Dist: cliff>=3.5.0 +Requires-Dist: iso8601>=0.1.11 +Requires-Dist: openstacksdk>=3.3.0 +Requires-Dist: osc-lib>=2.3.0 +Requires-Dist: oslo.i18n>=3.15.3 +Requires-Dist: python-keystoneclient>=3.22.0 +Requires-Dist: python-cinderclient>=3.3.0 +Requires-Dist: requests>=2.27.0 +Requires-Dist: stevedore>=2.0.1 + +======================== +Team and repository tags +======================== + +.. image:: https://governance.openstack.org/tc/badges/python-openstackclient.svg + :target: https://governance.openstack.org/tc/reference/tags/index.html + +.. Change things from this point on + +=============== +OpenStackClient +=============== + +.. image:: https://img.shields.io/pypi/v/python-openstackclient.svg + :target: https://pypi.org/project/python-openstackclient/ + :alt: Latest Version + +OpenStackClient (aka OSC) is a command-line client for OpenStack that brings +the command set for Compute, Identity, Image, Network, Object Store and Block +Storage APIs together in a single shell with a uniform command structure. + +The primary goal is to provide a unified shell command structure and a common +language to describe operations in OpenStack. + +* `PyPi`_ - package installation +* `Online Documentation`_ +* `Launchpad project`_ - bugs and feature requests +* `Blueprints`_ - feature specifications (historical only) +* `Source`_ +* `Developer`_ - getting started as a developer +* `Contributing`_ - contributing code +* `Testing`_ - testing code +* IRC: #openstack-sdks on OFTC (irc.oftc.net) +* License: Apache 2.0 + +.. _PyPi: https://pypi.org/project/python-openstackclient +.. _Online Documentation: https://docs.openstack.org/python-openstackclient/latest/ +.. _Blueprints: https://blueprints.launchpad.net/python-openstackclient +.. _`Launchpad project`: https://bugs.launchpad.net/python-openstackclient +.. _Source: https://opendev.org/openstack/python-openstackclient +.. _Developer: https://docs.openstack.org/project-team-guide/project-setup/python.html +.. _Contributing: https://docs.openstack.org/infra/manual/developers.html +.. _Testing: https://docs.openstack.org/python-openstackclient/latest/contributor/developing.html#testing +.. _Release Notes: https://docs.openstack.org/releasenotes/python-openstackclient + +Getting Started +=============== + +OpenStack Client can be installed from PyPI using pip:: + + pip install python-openstackclient + +There are a few variants on getting help. A list of global options and supported +commands is shown with ``--help``:: + + openstack --help + +There is also a ``help`` command that can be used to get help text for a specific +command:: + + openstack help + openstack help server create + +If you want to make changes to the OpenStackClient for testing and contribution, +make any changes and then run:: + + python setup.py develop + +or:: + + pip install -e . + +Configuration +============= + +The CLI is configured via environment variables and command-line +options as listed in https://docs.openstack.org/python-openstackclient/latest/cli/authentication.html. + +Authentication using username/password is most commonly used: + +- For a local user, your configuration will look like the one below:: + + export OS_AUTH_URL=<url-to-openstack-identity> + export OS_IDENTITY_API_VERSION=3 + export OS_PROJECT_NAME=<project-name> + export OS_PROJECT_DOMAIN_NAME=<project-domain-name> + export OS_USERNAME=<username> + export OS_USER_DOMAIN_NAME=<user-domain-name> + export OS_PASSWORD=<password> # (optional) + + The corresponding command-line options look very similar:: + + --os-auth-url <url> + --os-identity-api-version 3 + --os-project-name <project-name> + --os-project-domain-name <project-domain-name> + --os-username <username> + --os-user-domain-name <user-domain-name> + [--os-password <password>] + +- For a federated user, your configuration will look the so:: + + export OS_PROJECT_NAME=<project-name> + export OS_PROJECT_DOMAIN_NAME=<project-domain-name> + export OS_AUTH_URL=<url-to-openstack-identity> + export OS_IDENTITY_API_VERSION=3 + export OS_AUTH_PLUGIN=openid + export OS_AUTH_TYPE=v3oidcpassword + export OS_USERNAME=<username-in-idp> + export OS_PASSWORD=<password-in-idp> + export OS_IDENTITY_PROVIDER=<the-desired-idp-in-keystone> + export OS_CLIENT_ID=<the-client-id-configured-in-the-idp> + export OS_CLIENT_SECRET=<the-client-secred-configured-in-the-idp> + export OS_OPENID_SCOPE=<the-scopes-of-desired-attributes-to-claim-from-idp> + export OS_PROTOCOL=<the-protocol-used-in-the-apache2-oidc-proxy> + export OS_ACCESS_TOKEN_TYPE=<the-access-token-type-used-by-your-idp> + export OS_DISCOVERY_ENDPOINT=<the-well-known-endpoint-of-the-idp> + + The corresponding command-line options look very similar:: + + --os-project-name <project-name> + --os-project-domain-name <project-domain-name> + --os-auth-url <url-to-openstack-identity> + --os-identity-api-version 3 + --os-auth-plugin openid + --os-auth-type v3oidcpassword + --os-username <username-in-idp> + --os-password <password-in-idp> + --os-identity-provider <the-desired-idp-in-keystone> + --os-client-id <the-client-id-configured-in-the-idp> + --os-client-secret <the-client-secred-configured-in-the-idp> + --os-openid-scope <the-scopes-of-desired-attributes-to-claim-from-idp> + --os-protocol <the-protocol-used-in-the-apache2-oidc-proxy> + --os-access-token-type <the-access-token-type-used-by-your-idp> + --os-discovery-endpoint <the-well-known-endpoint-of-the-idp> + +If a password is not provided above (in plaintext), you will be interactively +prompted to provide one securely. + diff --git a/debian/changelog b/debian/changelog index be14d11..471cf81 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +python-openstackclient (7.4.0-0ubuntu1) plucky; urgency=medium + + * New upstream release for OpenStack Epoxy. + + -- James Page <james.page@ubuntu.com> Thu, 27 Feb 2025 12:47:04 +0000 + python-openstackclient (7.2.1-0ubuntu1) plucky; urgency=medium * d/gbp.conf, .launchpad.yaml: Sync from cloud-archive-tools for diff --git a/openstackclient/common/limits.py b/openstackclient/common/limits.py index cb2f331..ac613fd 100644 --- a/openstackclient/common/limits.py +++ b/openstackclient/common/limits.py @@ -130,7 +130,7 @@ class ShowLimits(command.Lister): if self.app.client_manager.is_volume_endpoint_enabled(): volume_client = self.app.client_manager.sdk_connection.volume volume_limits = volume_client.get_limits( - project_id=project_id, + project=project_id, ) if parsed_args.is_absolute: diff --git a/openstackclient/common/quota.py b/openstackclient/common/quota.py index 4356cae..638d2e1 100644 --- a/openstackclient/common/quota.py +++ b/openstackclient/common/quota.py @@ -249,9 +249,14 @@ class ListQuota(command.Lister): for project_id in project_ids: try: project_data = compute_client.get_quota_set(project_id) + # NOTE(stephenfin): Unfortunately, Nova raises a HTTP 400 (Bad + # Request) if the project ID is invalid, even though the project + # ID is actually the resource's identifier which would normally + # lead us to expect a HTTP 404 (Not Found). except ( - sdk_exceptions.NotFoundException, + sdk_exceptions.BadRequestException, sdk_exceptions.ForbiddenException, + sdk_exceptions.NotFoundException, ) as exc: # Project not found, move on to next one LOG.warning(f"Project {project_id} not found: {exc}") @@ -312,8 +317,8 @@ class ListQuota(command.Lister): try: project_data = volume_client.get_quota_set(project_id) except ( - sdk_exceptions.NotFoundException, sdk_exceptions.ForbiddenException, + sdk_exceptions.NotFoundException, ) as exc: # Project not found, move on to next one LOG.warning(f"Project {project_id} not found: {exc}") diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index f7b860d..dcadca1 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -714,7 +714,8 @@ class AddServerSecurityGroup(command.Command): for security_group in security_groups: try: compute_client.add_security_group_to_server( - server, security_group + server, + {'name': security_group}, ) except sdk_exceptions.HttpException as e: errors += 1 @@ -1356,14 +1357,26 @@ class CreateServer(command.ShowOne): 'This option requires cloud support.' ), ) - parser.add_argument( + secgroups = parser.add_mutually_exclusive_group() + secgroups.add_argument( + '--no-security-group', + dest='security_groups', + action='store_const', + const=[], + help=_( + 'Do not associate a security group with ports attached to ' + 'this server. This does not affect the security groups ' + 'associated with pre-existing ports.' + ), + ) + secgroups.add_argument( '--security-group', metavar='<security-group>', action='append', - default=[], dest='security_groups', help=_( - 'Security group to assign to this server (name or ID) ' + 'Security group to associate with ports attached to this ' + 'server (name or ID) ' '(repeat option to set multiple groups)' ), ) @@ -1980,22 +1993,24 @@ class CreateServer(command.ShowOne): networks = 'auto' # Check security group(s) exist and convert ID to name - security_groups = [] - if self.app.client_manager.is_network_endpoint_enabled(): - network_client = self.app.client_manager.network - for security_group in parsed_args.security_groups: - sg = network_client.find_security_group( - security_group, ignore_missing=False - ) - # Use security group ID to avoid multiple security group have - # same name in neutron networking backend - security_groups.append({'name': sg.id}) - else: # nova-network - for security_group in parsed_args.security_groups: - sg = compute_v2.find_security_group( - compute_client, security_group - ) - security_groups.append({'name': sg['name']}) + security_groups = None + if parsed_args.security_groups is not None: + security_groups = [] + if self.app.client_manager.is_network_endpoint_enabled(): + network_client = self.app.client_manager.network + for security_group in parsed_args.security_groups: + sg = network_client.find_security_group( + security_group, ignore_missing=False + ) + # Use security group ID to avoid multiple security group + # have same name in neutron networking backend + security_groups.append({'name': sg.id}) + else: # nova-network + for security_group in parsed_args.security_groups: + sg = compute_v2.find_security_group( + compute_client, security_group + ) + security_groups.append({'name': sg['name']}) hints = {} for key, values in parsed_args.hints.items(): @@ -2058,7 +2073,7 @@ class CreateServer(command.ShowOne): if files: kwargs['personality'] = files - if security_groups: + if security_groups is not None: kwargs['security_groups'] = security_groups if block_device_mapping_v2: @@ -4083,7 +4098,8 @@ class RemoveServerSecurityGroup(command.Command): for security_group in security_groups: try: compute_client.remove_security_group_from_server( - server, security_group + server, + {'name': security_group}, ) except sdk_exceptions.HttpException as e: errors += 1 diff --git a/openstackclient/compute/v2/usage.py b/openstackclient/compute/v2/usage.py index 27f9335..5d91358 100644 --- a/openstackclient/compute/v2/usage.py +++ b/openstackclient/compute/v2/usage.py @@ -153,7 +153,7 @@ class ListUsage(command.Lister): ) date_cli_format = "%Y-%m-%d" - now = datetime.datetime.utcnow() + now = datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None) if parsed_args.start: start = datetime.datetime.strptime( @@ -238,7 +238,7 @@ class ShowUsage(command.ShowOne): identity_client = self.app.client_manager.identity compute_client = self.app.client_manager.sdk_connection.compute date_cli_format = "%Y-%m-%d" - now = datetime.datetime.utcnow() + now = datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None) if parsed_args.start: start = datetime.datetime.strptime( diff --git a/openstackclient/identity/common.py b/openstackclient/identity/common.py index b8a5b88..9f4402f 100644 --- a/openstackclient/identity/common.py +++ b/openstackclient/identity/common.py @@ -184,13 +184,6 @@ def _get_token_resource(client, resource, parsed_name, parsed_domain=None): return parsed_name -def _get_domain_id_if_requested(identity_client, domain_name_or_id): - if not domain_name_or_id: - return None - domain = find_domain(identity_client, domain_name_or_id) - return domain.id - - def find_domain(identity_client, name_or_id): return _find_identity_resource( identity_client.domains, name_or_id, domains.Domain @@ -198,48 +191,43 @@ def find_domain(identity_client, name_or_id): def find_group(identity_client, name_or_id, domain_name_or_id=None): - domain_id = _get_domain_id_if_requested(identity_client, domain_name_or_id) - if not domain_id: + if domain_name_or_id is None: return _find_identity_resource( identity_client.groups, name_or_id, groups.Group ) - else: - domain_id = find_domain(identity_client, domain_id).id - return _find_identity_resource( - identity_client.groups, - name_or_id, - groups.Group, - domain_id=domain_id, - ) + + domain_id = find_domain(identity_client, domain_name_or_id).id + return _find_identity_resource( + identity_client.groups, + name_or_id, + groups.Group, + domain_id=domain_id, + ) def find_project(identity_client, name_or_id, domain_name_or_id=None): - domain_id = _get_domain_id_if_requested(identity_client, domain_name_or_id) - if not domain_id: + if domain_name_or_id is None: return _find_identity_resource( identity_client.projects, name_or_id, projects.Project ) - else: - domain_id = find_domain(identity_client, domain_id).id - return _find_identity_resource( - identity_client.projects, - name_or_id, - projects.Project, - domain_id=domain_id, - ) + domain_id = find_domain(identity_client, domain_name_or_id).id + return _find_identity_resource( + identity_client.projects, + name_or_id, + projects.Project, + domain_id=domain_id, + ) def find_user(identity_client, name_or_id, domain_name_or_id=None): - domain_id = _get_domain_id_if_requested(identity_client, domain_name_or_id) - if not domain_id: + if domain_name_or_id is None: return _find_identity_resource( identity_client.users, name_or_id, users.User ) - else: - domain_id = find_domain(identity_client, domain_id).id - return _find_identity_resource( - identity_client.users, name_or_id, users.User, domain_id=domain_id - ) + domain_id = find_domain(identity_client, domain_name_or_id).id + return _find_identity_resource( + identity_client.users, name_or_id, users.User, domain_id=domain_id + ) def _find_identity_resource( diff --git a/openstackclient/identity/v3/credential.py b/openstackclient/identity/v3/credential.py index 1b0d525..33297e9 100644 --- a/openstackclient/identity/v3/credential.py +++ b/openstackclient/identity/v3/credential.py @@ -28,6 +28,23 @@ from openstackclient.identity import common LOG = logging.getLogger(__name__) +def _format_credential(credential): + columns = ( + 'blob', + 'id', + 'project_id', + 'type', + 'user_id', + ) + return ( + columns, + utils.get_item_properties( + credential, + columns, + ), + ) + + class CreateCredential(command.ShowOne): _description = _("Create new credential") @@ -60,25 +77,24 @@ class CreateCredential(command.ShowOne): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity - user_id = utils.find_resource( - identity_client.users, parsed_args.user + identity_client = self.app.client_manager.sdk_connection.identity + user_id = identity_client.find_user( + parsed_args.user, ignore_missing=False ).id if parsed_args.project: - project = utils.find_resource( - identity_client.projects, parsed_args.project + project = identity_client.find_project( + parsed_args.project, ignore_missing=False ).id else: project = None - credential = identity_client.credentials.create( - user=user_id, + credential = identity_client.create_credential( + user_id=user_id, type=parsed_args.type, blob=parsed_args.data, - project=project, + project_id=project, ) - credential._info.pop('links') - return zip(*sorted(credential._info.items())) + return _format_credential(credential) class DeleteCredential(command.Command): @@ -95,11 +111,11 @@ class DeleteCredential(command.Command): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity result = 0 for i in parsed_args.credential: try: - identity_client.credentials.delete(i) + identity_client.delete_credential(i) except Exception as e: result += 1 LOG.error( @@ -137,14 +153,17 @@ class ListCredential(command.Lister): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity kwargs = {} if parsed_args.user: - user_id = common.find_user( - identity_client, - parsed_args.user, - parsed_args.user_domain, + domain_id = None + if parsed_args.user_domain: + domain_id = identity_client.find_domain( + parsed_args.user_domain, ignore_missing=False + ) + user_id = identity_client.find_user( + parsed_args.user, domain_id=domain_id, ignore_missing=False ).id kwargs["user_id"] = user_id @@ -153,7 +172,8 @@ class ListCredential(command.Lister): columns = ('ID', 'Type', 'User ID', 'Blob', 'Project ID') column_headers = ('ID', 'Type', 'User ID', 'Data', 'Project ID') - data = self.app.client_manager.identity.credentials.list(**kwargs) + data = identity_client.credentials(**kwargs) + return ( column_headers, ( @@ -206,20 +226,20 @@ class SetCredential(command.Command): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity - user_id = utils.find_resource( - identity_client.users, parsed_args.user + user_id = identity_client.find_user( + parsed_args.user, ignore_missing=False ).id if parsed_args.project: - project = utils.find_resource( - identity_client.projects, parsed_args.project + project = identity_client.find_project( + parsed_args.project, ignore_missing=False ).id else: project = None - identity_client.credentials.update( + identity_client.update_credential( parsed_args.credential, user=user_id, type=parsed_args.type, @@ -241,10 +261,7 @@ class ShowCredential(command.ShowOne): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity - credential = utils.find_resource( - identity_client.credentials, parsed_args.credential - ) + identity_client = self.app.client_manager.sdk_connection.identity + credential = identity_client.get_credential(parsed_args.credential) - credential._info.pop('links') - return zip(*sorted(credential._info.items())) + return _format_credential(credential) diff --git a/openstackclient/identity/v3/limit.py b/openstackclient/identity/v3/limit.py index 59cc139..44a3f63 100644 --- a/openstackclient/identity/v3/limit.py +++ b/openstackclient/identity/v3/limit.py @@ -90,6 +90,13 @@ class CreateLimit(command.ShowOne): region = common_utils.get_resource( identity_client.regions, parsed_args.region ) + else: + self.log.warning( + _( + "Passing 'None' to indicate no region is deprecated. " + "Instead, don't pass --region." + ) + ) limit = identity_client.limits.create( project, @@ -158,6 +165,14 @@ class ListLimit(command.Lister): region = common_utils.get_resource( identity_client.regions, parsed_args.region ) + else: + self.log.warning( + _( + "Passing 'None' to indicate no region is deprecated. " + "Instead, don't pass --region." + ) + ) + project = None if parsed_args.project: project = utils.find_resource( diff --git a/openstackclient/identity/v3/region.py b/openstackclient/identity/v3/region.py index ba8c02c..faa2bc4 100644 --- a/openstackclient/identity/v3/region.py +++ b/openstackclient/identity/v3/region.py @@ -25,6 +25,15 @@ from openstackclient.i18n import _ LOG = logging.getLogger(__name__) +def _format_region(region): + columns = ('id', 'description', 'parent_region_id') + column_headers = ('region', 'description', 'parent_region') + return ( + column_headers, + utils.get_item_properties(region, columns), + ) + + class CreateRegion(command.ShowOne): _description = _("Create new region") @@ -50,18 +59,15 @@ class CreateRegion(command.ShowOne): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity - region = identity_client.regions.create( + region = identity_client.create_region( id=parsed_args.region, - parent_region=parsed_args.parent_region, + parent_region_id=parsed_args.parent_region, description=parsed_args.description, ) - region._info['region'] = region._info.pop('id') - region._info['parent_region'] = region._info.pop('parent_region_id') - region._info.pop('links', None) - return zip(*sorted(region._info.items())) + return _format_region(region) class DeleteRegion(command.Command): @@ -78,11 +84,11 @@ class DeleteRegion(command.Command): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity result = 0 for i in parsed_args.region: try: - identity_client.regions.delete(i) + identity_client.delete_region(i) except Exception as e: result += 1 LOG.error( @@ -115,7 +121,7 @@ class ListRegion(command.Lister): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity kwargs = {} if parsed_args.parent_region: @@ -124,7 +130,7 @@ class ListRegion(command.Lister): columns_headers = ('Region', 'Parent Region', 'Description') columns = ('ID', 'Parent Region Id', 'Description') - data = identity_client.regions.list(**kwargs) + data = identity_client.regions(**kwargs) return ( columns_headers, ( @@ -161,15 +167,15 @@ class SetRegion(command.Command): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity kwargs = {} if parsed_args.description: kwargs['description'] = parsed_args.description if parsed_args.parent_region: - kwargs['parent_region'] = parsed_args.parent_region + kwargs['parent_region_id'] = parsed_args.parent_region - identity_client.regions.update(parsed_args.region, **kwargs) + identity_client.update_region(parsed_args.region, **kwargs) class ShowRegion(command.ShowOne): @@ -185,13 +191,8 @@ class ShowRegion(command.ShowOne): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity - region = utils.find_resource( - identity_client.regions, parsed_args.region - ) + region = identity_client.get_region(parsed_args.region) - region._info['region'] = region._info.pop('id') - region._info['parent_region'] = region._info.pop('parent_region_id') - region._info.pop('links', None) - return zip(*sorted(region._info.items())) + return _format_region(region) diff --git a/openstackclient/identity/v3/registered_limit.py b/openstackclient/identity/v3/registered_limit.py index f71ef1f..336151d 100644 --- a/openstackclient/identity/v3/registered_limit.py +++ b/openstackclient/identity/v3/registered_limit.py @@ -81,6 +81,13 @@ class CreateRegisteredLimit(command.ShowOne): region = common_utils.get_resource( identity_client.regions, parsed_args.region ) + else: + self.log.warning( + _( + "Passing 'None' to indicate no region is deprecated. " + "Instead, don't pass --region." + ) + ) registered_limit = identity_client.registered_limits.create( service, @@ -182,6 +189,13 @@ class ListRegisteredLimit(command.Lister): region = common_utils.get_resource( identity_client.regions, parsed_args.region ) + else: + self.log.warning( + _( + "Passing 'None' to indicate no region is deprecated. " + "Instead, don't pass --region." + ) + ) registered_limits = identity_client.registered_limits.list( service=service, @@ -280,6 +294,10 @@ class SetRegisteredLimit(command.ShowOne): region = common_utils.get_resource( identity_client.regions, parsed_args.region ) + else: + self.log.warning( + _("Passing 'None' to indicate no region is deprecated.") + ) registered_limit = identity_client.registered_limits.update( parsed_args.registered_limit_id, diff --git a/openstackclient/identity/v3/role.py b/openstackclient/identity/v3/role.py index c43f389..a7fb664 100644 --- a/openstackclient/identity/v3/role.py +++ b/openstackclient/identity/v3/role.py @@ -17,7 +17,7 @@ import logging -from keystoneauth1 import exceptions as ks_exc +from openstack import exceptions as sdk_exc from osc_lib.command import command from osc_lib import exceptions from osc_lib import utils @@ -29,6 +29,25 @@ from openstackclient.identity import common LOG = logging.getLogger(__name__) +def _format_role(role): + columns = ( + "id", + "name", + "domain_id", + "description", + ) + column_headers = ( + "id", + "name", + "domain_id", + "description", + ) + return ( + column_headers, + utils.get_item_properties(role, columns), + ) + + def _add_identity_and_resource_options_to_parser(parser): system_or_domain_or_project = parser.add_mutually_exclusive_group() system_or_domain_or_project.add_argument( @@ -63,32 +82,79 @@ def _add_identity_and_resource_options_to_parser(parser): common.add_inherited_option_to_parser(parser) +def _find_sdk_id( + find_command, name_or_id, validate_actor_existence=True, **kwargs +): + try: + resource = find_command( + name_or_id=name_or_id, ignore_missing=False, **kwargs + ) + + # Mimic the behavior of + # openstackclient.identity.common._find_identity_resource() + # and ignore if we don't have permission to find a resource. + except sdk_exc.ForbiddenException: + return name_or_id + except sdk_exc.ResourceNotFound as exc: + if not validate_actor_existence: + return name_or_id + raise exceptions.CommandError from exc + return resource.id + + def _process_identity_and_resource_options( - parsed_args, identity_client_manager, validate_actor_existence=True + parsed_args, identity_client, validate_actor_existence=True ): def _find_user(): - try: - return common.find_user( - identity_client_manager, - parsed_args.user, - parsed_args.user_domain, - ).id - except exceptions.CommandError: - if not validate_actor_existence: - return parsed_args.user - raise + domain_id = ( + _find_sdk_id( + identity_client.find_domain, + name_or_id=parsed_args.user_domain, + validate_actor_existence=validate_actor_existence, + ) + if parsed_args.user_domain + else None + ) + return _find_sdk_id( + identity_client.find_user, + name_or_id=parsed_args.user, + validate_actor_existence=validate_actor_existence, + domain_id=domain_id, + ) def _find_group(): - try: - return common.find_group( - identity_client_manager, - parsed_args.group, - parsed_args.group_domain, - ).id - except exceptions.CommandError: - if not validate_actor_existence: - return parsed_args.group - raise + domain_id = ( + _find_sdk_id( + identity_client.find_domain, + name_or_id=parsed_args.group_domain, + validate_actor_existence=validate_actor_existence, + ) + if parsed_args.group_domain + else None + ) + return _find_sdk_id( + identity_client.find_group, + name_or_id=parsed_args.group, + validate_actor_existence=validate_actor_existence, + domain_id=domain_id, + ) + + def _find_project(): + domain_id = ( + _find_sdk_id( + identity_client.find_domain, + name_or_id=parsed_args.project_domain, + validate_actor_existence=validate_actor_existence, + ) + if parsed_args.project_domain + else None + ) + return _find_sdk_id( + identity_client.find_project, + name_or_id=parsed_args.project, + validate_actor_existence=validate_actor_existence, + domain_id=domain_id, + ) kwargs = {} if parsed_args.user and parsed_args.system: @@ -96,34 +162,35 @@ def _process_identity_and_resource_options( kwargs['system'] = parsed_args.system elif parsed_args.user and parsed_args.domain: kwargs['user'] = _find_user() - kwargs['domain'] = common.find_domain( - identity_client_manager, - parsed_args.domain, - ).id + kwargs['domain'] = _find_sdk_id( + identity_client.find_domain, + name_or_id=parsed_args.domain, + validate_actor_existence=validate_actor_existence, + ) elif parsed_args.user and parsed_args.project: kwargs['user'] = _find_user() - kwargs['project'] = common.find_project( - identity_client_manager, - parsed_args.project, - parsed_args.project_domain, - ).id + kwargs['project'] = _find_project() elif parsed_args.group and parsed_args.system: kwargs['group'] = _find_group() kwargs['system'] = parsed_args.system elif parsed_args.group and parsed_args.domain: kwargs['group'] = _find_group() - kwargs['domain'] = common.find_domain( - identity_client_manager, - parsed_args.domain, - ).id + kwargs['domain'] = _find_sdk_id( + identity_client.find_domain, + name_or_id=parsed_args.domain, + validate_actor_existence=validate_actor_existence, + ) elif parsed_args.group and parsed_args.project: kwargs['group'] = _find_group() - kwargs['project'] = common.find_project( - identity_client_manager, - parsed_args.project, - parsed_args.project_domain, - ).id - kwargs['os_inherit_extension_inherited'] = parsed_args.inherited + kwargs['project'] = _find_project() + else: + msg = _( + "Role not added, incorrect set of arguments " + "provided. See openstack --help for more details" + ) + raise exceptions.CommandError(msg) + + kwargs['inherited'] = parsed_args.inherited return kwargs @@ -145,7 +212,7 @@ class AddRole(command.Command): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity if ( not parsed_args.user @@ -161,18 +228,71 @@ class AddRole(command.Command): domain_id = None if parsed_args.role_domain: - domain_id = common.find_domain( - identity_client, parsed_args.role_domain - ).id - role = utils.find_resource( - identity_client.roles, parsed_args.role, domain_id=domain_id + domain_id = _find_sdk_id( + identity_client.find_domain, name_or_id=parsed_args.role_domain + ) + role = _find_sdk_id( + identity_client.find_role, + name_or_id=parsed_args.role, + domain_id=domain_id, ) - kwargs = _process_identity_and_resource_options( - parsed_args, self.app.client_manager.identity + add_kwargs = _process_identity_and_resource_options( + parsed_args, identity_client ) - identity_client.roles.grant(role.id, **kwargs) + if add_kwargs.get("domain"): + if add_kwargs.get("user"): + identity_client.assign_domain_role_to_user( + domain=add_kwargs["domain"], + user=add_kwargs["user"], + role=role, + inherited=add_kwargs["inherited"], + ) + if add_kwargs.get("group"): + identity_client.assign_domain_role_to_group( + domain=add_kwargs["domain"], + group=add_kwargs["group"], + role=role, + inherited=add_kwargs["inherited"], + ) + elif add_kwargs.get("project"): + if add_kwargs.get("user"): + identity_client.assign_project_role_to_user( + project=add_kwargs["project"], + user=add_kwargs["user"], + role=role, + inherited=add_kwargs["inherited"], + ) + if add_kwargs.get("group"): + identity_client.assign_project_role_to_group( + project=add_kwargs["project"], + group=add_kwargs["group"], + role=role, + inherited=add_kwargs["inherited"], + ) + elif add_kwargs.get("system"): + if add_kwargs["inherited"]: + LOG.warning( + _( + "'--inherited' was given, which is not supported " + "when adding a system role. This will be an error " + "in a future release." + ) + ) + # TODO(0weng): This should be an error in a future release + if add_kwargs.get("user"): + identity_client.assign_system_role_to_user( + system=add_kwargs["system"], + user=add_kwargs["user"], + role=role, + ) + if add_kwargs.get("group"): + identity_client.assign_system_role_to_group( + system=add_kwargs["system"], + group=add_kwargs["group"], + role=role, + ) class CreateRole(command.ShowOne): @@ -204,37 +324,35 @@ class CreateRole(command.ShowOne): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity - domain_id = None + create_kwargs = {} if parsed_args.domain: - domain_id = common.find_domain( - identity_client, parsed_args.domain - ).id + create_kwargs['domain_id'] = _find_sdk_id( + identity_client.find_domain, name_or_id=parsed_args.domain + ) - options = common.get_immutable_options(parsed_args) + if parsed_args.name: + create_kwargs['name'] = parsed_args.name + if parsed_args.description: + create_kwargs['description'] = parsed_args.description + create_kwargs['options'] = common.get_immutable_options(parsed_args) try: - role = identity_client.roles.create( - name=parsed_args.name, - domain=domain_id, - description=parsed_args.description, - options=options, - ) + role = identity_client.create_role(**create_kwargs) - except ks_exc.Conflict: + except sdk_exc.ConflictException: if parsed_args.or_show: - role = utils.find_resource( - identity_client.roles, - parsed_args.name, - domain_id=domain_id, + role = identity_client.find_role( + name_or_id=parsed_args.name, + domain_id=parsed_args.domain, + ignore_missing=False, ) LOG.info(_('Returning existing role %s'), role.name) else: raise - role._info.pop('links') - return zip(*sorted(role._info.items())) + return _format_role(role) class DeleteRole(command.Command): @@ -245,7 +363,7 @@ class DeleteRole(command.Command): parser.add_argument( 'roles', metavar='<role>', - nargs="+", + nargs='+', help=_('Role(s) to delete (name or ID)'), ) parser.add_argument( @@ -256,20 +374,22 @@ class DeleteRole(command.Command): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity domain_id = None if parsed_args.domain: - domain_id = common.find_domain( - identity_client, parsed_args.domain - ).id + domain_id = _find_sdk_id( + identity_client.find_domain, parsed_args.domain + ) errors = 0 for role in parsed_args.roles: try: - role_obj = utils.find_resource( - identity_client.roles, role, domain_id=domain_id + role_id = _find_sdk_id( + identity_client.find_role, + name_or_id=role, + domain_id=domain_id, ) - identity_client.roles.delete(role_obj.id) + identity_client.delete_role(role=role_id, ignore_missing=False) except Exception as e: errors += 1 LOG.error( @@ -302,20 +422,17 @@ class ListRole(command.Lister): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity if parsed_args.domain: - domain = common.find_domain( - identity_client, - parsed_args.domain, + domain = identity_client.find_domain( + name_or_id=parsed_args.domain, ) columns = ('ID', 'Name', 'Domain') - data = identity_client.roles.list(domain_id=domain.id) - for role in data: - role.domain = domain.name + data = identity_client.roles(domain_id=domain.id) else: columns = ('ID', 'Name') - data = identity_client.roles.list() + data = identity_client.roles() return ( columns, @@ -323,7 +440,7 @@ class ListRole(command.Lister): utils.get_item_properties( s, columns, - formatters={}, + formatters={'Domain': lambda _: domain.name}, ) for s in data ), @@ -348,8 +465,7 @@ class RemoveRole(command.Command): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity - + identity_client = self.app.client_manager.sdk_connection.identity if ( not parsed_args.user and not parsed_args.domain @@ -364,19 +480,65 @@ class RemoveRole(command.Command): domain_id = None if parsed_args.role_domain: - domain_id = common.find_domain( - identity_client, parsed_args.role_domain - ).id - role = utils.find_resource( - identity_client.roles, parsed_args.role, domain_id=domain_id + domain_id = _find_sdk_id( + identity_client.find_domain, + name_or_id=parsed_args.role_domain, + ) + role = _find_sdk_id( + identity_client.find_role, + name_or_id=parsed_args.role, + domain_id=domain_id, ) - kwargs = _process_identity_and_resource_options( + remove_kwargs = _process_identity_and_resource_options( parsed_args, - self.app.client_manager.identity, + identity_client, validate_actor_existence=False, ) - identity_client.roles.revoke(role.id, **kwargs) + + if remove_kwargs.get("domain"): + if remove_kwargs.get("user"): + identity_client.unassign_domain_role_from_user( + domain=remove_kwargs["domain"], + user=remove_kwargs["user"], + role=role, + inherited=remove_kwargs["inherited"], + ) + if remove_kwargs.get("group"): + identity_client.unassign_domain_role_from_group( + domain=remove_kwargs["domain"], + group=remove_kwargs["group"], + role=role, + inherited=remove_kwargs["inherited"], + ) + elif remove_kwargs.get("project"): + if remove_kwargs.get("user"): + identity_client.unassign_project_role_from_user( + project=remove_kwargs["project"], + user=remove_kwargs["user"], + role=role, + inherited=remove_kwargs["inherited"], + ) + if remove_kwargs.get("group"): + identity_client.unassign_project_role_from_group( + project=remove_kwargs["project"], + group=remove_kwargs["group"], + role=role, + inherited=remove_kwargs["inherited"], + ) + elif remove_kwargs.get("system"): + if remove_kwargs.get("user"): + identity_client.unassign_system_role_from_user( + system=remove_kwargs["system"], + user=remove_kwargs["user"], + role=role, + ) + if remove_kwargs.get("group"): + identity_client.unassign_system_role_from_group( + system=remove_kwargs["system"], + group=remove_kwargs["group"], + role=role, + ) class SetRole(command.Command): @@ -408,25 +570,31 @@ class SetRole(command.Command): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity + + update_kwargs = {} + if parsed_args.description: + update_kwargs["description"] = parsed_args.description + if parsed_args.name: + update_kwargs["name"] = parsed_args.name domain_id = None if parsed_args.domain: - domain_id = common.find_domain( - identity_client, parsed_args.domain - ).id + domain_id = _find_sdk_id( + identity_client.find_domain, + name_or_id=parsed_args.domain, + ) + update_kwargs["domain_id"] = domain_id - options = common.get_immutable_options(parsed_args) - role = utils.find_resource( - identity_client.roles, parsed_args.role, domain_id=domain_id + update_kwargs["options"] = common.get_immutable_options(parsed_args) + role = _find_sdk_id( + identity_client.find_role, + name_or_id=parsed_args.role, + domain_id=domain_id, ) + update_kwargs["role"] = role - identity_client.roles.update( - role.id, - name=parsed_args.name, - description=parsed_args.description, - options=options, - ) + identity_client.update_role(**update_kwargs) class ShowRole(command.ShowOne): @@ -447,17 +615,19 @@ class ShowRole(command.ShowOne): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity domain_id = None if parsed_args.domain: - domain_id = common.find_domain( - identity_client, parsed_args.domain - ).id + domain_id = _find_sdk_id( + identity_client.find_domain, + name_or_id=parsed_args.domain, + ) - role = utils.find_resource( - identity_client.roles, parsed_args.role, domain_id=domain_id + role = identity_client.find_role( + name_or_id=parsed_args.role, + domain_id=domain_id, + ignore_missing=False, ) - role._info.pop('links') - return zip(*sorted(role._info.items())) + return _format_role(role) diff --git a/openstackclient/identity/v3/role_assignment.py b/openstackclient/identity/v3/role_assignment.py index 7d4dfcd..12e1527 100644 --- a/openstackclient/identity/v3/role_assignment.py +++ b/openstackclient/identity/v3/role_assignment.py @@ -148,7 +148,7 @@ class ListRoleAssignment(command.Lister): user_domain_id = None if parsed_args.user_domain: - project_domain_id = _find_sdk_id( + user_domain_id = _find_sdk_id( identity_client.find_domain, name_or_id=parsed_args.user_domain, ) diff --git a/openstackclient/identity/v3/service_provider.py b/openstackclient/identity/v3/service_provider.py index 79869ee..1a7b02f 100644 --- a/openstackclient/identity/v3/service_provider.py +++ b/openstackclient/identity/v3/service_provider.py @@ -25,6 +25,29 @@ from openstackclient.i18n import _ LOG = logging.getLogger(__name__) +def _format_service_provider(sp): + column_headers = ( + 'id', + 'enabled', + 'description', + 'auth_url', + 'sp_url', + 'relay_state_prefix', + ) + columns = ( + 'id', + 'is_enabled', + 'description', + 'auth_url', + 'sp_url', + 'relay_state_prefix', + ) + return ( + column_headers, + utils.get_item_properties(sp, columns), + ) + + class CreateServiceProvider(command.ShowOne): _description = _("Create new service provider") @@ -62,14 +85,14 @@ class CreateServiceProvider(command.ShowOne): enable_service_provider = parser.add_mutually_exclusive_group() enable_service_provider.add_argument( '--enable', - dest='enabled', + dest='is_enabled', action='store_true', default=True, help=_('Enable the service provider (default)'), ) enable_service_provider.add_argument( '--disable', - dest='enabled', + dest='is_enabled', action='store_false', help=_('Disable the service provider'), ) @@ -77,17 +100,27 @@ class CreateServiceProvider(command.ShowOne): return parser def take_action(self, parsed_args): - service_client = self.app.client_manager.identity - sp = service_client.federation.service_providers.create( - id=parsed_args.service_provider_id, - auth_url=parsed_args.auth_url, - description=parsed_args.description, - enabled=parsed_args.enabled, - sp_url=parsed_args.service_provider_url, - ) + service_client = self.app.client_manager.sdk_connection.identity + + kwargs = {} + + kwargs = {'id': parsed_args.service_provider_id} + + if parsed_args.is_enabled is not None: + kwargs['is_enabled'] = parsed_args.is_enabled - sp._info.pop('links', None) - return zip(*sorted(sp._info.items())) + if parsed_args.description: + kwargs['description'] = parsed_args.description + + if parsed_args.auth_url: + kwargs['auth_url'] = parsed_args.auth_url + + if parsed_args.service_provider_url: + kwargs['sp_url'] = parsed_args.service_provider_url + + sp = service_client.create_service_provider(**kwargs) + + return _format_service_provider(sp) class DeleteServiceProvider(command.Command): @@ -104,11 +137,11 @@ class DeleteServiceProvider(command.Command): return parser def take_action(self, parsed_args): - service_client = self.app.client_manager.identity + service_client = self.app.client_manager.sdk_connection.identity result = 0 for i in parsed_args.service_provider: try: - service_client.federation.service_providers.delete(i) + service_client.delete_service_provider(i) except Exception as e: result += 1 LOG.error( @@ -132,24 +165,32 @@ class ListServiceProvider(command.Lister): _description = _("List service providers") def take_action(self, parsed_args): - service_client = self.app.client_manager.identity - data = service_client.federation.service_providers.list() - - column_headers = ('ID', 'Enabled', 'Description', 'Auth URL') + service_client = self.app.client_manager.sdk_connection.identity + data = service_client.service_providers() + + column_headers = ( + 'ID', + 'Enabled', + 'Description', + 'Auth URL', + 'Service Provider URL', + 'Relay State Prefix', + ) + columns = ( + 'id', + 'is_enabled', + 'description', + 'auth_url', + 'sp_url', + 'relay_state_prefix', + ) return ( column_headers, - ( - utils.get_item_properties( - s, - column_headers, - formatters={}, - ) - for s in data - ), + (utils.get_item_properties(s, columns) for s in data), ) -class SetServiceProvider(command.Command): +class SetServiceProvider(command.ShowOne): _description = _("Set service provider properties") def get_parser(self, prog_name): @@ -181,33 +222,44 @@ class SetServiceProvider(command.Command): enable_service_provider = parser.add_mutually_exclusive_group() enable_service_provider.add_argument( '--enable', + dest='is_enabled', action='store_true', + default=None, help=_('Enable the service provider'), ) enable_service_provider.add_argument( '--disable', - action='store_true', + dest='is_enabled', + action='store_false', + default=None, help=_('Disable the service provider'), ) return parser def take_action(self, parsed_args): - federation_client = self.app.client_manager.identity.federation + service_client = self.app.client_manager.sdk_connection.identity - enabled = None - if parsed_args.enable is True: - enabled = True - elif parsed_args.disable is True: - enabled = False + kwargs = {} - federation_client.service_providers.update( + if parsed_args.is_enabled is not None: + kwargs['is_enabled'] = parsed_args.is_enabled + + if parsed_args.description: + kwargs['description'] = parsed_args.description + + if parsed_args.auth_url: + kwargs['auth_url'] = parsed_args.auth_url + + if parsed_args.service_provider_url: + kwargs['sp_url'] = parsed_args.service_provider_url + + service_provider = service_client.update_service_provider( parsed_args.service_provider, - enabled=enabled, - description=parsed_args.description, - auth_url=parsed_args.auth_url, - sp_url=parsed_args.service_provider_url, + **kwargs, ) + return _format_service_provider(service_provider) + class ShowServiceProvider(command.ShowOne): _description = _("Display service provider details") @@ -222,12 +274,10 @@ class ShowServiceProvider(command.ShowOne): return parser def take_action(self, parsed_args): - service_client = self.app.client_manager.identity - service_provider = utils.find_resource( - service_client.federation.service_providers, + service_client = self.app.client_manager.sdk_connection.identity + service_provider = service_client.find_service_provider( parsed_args.service_provider, - id=parsed_args.service_provider, + ignore_missing=False, ) - service_provider._info.pop('links', None) - return zip(*sorted(service_provider._info.items())) + return _format_service_provider(service_provider) diff --git a/openstackclient/identity/v3/trust.py b/openstackclient/identity/v3/trust.py index 33fee4a..447a57f 100644 --- a/openstackclient/identity/v3/trust.py +++ b/openstackclient/identity/v3/trust.py @@ -14,9 +14,10 @@ """Identity v3 Trust action implementations""" import datetime +import itertools import logging -from keystoneclient import exceptions as identity_exc +from openstack import exceptions as sdk_exceptions from osc_lib.command import command from osc_lib import exceptions from osc_lib import utils @@ -28,6 +29,25 @@ from openstackclient.identity import common LOG = logging.getLogger(__name__) +def _format_trust(trust): + columns = ( + 'expires_at', + 'id', + 'is_impersonation', + 'project_id', + 'redelegated_trust_id', + 'redelegation_count', + 'remaining_uses', + 'roles', + 'trustee_user_id', + 'trustor_user_id', + ) + return ( + columns, + utils.get_item_properties(trust, columns), + ) + + class CreateTrust(command.ShowOne): _description = _("Create new trust") @@ -52,6 +72,7 @@ class CreateTrust(command.ShowOne): parser.add_argument( '--role', metavar='<role>', + dest='roles', action='append', default=[], help=_( @@ -62,7 +83,7 @@ class CreateTrust(command.ShowOne): ) parser.add_argument( '--impersonate', - dest='impersonate', + dest='is_impersonation', action='store_true', default=False, help=_( @@ -92,58 +113,60 @@ class CreateTrust(command.ShowOne): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity + + kwargs = {} # NOTE(stevemar): Find the two users, project and roles that # are necessary for making a trust usable, the API dictates that # trustee, project and role are optional, but that makes the trust # pointless, and trusts are immutable, so let's enforce it at the # client level. - trustor_id = common.find_user( - identity_client, parsed_args.trustor, parsed_args.trustor_domain - ).id - trustee_id = common.find_user( - identity_client, parsed_args.trustee, parsed_args.trustee_domain - ).id - project_id = common.find_project( - identity_client, parsed_args.project, parsed_args.project_domain - ).id + try: + trustor_id = identity_client.find_user( + parsed_args.trustor, parsed_args.trustor_domain + ).id + kwargs['trustor_id'] = trustor_id + except sdk_exceptions.ForbiddenException: + kwargs['trustor_id'] = parsed_args.trustor + + try: + trustee_id = identity_client.find_user( + parsed_args.trustee, parsed_args.trustee_domain + ).id + kwargs['trustee_id'] = trustee_id + except sdk_exceptions.ForbiddenException: + kwargs['trustee_id'] = parsed_args.trustee + + try: + project_id = identity_client.find_project( + parsed_args.project, parsed_args.project_domain + ).id + kwargs['project_id'] = project_id + except sdk_exceptions.ForbiddenException: + kwargs['project_id'] = parsed_args.project role_ids = [] - for role in parsed_args.role: + for role in parsed_args.roles: try: - role_id = utils.find_resource( - identity_client.roles, - role, - ).id - except identity_exc.Forbidden: + role_id = identity_client.find_role(role).id + except sdk_exceptions.ForbiddenException: role_id = role role_ids.append(role_id) + kwargs['roles'] = role_ids - expires_at = None if parsed_args.expiration: expires_at = datetime.datetime.strptime( parsed_args.expiration, '%Y-%m-%dT%H:%M:%S' ) + kwargs['expires_at'] = expires_at - trust = identity_client.trusts.create( - trustee_id, - trustor_id, - impersonation=parsed_args.impersonate, - project=project_id, - role_ids=role_ids, - expires_at=expires_at, - ) - - trust._info.pop('roles_links', None) - trust._info.pop('links', None) + if parsed_args.is_impersonation: + kwargs['is_impersonation'] = parsed_args.is_impersonation - # Format roles into something sensible - roles = trust._info.pop('roles') - msg = ' '.join(r['name'] for r in roles) - trust._info['roles'] = msg + trust = identity_client.create_trust(**kwargs) - return zip(*sorted(trust._info.items())) + return _format_trust(trust) class DeleteTrust(command.Command): @@ -160,13 +183,15 @@ class DeleteTrust(command.Command): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity errors = 0 for trust in parsed_args.trust: try: - trust_obj = utils.find_resource(identity_client.trusts, trust) - identity_client.trusts.delete(trust_obj.id) + trust_obj = identity_client.find_trust( + trust, ignore_missing=False + ) + identity_client.delete_trust(trust_obj.id) except Exception as e: errors += 1 LOG.error( @@ -220,7 +245,7 @@ class ListTrust(command.Lister): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity + identity_client = self.app.client_manager.sdk_connection.identity auth_ref = self.app.client_manager.auth_ref if parsed_args.authuser and any( @@ -243,38 +268,50 @@ class ListTrust(command.Lister): raise exceptions.CommandError(msg) if parsed_args.authuser: - if auth_ref: - user = common.find_user(identity_client, auth_ref.user_id) - # We need two calls here as we want trusts with - # either the trustor or the trustee set to current user - # using a single call would give us trusts with both - # trustee and trustor set to current user - data1 = identity_client.trusts.list(trustor_user=user) - data2 = identity_client.trusts.list(trustee_user=user) - data = set(data1 + data2) + # We need two calls here as we want trusts with + # either the trustor or the trustee set to current user + # using a single call would give us trusts with both + # trustee and trustor set to current user + data = list( + { + x.id: x + for x in itertools.chain( + identity_client.trusts( + trustor_user_id=auth_ref.user_id + ), + identity_client.trusts( + trustee_user_id=auth_ref.user_id + ), + ) + }.values() + ) else: trustor = None if parsed_args.trustor: - trustor = common.find_user( - identity_client, - parsed_args.trustor, - parsed_args.trustor_domain, - ) + try: + trustor_id = identity_client.find_user( + parsed_args.trustor, parsed_args.trustor_domain + ).id + trustor = trustor_id + except sdk_exceptions.ForbiddenException: + trustor = parsed_args.trustor trustee = None if parsed_args.trustee: - trustee = common.find_user( - identity_client, - parsed_args.trustor, - parsed_args.trustor_domain, - ) - - data = self.app.client_manager.identity.trusts.list( - trustor_user=trustor, - trustee_user=trustee, + try: + trustee_id = identity_client.find_user( + parsed_args.trustee, parsed_args.trustee_domain + ).id + trustee = trustee_id + except sdk_exceptions.ForbiddenException: + trustee = parsed_args.trustee + + data = identity_client.trusts( + trustor_user_id=trustor, + trustee_user_id=trustee, ) - columns = ( + column_headers = ( 'ID', 'Expires At', 'Impersonation', @@ -282,9 +319,17 @@ class ListTrust(command.Lister): 'Trustee User ID', 'Trustor User ID', ) + columns = ( + 'id', + 'expires_at', + 'is_impersonation', + 'project_id', + 'trustee_user_id', + 'trustor_user_id', + ) return ( - columns, + column_headers, ( utils.get_item_properties( s, @@ -309,15 +354,9 @@ class ShowTrust(command.ShowOne): return parser def take_action(self, parsed_args): - identity_client = self.app.client_manager.identity - trust = utils.find_resource(identity_client.trusts, parsed_args.trust) - - trust._info.pop('roles_links', None) - trust._info.pop('links', None) - - # Format roles into something sensible - roles = trust._info.pop('roles') - msg = ' '.join(r['name'] for r in roles) - trust._info['roles'] = msg + identity_client = self.app.client_manager.sdk_connection.identity + trust = identity_client.find_trust( + parsed_args.trust, ignore_missing=False + ) - return zip(*sorted(trust._info.items())) + return _format_trust(trust) diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py index 094c507..fe237e4 100644 --- a/openstackclient/image/v2/image.py +++ b/openstackclient/image/v2/image.py @@ -576,6 +576,9 @@ class CreateImage(command.ShowOne): if parsed_args.filename: fp.close() + # NOTE(pas-ha): create_image returns the image object as it was created + # before the data was uploaded, need a refresh to show the final state + image = image_client.get_image(image) return _format_image(image) def _take_action_volume(self, parsed_args): diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py index de1910e..7636de0 100644 --- a/openstackclient/network/v2/network.py +++ b/openstackclient/network/v2/network.py @@ -14,6 +14,7 @@ from cliff import columns as cliff_columns from osc_lib.cli import format_columns +from osc_lib import exceptions from osc_lib import utils from osc_lib.utils import tags as _tag @@ -349,6 +350,25 @@ class CreateNetwork( ), ) + vlan_qinq_grp = parser.add_mutually_exclusive_group() + vlan_qinq_grp.add_argument( + '--qinq-vlan', + action='store_true', + help=self.enhance_help_neutron( + _("Enable VLAN QinQ (S-Tag ethtype 0x8a88) " "for the network") + ), + ) + vlan_qinq_grp.add_argument( + '--no-qinq-vlan', + action='store_true', + help=self.enhance_help_neutron( + _( + "Disable VLAN QinQ (S-Tag ethtype 0x8a88) " + "for the network" + ) + ), + ) + _add_additional_network_options(parser) _tag.add_tag_option_to_parser_for_create( parser, _('network'), enhance_help=self.enhance_help_neutron @@ -372,6 +392,19 @@ class CreateNetwork( attrs['vlan_transparent'] = True if parsed_args.no_transparent_vlan: attrs['vlan_transparent'] = False + + if parsed_args.qinq_vlan: + attrs['vlan_qinq'] = True + if parsed_args.no_qinq_vlan: + attrs['vlan_qinq'] = False + + if attrs.get('vlan_transparent') and attrs.get('vlan_qinq'): + msg = _( + "--transparent-vlan and --qinq-vlan can not be both enabled " + "for the network." + ) + raise exceptions.CommandError(msg) + attrs.update( self._parse_extra_properties(parsed_args.extra_properties) ) diff --git a/openstackclient/network/v2/network_flavor_profile.py b/openstackclient/network/v2/network_flavor_profile.py index 1fb5a80..d9a4b5d 100644 --- a/openstackclient/network/v2/network_flavor_profile.py +++ b/openstackclient/network/v2/network_flavor_profile.py @@ -18,7 +18,6 @@ from osc_lib import exceptions from osc_lib import utils from openstackclient.i18n import _ -from openstackclient.identity import common as identity_common from openstackclient.network import common LOG = logging.getLogger(__name__) @@ -29,7 +28,7 @@ def _get_columns(item): 'is_enabled': 'enabled', } - hidden_columns = ['location', 'name', 'tenant_id'] + hidden_columns = ['location', 'name', 'tenant_id', 'project_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, hidden_columns ) @@ -47,14 +46,6 @@ def _get_attrs(client_manager, parsed_args): attrs['enabled'] = True if parsed_args.disable: attrs['enabled'] = False - if 'project' in parsed_args and parsed_args.project is not None: - identity_client = client_manager.identity - project_id = identity_common.find_project( - identity_client, - parsed_args.project, - parsed_args.project_domain, - ).id - attrs['project_id'] = project_id return attrs @@ -69,12 +60,6 @@ class CreateNetworkFlavorProfile( def get_parser(self, prog_name): parser = super().get_parser(prog_name) parser.add_argument( - '--project', - metavar="<project>", - help=_("Owner's project (name or ID)"), - ) - identity_common.add_project_domain_option_to_parser(parser) - parser.add_argument( '--description', metavar="<description>", help=_("Description for the flavor profile"), @@ -212,7 +197,6 @@ class SetNetworkFlavorProfile(common.NeutronCommandWithExtraArgs): metavar="<flavor-profile>", help=_("Flavor profile to update (ID only)"), ) - identity_common.add_project_domain_option_to_parser(parser) parser.add_argument( '--description', metavar="<description>", diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py index c45b34a..3579194 100644 --- a/openstackclient/network/v2/port.py +++ b/openstackclient/network/v2/port.py @@ -38,6 +38,20 @@ class AdminStateColumn(cliff_columns.FormattableColumn): return 'UP' if self._value else 'DOWN' +class SubPortColumn(format_columns.ListDictColumn): + def _retrieve_subports(self): + if isinstance(self._value, dict): + self._value = self._value['sub_ports'] + + def human_readable(self): + self._retrieve_subports() + return super().human_readable() + + def machine_readable(self): + self._retrieve_subports() + return super().machine_readable() + + _formatters = { 'admin_state_up': AdminStateColumn, 'is_admin_state_up': AdminStateColumn, @@ -52,6 +66,8 @@ _formatters = { 'security_group_ids': format_columns.ListColumn, 'tags': format_columns.ListColumn, } +_list_formatters = copy.deepcopy(_formatters) +_list_formatters.update({'trunk_details': SubPortColumn}) def _get_columns(item): @@ -93,6 +109,7 @@ def _get_columns(item): 'status': 'status', 'tags': 'tags', 'trunk_details': 'trunk_details', + 'trusted': 'trusted', 'updated_at': 'updated_at', } return ( @@ -222,6 +239,10 @@ def _get_attrs(client_manager, parsed_args): and parsed_args.hardware_offload_type ): attrs['hardware_offload_type'] = parsed_args.hardware_offload_type + if parsed_args.not_trusted: + attrs['trusted'] = False + if parsed_args.trusted: + attrs['trusted'] = True return attrs @@ -388,6 +409,25 @@ def _add_updatable_args(parser, create=False): '(repeat option to set multiple hints)' ), ) + port_trusted = parser.add_mutually_exclusive_group() + port_trusted.add_argument( + '--trusted', + action='store_true', + help=_( + "Set port to be trusted. This will be populated into the " + "'binding:profile' dictionary and passed to the services " + "which expect it in this dictionary (for example, Nova)" + ), + ) + port_trusted.add_argument( + '--not-trusted', + action='store_true', + help=_( + "Set port to be not trusted. This will be populated into the " + "'binding:profile' dictionary and passed to the services " + "which expect it in this dictionary (for example, Nova)" + ), + ) # TODO(abhiraut): Use the SDK resource mapped attribute names once the @@ -498,12 +538,12 @@ class CreatePort(command.ShowOne, common.NeutronCommandWithExtraArgs): uplink_status_group.add_argument( '--enable-uplink-status-propagation', action='store_true', - help=_("Enable uplink status propagate"), + help=_("Enable uplink status propagation (default)"), ) uplink_status_group.add_argument( '--disable-uplink-status-propagation', action='store_true', - help=_("Disable uplink status propagate (default)"), + help=_("Disable uplink status propagation"), ) parser.add_argument( '--project', @@ -534,7 +574,7 @@ class CreatePort(command.ShowOne, common.NeutronCommandWithExtraArgs): '--security-group', metavar='<security-group>', action='append', - dest='security_group', + dest='security_groups', help=_( "Security group to associate with this port (name or ID) " "(repeat option to set multiple security groups)" @@ -542,8 +582,9 @@ class CreatePort(command.ShowOne, common.NeutronCommandWithExtraArgs): ) secgroups.add_argument( '--no-security-group', - dest='no_security_group', - action='store_true', + action='store_const', + const=[], + dest='security_groups', help=_("Associate no security groups with this port"), ) parser.add_argument( @@ -609,13 +650,11 @@ class CreatePort(command.ShowOne, common.NeutronCommandWithExtraArgs): elif parsed_args.no_fixed_ip: attrs['fixed_ips'] = [] - if parsed_args.security_group: + if parsed_args.security_groups is not None: attrs['security_group_ids'] = [ client.find_security_group(sg, ignore_missing=False).id - for sg in parsed_args.security_group + for sg in parsed_args.security_groups ] - elif parsed_args.no_security_group: - attrs['security_group_ids'] = [] if parsed_args.allowed_address_pairs: attrs['allowed_address_pairs'] = _convert_address_pairs( @@ -828,25 +867,30 @@ class ListPort(command.Lister): network_client = self.app.client_manager.network identity_client = self.app.client_manager.identity - columns = ( + columns = [ 'id', 'name', 'mac_address', 'fixed_ips', 'status', - ) - column_headers = ( + ] + column_headers = [ 'ID', 'Name', 'MAC Address', 'Fixed IP Addresses', 'Status', - ) + ] filters = {} if parsed_args.long: - columns += ('security_group_ids', 'device_owner', 'tags') - column_headers += ('Security Groups', 'Device Owner', 'Tags') + columns.extend( + ['security_groups', 'device_owner', 'tags', 'trunk_details'] + ) + column_headers.extend( + ['Security Groups', 'Device Owner', 'Tags', 'Trunk subports'] + ) + if parsed_args.device_owner is not None: filters['device_owner'] = parsed_args.device_owner if parsed_args.device_id is not None: @@ -894,6 +938,12 @@ class ListPort(command.Lister): data = network_client.ports(fields=columns, **filters) + if parsed_args.long: + columns = [ + 'security_group_ids' if item == 'security_groups' else item + for item in columns + ] + headers, attrs = utils.calculate_header_and_attrs( column_headers, columns, parsed_args ) @@ -903,7 +953,7 @@ class ListPort(command.Lister): utils.get_item_properties( s, attrs, - formatters=_formatters, + formatters=_list_formatters, ) for s in data ), @@ -982,7 +1032,7 @@ class SetPort(common.NeutronCommandWithExtraArgs): '--security-group', metavar='<security-group>', action='append', - dest='security_group', + dest='security_groups', help=_( "Security group to associate with this port (name or ID) " "(repeat option to set multiple security groups)" @@ -1053,6 +1103,18 @@ class SetPort(common.NeutronCommandWithExtraArgs): "(requires data plane status extension)" ), ) + uplink_status_group = parser.add_mutually_exclusive_group() + uplink_status_group.add_argument( + '--enable-uplink-status-propagation', + action='store_true', + help=_('Enable uplink status propagation'), + ) + uplink_status_group.add_argument( + '--disable-uplink-status-propagation', + action='store_true', + help=_('Disable uplink status propagation'), + ) + _tag.add_tag_option_to_parser_for_set(parser, _('port')) return parser @@ -1083,7 +1145,7 @@ class SetPort(common.NeutronCommandWithExtraArgs): if parsed_args.no_security_group: attrs['security_group_ids'] = [] - if parsed_args.security_group: + if parsed_args.security_groups: if 'security_group_ids' not in attrs: # NOTE(dtroyer): Get existing security groups, iterate the # list to force a new list object to be @@ -1094,7 +1156,7 @@ class SetPort(common.NeutronCommandWithExtraArgs): ] attrs['security_group_ids'].extend( client.find_security_group(sg, ignore_missing=False).id - for sg in parsed_args.security_group + for sg in parsed_args.security_groups ) if parsed_args.no_allowed_address_pair: @@ -1137,6 +1199,11 @@ class SetPort(common.NeutronCommandWithExtraArgs): raise exceptions.CommandError(msg) attrs['hints'] = expanded_hints + if parsed_args.not_trusted: + attrs['trusted'] = False + if parsed_args.trusted: + attrs['trusted'] = True + attrs.update( self._parse_extra_properties(parsed_args.extra_properties) ) @@ -1202,7 +1269,7 @@ class UnsetPort(common.NeutronUnsetCommandWithExtraArgs): '--security-group', metavar='<security-group>', action='append', - dest='security_group_ids', + dest='security_groups', help=_( "Security group which should be removed this port (name " "or ID) (repeat option to unset multiple security groups)" @@ -1287,9 +1354,9 @@ class UnsetPort(common.NeutronUnsetCommandWithExtraArgs): msg = _("Port does not contain binding-profile %s") % key raise exceptions.CommandError(msg) attrs['binding:profile'] = tmp_binding_profile - if parsed_args.security_group_ids: + if parsed_args.security_groups: try: - for sg in parsed_args.security_group_ids: + for sg in parsed_args.security_groups: sg_id = client.find_security_group( sg, ignore_missing=False ).id diff --git a/openstackclient/network/v2/router.py b/openstackclient/network/v2/router.py index 5193abc..0deae36 100644 --- a/openstackclient/network/v2/router.py +++ b/openstackclient/network/v2/router.py @@ -237,6 +237,9 @@ def _get_attrs(client_manager, parsed_args): if 'flavor_id' in parsed_args and parsed_args.flavor_id is not None: flavor = n_client.find_flavor(parsed_args.flavor_id) attrs['flavor_id'] = flavor.id + elif 'flavor' in parsed_args and parsed_args.flavor is not None: + flavor = n_client.find_flavor(parsed_args.flavor, ignore_missing=False) + attrs['flavor_id'] = flavor.id for attr in ('enable_default_route_bfd', 'enable_default_route_ecmp'): value = getattr(parsed_args, attr, None) diff --git a/openstackclient/tests/functional/compute/v2/test_server.py b/openstackclient/tests/functional/compute/v2/test_server.py index 19531da..47b6d7c 100644 --- a/openstackclient/tests/functional/compute/v2/test_server.py +++ b/openstackclient/tests/functional/compute/v2/test_server.py @@ -1295,7 +1295,7 @@ class ServerTests(common.ComputeTestCase): ) if ip_address in cmd_output['addresses']['private']: # Hang out for a bit and try again - print('retrying add port check') + print('retrying remove port check') wait_time += 10 time.sleep(10) else: @@ -1367,6 +1367,92 @@ class ServerTests(common.ComputeTestCase): addresses = cmd_output['addresses']['private'] self.assertIn(ip_address, addresses) + def test_server_add_remove_security_group(self): + name = uuid.uuid4().hex + cmd_output = self.openstack( + 'server create ' + + '--network private ' + + '--flavor ' + + self.flavor_name + + ' ' + + '--image ' + + self.image_name + + ' ' + + '--wait ' + + name, + parse_output=True, + ) + + self.assertIsNotNone(cmd_output['id']) + self.assertEqual(name, cmd_output['name']) + self.addCleanup(self.openstack, 'server delete --wait ' + name) + + # create security group + security_group_name = uuid.uuid4().hex + + cmd_output = self.openstack( + 'security group list', + parse_output=True, + ) + self.assertNotIn(security_group_name, cmd_output) + + cmd_output = self.openstack( + 'security group create ' + security_group_name, + parse_output=True, + ) + self.assertIsNotNone(cmd_output['id']) + self.addCleanup( + self.openstack, 'security group delete ' + security_group_name + ) + + # add security group to server, assert the name of the security group + # appears + self.openstack( + 'server add security group ' + name + ' ' + security_group_name + ) + + wait_time = 0 + while wait_time < 60: + cmd_output = self.openstack( + 'server show ' + name, + parse_output=True, + ) + if security_group_name not in [ + x['name'] for x in cmd_output['security_groups'] + ]: + # Hang out for a bit and try again + print('retrying add security group check') + wait_time += 10 + time.sleep(10) + else: + break + security_groups = [x['name'] for x in cmd_output['security_groups']] + self.assertIn(security_group_name, security_groups) + + # remove security group, assert the name of the security group doesn't + # appear + self.openstack( + 'server remove security group ' + name + ' ' + security_group_name + ) + + wait_time = 0 + while wait_time < 60: + cmd_output = self.openstack( + 'server show ' + name, + parse_output=True, + ) + if security_group_name not in [ + x['name'] for x in cmd_output['security_groups'] + ]: + # Hang out for a bit and try again + print('retrying remove security group check') + wait_time += 10 + time.sleep(10) + else: + break + security_groups = [x['name'] for x in cmd_output['security_groups']] + self.assertNotIn(security_group_name, security_groups) + def test_server_add_remove_volume(self): volume_wait_for = volume_common.BaseVolumeTests.wait_for_status diff --git a/openstackclient/tests/functional/identity/v3/common.py b/openstackclient/tests/functional/identity/v3/common.py index e44f291..ecabfd2 100644 --- a/openstackclient/tests/functional/identity/v3/common.py +++ b/openstackclient/tests/functional/identity/v3/common.py @@ -49,7 +49,7 @@ class IdentityTests(base.TestCase): ] ROLE_FIELDS = ['id', 'name', 'domain_id', 'description'] SERVICE_FIELDS = ['id', 'enabled', 'name', 'type', 'description'] - REGION_FIELDS = ['description', 'enabled', 'parent_region', 'region'] + REGION_FIELDS = ['description', 'parent_region', 'region'] ENDPOINT_FIELDS = [ 'id', 'region', diff --git a/openstackclient/tests/functional/identity/v3/test_application_credential.py b/openstackclient/tests/functional/identity/v3/test_application_credential.py index 4412592..39c735b 100644 --- a/openstackclient/tests/functional/identity/v3/test_application_credential.py +++ b/openstackclient/tests/functional/identity/v3/test_application_credential.py @@ -107,7 +107,8 @@ class ApplicationCredentialTests(common.IdentityTests): secret = data_utils.rand_name('secret') description = data_utils.rand_name('description') tomorrow = ( - datetime.datetime.utcnow() + datetime.timedelta(days=1) + datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None) + + datetime.timedelta(days=1) ).strftime('%Y-%m-%dT%H:%M:%S%z') role1, role2 = self._create_role_assignments() raw_output = self.openstack( diff --git a/openstackclient/tests/functional/identity/v3/test_role.py b/openstackclient/tests/functional/identity/v3/test_role.py index 16ddc23..f4c6832 100644 --- a/openstackclient/tests/functional/identity/v3/test_role.py +++ b/openstackclient/tests/functional/identity/v3/test_role.py @@ -93,6 +93,30 @@ class RoleTests(common.IdentityTests): ) self.assertEqual(0, len(raw_output)) + def test_role_add_inherited(self): + role_name = self._create_dummy_role() + username = self._create_dummy_user() + raw_output = self.openstack( + 'role add ' + f'--project {self.project_name} ' + f'--project-domain {self.domain_name} ' + f'--user {username} ' + f'--user-domain {self.domain_name} ' + '--inherited ' + f'{role_name}' + ) + self.addCleanup( + self.openstack, + 'role remove ' + f'--project {self.project_name} ' + f'--project-domain {self.domain_name} ' + f'--user {username} ' + f'--user-domain {self.domain_name} ' + '--inherited ' + f'{role_name}', + ) + self.assertEqual(0, len(raw_output)) + def test_role_remove(self): role_name = self._create_dummy_role() username = self._create_dummy_user() diff --git a/openstackclient/tests/functional/identity/v3/test_role_assignment.py b/openstackclient/tests/functional/identity/v3/test_role_assignment.py index 941563c..6c53bc2 100644 --- a/openstackclient/tests/functional/identity/v3/test_role_assignment.py +++ b/openstackclient/tests/functional/identity/v3/test_role_assignment.py @@ -151,6 +151,14 @@ class RoleAssignmentTests(common.IdentityTests): '--inherited ' f'{role_name}' ) + self.addCleanup( + self.openstack, + 'role remove ' + f'--project {self.project_name} ' + f'--user {username} ' + '--inherited ' + f'{role_name}', + ) self.assertEqual(0, len(raw_output)) raw_output = self.openstack('role assignment list --inherited') diff --git a/openstackclient/tests/functional/identity/v3/test_service_provider.py b/openstackclient/tests/functional/identity/v3/test_service_provider.py index 793223b..2f941d5 100644 --- a/openstackclient/tests/functional/identity/v3/test_service_provider.py +++ b/openstackclient/tests/functional/identity/v3/test_service_provider.py @@ -60,9 +60,5 @@ class ServiceProviderTests(common.IdentityTests): 'description': new_description, } ) - self.assertEqual(0, len(raw_output)) - raw_output = self.openstack( - f'service provider show {service_provider}' - ) updated_value = self.parse_show_as_object(raw_output) - self.assertIn(new_description, updated_value['description']) + self.assertEqual(new_description, updated_value.get('description')) diff --git a/openstackclient/tests/functional/network/v2/test_port.py b/openstackclient/tests/functional/network/v2/test_port.py index 24fbe0e..4530395 100644 --- a/openstackclient/tests/functional/network/v2/test_port.py +++ b/openstackclient/tests/functional/network/v2/test_port.py @@ -81,10 +81,20 @@ class PortTests(common.NetworkTagTests): self.addCleanup(self.openstack, f'port delete {id1}') self.assertEqual(self.NAME, json_output.get('name')) + # sg for port2 + sg_name1 = uuid.uuid4().hex json_output = self.openstack( - f'port create --network {self.NETWORK_NAME} {self.NAME}x', + f'security group create {sg_name1}', parse_output=True, ) + sg_id1 = json_output.get('id') + self.addCleanup(self.openstack, f'security group delete {sg_id1}') + json_output = self.openstack( + f'port create --network {self.NETWORK_NAME} ' + f'--security-group {sg_name1} {self.NAME}x', + parse_output=True, + ) + id2 = json_output.get('id') self.assertIsNotNone(id2) mac2 = json_output.get('mac_address') @@ -113,6 +123,12 @@ class PortTests(common.NetworkTagTests): id_list = [item.get('ID') for item in json_output] self.assertIn(id1, id_list) self.assertIn(id2, id_list) + item_sg_map = { + item.get('ID'): item.get('Security Groups') for item in json_output + } + self.assertIn(id1, item_sg_map.keys()) + self.assertIn(id2, item_sg_map.keys()) + self.assertIn([sg_id1], item_sg_map.values()) # Test list --mac-address json_output = self.openstack( @@ -127,6 +143,17 @@ class PortTests(common.NetworkTagTests): self.assertNotIn(mac1, item_map.values()) self.assertIn(mac2, item_map.values()) + # Test list --security-group + json_output = self.openstack( + f'port list --security-group {sg_id1}', + parse_output=True, + ) + item_map = { + item.get('ID'): item.get('Security Groups') for item in json_output + } + self.assertNotIn(id1, item_map.keys()) + self.assertIn(id2, item_map.keys()) + # Test list with unknown fields json_output = self.openstack( 'port list -c ID -c Name -c device_id', @@ -262,3 +289,82 @@ class PortTests(common.NetworkTagTests): f'{self.base_command} create --network {self.NETWORK_NAME} {args} {name}', parse_output=True, ) + + def _trunk_creation(self): + pport = uuid.uuid4().hex + sport1 = uuid.uuid4().hex + sport2 = uuid.uuid4().hex + trunk = uuid.uuid4().hex + json_output = self.openstack( + 'port create ' f'--network {self.NETWORK_NAME} {pport}', + parse_output=True, + ) + pport_id = json_output.get('id') + json_output = self.openstack( + 'port create ' f'--network {self.NETWORK_NAME} {sport1}', + parse_output=True, + ) + sport1_id = json_output.get('id') + json_output = self.openstack( + 'port create ' f'--network {self.NETWORK_NAME} {sport2}', + parse_output=True, + ) + sport2_id = json_output.get('id') + + self.openstack( + f'network trunk create --parent-port {pport} {trunk}', + ) + self.openstack( + f'network trunk set --subport port={sport1},' + f'segmentation-type=vlan,segmentation-id=100 {trunk}', + ) + self.openstack( + f'network trunk set --subport port={sport2},' + f'segmentation-type=vlan,segmentation-id=101 {trunk}', + ) + + # NOTE(ralonsoh): keep this order to first delete the trunk and then + # the ports. + self.addCleanup(self.openstack, f'port delete {pport_id}') + self.addCleanup(self.openstack, f'port delete {sport1_id}') + self.addCleanup(self.openstack, f'port delete {sport2_id}') + self.addCleanup(self.openstack, f'network trunk delete {trunk}') + + return pport_id, sport1_id, sport2_id + + def check_subports(self, subports, pport_id, sport1_id, sport2_id): + self.assertEqual(2, len(subports)) + for subport in subports: + if subport['port_id'] == sport1_id: + self.assertEqual(100, subport['segmentation_id']) + elif subport['port_id'] == sport2_id: + self.assertEqual(101, subport['segmentation_id']) + else: + self.fail( + f'Port {pport_id} does not have subport ' + f'{subport["port_id"]}' + ) + self.assertEqual('vlan', subport['segmentation_type']) + + def test_port_list_with_trunk(self): + pport_id, sport1_id, sport2_id = self._trunk_creation() + + # List all ports with "--long" flag to retrieve the trunk details + json_output = self.openstack( + 'port list --long', + parse_output=True, + ) + port = next(port for port in json_output if port['ID'] == pport_id) + subports = port['Trunk subports'] + self.check_subports(subports, pport_id, sport1_id, sport2_id) + + def test_port_show_with_trunk(self): + pport_id, sport1_id, sport2_id = self._trunk_creation() + + # List all ports with "--long" flag to retrieve the trunk details + port = self.openstack( + f'port show {pport_id}', + parse_output=True, + ) + subports = port['trunk_details']['sub_ports'] + self.check_subports(subports, pport_id, sport1_id, sport2_id) diff --git a/openstackclient/tests/unit/compute/v2/fakes.py b/openstackclient/tests/unit/compute/v2/fakes.py index d021c5d..62758c8 100644 --- a/openstackclient/tests/unit/compute/v2/fakes.py +++ b/openstackclient/tests/unit/compute/v2/fakes.py @@ -21,21 +21,15 @@ import uuid from keystoneauth1 import discover from openstack.compute.v2 import _proxy -from openstack.compute.v2 import aggregate as _aggregate from openstack.compute.v2 import availability_zone as _availability_zone from openstack.compute.v2 import extension as _extension from openstack.compute.v2 import flavor as _flavor -from openstack.compute.v2 import hypervisor as _hypervisor -from openstack.compute.v2 import keypair as _keypair from openstack.compute.v2 import limits as _limits from openstack.compute.v2 import migration as _migration from openstack.compute.v2 import server as _server from openstack.compute.v2 import server_action as _server_action -from openstack.compute.v2 import server_group as _server_group from openstack.compute.v2 import server_interface as _server_interface from openstack.compute.v2 import server_migration as _server_migration -from openstack.compute.v2 import service as _service -from openstack.compute.v2 import usage as _usage from openstack.compute.v2 import volume_attachment as _volume_attachment from openstackclient.tests.unit import fakes @@ -142,63 +136,6 @@ class TestComputev2( ): ... -def create_one_aggregate(attrs=None): - """Create a fake aggregate. - - :param dict attrs: A dictionary with all attributes - :return: A fake openstack.compute.v2.aggregate.Aggregate object - """ - attrs = attrs or {} - - # Set default attribute - aggregate_info = { - "name": "aggregate-name-" + uuid.uuid4().hex, - "availability_zone": "ag_zone", - "hosts": [], - "id": "aggregate-id-" + uuid.uuid4().hex, - "metadata": { - "availability_zone": "ag_zone", - "key1": "value1", - }, - } - - # Overwrite default attributes. - aggregate_info.update(attrs) - - aggregate = _aggregate.Aggregate(**aggregate_info) - return aggregate - - -def create_aggregates(attrs=None, count=2): - """Create multiple fake aggregates. - - :param dict attrs: A dictionary with all attributes - :param int count: The number of aggregates to fake - :return: A list of fake openstack.compute.v2.aggregate.Aggregate objects - """ - aggregates = [] - for i in range(0, count): - aggregates.append(create_one_aggregate(attrs)) - - return aggregates - - -def get_aggregates(aggregates=None, count=2): - """Get an iterable MagicMock object with a list of faked aggregates. - - If aggregates list is provided, then initialize the Mock object - with the list. Otherwise create one. - - :return: A list of fake openstack.compute.v2.aggregate.Aggregate objects - :param int count: The number of aggregates to fake - :return: An iterable Mock object with side_effect set to a list of faked - aggregates - """ - if aggregates is None: - aggregates = create_aggregates(count) - return mock.Mock(side_effect=aggregates) - - def create_one_agent(attrs=None): """Create a fake agent. @@ -544,51 +481,6 @@ def create_one_server_action(attrs=None): return server_action -def create_one_service(attrs=None): - """Create a fake service. - - :param dict attrs: A dictionary with all attributes - :return: A fake openstack.compute.v2.service.Service object - """ - attrs = attrs or {} - - # Set default attributes. - service_info = { - 'id': 'id-' + uuid.uuid4().hex, - 'host': 'host-' + uuid.uuid4().hex, - 'binary': 'binary-' + uuid.uuid4().hex, - 'status': 'enabled', - 'availability_zone': 'zone-' + uuid.uuid4().hex, - 'state': 'state-' + uuid.uuid4().hex, - 'updated_at': 'time-' + uuid.uuid4().hex, - 'disabled_reason': 'earthquake', - # Introduced in API microversion 2.11 - 'is_forced_down': False, - } - - # Overwrite default attributes. - service_info.update(attrs) - - return _service.Service(**service_info) - - -def create_services(attrs=None, count=2): - """Create multiple fake services. - - :param dict attrs: - A dictionary with all attributes - :param int count: - The number of services to fake - :return: - A list of FakeResource objects faking the services - """ - services = [] - for i in range(0, count): - services.append(create_one_service(attrs)) - - return services - - def create_one_flavor(attrs=None): """Create a fake flavor. @@ -678,61 +570,6 @@ def create_one_flavor_access(attrs=None): return flavor_access -def create_one_keypair(attrs=None): - """Create a fake keypair - - :param dict attrs: A dictionary with all attributes - :return: A fake openstack.compute.v2.keypair.Keypair object - """ - attrs = attrs or {} - - # Set default attributes. - keypair_info = { - 'name': 'keypair-name-' + uuid.uuid4().hex, - 'type': 'ssh', - 'fingerprint': 'dummy', - 'public_key': 'dummy', - 'user_id': 'user', - } - - # Overwrite default attributes. - keypair_info.update(attrs) - - return _keypair.Keypair(**keypair_info) - - -def create_keypairs(attrs=None, count=2): - """Create multiple fake keypairs. - - :param dict attrs: A dictionary with all attributes - :param int count: The number of keypairs to fake - :return: A list of fake openstack.compute.v2.keypair.Keypair objects - """ - - keypairs = [] - for i in range(0, count): - keypairs.append(create_one_keypair(attrs)) - - return keypairs - - -def get_keypairs(keypairs=None, count=2): - """Get an iterable MagicMock object with a list of faked keypairs. - - If keypairs list is provided, then initialize the Mock object with the - list. Otherwise create one. - - :param list keypairs: A list of fake openstack.compute.v2.keypair.Keypair - objects - :param int count: The number of keypairs to fake - :return: An iterable Mock object with side_effect set to a list of faked - keypairs - """ - if keypairs is None: - keypairs = create_keypairs(count) - return mock.Mock(side_effect=keypairs) - - def create_one_availability_zone(attrs=None): """Create a fake AZ. @@ -970,62 +807,6 @@ def get_networks(networks=None, count=2): return mock.Mock(side_effect=networks) -def create_one_usage(attrs=None): - """Create a fake usage. - - :param dict attrs: - A dictionary with all attributes - :return: - A FakeResource object, with tenant_id and other attributes - """ - if attrs is None: - attrs = {} - - # Set default attributes. - usage_info = { - 'project_id': 'usage-tenant-id-' + uuid.uuid4().hex, - 'total_memory_mb_usage': 512.0, - 'total_vcpus_usage': 1.0, - 'total_local_gb_usage': 1.0, - 'server_usages': [ - { - 'ended_at': None, - 'flavor': 'usage-flavor-' + uuid.uuid4().hex, - 'hours': 1.0, - 'local_gb': 1, - 'memory_mb': 512, - 'name': 'usage-name-' + uuid.uuid4().hex, - 'instance_id': uuid.uuid4().hex, - 'state': 'active', - 'uptime': 3600, - 'vcpus': 1, - } - ], - } - - # Overwrite default attributes. - usage_info.update(attrs) - - return _usage.Usage(**usage_info) - - -def create_usages(attrs=None, count=2): - """Create multiple fake services. - - :param dict attrs: - A dictionary with all attributes - :param int count: - The number of services to fake - :return: - A list of FakeResource objects faking the services - """ - usages = [] - for i in range(0, count): - usages.append(create_one_usage(attrs)) - - return usages - - def create_limits(attrs=None): """Create a fake limits object.""" attrs = attrs or {} @@ -1237,91 +1018,6 @@ def create_volume_attachments(attrs=None, count=2): return volume_attachments -def create_one_hypervisor(attrs=None): - """Create a fake hypervisor. - - :param dict attrs: A dictionary with all attributes - :return: A fake openstack.compute.v2.hypervisor.Hypervisor object - """ - attrs = attrs or {} - - # Set default attributes. - hypervisor_info = { - 'id': 'hypervisor-id-' + uuid.uuid4().hex, - 'hypervisor_hostname': 'hypervisor-hostname-' + uuid.uuid4().hex, - 'status': 'enabled', - 'host_ip': '192.168.0.10', - 'cpu_info': { - 'aaa': 'aaa', - }, - 'free_disk_gb': 50, - 'hypervisor_version': 2004001, - 'disk_available_least': 50, - 'local_gb': 50, - 'free_ram_mb': 1024, - 'service': { - 'host': 'aaa', - 'disabled_reason': None, - 'id': 1, - }, - 'vcpus_used': 0, - 'hypervisor_type': 'QEMU', - 'local_gb_used': 0, - 'vcpus': 4, - 'memory_mb_used': 512, - 'memory_mb': 1024, - 'current_workload': 0, - 'state': 'up', - 'running_vms': 0, - } - - # Overwrite default attributes. - hypervisor_info.update(attrs) - - hypervisor = _hypervisor.Hypervisor(**hypervisor_info, loaded=True) - return hypervisor - - -def create_hypervisors(attrs=None, count=2): - """Create multiple fake hypervisors. - - :param dict attrs: A dictionary with all attributes - :param int count: The number of hypervisors to fake - :return: A list of fake openstack.compute.v2.hypervisor.Hypervisor objects - """ - hypervisors = [] - for i in range(0, count): - hypervisors.append(create_one_hypervisor(attrs)) - - return hypervisors - - -def create_one_server_group(attrs=None): - """Create a fake server group - - :param dict attrs: A dictionary with all attributes - :return: A fake openstack.compute.v2.server_group.ServerGroup object - """ - if attrs is None: - attrs = {} - - # Set default attributes. - server_group_info = { - 'id': 'server-group-id-' + uuid.uuid4().hex, - 'member_ids': '', - 'metadata': {}, - 'name': 'server-group-name-' + uuid.uuid4().hex, - 'project_id': 'server-group-project-id-' + uuid.uuid4().hex, - 'user_id': 'server-group-user-id-' + uuid.uuid4().hex, - } - - # Overwrite default attributes. - server_group_info.update(attrs) - - server_group = _server_group.ServerGroup(**server_group_info) - return server_group - - def create_one_server_interface(attrs=None): """Create a fake SDK ServerInterface. diff --git a/openstackclient/tests/unit/compute/v2/test_aggregate.py b/openstackclient/tests/unit/compute/v2/test_aggregate.py index 933344e..f905d67 100644 --- a/openstackclient/tests/unit/compute/v2/test_aggregate.py +++ b/openstackclient/tests/unit/compute/v2/test_aggregate.py @@ -16,7 +16,9 @@ from unittest import mock from unittest.mock import call +from openstack.compute.v2 import aggregate as _aggregate from openstack import exceptions as sdk_exceptions +from openstack.test import fakes as sdk_fakes from osc_lib.cli import format_columns from osc_lib import exceptions @@ -26,8 +28,6 @@ from openstackclient.tests.unit.image.v2 import fakes as image_fakes class TestAggregate(compute_fakes.TestComputev2): - fake_ag = compute_fakes.create_one_aggregate() - columns = ( 'availability_zone', 'created_at', @@ -41,18 +41,25 @@ class TestAggregate(compute_fakes.TestComputev2): 'uuid', ) - data = ( - fake_ag.availability_zone, - fake_ag.created_at, - fake_ag.deleted_at, - format_columns.ListColumn(fake_ag.hosts), - fake_ag.id, - fake_ag.is_deleted, - fake_ag.name, - format_columns.DictColumn(fake_ag.metadata), - fake_ag.updated_at, - fake_ag.uuid, - ) + def setUp(self): + super().setUp() + + self.fake_ag = sdk_fakes.generate_fake_resource( + _aggregate.Aggregate, + metadata={'availability_zone': 'ag_zone', 'key1': 'value1'}, + ) + self.data = ( + self.fake_ag.availability_zone, + self.fake_ag.created_at, + self.fake_ag.deleted_at, + format_columns.ListColumn(self.fake_ag.hosts), + self.fake_ag.id, + self.fake_ag.is_deleted, + self.fake_ag.name, + format_columns.DictColumn(self.fake_ag.metadata), + self.fake_ag.updated_at, + self.fake_ag.uuid, + ) class TestAggregateAddHost(TestAggregate): @@ -155,13 +162,15 @@ class TestAggregateCreate(TestAggregate): class TestAggregateDelete(TestAggregate): - fake_ags = compute_fakes.create_aggregates(count=2) - def setUp(self): super().setUp() - self.compute_sdk_client.find_aggregate = compute_fakes.get_aggregates( - self.fake_ags + self.fake_ags = list( + sdk_fakes.generate_fake_resources(_aggregate.Aggregate, 2) + ) + + self.compute_sdk_client.find_aggregate = mock.Mock( + side_effect=[self.fake_ags[0], self.fake_ags[1]] ) self.cmd = aggregate.DeleteAggregate(self.app, None) @@ -526,25 +535,25 @@ class TestAggregateShow(TestAggregate): 'uuid', ) - data = ( - TestAggregate.fake_ag.availability_zone, - TestAggregate.fake_ag.created_at, - TestAggregate.fake_ag.deleted_at, - format_columns.ListColumn(TestAggregate.fake_ag.hosts), - TestAggregate.fake_ag.id, - TestAggregate.fake_ag.is_deleted, - TestAggregate.fake_ag.name, - format_columns.DictColumn(TestAggregate.fake_ag.metadata), - TestAggregate.fake_ag.updated_at, - TestAggregate.fake_ag.uuid, - ) - def setUp(self): super().setUp() self.compute_sdk_client.find_aggregate.return_value = self.fake_ag self.cmd = aggregate.ShowAggregate(self.app, None) + self.data = ( + self.fake_ag.availability_zone, + self.fake_ag.created_at, + self.fake_ag.deleted_at, + format_columns.ListColumn(self.fake_ag.hosts), + self.fake_ag.id, + self.fake_ag.is_deleted, + self.fake_ag.name, + format_columns.DictColumn(self.fake_ag.metadata), + self.fake_ag.updated_at, + self.fake_ag.uuid, + ) + def test_aggregate_show(self): arglist = [ 'ag1', diff --git a/openstackclient/tests/unit/compute/v2/test_console.py b/openstackclient/tests/unit/compute/v2/test_console.py index a179db5..d4c6940 100644 --- a/openstackclient/tests/unit/compute/v2/test_console.py +++ b/openstackclient/tests/unit/compute/v2/test_console.py @@ -15,6 +15,9 @@ from unittest import mock +from openstack.compute.v2 import server as _server +from openstack.test import fakes as sdk_fakes + from openstackclient.compute.v2 import console from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes from openstackclient.tests.unit import utils @@ -24,7 +27,7 @@ class TestConsoleLog(compute_fakes.TestComputev2): def setUp(self): super().setUp() - self._server = compute_fakes.create_one_sdk_server() + self._server = sdk_fakes.generate_fake_resource(_server.Server) self.compute_sdk_client.find_server.return_value = self._server self.cmd = console.ShowConsoleLog(self.app, None) @@ -76,11 +79,12 @@ class TestConsoleLog(compute_fakes.TestComputev2): class TestConsoleUrlShow(compute_fakes.TestComputev2): - _server = compute_fakes.create_one_sdk_server() - def setUp(self): super().setUp() + + self._server = sdk_fakes.generate_fake_resource(_server.Server) self.compute_sdk_client.find_server.return_value = self._server + fake_console_data = { 'url': 'http://localhost', 'protocol': 'fake_protocol', diff --git a/openstackclient/tests/unit/compute/v2/test_hypervisor.py b/openstackclient/tests/unit/compute/v2/test_hypervisor.py index 2c83fe4..da6e7e5 100644 --- a/openstackclient/tests/unit/compute/v2/test_hypervisor.py +++ b/openstackclient/tests/unit/compute/v2/test_hypervisor.py @@ -14,7 +14,9 @@ import json +from openstack.compute.v2 import hypervisor as _hypervisor from openstack import exceptions as sdk_exceptions +from openstack.test import fakes as sdk_fakes from osc_lib.cli import format_columns from osc_lib import exceptions @@ -27,8 +29,12 @@ class TestHypervisorList(compute_fakes.TestComputev2): super().setUp() # Fake hypervisors to be listed up - self.hypervisors = compute_fakes.create_hypervisors() - self.compute_sdk_client.hypervisors.return_value = self.hypervisors + self.hypervisors = list( + sdk_fakes.generate_fake_resources(_hypervisor.Hypervisor, count=2) + ) + self.compute_sdk_client.hypervisors.return_value = iter( + self.hypervisors + ) self.columns = ( "ID", @@ -125,9 +131,9 @@ class TestHypervisorList(compute_fakes.TestComputev2): ( self.hypervisors[0].id, self.hypervisors[0].name, - self.hypervisors[1].hypervisor_type, - self.hypervisors[1].host_ip, - self.hypervisors[1].state, + self.hypervisors[0].hypervisor_type, + self.hypervisors[0].host_ip, + self.hypervisors[0].state, ), ) @@ -290,10 +296,11 @@ class TestHypervisorShow(compute_fakes.TestComputev2): ) # Fake hypervisors to be listed up - self.hypervisor = compute_fakes.create_one_hypervisor( - attrs={ - 'uptime': uptime_string, - } + self.hypervisor = sdk_fakes.generate_fake_resource( + _hypervisor.Hypervisor, + uptime=uptime_string, + service={"id": 1, "host": "aaa"}, + cpu_info={"aaa": "aaa"}, ) self.compute_sdk_client.find_hypervisor.return_value = self.hypervisor @@ -332,18 +339,18 @@ class TestHypervisorShow(compute_fakes.TestComputev2): self.data_v288 = ( [], - format_columns.DictColumn({'aaa': 'aaa'}), - '192.168.0.10', + format_columns.DictColumn(self.hypervisor.cpu_info), + self.hypervisor.host_ip, '01:28:24', self.hypervisor.name, - 'QEMU', - 2004001, + self.hypervisor.hypervisor_type, + self.hypervisor.hypervisor_version, self.hypervisor.id, '0.94, 0.62, 0.50', - 'aaa', - 1, - 'up', - 'enabled', + self.hypervisor.service_details["host"], + self.hypervisor.service_details["id"], + self.hypervisor.state, + self.hypervisor.status, '3 days, 11:15', '1', ) @@ -378,31 +385,31 @@ class TestHypervisorShow(compute_fakes.TestComputev2): ) self.data = ( [], - format_columns.DictColumn({'aaa': 'aaa'}), - 0, - 50, - 50, - 1024, - '192.168.0.10', + format_columns.DictColumn(self.hypervisor.cpu_info), + self.hypervisor.current_workload, + self.hypervisor.disk_available, + self.hypervisor.local_disk_free, + self.hypervisor.memory_free, + self.hypervisor.host_ip, '01:28:24', self.hypervisor.name, - 'QEMU', - 2004001, + self.hypervisor.hypervisor_type, + self.hypervisor.hypervisor_version, self.hypervisor.id, '0.94, 0.62, 0.50', - 50, - 0, - 1024, - 512, - 0, - 'aaa', + self.hypervisor.local_disk_size, + self.hypervisor.local_disk_used, + self.hypervisor.memory_size, + self.hypervisor.memory_used, + self.hypervisor.running_vms, + self.hypervisor.service_details["host"], 1, - 'up', - 'enabled', + self.hypervisor.state, + self.hypervisor.status, '3 days, 11:15', '1', - 4, - 0, + self.hypervisor.vcpus, + self.hypervisor.vcpus_used, ) # Get the command object to test @@ -537,27 +544,27 @@ class TestHypervisorShow(compute_fakes.TestComputev2): ) expected_data = ( [], - format_columns.DictColumn({'aaa': 'aaa'}), - 0, - 50, - 50, - 1024, - '192.168.0.10', + format_columns.DictColumn(self.hypervisor.cpu_info), + self.hypervisor.current_workload, + self.hypervisor.disk_available, + self.hypervisor.local_disk_free, + self.hypervisor.memory_free, + self.hypervisor.host_ip, self.hypervisor.name, - 'QEMU', - 2004001, + self.hypervisor.hypervisor_type, + self.hypervisor.hypervisor_version, self.hypervisor.id, - 50, - 0, - 1024, - 512, - 0, - 'aaa', + self.hypervisor.local_disk_size, + self.hypervisor.local_disk_used, + self.hypervisor.memory_size, + self.hypervisor.memory_used, + self.hypervisor.running_vms, + self.hypervisor.service_details["host"], 1, - 'up', - 'enabled', - 4, - 0, + self.hypervisor.state, + self.hypervisor.status, + self.hypervisor.vcpus, + self.hypervisor.vcpus_used, ) self.assertEqual(expected_columns, columns) diff --git a/openstackclient/tests/unit/compute/v2/test_keypair.py b/openstackclient/tests/unit/compute/v2/test_keypair.py index d6be7d0..0ce08b4 100644 --- a/openstackclient/tests/unit/compute/v2/test_keypair.py +++ b/openstackclient/tests/unit/compute/v2/test_keypair.py @@ -12,17 +12,18 @@ # License for the specific language governing permissions and limitations # under the License. -import copy from unittest import mock from unittest.mock import call import uuid +from openstack.compute.v2 import keypair as _keypair +from openstack.identity.v3 import project as _project +from openstack.identity.v3 import user as _user +from openstack.test import fakes as sdk_fakes from osc_lib import exceptions from openstackclient.compute.v2 import keypair from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes -from openstackclient.tests.unit import fakes -from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes from openstackclient.tests.unit import utils as tests_utils @@ -31,20 +32,17 @@ class TestKeypair(compute_fakes.TestComputev2): super().setUp() # Initialize the user mock + self._user = sdk_fakes.generate_fake_resource(_user.User) self.users_mock = self.identity_client.users self.users_mock.reset_mock() - self.users_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.USER), - loaded=True, - ) + self.users_mock.get.return_value = self._user class TestKeypairCreate(TestKeypair): def setUp(self): super().setUp() - self.keypair = compute_fakes.create_one_keypair() + self.keypair = sdk_fakes.generate_fake_resource(_keypair.Keypair) self.columns = ( 'created_at', @@ -122,7 +120,7 @@ class TestKeypairCreate(TestKeypair): ) as mock_open: mock_open.return_value = mock.MagicMock() m_file = mock_open.return_value.__enter__.return_value - m_file.read.return_value = 'dummy' + m_file.read.return_value = self.keypair.public_key columns, data = self.cmd.take_action(parsed_args) @@ -208,7 +206,7 @@ class TestKeypairCreate(TestKeypair): ) as mock_open: mock_open.return_value = mock.MagicMock() m_file = mock_open.return_value.__enter__.return_value - m_file.read.return_value = 'dummy' + m_file.read.return_value = self.keypair.public_key columns, data = self.cmd.take_action(parsed_args) self.compute_sdk_client.create_keypair.assert_called_with( @@ -263,11 +261,11 @@ class TestKeypairCreate(TestKeypair): arglist = [ '--user', - identity_fakes.user_name, + self._user.name, self.keypair.name, ] verifylist = [ - ('user', identity_fakes.user_name), + ('user', self._user.name), ('name', self.keypair.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -276,7 +274,7 @@ class TestKeypairCreate(TestKeypair): self.compute_sdk_client.create_keypair.assert_called_with( name=self.keypair.name, - user_id=identity_fakes.user_id, + user_id=self._user.id, public_key=mock_generate.return_value.public_key, ) @@ -288,11 +286,11 @@ class TestKeypairCreate(TestKeypair): arglist = [ '--user', - identity_fakes.user_name, + self._user.name, self.keypair.name, ] verifylist = [ - ('user', identity_fakes.user_name), + ('user', self._user.name), ('name', self.keypair.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -306,11 +304,13 @@ class TestKeypairCreate(TestKeypair): class TestKeypairDelete(TestKeypair): - keypairs = compute_fakes.create_keypairs(count=2) - def setUp(self): super().setUp() + self.keypairs = list( + sdk_fakes.generate_fake_resources(_keypair.Keypair, count=2) + ) + self.cmd = keypair.DeleteKeypair(self.app, None) def test_keypair_delete(self): @@ -374,9 +374,9 @@ class TestKeypairDelete(TestKeypair): def test_keypair_delete_with_user(self): self.set_compute_api_version('2.10') - arglist = ['--user', identity_fakes.user_name, self.keypairs[0].name] + arglist = ['--user', self._user.name, self.keypairs[0].name] verifylist = [ - ('user', identity_fakes.user_name), + ('user', self._user.name), ('name', [self.keypairs[0].name]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -386,16 +386,16 @@ class TestKeypairDelete(TestKeypair): self.assertIsNone(ret) self.compute_sdk_client.delete_keypair.assert_called_with( self.keypairs[0].name, - user_id=identity_fakes.user_id, + user_id=self._user.id, ignore_missing=False, ) def test_keypair_delete_with_user_pre_v210(self): self.set_compute_api_version('2.9') - arglist = ['--user', identity_fakes.user_name, self.keypairs[0].name] + arglist = ['--user', self._user.name, self.keypairs[0].name] verifylist = [ - ('user', identity_fakes.user_name), + ('user', self._user.name), ('name', [self.keypairs[0].name]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -409,17 +409,19 @@ class TestKeypairDelete(TestKeypair): class TestKeypairList(TestKeypair): - # Return value of self.compute_sdk_client.keypairs(). - keypairs = compute_fakes.create_keypairs(count=1) - def setUp(self): super().setUp() - self.compute_sdk_client.keypairs.return_value = self.keypairs + self.keypairs = list( + sdk_fakes.generate_fake_resources(_keypair.Keypair, count=1) + ) + self.compute_sdk_client.keypairs.return_value = iter(self.keypairs) # Get the command object to test self.cmd = keypair.ListKeypair(self.app, None) + self._project = sdk_fakes.generate_fake_resource(_project.Project) + def test_keypair_list_no_options(self): arglist = [] verifylist = [] @@ -475,26 +477,22 @@ class TestKeypairList(TestKeypair): users_mock = self.identity_client.users users_mock.reset_mock() - users_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.USER), - loaded=True, - ) + users_mock.get.return_value = self._user arglist = [ '--user', - identity_fakes.user_name, + self._user.name, ] verifylist = [ - ('user', identity_fakes.user_name), + ('user', self._user.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) - users_mock.get.assert_called_with(identity_fakes.user_name) + users_mock.get.assert_called_with(self._user.name) self.compute_sdk_client.keypairs.assert_called_with( - user_id=identity_fakes.user_id, + user_id=self._user.id, ) self.assertEqual(('Name', 'Fingerprint', 'Type'), columns) @@ -514,10 +512,10 @@ class TestKeypairList(TestKeypair): arglist = [ '--user', - identity_fakes.user_name, + self._user.name, ] verifylist = [ - ('user', identity_fakes.user_name), + ('user', self._user.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -533,32 +531,22 @@ class TestKeypairList(TestKeypair): projects_mock = self.identity_client.tenants projects_mock.reset_mock() - projects_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.PROJECT), - loaded=True, - ) + projects_mock.get.return_value = self._project users_mock = self.identity_client.users users_mock.reset_mock() - users_mock.list.return_value = [ - fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.USER), - loaded=True, - ), - ] + users_mock.list.return_value = [self._user] - arglist = ['--project', identity_fakes.project_name] - verifylist = [('project', identity_fakes.project_name)] + arglist = ['--project', self._project.name] + verifylist = [('project', self._project.name)] parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) - projects_mock.get.assert_called_with(identity_fakes.project_name) - users_mock.list.assert_called_with(tenant_id=identity_fakes.project_id) + projects_mock.get.assert_called_with(self._project.name) + users_mock.list.assert_called_with(tenant_id=self._project.id) self.compute_sdk_client.keypairs.assert_called_with( - user_id=identity_fakes.user_id, + user_id=self._user.id, ) self.assertEqual(('Name', 'Fingerprint', 'Type'), columns) @@ -576,8 +564,8 @@ class TestKeypairList(TestKeypair): def test_keypair_list_with_project_pre_v210(self): self.set_compute_api_version('2.9') - arglist = ['--project', identity_fakes.project_name] - verifylist = [('project', identity_fakes.project_name)] + arglist = ['--project', self._project.name] + verifylist = [('project', self._project.name)] parsed_args = self.check_parser(self.cmd, arglist, verifylist) ex = self.assertRaises( @@ -590,9 +578,9 @@ class TestKeypairList(TestKeypair): def test_keypair_list_conflicting_user_options(self): arglist = [ '--user', - identity_fakes.user_name, + self._user.name, '--project', - identity_fakes.project_name, + self._project.name, ] self.assertRaises( @@ -707,7 +695,7 @@ class TestKeypairShow(TestKeypair): ) def test_keypair_show(self): - self.keypair = compute_fakes.create_one_keypair() + self.keypair = sdk_fakes.generate_fake_resource(_keypair.Keypair) self.compute_sdk_client.find_keypair.return_value = self.keypair self.data = ( @@ -735,7 +723,7 @@ class TestKeypairShow(TestKeypair): self.assertEqual(self.data, data) def test_keypair_show_public(self): - self.keypair = compute_fakes.create_one_keypair() + self.keypair = sdk_fakes.generate_fake_resource(_keypair.Keypair) self.compute_sdk_client.find_keypair.return_value = self.keypair arglist = ['--public-key', self.keypair.name] @@ -751,7 +739,7 @@ class TestKeypairShow(TestKeypair): def test_keypair_show_with_user(self): self.set_compute_api_version('2.10') - self.keypair = compute_fakes.create_one_keypair() + self.keypair = sdk_fakes.generate_fake_resource(_keypair.Keypair) self.compute_sdk_client.find_keypair.return_value = self.keypair self.data = ( @@ -767,22 +755,22 @@ class TestKeypairShow(TestKeypair): arglist = [ '--user', - identity_fakes.user_name, + self._user.name, self.keypair.name, ] verifylist = [ - ('user', identity_fakes.user_name), + ('user', self._user.name), ('name', self.keypair.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) - self.users_mock.get.assert_called_with(identity_fakes.user_name) + self.users_mock.get.assert_called_with(self._user.name) self.compute_sdk_client.find_keypair.assert_called_with( self.keypair.name, ignore_missing=False, - user_id=identity_fakes.user_id, + user_id=self._user.id, ) self.assertEqual(self.columns, columns) @@ -791,14 +779,14 @@ class TestKeypairShow(TestKeypair): def test_keypair_show_with_user_pre_v210(self): self.set_compute_api_version('2.9') - self.keypair = compute_fakes.create_one_keypair() + self.keypair = sdk_fakes.generate_fake_resource(_keypair.Keypair) arglist = [ '--user', - identity_fakes.user_name, + self._user.name, self.keypair.name, ] verifylist = [ - ('user', identity_fakes.user_name), + ('user', self._user.name), ('name', self.keypair.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) diff --git a/openstackclient/tests/unit/compute/v2/test_server.py b/openstackclient/tests/unit/compute/v2/test_server.py index a07e333..789daad 100644 --- a/openstackclient/tests/unit/compute/v2/test_server.py +++ b/openstackclient/tests/unit/compute/v2/test_server.py @@ -21,7 +21,9 @@ from unittest import mock import uuid import iso8601 +from openstack.compute.v2 import server_group as _server_group from openstack import exceptions as sdk_exceptions +from openstack.test import fakes as sdk_fakes from osc_lib.cli import format_columns from osc_lib import exceptions from osc_lib import utils as common_utils @@ -1165,7 +1167,7 @@ class TestServerAddSecurityGroup(compute_fakes.TestComputev2): self.server.id, ignore_missing=False ) self.compute_sdk_client.add_security_group_to_server.assert_called_once_with( - self.server, 'fake_sg' + self.server, {'name': 'fake_sg'} ) mock_find_nova_net_sg.assert_called_once_with( self.compute_sdk_client, 'fake_sg' @@ -1186,7 +1188,7 @@ class TestServerAddSecurityGroup(compute_fakes.TestComputev2): self.server.id, ignore_missing=False ) self.compute_sdk_client.add_security_group_to_server.assert_called_once_with( - self.server, 'fake_sg' + self.server, {'name': 'fake_sg'} ) self.assertIsNone(result) @@ -1375,7 +1377,9 @@ class TestServerCreate(TestServer): self.assertEqual(self.datalist(), data) def test_server_create_with_options(self): - server_group = compute_fakes.create_one_server_group() + server_group = sdk_fakes.generate_fake_resource( + _server_group.ServerGroup + ) self.compute_sdk_client.find_server_group.return_value = server_group security_group = network_fakes.create_one_security_group() @@ -1544,6 +1548,60 @@ class TestServerCreate(TestServer): self.assertEqual(self.columns, columns) self.assertEqual(self.datalist(), data) + def test_server_create_with_no_security_group(self): + arglist = [ + '--image', + self.image.id, + '--flavor', + self.flavor.id, + '--no-security-group', + self.server.name, + ] + verifylist = [ + ('image', self.image.id), + ('flavor', self.flavor.id), + ('key_name', None), + ('properties', None), + ('security_groups', []), + ('hints', {}), + ('server_group', None), + ('config_drive', False), + ('password', None), + ('server_name', self.server.name), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + + self.compute_sdk_client.find_flavor.assert_has_calls( + [mock.call(self.flavor.id, ignore_missing=False)] * 2 + ) + self.network_client.find_security_group.assert_not_called() + self.image_client.find_image.assert_called_once_with( + self.image.id, ignore_missing=False + ) + self.compute_sdk_client.create_server.assert_called_once_with( + name=self.server.name, + image_id=self.image.id, + flavor_id=self.flavor.id, + min_count=1, + max_count=1, + security_groups=[], + networks=[], + block_device_mapping=[ + { + 'uuid': self.image.id, + 'boot_index': 0, + 'source_type': 'image', + 'destination_type': 'local', + 'delete_on_termination': True, + }, + ], + ) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist(), data) + def test_server_create_with_network(self): network_net1 = network_fakes.create_one_network() network_net2 = network_fakes.create_one_network() @@ -7400,7 +7458,7 @@ class TestServerRemoveSecurityGroup(TestServer): self.server.id, ignore_missing=False ) self.compute_sdk_client.remove_security_group_from_server.assert_called_once_with( - self.server, 'fake_sg' + self.server, {'name': 'fake_sg'} ) mock_find_nova_net_sg.assert_called_once_with( self.compute_sdk_client, 'fake_sg' @@ -7421,7 +7479,7 @@ class TestServerRemoveSecurityGroup(TestServer): self.server.id, ignore_missing=False ) self.compute_sdk_client.remove_security_group_from_server.assert_called_once_with( - self.server, 'fake_sg' + self.server, {'name': 'fake_sg'} ) self.assertIsNone(result) diff --git a/openstackclient/tests/unit/compute/v2/test_server_group.py b/openstackclient/tests/unit/compute/v2/test_server_group.py index 2bef027..2e34493 100644 --- a/openstackclient/tests/unit/compute/v2/test_server_group.py +++ b/openstackclient/tests/unit/compute/v2/test_server_group.py @@ -13,6 +13,8 @@ # under the License. # +from openstack.compute.v2 import server_group as _server_group +from openstack.test import fakes as sdk_fakes from osc_lib.cli import format_columns from osc_lib import exceptions @@ -22,27 +24,31 @@ from openstackclient.tests.unit import utils as tests_utils class TestServerGroup(compute_fakes.TestComputev2): - fake_server_group = compute_fakes.create_one_server_group() - - columns = ( - 'id', - 'members', - 'name', - 'policy', - 'project_id', - 'rules', - 'user_id', - ) - - data = ( - fake_server_group.id, - format_columns.ListColumn(fake_server_group.member_ids), - fake_server_group.name, - fake_server_group.policy, - fake_server_group.project_id, - format_columns.DictColumn(fake_server_group.rules), - fake_server_group.user_id, - ) + def setUp(self): + super().setUp() + + self.fake_server_group = sdk_fakes.generate_fake_resource( + _server_group.ServerGroup + ) + + self.columns = ( + 'id', + 'members', + 'name', + 'policy', + 'project_id', + 'rules', + 'user_id', + ) + self.data = ( + self.fake_server_group.id, + format_columns.ListColumn(self.fake_server_group.member_ids), + self.fake_server_group.name, + self.fake_server_group.policy, + self.fake_server_group.project_id, + format_columns.DictColumn(self.fake_server_group.rules), + self.fake_server_group.user_id, + ) class TestServerGroupCreate(TestServerGroup): @@ -262,82 +268,6 @@ class TestServerGroupDelete(TestServerGroup): class TestServerGroupList(TestServerGroup): - list_columns = ( - 'ID', - 'Name', - 'Policies', - ) - - list_columns_long = ( - 'ID', - 'Name', - 'Policies', - 'Members', - 'Project Id', - 'User Id', - ) - - list_columns_v264 = ( - 'ID', - 'Name', - 'Policy', - ) - - list_columns_v264_long = ( - 'ID', - 'Name', - 'Policy', - 'Members', - 'Project Id', - 'User Id', - ) - - list_data = ( - ( - TestServerGroup.fake_server_group.id, - TestServerGroup.fake_server_group.name, - format_columns.ListColumn( - TestServerGroup.fake_server_group.policies - ), - ), - ) - - list_data_long = ( - ( - TestServerGroup.fake_server_group.id, - TestServerGroup.fake_server_group.name, - format_columns.ListColumn( - TestServerGroup.fake_server_group.policies - ), - format_columns.ListColumn( - TestServerGroup.fake_server_group.member_ids - ), - TestServerGroup.fake_server_group.project_id, - TestServerGroup.fake_server_group.user_id, - ), - ) - - list_data_v264 = ( - ( - TestServerGroup.fake_server_group.id, - TestServerGroup.fake_server_group.name, - TestServerGroup.fake_server_group.policy, - ), - ) - - list_data_v264_long = ( - ( - TestServerGroup.fake_server_group.id, - TestServerGroup.fake_server_group.name, - TestServerGroup.fake_server_group.policy, - format_columns.ListColumn( - TestServerGroup.fake_server_group.member_ids - ), - TestServerGroup.fake_server_group.project_id, - TestServerGroup.fake_server_group.user_id, - ), - ) - def setUp(self): super().setUp() @@ -359,8 +289,21 @@ class TestServerGroupList(TestServerGroup): self.compute_sdk_client.server_groups.assert_called_once_with() - self.assertCountEqual(self.list_columns, columns) - self.assertCountEqual(self.list_data, tuple(data)) + expected_columns = ( + 'ID', + 'Name', + 'Policies', + ) + expected_data = ( + ( + self.fake_server_group.id, + self.fake_server_group.name, + format_columns.ListColumn(self.fake_server_group.policies), + ), + ) + + self.assertCountEqual(expected_columns, columns) + self.assertCountEqual(expected_data, tuple(data)) def test_server_group_list_with_all_projects_and_long(self): arglist = [ @@ -379,8 +322,27 @@ class TestServerGroupList(TestServerGroup): all_projects=True ) - self.assertCountEqual(self.list_columns_long, columns) - self.assertCountEqual(self.list_data_long, tuple(data)) + expected_columns = ( + 'ID', + 'Name', + 'Policies', + 'Members', + 'Project Id', + 'User Id', + ) + expected_data = ( + ( + self.fake_server_group.id, + self.fake_server_group.name, + format_columns.ListColumn(self.fake_server_group.policies), + format_columns.ListColumn(self.fake_server_group.member_ids), + self.fake_server_group.project_id, + self.fake_server_group.user_id, + ), + ) + + self.assertCountEqual(expected_columns, columns) + self.assertCountEqual(expected_data, tuple(data)) def test_server_group_list_with_limit(self): arglist = [ @@ -428,8 +390,21 @@ class TestServerGroupList(TestServerGroup): columns, data = self.cmd.take_action(parsed_args) self.compute_sdk_client.server_groups.assert_called_once_with() - self.assertCountEqual(self.list_columns_v264, columns) - self.assertCountEqual(self.list_data_v264, tuple(data)) + expected_columns = ( + 'ID', + 'Name', + 'Policy', + ) + expected_data = ( + ( + self.fake_server_group.id, + self.fake_server_group.name, + self.fake_server_group.policy, + ), + ) + + self.assertCountEqual(expected_columns, columns) + self.assertCountEqual(expected_data, tuple(data)) def test_server_group_list_with_all_projects_and_long_v264(self): self.set_compute_api_version('2.64') @@ -448,8 +423,27 @@ class TestServerGroupList(TestServerGroup): all_projects=True ) - self.assertCountEqual(self.list_columns_v264_long, columns) - self.assertCountEqual(self.list_data_v264_long, tuple(data)) + expected_columns = ( + 'ID', + 'Name', + 'Policy', + 'Members', + 'Project Id', + 'User Id', + ) + expected_data = ( + ( + self.fake_server_group.id, + self.fake_server_group.name, + self.fake_server_group.policy, + format_columns.ListColumn(self.fake_server_group.member_ids), + self.fake_server_group.project_id, + self.fake_server_group.user_id, + ), + ) + + self.assertCountEqual(expected_columns, columns) + self.assertCountEqual(expected_data, tuple(data)) class TestServerGroupShow(TestServerGroup): diff --git a/openstackclient/tests/unit/compute/v2/test_server_volume.py b/openstackclient/tests/unit/compute/v2/test_server_volume.py index e598532..d42da95 100644 --- a/openstackclient/tests/unit/compute/v2/test_server_volume.py +++ b/openstackclient/tests/unit/compute/v2/test_server_volume.py @@ -10,19 +10,26 @@ # License for the specific language governing permissions and limitations # under the License. +from openstack.block_storage.v3 import volume as _volume +from openstack.compute.v2 import server as _server +from openstack.compute.v2 import volume_attachment as _volume_attachment +from openstack.test import fakes as sdk_fakes from osc_lib import exceptions from openstackclient.compute.v2 import server_volume from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes -from openstackclient.tests.unit.volume.v2 import fakes as volume_fakes class TestServerVolumeList(compute_fakes.TestComputev2): def setUp(self): super().setUp() - self.server = compute_fakes.create_one_sdk_server() - self.volume_attachments = compute_fakes.create_volume_attachments() + self.server = sdk_fakes.generate_fake_resource(_server.Server) + self.volume_attachments = list( + sdk_fakes.generate_fake_resources( + _volume_attachment.VolumeAttachment, count=2 + ) + ) self.compute_sdk_client.find_server.return_value = self.server self.compute_sdk_client.volume_attachments.return_value = ( @@ -217,10 +224,10 @@ class TestServerVolumeUpdate(compute_fakes.TestComputev2): def setUp(self): super().setUp() - self.server = compute_fakes.create_one_sdk_server() + self.server = sdk_fakes.generate_fake_resource(_server.Server) self.compute_sdk_client.find_server.return_value = self.server - self.volume = volume_fakes.create_one_sdk_volume() + self.volume = sdk_fakes.generate_fake_resource(_volume.Volume) self.volume_sdk_client.find_volume.return_value = self.volume # Get the command object to test diff --git a/openstackclient/tests/unit/compute/v2/test_service.py b/openstackclient/tests/unit/compute/v2/test_service.py index 2997fec..ce7791d 100644 --- a/openstackclient/tests/unit/compute/v2/test_service.py +++ b/openstackclient/tests/unit/compute/v2/test_service.py @@ -14,6 +14,8 @@ from unittest import mock +from openstack.compute.v2 import service as _service +from openstack.test import fakes as sdk_fakes from osc_lib import exceptions from openstackclient.compute.v2 import service @@ -21,11 +23,13 @@ from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes class TestServiceDelete(compute_fakes.TestComputev2): - services = compute_fakes.create_services(count=2) - def setUp(self): super().setUp() + self.services = list( + sdk_fakes.generate_fake_resources(_service.Service, count=2) + ) + self.compute_sdk_client.delete_service.return_value = None # Get the command object to test @@ -94,35 +98,11 @@ class TestServiceDelete(compute_fakes.TestComputev2): class TestServiceList(compute_fakes.TestComputev2): - service = compute_fakes.create_one_service() - - columns = ( - 'ID', - 'Binary', - 'Host', - 'Zone', - 'Status', - 'State', - 'Updated At', - ) - columns_long = columns + ('Disabled Reason',) - - data = [ - ( - service.id, - service.binary, - service.host, - service.availability_zone, - service.status, - service.state, - service.updated_at, - ) - ] - data_long = [data[0] + (service.disabled_reason,)] - def setUp(self): super().setUp() + self.service = sdk_fakes.generate_fake_resource(_service.Service) + self.compute_sdk_client.services.return_value = [self.service] # Get the command object to test @@ -151,8 +131,29 @@ class TestServiceList(compute_fakes.TestComputev2): binary=self.service.binary, ) - self.assertEqual(self.columns, columns) - self.assertEqual(self.data, list(data)) + expected_columns = ( + 'ID', + 'Binary', + 'Host', + 'Zone', + 'Status', + 'State', + 'Updated At', + ) + expected_data = [ + ( + self.service.id, + self.service.binary, + self.service.host, + self.service.availability_zone, + self.service.status, + self.service.state, + self.service.updated_at, + ) + ] + + self.assertEqual(expected_columns, columns) + self.assertEqual(expected_data, list(data)) def test_service_list_with_long_option(self): arglist = [ @@ -179,8 +180,31 @@ class TestServiceList(compute_fakes.TestComputev2): binary=self.service.binary, ) - self.assertEqual(self.columns_long, columns) - self.assertEqual(self.data_long, list(data)) + expected_columns = ( + 'ID', + 'Binary', + 'Host', + 'Zone', + 'Status', + 'State', + 'Updated At', + 'Disabled Reason', + ) + expected_data = [ + ( + self.service.id, + self.service.binary, + self.service.host, + self.service.availability_zone, + self.service.status, + self.service.state, + self.service.updated_at, + self.service.disabled_reason, + ) + ] + + self.assertEqual(expected_columns, columns) + self.assertEqual(expected_data, list(data)) def test_service_list_with_long_option_2_11(self): self.set_compute_api_version('2.11') @@ -210,18 +234,40 @@ class TestServiceList(compute_fakes.TestComputev2): ) # In 2.11 there is also a forced_down column. - columns_long = self.columns_long + ('Forced Down',) - data_long = [self.data_long[0] + (self.service.is_forced_down,)] + expected_columns = ( + 'ID', + 'Binary', + 'Host', + 'Zone', + 'Status', + 'State', + 'Updated At', + 'Disabled Reason', + 'Forced Down', + ) + expected_data = [ + ( + self.service.id, + self.service.binary, + self.service.host, + self.service.availability_zone, + self.service.status, + self.service.state, + self.service.updated_at, + self.service.disabled_reason, + self.service.is_forced_down, + ) + ] - self.assertEqual(columns_long, columns) - self.assertEqual(data_long, list(data)) + self.assertEqual(expected_columns, columns) + self.assertEqual(expected_data, list(data)) class TestServiceSet(compute_fakes.TestComputev2): def setUp(self): super().setUp() - self.service = compute_fakes.create_one_service() + self.service = sdk_fakes.generate_fake_resource(_service.Service) self.compute_sdk_client.enable_service.return_value = self.service self.compute_sdk_client.disable_service.return_value = self.service diff --git a/openstackclient/tests/unit/compute/v2/test_usage.py b/openstackclient/tests/unit/compute/v2/test_usage.py index 2efd25b..346e2fb 100644 --- a/openstackclient/tests/unit/compute/v2/test_usage.py +++ b/openstackclient/tests/unit/compute/v2/test_usage.py @@ -14,9 +14,12 @@ import datetime from unittest import mock +from openstack.compute.v2 import usage as _usage +from openstack.identity.v3 import project as _project +from openstack.test import fakes as sdk_fakes + from openstackclient.compute.v2 import usage as usage_cmds from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes -from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes class TestUsage(compute_fakes.TestComputev2): @@ -28,11 +31,11 @@ class TestUsage(compute_fakes.TestComputev2): class TestUsageList(TestUsage): - project = identity_fakes.FakeProject.create_one_project() + project = sdk_fakes.generate_fake_resource(_project.Project) # Return value of self.usage_mock.list(). - usages = compute_fakes.create_usages( - attrs={'project_id': project.name}, count=1 - ) + usages = [ + sdk_fakes.generate_fake_resource(_usage.Usage, project_id=project.name) + ] columns = ( "Project", @@ -123,9 +126,11 @@ class TestUsageList(TestUsage): class TestUsageShow(TestUsage): - project = identity_fakes.FakeProject.create_one_project() + project = sdk_fakes.generate_fake_resource(_project.Project) # Return value of self.usage_mock.list(). - usage = compute_fakes.create_one_usage(attrs={'project_id': project.name}) + usage = sdk_fakes.generate_fake_resource( + _usage.Usage, project_id=project.name + ) columns = ( 'Project', diff --git a/openstackclient/tests/unit/identity/v2_0/test_catalog.py b/openstackclient/tests/unit/identity/v2_0/test_catalog.py index 63b3d47..ef8b1cf 100644 --- a/openstackclient/tests/unit/identity/v2_0/test_catalog.py +++ b/openstackclient/tests/unit/identity/v2_0/test_catalog.py @@ -53,8 +53,7 @@ class TestCatalogList(TestCatalog): identity_fakes.TOKEN, fake_service=self.service_catalog, ) - self.ar_mock = mock.PropertyMock(return_value=auth_ref) - type(self.app.client_manager).auth_ref = self.ar_mock + self.app.client_manager.auth_ref = auth_ref arglist = [] verifylist = [] @@ -99,8 +98,7 @@ class TestCatalogList(TestCatalog): identity_fakes.TOKEN, fake_service=service_catalog, ) - self.ar_mock = mock.PropertyMock(return_value=auth_ref) - type(self.app.client_manager).auth_ref = self.ar_mock + self.app.client_manager.auth_ref = auth_ref arglist = [] verifylist = [] @@ -136,8 +134,7 @@ class TestCatalogShow(TestCatalog): identity_fakes.UNSCOPED_TOKEN, fake_service=self.service_catalog, ) - self.ar_mock = mock.PropertyMock(return_value=auth_ref) - type(self.app.client_manager).auth_ref = self.ar_mock + self.app.client_manager.auth_ref = auth_ref arglist = [ 'compute', diff --git a/openstackclient/tests/unit/identity/v2_0/test_role.py b/openstackclient/tests/unit/identity/v2_0/test_role.py index 830653b..117d2f0 100644 --- a/openstackclient/tests/unit/identity/v2_0/test_role.py +++ b/openstackclient/tests/unit/identity/v2_0/test_role.py @@ -58,8 +58,7 @@ class TestRole(identity_fakes.TestIdentityv2): identity_fakes.TOKEN, fake_service=self.fake_service, ) - self.ar_mock = mock.PropertyMock(return_value=auth_ref) - type(self.app.client_manager).auth_ref = self.ar_mock + self.app.client_manager.auth_ref = auth_ref class TestRoleAdd(TestRole): diff --git a/openstackclient/tests/unit/identity/v2_0/test_role_assignment.py b/openstackclient/tests/unit/identity/v2_0/test_role_assignment.py index a06c270..741b3ee 100644 --- a/openstackclient/tests/unit/identity/v2_0/test_role_assignment.py +++ b/openstackclient/tests/unit/identity/v2_0/test_role_assignment.py @@ -169,7 +169,8 @@ class TestRoleAssignmentList(TestRoleAssignment): self.assertEqual(datalist, tuple(data)) def test_role_assignment_list_def_creds(self): - auth_ref = self.app.client_manager.auth_ref = mock.Mock() + self.app.client_manager.auth_ref = mock.Mock() + auth_ref = self.app.client_manager.auth_ref auth_ref.project_id.return_value = identity_fakes.project_id auth_ref.user_id.return_value = identity_fakes.user_id diff --git a/openstackclient/tests/unit/identity/v2_0/test_token.py b/openstackclient/tests/unit/identity/v2_0/test_token.py index 1e90104..56a5a2c 100644 --- a/openstackclient/tests/unit/identity/v2_0/test_token.py +++ b/openstackclient/tests/unit/identity/v2_0/test_token.py @@ -11,29 +11,17 @@ # 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 unittest import mock from openstackclient.identity.v2_0 import token from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes -class TestToken(identity_fakes.TestIdentityv2): - fake_user = identity_fakes.FakeUser.create_one_user() - fake_project = identity_fakes.FakeProject.create_one_project() - +class TestTokenIssue(identity_fakes.TestIdentityv2): def setUp(self): super().setUp() - # Get a shortcut to the Auth Ref Mock - self.ar_mock = mock.PropertyMock() - type(self.app.client_manager).auth_ref = self.ar_mock - - -class TestTokenIssue(TestToken): - def setUp(self): - super().setUp() + self.fake_user = identity_fakes.FakeUser.create_one_user() + self.fake_project = identity_fakes.FakeProject.create_one_project() self.cmd = token.IssueToken(self.app, None) @@ -41,8 +29,7 @@ class TestTokenIssue(TestToken): auth_ref = identity_fakes.fake_auth_ref( identity_fakes.TOKEN, ) - self.ar_mock = mock.PropertyMock(return_value=auth_ref) - type(self.app.client_manager).auth_ref = self.ar_mock + self.app.client_manager.auth_ref = auth_ref arglist = [] verifylist = [] @@ -67,8 +54,7 @@ class TestTokenIssue(TestToken): auth_ref = identity_fakes.fake_auth_ref( identity_fakes.UNSCOPED_TOKEN, ) - self.ar_mock = mock.PropertyMock(return_value=auth_ref) - type(self.app.client_manager).auth_ref = self.ar_mock + self.app.client_manager.auth_ref = auth_ref arglist = [] verifylist = [] @@ -91,7 +77,7 @@ class TestTokenIssue(TestToken): self.assertEqual(datalist, data) -class TestTokenRevoke(TestToken): +class TestTokenRevoke(identity_fakes.TestIdentityv2): TOKEN = 'fob' def setUp(self): diff --git a/openstackclient/tests/unit/identity/v3/test_catalog.py b/openstackclient/tests/unit/identity/v3/test_catalog.py index ed2db3b..df292b1 100644 --- a/openstackclient/tests/unit/identity/v3/test_catalog.py +++ b/openstackclient/tests/unit/identity/v3/test_catalog.py @@ -9,7 +9,6 @@ # 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 unittest import mock @@ -72,8 +71,7 @@ class TestCatalogList(TestCatalog): identity_fakes.TOKEN_WITH_PROJECT_ID, fake_service=self.fake_service, ) - self.ar_mock = mock.PropertyMock(return_value=auth_ref) - type(self.app.client_manager).auth_ref = self.ar_mock + self.app.client_manager.auth_ref = auth_ref arglist = [] verifylist = [] @@ -110,8 +108,7 @@ class TestCatalogShow(TestCatalog): identity_fakes.TOKEN_WITH_PROJECT_ID, fake_service=self.fake_service, ) - self.ar_mock = mock.PropertyMock(return_value=auth_ref) - type(self.app.client_manager).auth_ref = self.ar_mock + self.app.client_manager.auth_ref = auth_ref arglist = [ 'compute', diff --git a/openstackclient/tests/unit/identity/v3/test_credential.py b/openstackclient/tests/unit/identity/v3/test_credential.py index 794f40b..f21fd71 100644 --- a/openstackclient/tests/unit/identity/v3/test_credential.py +++ b/openstackclient/tests/unit/identity/v3/test_credential.py @@ -10,9 +10,13 @@ # License for the specific language governing permissions and limitations # under the License. -from unittest import mock from unittest.mock import call +from openstack import exceptions as sdk_exceptions +from openstack.identity.v3 import credential as _credential +from openstack.identity.v3 import project as _project +from openstack.identity.v3 import user as _user +from openstack.test import fakes as sdk_fakes from osc_lib import exceptions from openstackclient.identity.v3 import credential @@ -20,26 +24,9 @@ from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes from openstackclient.tests.unit import utils -class TestCredential(identity_fakes.TestIdentityv3): - def setUp(self): - super().setUp() - - # Get a shortcut to the CredentialManager Mock - self.credentials_mock = self.identity_client.credentials - self.credentials_mock.reset_mock() - - # Get a shortcut to the UserManager Mock - self.users_mock = self.identity_client.users - self.users_mock.reset_mock() - - # Get a shortcut to the ProjectManager Mock - self.projects_mock = self.identity_client.projects - self.projects_mock.reset_mock() - - -class TestCredentialCreate(TestCredential): - user = identity_fakes.FakeUser.create_one_user() - project = identity_fakes.FakeProject.create_one_project() +class TestCredentialCreate(identity_fakes.TestIdentityv3): + user = sdk_fakes.generate_fake_resource(_user.User) + project = sdk_fakes.generate_fake_resource(_project.Project) columns = ( 'blob', 'id', @@ -51,12 +38,17 @@ class TestCredentialCreate(TestCredential): def setUp(self): super().setUp() - self.credential = identity_fakes.FakeCredential.create_one_credential( - attrs={'user_id': self.user.id, 'project_id': self.project.id} + self.credential = sdk_fakes.generate_fake_resource( + resource_type=_credential.Credential, + user_id=self.user.id, + project_id=self.project.id, + type='cert', ) - self.credentials_mock.create.return_value = self.credential - self.users_mock.get.return_value = self.user - self.projects_mock.get.return_value = self.project + self.identity_sdk_client.create_credential.return_value = ( + self.credential + ) + self.identity_sdk_client.find_user.return_value = self.user + self.identity_sdk_client.find_project.return_value = self.project self.data = ( self.credential.blob, self.credential.id, @@ -81,12 +73,14 @@ class TestCredentialCreate(TestCredential): columns, data = self.cmd.take_action(parsed_args) kwargs = { - 'user': self.credential.user_id, + 'user_id': self.credential.user_id, 'type': self.credential.type, 'blob': self.credential.blob, - 'project': None, + 'project_id': None, } - self.credentials_mock.create.assert_called_once_with(**kwargs) + self.identity_sdk_client.create_credential.assert_called_once_with( + **kwargs + ) self.assertEqual(self.columns, columns) self.assertEqual(self.data, data) @@ -111,47 +105,53 @@ class TestCredentialCreate(TestCredential): columns, data = self.cmd.take_action(parsed_args) kwargs = { - 'user': self.credential.user_id, + 'user_id': self.credential.user_id, 'type': self.credential.type, 'blob': self.credential.blob, - 'project': self.credential.project_id, + 'project_id': self.credential.project_id, } - self.credentials_mock.create.assert_called_once_with(**kwargs) + self.identity_sdk_client.create_credential.assert_called_once_with( + **kwargs + ) self.assertEqual(self.columns, columns) self.assertEqual(self.data, data) -class TestCredentialDelete(TestCredential): - credentials = identity_fakes.FakeCredential.create_credentials(count=2) - +class TestCredentialDelete(identity_fakes.TestIdentityv3): def setUp(self): super().setUp() - self.credentials_mock.delete.return_value = None + self.identity_sdk_client.delete_credential.return_value = None # Get the command object to test self.cmd = credential.DeleteCredential(self.app, None) def test_credential_delete(self): + credential = sdk_fakes.generate_fake_resource( + _credential.Credential, + ) arglist = [ - self.credentials[0].id, + credential.id, ] verifylist = [ - ('credential', [self.credentials[0].id]), + ('credential', [credential.id]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) result = self.cmd.take_action(parsed_args) - self.credentials_mock.delete.assert_called_with( - self.credentials[0].id, + self.identity_sdk_client.delete_credential.assert_called_with( + credential.id, ) self.assertIsNone(result) def test_credential_multi_delete(self): + credentials = sdk_fakes.generate_fake_resources( + _credential.Credential, count=2 + ) arglist = [] - for c in self.credentials: + for c in credentials: arglist.append(c.id) verifylist = [ ('credential', arglist), @@ -161,25 +161,26 @@ class TestCredentialDelete(TestCredential): result = self.cmd.take_action(parsed_args) calls = [] - for c in self.credentials: + for c in credentials: calls.append(call(c.id)) - self.credentials_mock.delete.assert_has_calls(calls) + self.identity_sdk_client.delete_credential.assert_has_calls(calls) self.assertIsNone(result) def test_credential_multi_delete_with_exception(self): + credential = sdk_fakes.generate_fake_resource( + _credential.Credential, + ) arglist = [ - self.credentials[0].id, + credential.id, 'unexist_credential', ] - verifylist = [ - ('credential', [self.credentials[0].id, 'unexist_credential']) - ] + verifylist = [('credential', [credential.id, 'unexist_credential'])] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - delete_mock_result = [None, exceptions.CommandError] - self.credentials_mock.delete = mock.Mock( - side_effect=delete_mock_result - ) + self.identity_sdk_client.delete_credential.side_effect = [ + None, + sdk_exceptions.NotFoundException, + ] try: self.cmd.take_action(parsed_args) @@ -187,12 +188,16 @@ class TestCredentialDelete(TestCredential): except exceptions.CommandError as e: self.assertEqual('1 of 2 credential failed to delete.', str(e)) - self.credentials_mock.delete.assert_any_call(self.credentials[0].id) - self.credentials_mock.delete.assert_any_call('unexist_credential') + self.identity_sdk_client.delete_credential.assert_any_call( + credential.id + ) + self.identity_sdk_client.delete_credential.assert_any_call( + 'unexist_credential' + ) -class TestCredentialList(TestCredential): - credential = identity_fakes.FakeCredential.create_one_credential() +class TestCredentialList(identity_fakes.TestIdentityv3): + credential = sdk_fakes.generate_fake_resource(_credential.Credential) columns = ('ID', 'Type', 'User ID', 'Data', 'Project ID') data = ( @@ -208,10 +213,10 @@ class TestCredentialList(TestCredential): def setUp(self): super().setUp() - self.user = identity_fakes.FakeUser.create_one_user() - self.users_mock.get.return_value = self.user + self.user = sdk_fakes.generate_fake_resource(_user.User) + self.identity_sdk_client.find_user.return_value = self.user - self.credentials_mock.list.return_value = [self.credential] + self.identity_sdk_client.credentials.return_value = [self.credential] # Get the command object to test self.cmd = credential.ListCredential(self.app, None) @@ -223,7 +228,7 @@ class TestCredentialList(TestCredential): columns, data = self.cmd.take_action(parsed_args) - self.credentials_mock.list.assert_called_with() + self.identity_sdk_client.credentials.assert_called_with() self.assertEqual(self.columns, columns) self.assertEqual(self.data, tuple(data)) @@ -246,15 +251,17 @@ class TestCredentialList(TestCredential): 'user_id': self.user.id, 'type': self.credential.type, } - self.users_mock.get.assert_called_with(self.credential.user_id) - self.credentials_mock.list.assert_called_with(**kwargs) + self.identity_sdk_client.find_user.assert_called_with( + self.credential.user_id, domain_id=None, ignore_missing=False + ) + self.identity_sdk_client.credentials.assert_called_with(**kwargs) self.assertEqual(self.columns, columns) self.assertEqual(self.data, tuple(data)) -class TestCredentialSet(TestCredential): - credential = identity_fakes.FakeCredential.create_one_credential() +class TestCredentialSet(identity_fakes.TestIdentityv3): + credential = sdk_fakes.generate_fake_resource(_credential.Credential) def setUp(self): super().setUp() @@ -343,7 +350,7 @@ class TestCredentialSet(TestCredential): self.assertIsNone(result) -class TestCredentialShow(TestCredential): +class TestCredentialShow(identity_fakes.TestIdentityv3): columns = ( 'blob', 'id', @@ -355,8 +362,10 @@ class TestCredentialShow(TestCredential): def setUp(self): super().setUp() - self.credential = identity_fakes.FakeCredential.create_one_credential() - self.credentials_mock.get.return_value = self.credential + self.credential = sdk_fakes.generate_fake_resource( + _credential.Credential + ) + self.identity_sdk_client.get_credential.return_value = self.credential self.data = ( self.credential.blob, self.credential.id, @@ -378,6 +387,8 @@ class TestCredentialShow(TestCredential): columns, data = self.cmd.take_action(parsed_args) - self.credentials_mock.get.assert_called_once_with(self.credential.id) + self.identity_sdk_client.get_credential.assert_called_once_with( + self.credential.id + ) self.assertEqual(self.columns, columns) self.assertEqual(self.data, data) diff --git a/openstackclient/tests/unit/identity/v3/test_project.py b/openstackclient/tests/unit/identity/v3/test_project.py index 9b7fc8c..9085498 100644 --- a/openstackclient/tests/unit/identity/v3/test_project.py +++ b/openstackclient/tests/unit/identity/v3/test_project.py @@ -11,7 +11,6 @@ # 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 unittest import mock from unittest.mock import call @@ -914,8 +913,7 @@ class TestProjectList(TestProject): auth_ref = identity_fakes.fake_auth_ref( identity_fakes.TOKEN_WITH_PROJECT_ID, ) - ar_mock = mock.PropertyMock(return_value=auth_ref) - type(self.app.client_manager).auth_ref = ar_mock + self.app.client_manager.auth_ref = auth_ref arglist = [ '--my-projects', diff --git a/openstackclient/tests/unit/identity/v3/test_region.py b/openstackclient/tests/unit/identity/v3/test_region.py index 9b66c3c..eecb079 100644 --- a/openstackclient/tests/unit/identity/v3/test_region.py +++ b/openstackclient/tests/unit/identity/v3/test_region.py @@ -11,55 +11,44 @@ # under the License. # -import copy + +from openstack.identity.v3 import region as _region +from openstack.test import fakes as sdk_fakes from openstackclient.identity.v3 import region -from openstackclient.tests.unit import fakes from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes -class TestRegion(identity_fakes.TestIdentityv3): - def setUp(self): - super().setUp() - - # Get a shortcut to the RegionManager Mock - self.regions_mock = self.identity_client.regions - self.regions_mock.reset_mock() - - -class TestRegionCreate(TestRegion): +class TestRegionCreate(identity_fakes.TestIdentityv3): + region = sdk_fakes.generate_fake_resource(_region.Region) columns = ( + 'region', 'description', 'parent_region', - 'region', ) datalist = ( - identity_fakes.region_description, - identity_fakes.region_parent_region_id, - identity_fakes.region_id, + region.id, + region.description, + region.parent_region_id, ) def setUp(self): super().setUp() - self.regions_mock.create.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.REGION), - loaded=True, - ) + self.identity_sdk_client.create_region.return_value = self.region # Get the command object to test self.cmd = region.CreateRegion(self.app, None) def test_region_create_description(self): arglist = [ - identity_fakes.region_id, + self.region.id, '--description', - identity_fakes.region_description, + self.region.description, ] verifylist = [ - ('region', identity_fakes.region_id), - ('description', identity_fakes.region_description), + ('region', self.region.id), + ('description', self.region.description), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -70,21 +59,21 @@ class TestRegionCreate(TestRegion): # Set expected values kwargs = { - 'description': identity_fakes.region_description, - 'id': identity_fakes.region_id, - 'parent_region': None, + 'description': self.region.description, + 'id': self.region.id, + 'parent_region_id': None, } - self.regions_mock.create.assert_called_with(**kwargs) + self.identity_sdk_client.create_region.assert_called_with(**kwargs) self.assertEqual(self.columns, columns) self.assertEqual(self.datalist, data) def test_region_create_no_options(self): arglist = [ - identity_fakes.region_id, + self.region.id, ] verifylist = [ - ('region', identity_fakes.region_id), + ('region', self.region.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -96,23 +85,23 @@ class TestRegionCreate(TestRegion): # Set expected values kwargs = { 'description': None, - 'id': identity_fakes.region_id, - 'parent_region': None, + 'id': self.region.id, + 'parent_region_id': None, } - self.regions_mock.create.assert_called_with(**kwargs) + self.identity_sdk_client.create_region.assert_called_with(**kwargs) self.assertEqual(self.columns, columns) self.assertEqual(self.datalist, data) def test_region_create_parent_region_id(self): arglist = [ - identity_fakes.region_id, + self.region.id, '--parent-region', - identity_fakes.region_parent_region_id, + self.region.parent_region_id, ] verifylist = [ - ('region', identity_fakes.region_id), - ('parent_region', identity_fakes.region_parent_region_id), + ('region', self.region.id), + ('parent_region', self.region.parent_region_id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -124,41 +113,43 @@ class TestRegionCreate(TestRegion): # Set expected values kwargs = { 'description': None, - 'id': identity_fakes.region_id, - 'parent_region': identity_fakes.region_parent_region_id, + 'id': self.region.id, + 'parent_region_id': self.region.parent_region_id, } - self.regions_mock.create.assert_called_with(**kwargs) + self.identity_sdk_client.create_region.assert_called_with(**kwargs) self.assertEqual(self.columns, columns) self.assertEqual(self.datalist, data) -class TestRegionDelete(TestRegion): +class TestRegionDelete(identity_fakes.TestIdentityv3): def setUp(self): super().setUp() - self.regions_mock.delete.return_value = None + self.region = sdk_fakes.generate_fake_resource(_region.Region) + self.identity_sdk_client.delete_region.return_value = None # Get the command object to test self.cmd = region.DeleteRegion(self.app, None) def test_region_delete_no_options(self): arglist = [ - identity_fakes.region_id, + self.region.id, ] verifylist = [ - ('region', [identity_fakes.region_id]), + ('region', [self.region.id]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) result = self.cmd.take_action(parsed_args) - self.regions_mock.delete.assert_called_with( - identity_fakes.region_id, + self.identity_sdk_client.delete_region.assert_called_with( + self.region.id, ) self.assertIsNone(result) -class TestRegionList(TestRegion): +class TestRegionList(identity_fakes.TestIdentityv3): + region = sdk_fakes.generate_fake_resource(_region.Region) columns = ( 'Region', 'Parent Region', @@ -166,22 +157,16 @@ class TestRegionList(TestRegion): ) datalist = ( ( - identity_fakes.region_id, - identity_fakes.region_parent_region_id, - identity_fakes.region_description, + region.id, + region.parent_region_id, + region.description, ), ) def setUp(self): super().setUp() - self.regions_mock.list.return_value = [ - fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.REGION), - loaded=True, - ), - ] + self.identity_sdk_client.regions.return_value = [self.region] # Get the command object to test self.cmd = region.ListRegion(self.app, None) @@ -195,7 +180,7 @@ class TestRegionList(TestRegion): # returns a tuple containing the column names and an iterable # containing the data to be listed. columns, data = self.cmd.take_action(parsed_args) - self.regions_mock.list.assert_called_with() + self.identity_sdk_client.regions.assert_called_with() self.assertEqual(self.columns, columns) self.assertEqual(self.datalist, tuple(data)) @@ -203,10 +188,10 @@ class TestRegionList(TestRegion): def test_region_list_parent_region_id(self): arglist = [ '--parent-region', - identity_fakes.region_parent_region_id, + self.region.parent_region_id, ] verifylist = [ - ('parent_region', identity_fakes.region_parent_region_id), + ('parent_region', self.region.parent_region_id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -214,41 +199,37 @@ class TestRegionList(TestRegion): # returns a tuple containing the column names and an iterable # containing the data to be listed. columns, data = self.cmd.take_action(parsed_args) - self.regions_mock.list.assert_called_with( - parent_region_id=identity_fakes.region_parent_region_id + self.identity_sdk_client.regions.assert_called_with( + parent_region_id=self.region.parent_region_id ) self.assertEqual(self.columns, columns) self.assertEqual(self.datalist, tuple(data)) -class TestRegionSet(TestRegion): +class TestRegionSet(identity_fakes.TestIdentityv3): def setUp(self): super().setUp() - self.regions_mock.update.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.REGION), - loaded=True, - ) + self.region = sdk_fakes.generate_fake_resource(_region.Region) # Get the command object to test self.cmd = region.SetRegion(self.app, None) def test_region_set_no_options(self): arglist = [ - identity_fakes.region_id, + self.region.id, ] verifylist = [ - ('region', identity_fakes.region_id), + ('region', self.region.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) result = self.cmd.take_action(parsed_args) kwargs = {} - self.regions_mock.update.assert_called_with( - identity_fakes.region_id, **kwargs + self.identity_sdk_client.update_region.assert_called_with( + self.region.id, **kwargs ) self.assertIsNone(result) @@ -256,11 +237,11 @@ class TestRegionSet(TestRegion): arglist = [ '--description', 'qwerty', - identity_fakes.region_id, + self.region.id, ] verifylist = [ ('description', 'qwerty'), - ('region', identity_fakes.region_id), + ('region', self.region.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -270,8 +251,8 @@ class TestRegionSet(TestRegion): kwargs = { 'description': 'qwerty', } - self.regions_mock.update.assert_called_with( - identity_fakes.region_id, **kwargs + self.identity_sdk_client.update_region.assert_called_with( + self.region.id, **kwargs ) self.assertIsNone(result) @@ -279,11 +260,11 @@ class TestRegionSet(TestRegion): arglist = [ '--parent-region', 'new_parent', - identity_fakes.region_id, + self.region.id, ] verifylist = [ ('parent_region', 'new_parent'), - ('region', identity_fakes.region_id), + ('region', self.region.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -291,33 +272,30 @@ class TestRegionSet(TestRegion): # Set expected values kwargs = { - 'parent_region': 'new_parent', + 'parent_region_id': 'new_parent', } - self.regions_mock.update.assert_called_with( - identity_fakes.region_id, **kwargs + self.identity_sdk_client.update_region.assert_called_with( + self.region.id, **kwargs ) self.assertIsNone(result) -class TestRegionShow(TestRegion): +class TestRegionShow(identity_fakes.TestIdentityv3): def setUp(self): super().setUp() - self.regions_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.REGION), - loaded=True, - ) + self.region = sdk_fakes.generate_fake_resource(_region.Region) + self.identity_sdk_client.get_region.return_value = self.region # Get the command object to test self.cmd = region.ShowRegion(self.app, None) def test_region_show(self): arglist = [ - identity_fakes.region_id, + self.region.id, ] verifylist = [ - ('region', identity_fakes.region_id), + ('region', self.region.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -325,15 +303,15 @@ class TestRegionShow(TestRegion): # returns a two-part tuple with a tuple of column names and a tuple of # data to be shown. columns, data = self.cmd.take_action(parsed_args) - self.regions_mock.get.assert_called_with( - identity_fakes.region_id, + self.identity_sdk_client.get_region.assert_called_with( + self.region.id, ) - collist = ('description', 'parent_region', 'region') + collist = ('region', 'description', 'parent_region') self.assertEqual(collist, columns) datalist = ( - identity_fakes.region_description, - identity_fakes.region_parent_region_id, - identity_fakes.region_id, + self.region.id, + self.region.description, + self.region.parent_region_id, ) self.assertEqual(datalist, data) diff --git a/openstackclient/tests/unit/identity/v3/test_role.py b/openstackclient/tests/unit/identity/v3/test_role.py index 09b7536..e4a27ed 100644 --- a/openstackclient/tests/unit/identity/v3/test_role.py +++ b/openstackclient/tests/unit/identity/v3/test_role.py @@ -13,110 +13,177 @@ # under the License. # -import copy from unittest import mock from osc_lib import exceptions -from osc_lib import utils -from openstackclient.identity import common +from openstack import exceptions as sdk_exc +from openstack.identity.v3 import domain as _domain +from openstack.identity.v3 import group as _group +from openstack.identity.v3 import project as _project +from openstack.identity.v3 import role as _role +from openstack.identity.v3 import system as _system +from openstack.identity.v3 import user as _user +from openstack.test import fakes as sdk_fakes + from openstackclient.identity.v3 import role -from openstackclient.tests.unit import fakes from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes +from openstackclient.tests.unit import utils as test_utils + + +class TestRoleInherited(identity_fakes.TestIdentityv3): + def _is_inheritance_testcase(self): + return True -class TestRole(identity_fakes.TestIdentityv3): +class TestFindSDKId(test_utils.TestCase): def setUp(self): super().setUp() + self.user = sdk_fakes.generate_fake_resource(_user.User) + self.identity_sdk_client = mock.Mock() + self.identity_sdk_client.find_user = mock.Mock() - # Get a shortcut to the UserManager Mock - self.users_mock = self.identity_client.users - self.users_mock.reset_mock() + def test_find_sdk_id_validate(self): + self.identity_sdk_client.find_user.side_effect = [self.user] - # Get a shortcut to the UserManager Mock - self.groups_mock = self.identity_client.groups - self.groups_mock.reset_mock() + result = role._find_sdk_id( + self.identity_sdk_client.find_user, + name_or_id=self.user.id, + validate_actor_existence=True, + ) + self.assertEqual(self.user.id, result) - # Get a shortcut to the DomainManager Mock - self.domains_mock = self.identity_client.domains - self.domains_mock.reset_mock() + def test_find_sdk_id_no_validate(self): + self.identity_sdk_client.find_user.side_effect = [self.user] - # Get a shortcut to the ProjectManager Mock - self.projects_mock = self.identity_client.projects - self.projects_mock.reset_mock() + result = role._find_sdk_id( + self.identity_sdk_client.find_user, + name_or_id=self.user.id, + validate_actor_existence=False, + ) + self.assertEqual(self.user.id, result) - # Get a shortcut to the RoleManager Mock - self.roles_mock = self.identity_client.roles - self.roles_mock.reset_mock() + def test_find_sdk_id_not_found_validate(self): + self.identity_sdk_client.find_user.side_effect = [ + sdk_exc.ResourceNotFound, + ] - def _is_inheritance_testcase(self): - return False + self.assertRaises( + exceptions.CommandError, + role._find_sdk_id, + self.identity_sdk_client.find_user, + name_or_id=self.user.id, + validate_actor_existence=True, + ) + + def test_find_sdk_id_not_found_no_validate(self): + self.identity_sdk_client.find_user.side_effect = [ + sdk_exc.ResourceNotFound, + ] + + result = role._find_sdk_id( + self.identity_sdk_client.find_user, + name_or_id=self.user.id, + validate_actor_existence=False, + ) + self.assertEqual(self.user.id, result) + + def test_find_sdk_id_forbidden_validate(self): + self.identity_sdk_client.find_user.side_effect = [ + sdk_exc.ForbiddenException, + ] + + result = role._find_sdk_id( + self.identity_sdk_client.find_user, + name_or_id=self.user.id, + validate_actor_existence=True, + ) + + self.assertEqual(self.user.id, result) + + def test_find_sdk_id_forbidden_no_validate(self): + self.identity_sdk_client.find_user.side_effect = [ + sdk_exc.ForbiddenException, + ] + + result = role._find_sdk_id( + self.identity_sdk_client.find_user, + name_or_id=self.user.id, + validate_actor_existence=False, + ) + + self.assertEqual(self.user.id, result) -class TestRoleInherited(TestRole): +class TestRoleAdd(identity_fakes.TestIdentityv3): def _is_inheritance_testcase(self): - return True + return False + user = sdk_fakes.generate_fake_resource(_user.User) + group = sdk_fakes.generate_fake_resource(_group.Group) + domain = sdk_fakes.generate_fake_resource(_domain.Domain) + project = sdk_fakes.generate_fake_resource(_project.Project) -class TestRoleAdd(TestRole): def setUp(self): super().setUp() - self.users_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.USER), - loaded=True, - ) + self.identity_sdk_client.find_user.return_value = self.user + self.identity_sdk_client.find_group.return_value = self.group + self.identity_sdk_client.find_domain.return_value = self.domain + self.identity_sdk_client.find_project.return_value = self.project - self.groups_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.GROUP), - loaded=True, + self.role = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=None, + description=None, ) - - self.domains_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.DOMAIN), - loaded=True, + self.identity_sdk_client.find_role.return_value = self.role + self.role_with_domain = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=self.domain.id, + description=None, ) - self.projects_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.PROJECT), - loaded=True, + self.identity_sdk_client.assign_domain_role_to_user.return_value = ( + self.role ) - - self.roles_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE), - loaded=True, + self.identity_sdk_client.assign_domain_role_to_group.return_value = ( + self.role ) - self.roles_mock.grant.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE), - loaded=True, + self.identity_sdk_client.assign_project_role_to_user.return_value = ( + self.role + ) + self.identity_sdk_client.assign_project_role_to_group.return_value = ( + self.role + ) + self.identity_sdk_client.assign_system_role_to_user.return_value = ( + self.role + ) + self.identity_sdk_client.assign_system_role_to_group.return_value = ( + self.role ) # Get the command object to test self.cmd = role.AddRole(self.app, None) - def test_role_add_user_system(self): + @mock.patch.object(role.LOG, 'warning') + def test_role_add_user_system(self, mock_warning): arglist = [ '--user', - identity_fakes.user_name, + self.user.name, '--system', 'all', - identity_fakes.role_name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ - ('user', identity_fakes.user_name), + ('user', self.user.name), ('group', None), ('system', 'all'), ('domain', None), ('project', None), - ('role', identity_fakes.role_name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -125,32 +192,36 @@ class TestRoleAdd(TestRole): # Set expected values kwargs = { - 'user': identity_fakes.user_id, 'system': 'all', - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'user': self.user.id, + 'role': self.role.id, } - # RoleManager.grant(role, user=, group=, domain=, project=) - self.roles_mock.grant.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.assign_system_role_to_user.assert_called_with( + **kwargs ) self.assertIsNone(result) + if self._is_inheritance_testcase(): + mock_warning.assert_called_with( + "'--inherited' was given, which is not supported when adding a system role; this will be an error in a future release" + ) + def test_role_add_user_domain(self): arglist = [ '--user', - identity_fakes.user_name, + self.user.name, '--domain', - identity_fakes.domain_name, - identity_fakes.role_name, + self.domain.name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ - ('user', identity_fakes.user_name), + ('user', self.user.name), ('group', None), - ('domain', identity_fakes.domain_name), + ('domain', self.domain.name), ('project', None), - ('role', identity_fakes.role_name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -159,32 +230,32 @@ class TestRoleAdd(TestRole): # Set expected values kwargs = { - 'user': identity_fakes.user_id, - 'domain': identity_fakes.domain_id, - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'domain': self.domain.id, + 'user': self.user.id, + 'role': self.role.id, + 'inherited': self._is_inheritance_testcase(), } - # RoleManager.grant(role, user=, group=, domain=, project=) - self.roles_mock.grant.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.assign_domain_role_to_user.assert_called_with( + **kwargs ) self.assertIsNone(result) def test_role_add_user_project(self): arglist = [ '--user', - identity_fakes.user_name, + self.user.name, '--project', - identity_fakes.project_name, - identity_fakes.role_name, + self.project.name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ - ('user', identity_fakes.user_name), + ('user', self.user.name), ('group', None), ('domain', None), - ('project', identity_fakes.project_name), - ('role', identity_fakes.role_name), + ('project', self.project.name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -193,33 +264,34 @@ class TestRoleAdd(TestRole): # Set expected values kwargs = { - 'user': identity_fakes.user_id, - 'project': identity_fakes.project_id, - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'project': self.project.id, + 'user': self.user.id, + 'role': self.role.id, + 'inherited': self._is_inheritance_testcase(), } - # RoleManager.grant(role, user=, group=, domain=, project=) - self.roles_mock.grant.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.assign_project_role_to_user.assert_called_with( + **kwargs ) self.assertIsNone(result) - def test_role_add_group_system(self): + @mock.patch.object(role.LOG, 'warning') + def test_role_add_group_system(self, mock_warning): arglist = [ '--group', - identity_fakes.group_name, + self.group.name, '--system', 'all', - identity_fakes.role_name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ ('user', None), - ('group', identity_fakes.group_name), + ('group', self.group.name), ('system', 'all'), ('domain', None), ('project', None), - ('role', identity_fakes.role_name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -228,32 +300,36 @@ class TestRoleAdd(TestRole): # Set expected values kwargs = { - 'group': identity_fakes.group_id, 'system': 'all', - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'group': self.group.id, + 'role': self.role.id, } - # RoleManager.grant(role, user=, group=, domain=, project=) - self.roles_mock.grant.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.assign_system_role_to_group.assert_called_with( + **kwargs ) self.assertIsNone(result) + if self._is_inheritance_testcase(): + mock_warning.assert_called_with( + "'--inherited' was given, which is not supported when adding a system role; this will be an error in a future release" + ) + def test_role_add_group_domain(self): arglist = [ '--group', - identity_fakes.group_name, + self.group.name, '--domain', - identity_fakes.domain_name, - identity_fakes.role_name, + self.domain.name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ ('user', None), - ('group', identity_fakes.group_name), - ('domain', identity_fakes.domain_name), + ('group', self.group.name), + ('domain', self.domain.name), ('project', None), - ('role', identity_fakes.role_name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -262,32 +338,32 @@ class TestRoleAdd(TestRole): # Set expected values kwargs = { - 'group': identity_fakes.group_id, - 'domain': identity_fakes.domain_id, - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'domain': self.domain.id, + 'group': self.group.id, + 'role': self.role.id, + 'inherited': self._is_inheritance_testcase(), } - # RoleManager.grant(role, user=, group=, domain=, project=) - self.roles_mock.grant.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.assign_domain_role_to_group.assert_called_with( + **kwargs ) self.assertIsNone(result) def test_role_add_group_project(self): arglist = [ '--group', - identity_fakes.group_name, + self.group.name, '--project', - identity_fakes.project_name, - identity_fakes.role_name, + self.project.name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ ('user', None), - ('group', identity_fakes.group_name), + ('group', self.group.name), ('domain', None), - ('project', identity_fakes.project_name), - ('role', identity_fakes.role_name), + ('project', self.project.name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -296,39 +372,36 @@ class TestRoleAdd(TestRole): # Set expected values kwargs = { - 'group': identity_fakes.group_id, - 'project': identity_fakes.project_id, - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'project': self.project.id, + 'group': self.group.id, + 'role': self.role.id, + 'inherited': self._is_inheritance_testcase(), } - # RoleManager.grant(role, user=, group=, domain=, project=) - self.roles_mock.grant.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.assign_project_role_to_group.assert_called_with( + **kwargs ) self.assertIsNone(result) def test_role_add_domain_role_on_user_project(self): - self.roles_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE_2), - loaded=True, - ) + self.identity_sdk_client.find_role.return_value = self.role_with_domain + arglist = [ '--user', - identity_fakes.user_name, + self.user.name, '--project', - identity_fakes.project_name, + self.project.name, '--role-domain', - identity_fakes.domain_name, - identity_fakes.ROLE_2['name'], + self.domain.name, + self.role_with_domain.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ - ('user', identity_fakes.user_name), + ('user', self.user.name), ('group', None), ('domain', None), - ('project', identity_fakes.project_name), - ('role', identity_fakes.ROLE_2['name']), + ('project', self.project.name), + ('role', self.role_with_domain.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -337,26 +410,26 @@ class TestRoleAdd(TestRole): # Set expected values kwargs = { - 'user': identity_fakes.user_id, - 'project': identity_fakes.project_id, - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'project': self.project.id, + 'user': self.user.id, + 'role': self.role_with_domain.id, + 'inherited': self._is_inheritance_testcase(), } - # RoleManager.grant(role, user=, group=, domain=, project=) - self.roles_mock.grant.assert_called_with( - identity_fakes.ROLE_2['id'], **kwargs + self.identity_sdk_client.assign_project_role_to_user.assert_called_with( + **kwargs ) self.assertIsNone(result) def test_role_add_with_error(self): arglist = [ - identity_fakes.role_name, + self.role.name, ] verifylist = [ ('user', None), ('group', None), ('domain', None), ('project', None), - ('role', identity_fakes.role_name), + ('role', self.role.name), ('inherited', False), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -369,31 +442,47 @@ class TestRoleAddInherited(TestRoleAdd, TestRoleInherited): pass -class TestRoleCreate(TestRole): +class TestRoleCreate(identity_fakes.TestIdentityv3): + collist = ('id', 'name', 'domain_id', 'description') + domain = sdk_fakes.generate_fake_resource(_domain.Domain) + def setUp(self): super().setUp() - self.domains_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.DOMAIN), - loaded=True, + self.role = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=None, + description=None, ) - - self.roles_mock.create.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE), - loaded=True, + self.role_with_domain = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=self.domain.id, + description=None, + ) + self.role_with_description = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=None, + description='role description', ) + self.role_with_immutable_option = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=None, + description=None, + options={'immutable': True}, + ) + self.identity_sdk_client.find_domain.return_value = self.domain # Get the command object to test self.cmd = role.CreateRole(self.app, None) def test_role_create_no_options(self): + self.identity_sdk_client.create_role.return_value = self.role + arglist = [ - identity_fakes.role_name, + self.role.name, ] verifylist = [ - ('name', identity_fakes.role_name), + ('name', self.role.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -404,39 +493,34 @@ class TestRoleCreate(TestRole): # Set expected values kwargs = { - 'domain': None, - 'name': identity_fakes.role_name, - 'description': None, + 'name': self.role.name, 'options': {}, } - # RoleManager.create(name=, domain=) - self.roles_mock.create.assert_called_with(**kwargs) + self.identity_sdk_client.create_role.assert_called_with(**kwargs) - collist = ('domain', 'id', 'name') - self.assertEqual(collist, columns) + self.assertEqual(self.collist, columns) datalist = ( + self.role.id, + self.role.name, + None, None, - identity_fakes.role_id, - identity_fakes.role_name, ) self.assertEqual(datalist, data) def test_role_create_with_domain(self): - self.roles_mock.create.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE_2), - loaded=True, + self.identity_sdk_client.create_role.return_value = ( + self.role_with_domain ) arglist = [ '--domain', - identity_fakes.domain_name, - identity_fakes.ROLE_2['name'], + self.domain.name, + self.role_with_domain.name, ] verifylist = [ - ('domain', identity_fakes.domain_name), - ('name', identity_fakes.ROLE_2['name']), + ('domain', self.domain.name), + ('name', self.role_with_domain.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -447,38 +531,35 @@ class TestRoleCreate(TestRole): # Set expected values kwargs = { - 'domain': identity_fakes.domain_id, - 'name': identity_fakes.ROLE_2['name'], - 'description': None, + 'domain_id': self.domain.id, + 'name': self.role_with_domain.name, 'options': {}, } - # RoleManager.create(name=, domain=) - self.roles_mock.create.assert_called_with(**kwargs) + self.identity_sdk_client.create_role.assert_called_with(**kwargs) - collist = ('domain', 'id', 'name') - self.assertEqual(collist, columns) + self.assertEqual(self.collist, columns) datalist = ( - identity_fakes.domain_id, - identity_fakes.ROLE_2['id'], - identity_fakes.ROLE_2['name'], + self.role_with_domain.id, + self.role_with_domain.name, + self.domain.id, + None, ) self.assertEqual(datalist, data) def test_role_create_with_description(self): - self.roles_mock.create.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE_2), - loaded=True, + self.identity_sdk_client.create_role.return_value = ( + self.role_with_description ) + arglist = [ '--description', - identity_fakes.role_description, - identity_fakes.ROLE_2['name'], + self.role_with_description.description, + self.role_with_description.name, ] verifylist = [ - ('description', identity_fakes.role_description), - ('name', identity_fakes.ROLE_2['name']), + ('description', self.role_with_description.description), + ('name', self.role_with_description.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -489,37 +570,32 @@ class TestRoleCreate(TestRole): # Set expected values kwargs = { - 'description': identity_fakes.role_description, - 'name': identity_fakes.ROLE_2['name'], - 'domain': None, + 'name': self.role_with_description.name, + 'description': self.role_with_description.description, 'options': {}, } - # RoleManager.create(name=, domain=) - self.roles_mock.create.assert_called_with(**kwargs) + self.identity_sdk_client.create_role.assert_called_with(**kwargs) - collist = ('domain', 'id', 'name') - self.assertEqual(collist, columns) + self.assertEqual(self.collist, columns) datalist = ( - 'd1', - identity_fakes.ROLE_2['id'], - identity_fakes.ROLE_2['name'], + self.role_with_description.id, + self.role_with_description.name, + None, + self.role_with_description.description, ) self.assertEqual(datalist, data) def test_role_create_with_immutable_option(self): - self.roles_mock.create.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE_2), - loaded=True, - ) + self.identity_sdk_client.create_role.return_value = self.role + arglist = [ '--immutable', - identity_fakes.ROLE_2['name'], + self.role.name, ] verifylist = [ ('immutable', True), - ('name', identity_fakes.ROLE_2['name']), + ('name', self.role.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -531,36 +607,30 @@ class TestRoleCreate(TestRole): # Set expected values kwargs = { 'options': {'immutable': True}, - 'description': None, - 'name': identity_fakes.ROLE_2['name'], - 'domain': None, + 'name': self.role.name, } - # RoleManager.create(name=, domain=) - self.roles_mock.create.assert_called_with(**kwargs) + self.identity_sdk_client.create_role.assert_called_with(**kwargs) - collist = ('domain', 'id', 'name') - self.assertEqual(collist, columns) + self.assertEqual(self.collist, columns) datalist = ( - 'd1', - identity_fakes.ROLE_2['id'], - identity_fakes.ROLE_2['name'], + self.role.id, + self.role.name, + None, + None, ) self.assertEqual(datalist, data) def test_role_create_with_no_immutable_option(self): - self.roles_mock.create.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE_2), - loaded=True, - ) + self.identity_sdk_client.create_role.return_value = self.role + arglist = [ '--no-immutable', - identity_fakes.ROLE_2['name'], + self.role.name, ] verifylist = [ ('no_immutable', True), - ('name', identity_fakes.ROLE_2['name']), + ('name', self.role.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -572,88 +642,94 @@ class TestRoleCreate(TestRole): # Set expected values kwargs = { 'options': {'immutable': False}, - 'description': None, - 'name': identity_fakes.ROLE_2['name'], - 'domain': None, + 'name': self.role.name, } - # RoleManager.create(name=, domain=) - self.roles_mock.create.assert_called_with(**kwargs) + self.identity_sdk_client.create_role.assert_called_with(**kwargs) - collist = ('domain', 'id', 'name') - self.assertEqual(collist, columns) + self.assertEqual(self.collist, columns) datalist = ( - 'd1', - identity_fakes.ROLE_2['id'], - identity_fakes.ROLE_2['name'], + self.role.id, + self.role.name, + None, + None, ) self.assertEqual(datalist, data) -class TestRoleDelete(TestRole): +class TestRoleDelete(identity_fakes.TestIdentityv3): def setUp(self): super().setUp() - self.roles_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE), - loaded=True, - ) - self.roles_mock.delete.return_value = None - # Get the command object to test self.cmd = role.DeleteRole(self.app, None) def test_role_delete_no_options(self): + self.role = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=None, + description=None, + ) + self.identity_sdk_client.find_role.return_value = self.role + self.identity_sdk_client.delete_role.return_value = None + arglist = [ - identity_fakes.role_name, + self.role.name, ] verifylist = [ - ('roles', [identity_fakes.role_name]), + ('roles', [self.role.name]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) result = self.cmd.take_action(parsed_args) - self.roles_mock.delete.assert_called_with( - identity_fakes.role_id, + self.identity_sdk_client.delete_role.assert_called_with( + role=self.role.id, + ignore_missing=False, ) self.assertIsNone(result) def test_role_delete_with_domain(self): - self.roles_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE_2), - loaded=True, + self.domain = sdk_fakes.generate_fake_resource(_domain.Domain) + self.role_with_domain = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=self.domain.id, + description=None, ) - self.roles_mock.delete.return_value = None + self.identity_sdk_client.find_role.return_value = self.role_with_domain + self.identity_sdk_client.delete_role.return_value = None arglist = [ '--domain', - identity_fakes.domain_name, - identity_fakes.ROLE_2['name'], + self.domain.name, + self.role_with_domain.name, ] verifylist = [ - ('roles', [identity_fakes.ROLE_2['name']]), - ('domain', identity_fakes.domain_name), + ('roles', [self.role_with_domain.name]), + ('domain', self.domain.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) result = self.cmd.take_action(parsed_args) - self.roles_mock.delete.assert_called_with( - identity_fakes.ROLE_2['id'], + self.identity_sdk_client.delete_role.assert_called_with( + role=self.role_with_domain.id, + ignore_missing=False, ) self.assertIsNone(result) - @mock.patch.object(utils, 'find_resource') - def test_delete_multi_roles_with_exception(self, find_mock): - find_mock.side_effect = [ - self.roles_mock.get.return_value, - exceptions.CommandError, + def test_delete_multi_roles_with_exception(self): + self.role = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=None, + description=None, + ) + self.identity_sdk_client.find_role.side_effect = [ + self.role, + sdk_exc.ResourceNotFound, ] arglist = [ - identity_fakes.role_name, + self.role.id, 'unexist_role', ] verifylist = [ @@ -667,44 +743,62 @@ class TestRoleDelete(TestRole): except exceptions.CommandError as e: self.assertEqual('1 of 2 roles failed to delete.', str(e)) - find_mock.assert_any_call( - self.roles_mock, identity_fakes.role_name, domain_id=None - ) - find_mock.assert_any_call( - self.roles_mock, 'unexist_role', domain_id=None + self.identity_sdk_client.find_role.assert_has_calls( + [ + mock.call( + name_or_id=self.role.id, + ignore_missing=False, + domain_id=None, + ), + mock.call( + name_or_id='unexist_role', + ignore_missing=False, + domain_id=None, + ), + ] ) - self.assertEqual(2, find_mock.call_count) - self.roles_mock.delete.assert_called_once_with(identity_fakes.role_id) + self.assertEqual(2, self.identity_sdk_client.find_role.call_count) + self.identity_sdk_client.delete_role.assert_called_once_with( + role=self.role.id, ignore_missing=False + ) -class TestRoleList(TestRole): +class TestRoleList(identity_fakes.TestIdentityv3): columns = ( 'ID', 'Name', ) - datalist = ( - ( - identity_fakes.role_id, - identity_fakes.role_name, - ), - ) + domain = sdk_fakes.generate_fake_resource(_domain.Domain) def setUp(self): super().setUp() - self.roles_mock.list.return_value = [ - fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE), - loaded=True, - ), + self.role = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=None, + description=None, + ) + self.role_with_domain = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=self.domain.id, + description=None, + ) + self.identity_sdk_client.roles.return_value = [ + self.role, + self.role_with_domain, ] + self.identity_sdk_client.find_domain.return_value = self.domain - self.domains_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.DOMAIN), - loaded=True, + self.datalist = ( + ( + self.role.id, + self.role.name, + ), + ( + self.role_with_domain.id, + self.role_with_domain.name, + ), ) # Get the command object to test @@ -720,25 +814,19 @@ class TestRoleList(TestRole): # containing the data to be listed. columns, data = self.cmd.take_action(parsed_args) - self.roles_mock.list.assert_called_with() + self.identity_sdk_client.roles.assert_called_with() self.assertEqual(self.columns, columns) self.assertEqual(self.datalist, tuple(data)) def test_role_list_domain_role(self): - self.roles_mock.list.return_value = [ - fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE_2), - loaded=True, - ), - ] + self.identity_sdk_client.roles.return_value = [self.role_with_domain] arglist = [ '--domain', - identity_fakes.domain_name, + self.domain.name, ] verifylist = [ - ('domain', identity_fakes.domain_name), + ('domain', self.domain.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -748,56 +836,51 @@ class TestRoleList(TestRole): columns, data = self.cmd.take_action(parsed_args) # Set expected values - kwargs = {'domain_id': identity_fakes.domain_id} - # RoleManager.list(user=, group=, domain=, project=, **kwargs) - self.roles_mock.list.assert_called_with(**kwargs) + kwargs = {'domain_id': self.domain.id} + self.identity_sdk_client.roles.assert_called_with(**kwargs) collist = ('ID', 'Name', 'Domain') self.assertEqual(collist, columns) datalist = ( ( - identity_fakes.ROLE_2['id'], - identity_fakes.ROLE_2['name'], - identity_fakes.domain_name, + self.role_with_domain.id, + self.role_with_domain.name, + self.domain.name, ), ) self.assertEqual(datalist, tuple(data)) -class TestRoleRemove(TestRole): - def setUp(self): - super().setUp() +class TestRoleRemove(identity_fakes.TestIdentityv3): + def _is_inheritance_testcase(self): + return False - self.users_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.USER), - loaded=True, - ) + user = sdk_fakes.generate_fake_resource(_user.User) + group = sdk_fakes.generate_fake_resource(_group.Group) + domain = sdk_fakes.generate_fake_resource(_domain.Domain) + project = sdk_fakes.generate_fake_resource(_project.Project) + system = sdk_fakes.generate_fake_resource(_system.System) - self.groups_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.GROUP), - loaded=True, - ) + def setUp(self): + super().setUp() - self.domains_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.DOMAIN), - loaded=True, + self.role = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=None, + description=None, ) + self.identity_sdk_client.find_role.return_value = self.role + self.identity_sdk_client.find_user.return_value = self.user + self.identity_sdk_client.find_group.return_value = self.group + self.identity_sdk_client.find_domain.return_value = self.domain + self.identity_sdk_client.find_project.return_value = self.project - self.projects_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.PROJECT), - loaded=True, - ) - - self.roles_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE), - loaded=True, - ) - self.roles_mock.revoke.return_value = None + self.identity_sdk_client.unassign_domain_role_from_user.return_value = None + self.identity_sdk_client.unassign_domain_role_from_group.return_value = None + self.identity_sdk_client.unassign_project_role_from_user.return_value = None + self.identity_sdk_client.unassign_project_role_from_group.return_value = None + self.identity_sdk_client.unassign_system_role_from_user.return_value = None + self.identity_sdk_client.unassign_system_role_from_group.return_value = None # Get the command object to test self.cmd = role.RemoveRole(self.app, None) @@ -805,20 +888,20 @@ class TestRoleRemove(TestRole): def test_role_remove_user_system(self): arglist = [ '--user', - identity_fakes.user_name, + self.user.name, '--system', 'all', - identity_fakes.role_name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ - ('user', identity_fakes.user_name), + ('user', self.user.name), ('group', None), ('system', 'all'), ('domain', None), ('project', None), - ('role', identity_fakes.role_name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -827,40 +910,39 @@ class TestRoleRemove(TestRole): # Set expected values kwargs = { - 'user': identity_fakes.user_id, + 'user': self.user.id, 'system': 'all', - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'role': self.role.id, } - # RoleManager.revoke(role, user=, group=, domain=, project=) - self.roles_mock.revoke.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.unassign_system_role_from_user.assert_called_with( + **kwargs ) self.assertIsNone(result) - @mock.patch.object(common, 'find_user') - def test_role_remove_non_existent_user_system(self, find_mock): - # Simulate the user not being in keystone, the client should gracefully + def test_role_remove_non_existent_user_system(self): + # Simulate the user not being in keystone; the client should gracefully # handle this exception and send the request to remove the role since # keystone supports removing role assignments with non-existent actors # (e.g., users or groups). - find_mock.side_effect = exceptions.CommandError - + self.identity_sdk_client.find_user.side_effect = [ + sdk_exc.ResourceNotFound, + ] arglist = [ '--user', - identity_fakes.user_id, + self.user.id, '--system', 'all', - identity_fakes.role_name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ - ('user', identity_fakes.user_id), + ('user', self.user.id), ('group', None), ('system', 'all'), ('domain', None), ('project', None), - ('role', identity_fakes.role_name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -869,32 +951,31 @@ class TestRoleRemove(TestRole): # Set expected values kwargs = { - 'user': identity_fakes.user_id, + 'user': self.user.id, 'system': 'all', - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'role': self.role.id, } - # RoleManager.revoke(role, user=, group=, domain=, project=) - self.roles_mock.revoke.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.unassign_system_role_from_user.assert_called_with( + **kwargs ) self.assertIsNone(result) def test_role_remove_user_domain(self): arglist = [ '--user', - identity_fakes.user_name, + self.user.name, '--domain', - identity_fakes.domain_name, - identity_fakes.role_name, + self.domain.name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ - ('user', identity_fakes.user_name), + ('user', self.user.name), ('group', None), - ('domain', identity_fakes.domain_name), + ('domain', self.domain.name), ('project', None), - ('role', identity_fakes.role_name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -903,39 +984,39 @@ class TestRoleRemove(TestRole): # Set expected values kwargs = { - 'user': identity_fakes.user_id, - 'domain': identity_fakes.domain_id, - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'user': self.user.id, + 'domain': self.domain.id, + 'role': self.role.id, + 'inherited': self._is_inheritance_testcase(), } - # RoleManager.revoke(role, user=, group=, domain=, project=) - self.roles_mock.revoke.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.unassign_domain_role_from_user.assert_called_with( + **kwargs ) self.assertIsNone(result) - @mock.patch.object(common, 'find_user') - def test_role_remove_non_existent_user_domain(self, find_mock): + def test_role_remove_non_existent_user_domain(self): # Simulate the user not being in keystone, the client the gracefully # handle this exception and send the request to remove the role since # keystone will validate. - find_mock.side_effect = exceptions.CommandError - + self.identity_sdk_client.find_user.side_effect = [ + sdk_exc.ResourceNotFound, + ] arglist = [ '--user', - identity_fakes.user_id, + self.user.id, '--domain', - identity_fakes.domain_name, - identity_fakes.role_name, + self.domain.name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ - ('user', identity_fakes.user_id), + ('user', self.user.id), ('group', None), ('system', None), - ('domain', identity_fakes.domain_name), + ('domain', self.domain.name), ('project', None), - ('role', identity_fakes.role_name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -944,32 +1025,32 @@ class TestRoleRemove(TestRole): # Set expected values kwargs = { - 'user': identity_fakes.user_id, - 'domain': identity_fakes.domain_id, - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'user': self.user.id, + 'domain': self.domain.id, + 'role': self.role.id, + 'inherited': self._is_inheritance_testcase(), } - # RoleManager.revoke(role, user=, group=, domain=, project=) - self.roles_mock.revoke.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.unassign_domain_role_from_user.assert_called_with( + **kwargs ) self.assertIsNone(result) def test_role_remove_user_project(self): arglist = [ '--user', - identity_fakes.user_name, + self.user.name, '--project', - identity_fakes.project_name, - identity_fakes.role_name, + self.project.name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ - ('user', identity_fakes.user_name), + ('user', self.user.name), ('group', None), ('domain', None), - ('project', identity_fakes.project_name), - ('role', identity_fakes.role_name), + ('project', self.project.name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -978,39 +1059,40 @@ class TestRoleRemove(TestRole): # Set expected values kwargs = { - 'user': identity_fakes.user_id, - 'project': identity_fakes.project_id, - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'user': self.user.id, + 'project': self.project.id, + 'role': self.role.id, + 'inherited': self._is_inheritance_testcase(), } - # RoleManager.revoke(role, user=, group=, domain=, project=) - self.roles_mock.revoke.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.unassign_project_role_from_user.assert_called_with( + **kwargs ) self.assertIsNone(result) - @mock.patch.object(common, 'find_user') - def test_role_remove_non_existent_user_project(self, find_mock): + def test_role_remove_non_existent_user_project(self): # Simulate the user not being in keystone, the client the gracefully # handle this exception and send the request to remove the role since # keystone will validate. - find_mock.side_effect = exceptions.CommandError + self.identity_sdk_client.find_user.side_effect = [ + sdk_exc.ResourceNotFound, + ] arglist = [ '--user', - identity_fakes.user_id, + self.user.id, '--project', - identity_fakes.project_name, - identity_fakes.role_name, + self.project.name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ - ('user', identity_fakes.user_id), + ('user', self.user.id), ('group', None), ('system', None), ('domain', None), - ('project', identity_fakes.project_name), - ('role', identity_fakes.role_name), + ('project', self.project.name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1019,34 +1101,34 @@ class TestRoleRemove(TestRole): # Set expected values kwargs = { - 'user': identity_fakes.user_id, - 'project': identity_fakes.project_id, - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'user': self.user.id, + 'project': self.project.id, + 'role': self.role.id, + 'inherited': self._is_inheritance_testcase(), } - # RoleManager.revoke(role, user=, group=, domain=, project=) - self.roles_mock.revoke.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.unassign_project_role_from_user.assert_called_with( + **kwargs ) self.assertIsNone(result) def test_role_remove_group_system(self): arglist = [ '--group', - identity_fakes.group_name, + self.group.name, '--system', 'all', - identity_fakes.role_name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ ('user', None), - ('group', identity_fakes.group_name), + ('group', self.group.name), ('system', 'all'), ('domain', None), ('project', None), - ('role', identity_fakes.role_name), - ('role', identity_fakes.role_name), + ('role', self.role.name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1055,39 +1137,39 @@ class TestRoleRemove(TestRole): # Set expected values kwargs = { - 'group': identity_fakes.group_id, + 'group': self.group.id, 'system': 'all', - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'role': self.role.id, } - # RoleManager.revoke(role, user=, group=, domain=, project=) - self.roles_mock.revoke.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.unassign_system_role_from_group.assert_called_with( + **kwargs ) self.assertIsNone(result) - @mock.patch.object(common, 'find_group') - def test_role_remove_non_existent_group_system(self, find_mock): + def test_role_remove_non_existent_group_system(self): # Simulate the user not being in keystone, the client the gracefully # handle this exception and send the request to remove the role since # keystone will validate. - find_mock.side_effect = exceptions.CommandError + self.identity_sdk_client.find_group.side_effect = [ + sdk_exc.ResourceNotFound, + ] arglist = [ '--group', - identity_fakes.group_id, + self.group.id, '--system', 'all', - identity_fakes.role_name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ ('user', None), - ('group', identity_fakes.group_id), + ('group', self.group.id), ('system', 'all'), ('domain', None), ('project', None), - ('role', identity_fakes.role_name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1096,33 +1178,32 @@ class TestRoleRemove(TestRole): # Set expected values kwargs = { - 'group': identity_fakes.group_id, + 'group': self.group.id, 'system': 'all', - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'role': self.role.id, } - # RoleManager.revoke(role, user=, group=, domain=, project=) - self.roles_mock.revoke.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.unassign_system_role_from_group.assert_called_with( + **kwargs ) self.assertIsNone(result) def test_role_remove_group_domain(self): arglist = [ '--group', - identity_fakes.group_name, + self.group.name, '--domain', - identity_fakes.domain_name, - identity_fakes.role_name, + self.domain.name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ ('user', None), - ('group', identity_fakes.group_name), - ('domain', identity_fakes.domain_name), + ('group', self.group.name), + ('domain', self.domain.name), ('project', None), - ('role', identity_fakes.role_name), - ('role', identity_fakes.role_name), + ('role', self.role.name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1131,39 +1212,40 @@ class TestRoleRemove(TestRole): # Set expected values kwargs = { - 'group': identity_fakes.group_id, - 'domain': identity_fakes.domain_id, - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'group': self.group.id, + 'domain': self.domain.id, + 'role': self.role.id, + 'inherited': self._is_inheritance_testcase(), } - # RoleManager.revoke(role, user=, group=, domain=, project=) - self.roles_mock.revoke.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.unassign_domain_role_from_group.assert_called_with( + **kwargs ) self.assertIsNone(result) - @mock.patch.object(common, 'find_group') - def test_role_remove_non_existent_group_domain(self, find_mock): + def test_role_remove_non_existent_group_domain(self): # Simulate the user not being in keystone, the client the gracefully # handle this exception and send the request to remove the role since # keystone will validate. - find_mock.side_effect = exceptions.CommandError + self.identity_sdk_client.find_group.side_effect = [ + sdk_exc.ResourceNotFound, + ] arglist = [ '--group', - identity_fakes.group_id, + self.group.id, '--domain', - identity_fakes.domain_name, - identity_fakes.role_name, + self.domain.name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ ('user', None), - ('group', identity_fakes.group_id), + ('group', self.group.id), ('system', None), - ('domain', identity_fakes.domain_name), + ('domain', self.domain.name), ('project', None), - ('role', identity_fakes.role_name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1172,32 +1254,32 @@ class TestRoleRemove(TestRole): # Set expected values kwargs = { - 'group': identity_fakes.group_id, - 'domain': identity_fakes.domain_id, - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'group': self.group.id, + 'domain': self.domain.id, + 'role': self.role.id, + 'inherited': self._is_inheritance_testcase(), } - # RoleManager.revoke(role, user=, group=, domain=, project=) - self.roles_mock.revoke.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.unassign_domain_role_from_group.assert_called_with( + **kwargs ) self.assertIsNone(result) def test_role_remove_group_project(self): arglist = [ '--group', - identity_fakes.group_name, + self.group.name, '--project', - identity_fakes.project_name, - identity_fakes.role_name, + self.project.name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ ('user', None), - ('group', identity_fakes.group_name), + ('group', self.group.name), ('domain', None), - ('project', identity_fakes.project_name), - ('role', identity_fakes.role_name), + ('project', self.project.name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1206,39 +1288,39 @@ class TestRoleRemove(TestRole): # Set expected values kwargs = { - 'group': identity_fakes.group_id, - 'project': identity_fakes.project_id, - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'group': self.group.id, + 'project': self.project.id, + 'role': self.role.id, + 'inherited': self._is_inheritance_testcase(), } - # RoleManager.revoke(role, user=, group=, domain=, project=) - self.roles_mock.revoke.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.unassign_project_role_from_group.assert_called_with( + **kwargs ) self.assertIsNone(result) - @mock.patch.object(common, 'find_group') - def test_role_remove_non_existent_group_project(self, find_mock): + def test_role_remove_non_existent_group_project(self): # Simulate the user not being in keystone, the client the gracefully # handle this exception and send the request to remove the role since # keystone will validate. - find_mock.side_effect = exceptions.CommandError - + self.identity_sdk_client.find_group.side_effect = [ + sdk_exc.ResourceNotFound, + ] arglist = [ '--group', - identity_fakes.group_id, + self.group.id, '--project', - identity_fakes.project_name, - identity_fakes.role_name, + self.project.name, + self.role.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ ('user', None), - ('group', identity_fakes.group_id), + ('group', self.group.id), ('system', None), ('domain', None), - ('project', identity_fakes.project_name), - ('role', identity_fakes.role_name), + ('project', self.project.name), + ('role', self.role.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1247,37 +1329,38 @@ class TestRoleRemove(TestRole): # Set expected values kwargs = { - 'group': identity_fakes.group_id, - 'project': identity_fakes.project_id, - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'group': self.group.id, + 'project': self.project.id, + 'role': self.role.id, + 'inherited': self._is_inheritance_testcase(), } - # RoleManager.revoke(role, user=, group=, domain=, project=) - self.roles_mock.revoke.assert_called_with( - identity_fakes.role_id, **kwargs + self.identity_sdk_client.unassign_project_role_from_group.assert_called_with( + **kwargs ) self.assertIsNone(result) def test_role_remove_domain_role_on_group_domain(self): - self.roles_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE_2), - loaded=True, + self.role_with_domain = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=self.domain.id, + description=None, ) + self.identity_sdk_client.find_role.return_value = self.role_with_domain arglist = [ '--group', - identity_fakes.group_name, + self.group.name, '--domain', - identity_fakes.domain_name, - identity_fakes.ROLE_2['name'], + self.domain.name, + self.role_with_domain.name, ] if self._is_inheritance_testcase(): arglist.append('--inherited') verifylist = [ ('user', None), - ('group', identity_fakes.group_name), - ('domain', identity_fakes.domain_name), + ('group', self.group.name), + ('domain', self.domain.name), ('project', None), - ('role', identity_fakes.ROLE_2['name']), + ('role', self.role_with_domain.name), ('inherited', self._is_inheritance_testcase()), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1286,26 +1369,26 @@ class TestRoleRemove(TestRole): # Set expected values kwargs = { - 'group': identity_fakes.group_id, - 'domain': identity_fakes.domain_id, - 'os_inherit_extension_inherited': self._is_inheritance_testcase(), + 'group': self.group.id, + 'domain': self.domain.id, + 'role': self.role_with_domain.id, + 'inherited': self._is_inheritance_testcase(), } - # RoleManager.revoke(role, user=, group=, domain=, project=) - self.roles_mock.revoke.assert_called_with( - identity_fakes.ROLE_2['id'], **kwargs + self.identity_sdk_client.unassign_domain_role_from_group.assert_called_with( + **kwargs ) self.assertIsNone(result) def test_role_remove_with_error(self): arglist = [ - identity_fakes.role_name, + self.role.name, ] verifylist = [ ('user', None), ('group', None), ('domain', None), ('project', None), - ('role', identity_fakes.role_name), + ('role', self.role.name), ('inherited', False), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1314,29 +1397,37 @@ class TestRoleRemove(TestRole): ) -class TestRoleSet(TestRole): +class TestRoleSet(identity_fakes.TestIdentityv3): def setUp(self): super().setUp() - self.roles_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE), - loaded=True, + self.domain = sdk_fakes.generate_fake_resource(_domain.Domain) + self.role_with_domain = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=self.domain.id, + description=None, ) - self.roles_mock.update.return_value = None # Get the command object to test self.cmd = role.SetRole(self.app, None) def test_role_set_no_options(self): + self.role = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=None, + description=None, + ) + self.identity_sdk_client.find_role.return_value = self.role + self.identity_sdk_client.update_role.return_value = self.role + arglist = [ '--name', 'over', - identity_fakes.role_name, + self.role.name, ] verifylist = [ ('name', 'over'), - ('role', identity_fakes.role_name), + ('role', self.role.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1345,32 +1436,32 @@ class TestRoleSet(TestRole): # Set expected values kwargs = { 'name': 'over', - 'description': None, + 'role': self.role.id, 'options': {}, } - # RoleManager.update(role, name=) - self.roles_mock.update.assert_called_with( - identity_fakes.role_id, **kwargs - ) + self.identity_sdk_client.update_role.assert_called_with(**kwargs) self.assertIsNone(result) def test_role_set_domain_role(self): - self.roles_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE_2), - loaded=True, + self.domain2 = sdk_fakes.generate_fake_resource(_domain.Domain) + self.identity_sdk_client.find_domain.return_value = self.domain2 + + self.identity_sdk_client.find_role.return_value = self.role_with_domain + self.identity_sdk_client.update_role.return_value = ( + self.role_with_domain ) + arglist = [ '--name', 'over', '--domain', - identity_fakes.domain_name, - identity_fakes.ROLE_2['name'], + self.domain2.name, + self.role_with_domain.name, ] verifylist = [ ('name', 'over'), - ('domain', identity_fakes.domain_name), - ('role', identity_fakes.ROLE_2['name']), + ('domain', self.domain2.name), + ('role', self.role_with_domain.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1379,32 +1470,27 @@ class TestRoleSet(TestRole): # Set expected values kwargs = { 'name': 'over', - 'description': None, + 'role': self.role_with_domain.id, + 'domain_id': self.domain2.id, 'options': {}, } - # RoleManager.update(role, name=) - self.roles_mock.update.assert_called_with( - identity_fakes.ROLE_2['id'], **kwargs - ) + self.identity_sdk_client.update_role.assert_called_with(**kwargs) self.assertIsNone(result) def test_role_set_description(self): - self.roles_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE_2), - loaded=True, - ) + self.identity_sdk_client.find_role.return_value = self.role_with_domain + arglist = [ '--name', 'over', '--description', - identity_fakes.role_description, - identity_fakes.ROLE_2['name'], + 'role description', + self.role_with_domain.name, ] verifylist = [ ('name', 'over'), - ('description', identity_fakes.role_description), - ('role', identity_fakes.ROLE_2['name']), + ('description', 'role description'), + ('role', self.role_with_domain.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1413,31 +1499,26 @@ class TestRoleSet(TestRole): # Set expected values kwargs = { 'name': 'over', - 'description': identity_fakes.role_description, + 'description': 'role description', + 'role': self.role_with_domain.id, 'options': {}, } - # RoleManager.update(role, name=) - self.roles_mock.update.assert_called_with( - identity_fakes.ROLE_2['id'], **kwargs - ) + self.identity_sdk_client.update_role.assert_called_with(**kwargs) self.assertIsNone(result) def test_role_set_with_immutable(self): - self.roles_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE_2), - loaded=True, - ) + self.identity_sdk_client.find_role.return_value = self.role_with_domain + arglist = [ '--name', 'over', '--immutable', - identity_fakes.ROLE_2['name'], + self.role_with_domain.name, ] verifylist = [ ('name', 'over'), ('immutable', True), - ('role', identity_fakes.ROLE_2['name']), + ('role', self.role_with_domain.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1446,31 +1527,25 @@ class TestRoleSet(TestRole): # Set expected values kwargs = { 'name': 'over', - 'description': None, + 'role': self.role_with_domain.id, 'options': {'immutable': True}, } - # RoleManager.update(role, name=) - self.roles_mock.update.assert_called_with( - identity_fakes.ROLE_2['id'], **kwargs - ) + self.identity_sdk_client.update_role.assert_called_with(**kwargs) self.assertIsNone(result) def test_role_set_with_no_immutable(self): - self.roles_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE_2), - loaded=True, - ) + self.identity_sdk_client.find_role.return_value = self.role_with_domain + arglist = [ '--name', 'over', '--no-immutable', - identity_fakes.ROLE_2['name'], + self.role_with_domain.name, ] verifylist = [ ('name', 'over'), ('no_immutable', True), - ('role', identity_fakes.ROLE_2['name']), + ('role', self.role_with_domain.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1479,35 +1554,37 @@ class TestRoleSet(TestRole): # Set expected values kwargs = { 'name': 'over', - 'description': None, + 'role': self.role_with_domain.id, 'options': {'immutable': False}, } - # RoleManager.update(role, name=) - self.roles_mock.update.assert_called_with( - identity_fakes.ROLE_2['id'], **kwargs - ) + self.identity_sdk_client.update_role.assert_called_with(**kwargs) self.assertIsNone(result) -class TestRoleShow(TestRole): +class TestRoleShow(identity_fakes.TestIdentityv3): + domain = sdk_fakes.generate_fake_resource(_domain.Domain) + def setUp(self): super().setUp() - self.roles_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE), - loaded=True, - ) + self.identity_sdk_client.find_domain.return_value = self.domain # Get the command object to test self.cmd = role.ShowRole(self.app, None) def test_role_show(self): + self.role = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=None, + description=None, + ) + self.identity_sdk_client.find_role.return_value = self.role + arglist = [ - identity_fakes.role_name, + self.role.name, ] verifylist = [ - ('role', identity_fakes.role_name), + ('role', self.role.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1516,34 +1593,38 @@ class TestRoleShow(TestRole): # data to be shown. columns, data = self.cmd.take_action(parsed_args) - # RoleManager.get(role) - self.roles_mock.get.assert_called_with( - identity_fakes.role_name, + self.identity_sdk_client.find_role.assert_called_with( + name_or_id=self.role.name, + domain_id=None, + ignore_missing=False, ) - collist = ('domain', 'id', 'name') + collist = ('id', 'name', 'domain_id', 'description') self.assertEqual(collist, columns) datalist = ( + self.role.id, + self.role.name, + None, None, - identity_fakes.role_id, - identity_fakes.role_name, ) self.assertEqual(datalist, data) def test_role_show_domain_role(self): - self.roles_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE_2), - loaded=True, + self.role_with_domain = sdk_fakes.generate_fake_resource( + resource_type=_role.Role, + domain_id=self.domain.id, + description=None, ) + self.identity_sdk_client.find_role.return_value = self.role_with_domain + arglist = [ '--domain', - identity_fakes.domain_name, - identity_fakes.ROLE_2['name'], + self.domain.name, + self.role_with_domain.id, ] verifylist = [ - ('domain', identity_fakes.domain_name), - ('role', identity_fakes.ROLE_2['name']), + ('domain', self.domain.name), + ('role', self.role_with_domain.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1552,23 +1633,18 @@ class TestRoleShow(TestRole): # data to be shown. columns, data = self.cmd.take_action(parsed_args) - # RoleManager.get(role). This is called from utils.find_resource(). - # In fact, the current implementation calls the get(role) first with - # just the name, then with the name+domain_id. So technically we should - # mock this out with a call list, with the first call returning None - # and the second returning the object. However, if we did that we are - # then just testing the current sequencing within the utils method, and - # would become brittle to changes within that method. Hence we just - # check for the first call which is always lookup by name. - self.roles_mock.get.assert_called_with( - identity_fakes.ROLE_2['name'], + self.identity_sdk_client.find_role.assert_called_with( + name_or_id=self.role_with_domain.id, + domain_id=self.domain.id, + ignore_missing=False, ) - collist = ('domain', 'id', 'name') + collist = ('id', 'name', 'domain_id', 'description') self.assertEqual(collist, columns) datalist = ( - identity_fakes.domain_id, - identity_fakes.ROLE_2['id'], - identity_fakes.ROLE_2['name'], + self.role_with_domain.id, + self.role_with_domain.name, + self.domain.id, + None, ) self.assertEqual(datalist, data) diff --git a/openstackclient/tests/unit/identity/v3/test_role_assignment.py b/openstackclient/tests/unit/identity/v3/test_role_assignment.py index ec7c7da..6fc6646 100644 --- a/openstackclient/tests/unit/identity/v3/test_role_assignment.py +++ b/openstackclient/tests/unit/identity/v3/test_role_assignment.py @@ -165,10 +165,13 @@ class TestRoleAssignmentList(identity_fakes.TestIdentityv3): arglist = ['--user', self.user.name] verifylist = [ ('user', self.user.name), + ('user_domain', None), ('group', None), + ('group_domain', None), ('system', None), ('domain', None), ('project', None), + ('project_domain', None), ('role', None), ('effective', None), ('inherited', False), @@ -181,6 +184,79 @@ class TestRoleAssignmentList(identity_fakes.TestIdentityv3): # containing the data to be listed. columns, data = self.cmd.take_action(parsed_args) + self.identity_sdk_client.find_user.assert_called_with( + name_or_id=self.user.name, ignore_missing=False, domain_id=None + ) + self.identity_sdk_client.role_assignments.assert_called_with( + role_id=None, + user_id=self.user.id, + group_id=None, + scope_project_id=None, + scope_domain_id=None, + scope_system=None, + effective=None, + include_names=None, + inherited_to=None, + ) + + self.assertEqual(self.columns, columns) + datalist = ( + ( + self.role.id, + self.user.id, + '', + '', + self.domain.id, + '', + False, + ), + ( + self.role.id, + self.user.id, + '', + self.project.id, + '', + '', + False, + ), + ) + self.assertEqual(datalist, tuple(data)) + + def test_role_assignment_list_user_with_domain(self): + self.identity_sdk_client.role_assignments.return_value = [ + self.assignment_with_domain_id_and_user_id, + self.assignment_with_project_id_and_user_id, + ] + + arglist = ['--user', self.user.name, '--user-domain', self.domain.name] + verifylist = [ + ('user', self.user.name), + ('user_domain', self.domain.name), + ('group', None), + ('group_domain', None), + ('system', None), + ('domain', None), + ('project', None), + ('role', None), + ('effective', None), + ('inherited', False), + ('names', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # In base command class Lister in cliff, abstract method take_action() + # returns a tuple containing the column names and an iterable + # containing the data to be listed. + columns, data = self.cmd.take_action(parsed_args) + + self.identity_sdk_client.find_domain.assert_called_with( + name_or_id=self.domain.name, ignore_missing=False + ) + self.identity_sdk_client.find_user.assert_called_with( + name_or_id=self.user.name, + ignore_missing=False, + domain_id=self.domain.id, + ) self.identity_sdk_client.role_assignments.assert_called_with( role_id=None, user_id=self.user.id, @@ -230,10 +306,13 @@ class TestRoleAssignmentList(identity_fakes.TestIdentityv3): arglist = ['--user', self.user.id] verifylist = [ ('user', self.user.id), + ('user_domain', None), ('group', None), + ('group_domain', None), ('system', None), ('domain', None), ('project', None), + ('project_domain', None), ('role', None), ('effective', None), ('inherited', False), @@ -290,10 +369,13 @@ class TestRoleAssignmentList(identity_fakes.TestIdentityv3): arglist = ['--group', self.group.name] verifylist = [ ('user', None), + ('user_domain', None), ('group', self.group.name), + ('group_domain', None), ('system', None), ('domain', None), ('project', None), + ('project_domain', None), ('role', None), ('effective', None), ('inherited', False), @@ -306,6 +388,85 @@ class TestRoleAssignmentList(identity_fakes.TestIdentityv3): # containing the data to be listed. columns, data = self.cmd.take_action(parsed_args) + self.identity_sdk_client.find_group.assert_called_with( + name_or_id=self.group.name, ignore_missing=False, domain_id=None + ) + self.identity_sdk_client.role_assignments.assert_called_with( + role_id=None, + user_id=None, + group_id=self.group.id, + scope_project_id=None, + scope_domain_id=None, + scope_system=None, + effective=None, + include_names=None, + inherited_to=None, + ) + + self.assertEqual(self.columns, columns) + datalist = ( + ( + self.role.id, + '', + self.group.id, + '', + self.domain.id, + '', + False, + ), + ( + self.role.id, + '', + self.group.id, + self.project.id, + '', + '', + False, + ), + ) + self.assertEqual(datalist, tuple(data)) + + def test_role_assignment_list_group_with_domain(self): + self.identity_sdk_client.role_assignments.return_value = [ + self.assignment_with_domain_id_and_group_id, + self.assignment_with_project_id_and_group_id, + ] + + arglist = [ + '--group', + self.group.name, + '--group-domain', + self.domain.name, + ] + verifylist = [ + ('user', None), + ('user_domain', None), + ('group', self.group.name), + ('group_domain', self.domain.name), + ('system', None), + ('domain', None), + ('project', None), + ('project_domain', None), + ('role', None), + ('effective', None), + ('inherited', False), + ('names', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # In base command class Lister in cliff, abstract method take_action() + # returns a tuple containing the column names and an iterable + # containing the data to be listed. + columns, data = self.cmd.take_action(parsed_args) + + self.identity_sdk_client.find_domain.assert_called_with( + name_or_id=self.domain.name, ignore_missing=False + ) + self.identity_sdk_client.find_group.assert_called_with( + name_or_id=self.group.name, + ignore_missing=False, + domain_id=self.domain.id, + ) self.identity_sdk_client.role_assignments.assert_called_with( role_id=None, user_id=None, @@ -350,10 +511,13 @@ class TestRoleAssignmentList(identity_fakes.TestIdentityv3): arglist = ['--domain', self.domain.name] verifylist = [ ('user', None), + ('user_domain', None), ('group', None), + ('group_domain', None), ('system', None), ('domain', self.domain.name), ('project', None), + ('project_domain', None), ('role', None), ('effective', None), ('inherited', False), @@ -410,10 +574,13 @@ class TestRoleAssignmentList(identity_fakes.TestIdentityv3): arglist = ['--project', self.project.name] verifylist = [ ('user', None), + ('user_domain', None), ('group', None), + ('group_domain', None), ('system', None), ('domain', None), ('project', self.project.name), + ('project_domain', None), ('role', None), ('effective', None), ('inherited', False), @@ -426,6 +593,85 @@ class TestRoleAssignmentList(identity_fakes.TestIdentityv3): # containing the data to be listed. columns, data = self.cmd.take_action(parsed_args) + self.identity_sdk_client.find_project.assert_called_with( + name_or_id=self.project.name, ignore_missing=False, domain_id=None + ) + self.identity_sdk_client.role_assignments.assert_called_with( + role_id=None, + user_id=None, + group_id=None, + scope_project_id=self.project.id, + scope_domain_id=None, + scope_system=None, + effective=None, + include_names=None, + inherited_to=None, + ) + + self.assertEqual(self.columns, columns) + datalist = ( + ( + self.role.id, + self.user.id, + '', + self.project.id, + '', + '', + False, + ), + ( + self.role.id, + '', + self.group.id, + self.project.id, + '', + '', + False, + ), + ) + self.assertEqual(datalist, tuple(data)) + + def test_role_assignment_list_project_with_domain(self): + self.identity_sdk_client.role_assignments.return_value = [ + self.assignment_with_project_id_and_user_id, + self.assignment_with_project_id_and_group_id, + ] + + arglist = [ + '--project', + self.project.name, + '--project-domain', + self.domain.name, + ] + verifylist = [ + ('user', None), + ('user_domain', None), + ('group', None), + ('group_domain', None), + ('system', None), + ('domain', None), + ('project', self.project.name), + ('project_domain', self.domain.name), + ('role', None), + ('effective', None), + ('inherited', False), + ('names', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # In base command class Lister in cliff, abstract method take_action() + # returns a tuple containing the column names and an iterable + # containing the data to be listed. + columns, data = self.cmd.take_action(parsed_args) + + self.identity_sdk_client.find_domain.assert_called_with( + name_or_id=self.domain.name, ignore_missing=False + ) + self.identity_sdk_client.find_project.assert_called_with( + name_or_id=self.project.name, + ignore_missing=False, + domain_id=self.domain.id, + ) self.identity_sdk_client.role_assignments.assert_called_with( role_id=None, user_id=None, @@ -462,7 +708,8 @@ class TestRoleAssignmentList(identity_fakes.TestIdentityv3): self.assertEqual(datalist, tuple(data)) def test_role_assignment_list_def_creds(self): - auth_ref = self.app.client_manager.auth_ref = mock.Mock() + self.app.client_manager.auth_ref = mock.Mock() + auth_ref = self.app.client_manager.auth_ref auth_ref.project_id.return_value = self.project.id auth_ref.user_id.return_value = self.user.id @@ -476,10 +723,13 @@ class TestRoleAssignmentList(identity_fakes.TestIdentityv3): ] verifylist = [ ('user', None), + ('user_domain', None), ('group', None), + ('group_domain', None), ('system', None), ('domain', None), ('project', None), + ('project_domain', None), ('role', None), ('effective', None), ('inherited', False), @@ -529,10 +779,13 @@ class TestRoleAssignmentList(identity_fakes.TestIdentityv3): arglist = ['--effective'] verifylist = [ ('user', None), + ('user_domain', None), ('group', None), + ('group_domain', None), ('system', None), ('domain', None), ('project', None), + ('project_domain', None), ('role', None), ('effective', True), ('inherited', False), @@ -611,10 +864,13 @@ class TestRoleAssignmentList(identity_fakes.TestIdentityv3): arglist = ['--inherited'] verifylist = [ ('user', None), + ('user_domain', None), ('group', None), + ('group_domain', None), ('system', None), ('domain', None), ('project', None), + ('project_domain', None), ('role', None), ('effective', None), ('inherited', True), @@ -707,10 +963,13 @@ class TestRoleAssignmentList(identity_fakes.TestIdentityv3): arglist = ['--names'] verifylist = [ ('user', None), + ('user_domain', None), ('group', None), + ('group_domain', None), ('system', None), ('domain', None), ('project', None), + ('project_domain', None), ('role', None), ('effective', None), ('inherited', False), @@ -799,10 +1058,13 @@ class TestRoleAssignmentList(identity_fakes.TestIdentityv3): ] verifylist = [ ('user', None), + ('user_domain', None), ('group', None), + ('group_domain', None), ('system', None), ('domain', None), ('project', None), + ('project_domain', None), ('role', role_2.name), ('effective', None), ('inherited', False), diff --git a/openstackclient/tests/unit/identity/v3/test_service_provider.py b/openstackclient/tests/unit/identity/v3/test_service_provider.py index 23402d9..185cdc6 100644 --- a/openstackclient/tests/unit/identity/v3/test_service_provider.py +++ b/openstackclient/tests/unit/identity/v3/test_service_provider.py @@ -12,92 +12,88 @@ # License for the specific language governing permissions and limitations # under the License. -import copy + +from openstack.identity.v3 import service_provider as _service_provider +from openstack.test import fakes as sdk_fakes from openstackclient.identity.v3 import service_provider -from openstackclient.tests.unit import fakes from openstackclient.tests.unit.identity.v3 import fakes as service_fakes -class TestServiceProvider(service_fakes.TestFederatedIdentity): - def setUp(self): - super().setUp() - - federation_lib = self.identity_client.federation - self.service_providers_mock = federation_lib.service_providers - self.service_providers_mock.reset_mock() - - -class TestServiceProviderCreate(TestServiceProvider): +class TestServiceProviderCreate(service_fakes.TestFederatedIdentity): columns = ( - 'auth_url', - 'description', - 'enabled', 'id', + 'enabled', + 'description', + 'auth_url', 'sp_url', - ) - datalist = ( - service_fakes.sp_auth_url, - service_fakes.sp_description, - True, - service_fakes.sp_id, - service_fakes.service_provider_url, + 'relay_state_prefix', ) def setUp(self): super().setUp() - copied_sp = copy.deepcopy(service_fakes.SERVICE_PROVIDER) - resource = fakes.FakeResource(None, copied_sp, loaded=True) - self.service_providers_mock.create.return_value = resource + self.service_provider = sdk_fakes.generate_fake_resource( + _service_provider.ServiceProvider + ) + self.identity_sdk_client.create_service_provider.return_value = ( + self.service_provider + ) + self.data = ( + self.service_provider.id, + self.service_provider.is_enabled, + self.service_provider.description, + self.service_provider.auth_url, + self.service_provider.sp_url, + self.service_provider.relay_state_prefix, + ) self.cmd = service_provider.CreateServiceProvider(self.app, None) def test_create_service_provider_required_options_only(self): arglist = [ '--auth-url', - service_fakes.sp_auth_url, + self.service_provider.auth_url, '--service-provider-url', - service_fakes.service_provider_url, - service_fakes.sp_id, + self.service_provider.sp_url, + self.service_provider.id, ] verifylist = [ - ('auth_url', service_fakes.sp_auth_url), - ('service_provider_url', service_fakes.service_provider_url), - ('service_provider_id', service_fakes.sp_id), + ('auth_url', self.service_provider.auth_url), + ('service_provider_url', self.service_provider.sp_url), + ('service_provider_id', self.service_provider.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) # Set expected values kwargs = { - 'enabled': True, - 'description': None, - 'auth_url': service_fakes.sp_auth_url, - 'sp_url': service_fakes.service_provider_url, + 'is_enabled': True, + 'auth_url': self.service_provider.auth_url, + 'sp_url': self.service_provider.sp_url, } - self.service_providers_mock.create.assert_called_with( - id=service_fakes.sp_id, **kwargs + self.identity_sdk_client.create_service_provider.assert_called_with( + id=self.service_provider.id, **kwargs ) self.assertEqual(self.columns, columns) - self.assertEqual(self.datalist, data) + self.assertEqual(self.data, data) def test_create_service_provider_description(self): arglist = [ '--description', - service_fakes.sp_description, + self.service_provider.description, '--auth-url', - service_fakes.sp_auth_url, + self.service_provider.auth_url, '--service-provider-url', - service_fakes.service_provider_url, - service_fakes.sp_id, + self.service_provider.sp_url, + self.service_provider.id, ] verifylist = [ - ('description', service_fakes.sp_description), - ('auth_url', service_fakes.sp_auth_url), - ('service_provider_url', service_fakes.service_provider_url), - ('service_provider_id', service_fakes.sp_id), + ('description', self.service_provider.description), + ('auth_url', self.service_provider.auth_url), + ('service_provider_url', self.service_provider.sp_url), + ('service_provider_id', self.service_provider.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -105,111 +101,85 @@ class TestServiceProviderCreate(TestServiceProvider): # Set expected values kwargs = { - 'description': service_fakes.sp_description, - 'auth_url': service_fakes.sp_auth_url, - 'sp_url': service_fakes.service_provider_url, - 'enabled': True, + 'description': self.service_provider.description, + 'auth_url': self.service_provider.auth_url, + 'sp_url': self.service_provider.sp_url, + 'is_enabled': self.service_provider.is_enabled, } - self.service_providers_mock.create.assert_called_with( - id=service_fakes.sp_id, **kwargs + self.identity_sdk_client.create_service_provider.assert_called_with( + id=self.service_provider.id, **kwargs ) self.assertEqual(self.columns, columns) - self.assertEqual(self.datalist, data) + self.assertEqual(self.data, data) def test_create_service_provider_disabled(self): - # Prepare FakeResource object - service_provider = copy.deepcopy(service_fakes.SERVICE_PROVIDER) - service_provider['enabled'] = False - service_provider['description'] = None - - resource = fakes.FakeResource(None, service_provider, loaded=True) - self.service_providers_mock.create.return_value = resource - arglist = [ '--auth-url', - service_fakes.sp_auth_url, + self.service_provider.auth_url, '--service-provider-url', - service_fakes.service_provider_url, + self.service_provider.sp_url, '--disable', - service_fakes.sp_id, + self.service_provider.id, ] verifylist = [ - ('auth_url', service_fakes.sp_auth_url), - ('service_provider_url', service_fakes.service_provider_url), - ('service_provider_id', service_fakes.sp_id), + ('auth_url', self.service_provider.auth_url), + ('service_provider_url', self.service_provider.sp_url), + ('service_provider_id', self.service_provider.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) # Set expected values kwargs = { - 'auth_url': service_fakes.sp_auth_url, - 'sp_url': service_fakes.service_provider_url, - 'enabled': False, - 'description': None, + 'auth_url': self.service_provider.auth_url, + 'sp_url': self.service_provider.sp_url, + 'is_enabled': False, } - self.service_providers_mock.create.assert_called_with( - id=service_fakes.sp_id, **kwargs + self.identity_sdk_client.create_service_provider.assert_called_with( + id=self.service_provider.id, **kwargs ) self.assertEqual(self.columns, columns) - datalist = ( - service_fakes.sp_auth_url, - None, - False, - service_fakes.sp_id, - service_fakes.service_provider_url, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.data, data) -class TestServiceProviderDelete(TestServiceProvider): +class TestServiceProviderDelete(service_fakes.TestFederatedIdentity): def setUp(self): super().setUp() - # This is the return value for utils.find_resource() - self.service_providers_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(service_fakes.SERVICE_PROVIDER), - loaded=True, + self.service_provider = sdk_fakes.generate_fake_resource( + _service_provider.ServiceProvider ) - - self.service_providers_mock.delete.return_value = None + self.identity_sdk_client.delete_service_provider.return_value = None self.cmd = service_provider.DeleteServiceProvider(self.app, None) def test_delete_service_provider(self): arglist = [ - service_fakes.sp_id, + self.service_provider.id, ] verifylist = [ - ('service_provider', [service_fakes.sp_id]), + ('service_provider', [self.service_provider.id]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) result = self.cmd.take_action(parsed_args) - self.service_providers_mock.delete.assert_called_with( - service_fakes.sp_id, + self.identity_sdk_client.delete_service_provider.assert_called_with( + self.service_provider.id, ) self.assertIsNone(result) -class TestServiceProviderList(TestServiceProvider): +class TestServiceProviderList(service_fakes.TestFederatedIdentity): def setUp(self): super().setUp() - self.service_providers_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(service_fakes.SERVICE_PROVIDER), - loaded=True, + self.service_provider = sdk_fakes.generate_fake_resource( + _service_provider.ServiceProvider ) - self.service_providers_mock.list.return_value = [ - fakes.FakeResource( - None, - copy.deepcopy(service_fakes.SERVICE_PROVIDER), - loaded=True, - ), + self.identity_sdk_client.service_providers.return_value = [ + self.service_provider ] # Get the command object to test @@ -225,39 +195,56 @@ class TestServiceProviderList(TestServiceProvider): # containing the data to be listed. columns, data = self.cmd.take_action(parsed_args) - self.service_providers_mock.list.assert_called_with() + self.identity_sdk_client.service_providers.assert_called_with() - collist = ('ID', 'Enabled', 'Description', 'Auth URL') + collist = ( + 'ID', + 'Enabled', + 'Description', + 'Auth URL', + 'Service Provider URL', + 'Relay State Prefix', + ) self.assertEqual(collist, columns) datalist = ( ( - service_fakes.sp_id, + self.service_provider.id, True, - service_fakes.sp_description, - service_fakes.sp_auth_url, + self.service_provider.description, + self.service_provider.auth_url, + self.service_provider.sp_url, + self.service_provider.relay_state_prefix, ), ) self.assertEqual(tuple(data), datalist) -class TestServiceProviderSet(TestServiceProvider): +class TestServiceProviderSet(service_fakes.TestFederatedIdentity): columns = ( - 'auth_url', - 'description', - 'enabled', 'id', + 'enabled', + 'description', + 'auth_url', 'sp_url', - ) - datalist = ( - service_fakes.sp_auth_url, - service_fakes.sp_description, - False, - service_fakes.sp_id, - service_fakes.service_provider_url, + 'relay_state_prefix', ) def setUp(self): super().setUp() + self.service_provider = sdk_fakes.generate_fake_resource( + _service_provider.ServiceProvider + ) + self.identity_sdk_client.update_service_provider.return_value = ( + self.service_provider + ) + self.data = ( + self.service_provider.id, + self.service_provider.is_enabled, + self.service_provider.description, + self.service_provider.auth_url, + self.service_provider.sp_url, + self.service_provider.relay_state_prefix, + ) self.cmd = service_provider.SetServiceProvider(self.app, None) def test_service_provider_disable(self): @@ -265,144 +252,107 @@ class TestServiceProviderSet(TestServiceProvider): Set Service Provider's ``enabled`` attribute to False. """ - - def prepare(self): - """Prepare fake return objects before the test is executed""" - updated_sp = copy.deepcopy(service_fakes.SERVICE_PROVIDER) - updated_sp['enabled'] = False - resources = fakes.FakeResource(None, updated_sp, loaded=True) - self.service_providers_mock.update.return_value = resources - - prepare(self) arglist = [ '--disable', - service_fakes.sp_id, + self.service_provider.id, ] verifylist = [ - ('service_provider', service_fakes.sp_id), - ('enable', False), - ('disable', True), + ('service_provider', self.service_provider.id), + ('is_enabled', False), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - self.service_providers_mock.update.assert_called_with( - service_fakes.sp_id, - enabled=False, - description=None, - auth_url=None, - sp_url=None, + columns, data = self.cmd.take_action(parsed_args) + self.identity_sdk_client.update_service_provider.assert_called_with( + self.service_provider.id, + is_enabled=False, ) + self.assertEqual(columns, self.columns) + self.assertEqual(data, self.data) def test_service_provider_enable(self): """Enable Service Provider. Set Service Provider's ``enabled`` attribute to True. """ - - def prepare(self): - """Prepare fake return objects before the test is executed""" - resources = fakes.FakeResource( - None, - copy.deepcopy(service_fakes.SERVICE_PROVIDER), - loaded=True, - ) - self.service_providers_mock.update.return_value = resources - - prepare(self) arglist = [ '--enable', - service_fakes.sp_id, + self.service_provider.id, ] verifylist = [ - ('service_provider', service_fakes.sp_id), - ('enable', True), - ('disable', False), + ('service_provider', self.service_provider.id), + ('is_enabled', True), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.service_providers_mock.update.assert_called_with( - service_fakes.sp_id, - enabled=True, - description=None, - auth_url=None, - sp_url=None, + columns, data = self.cmd.take_action(parsed_args) + self.identity_sdk_client.update_service_provider.assert_called_with( + self.service_provider.id, + is_enabled=True, ) + self.assertEqual(columns, self.columns) + self.assertEqual(data, self.data) def test_service_provider_no_options(self): - def prepare(self): - """Prepare fake return objects before the test is executed""" - resources = fakes.FakeResource( - None, - copy.deepcopy(service_fakes.SERVICE_PROVIDER), - loaded=True, - ) - self.service_providers_mock.get.return_value = resources - - resources = fakes.FakeResource( - None, - copy.deepcopy(service_fakes.SERVICE_PROVIDER), - loaded=True, - ) - self.service_providers_mock.update.return_value = resources - - prepare(self) arglist = [ - service_fakes.sp_id, + self.service_provider.id, ] verifylist = [ - ('service_provider', service_fakes.sp_id), + ('service_provider', self.service_provider.id), ('description', None), - ('enable', False), - ('disable', False), + ('is_enabled', None), ('auth_url', None), ('service_provider_url', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) + columns, data = self.cmd.take_action(parsed_args) + self.assertEqual(columns, self.columns) + self.assertEqual(data, self.data) -class TestServiceProviderShow(TestServiceProvider): +class TestServiceProviderShow(service_fakes.TestFederatedIdentity): def setUp(self): super().setUp() - ret = fakes.FakeResource( - None, - copy.deepcopy(service_fakes.SERVICE_PROVIDER), - loaded=True, + self.service_provider = sdk_fakes.generate_fake_resource( + _service_provider.ServiceProvider + ) + self.identity_sdk_client.find_service_provider.return_value = ( + self.service_provider + ) + self.data = ( + self.service_provider.id, + self.service_provider.is_enabled, + self.service_provider.description, + self.service_provider.auth_url, + self.service_provider.sp_url, + self.service_provider.relay_state_prefix, ) - self.service_providers_mock.get.side_effect = [ - Exception("Not found"), - ret, - ] - self.service_providers_mock.get.return_value = ret # Get the command object to test self.cmd = service_provider.ShowServiceProvider(self.app, None) def test_service_provider_show(self): arglist = [ - service_fakes.sp_id, + self.service_provider.id, ] verifylist = [ - ('service_provider', service_fakes.sp_id), + ('service_provider', self.service_provider.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) - self.service_providers_mock.get.assert_called_with( - service_fakes.sp_id, id='BETA' + self.identity_sdk_client.find_service_provider.assert_called_with( + self.service_provider.id, + ignore_missing=False, ) - collist = ('auth_url', 'description', 'enabled', 'id', 'sp_url') - self.assertEqual(collist, columns) - datalist = ( - service_fakes.sp_auth_url, - service_fakes.sp_description, - True, - service_fakes.sp_id, - service_fakes.service_provider_url, + collist = ( + 'id', + 'enabled', + 'description', + 'auth_url', + 'sp_url', + 'relay_state_prefix', ) - self.assertEqual(data, datalist) + self.assertEqual(collist, columns) + self.assertEqual(data, self.data) diff --git a/openstackclient/tests/unit/identity/v3/test_token.py b/openstackclient/tests/unit/identity/v3/test_token.py index 96375ea..f8d09b7 100644 --- a/openstackclient/tests/unit/identity/v3/test_token.py +++ b/openstackclient/tests/unit/identity/v3/test_token.py @@ -11,24 +11,12 @@ # 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 unittest import mock from openstackclient.identity.v3 import token from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes -class TestToken(identity_fakes.TestIdentityv3): - def setUp(self): - super().setUp() - - # Get a shortcut to the Auth Ref Mock - self.ar_mock = mock.PropertyMock() - type(self.app.client_manager).auth_ref = self.ar_mock - - -class TestTokenIssue(TestToken): +class TestTokenIssue(identity_fakes.TestIdentityv3): def setUp(self): super().setUp() @@ -38,8 +26,7 @@ class TestTokenIssue(TestToken): auth_ref = identity_fakes.fake_auth_ref( identity_fakes.TOKEN_WITH_PROJECT_ID, ) - self.ar_mock = mock.PropertyMock(return_value=auth_ref) - type(self.app.client_manager).auth_ref = self.ar_mock + self.app.client_manager.auth_ref = auth_ref arglist = [] verifylist = [] @@ -64,8 +51,7 @@ class TestTokenIssue(TestToken): auth_ref = identity_fakes.fake_auth_ref( identity_fakes.TOKEN_WITH_DOMAIN_ID, ) - self.ar_mock = mock.PropertyMock(return_value=auth_ref) - type(self.app.client_manager).auth_ref = self.ar_mock + self.app.client_manager.auth_ref = auth_ref arglist = [] verifylist = [] @@ -90,8 +76,7 @@ class TestTokenIssue(TestToken): auth_ref = identity_fakes.fake_auth_ref( identity_fakes.UNSCOPED_TOKEN, ) - self.ar_mock = mock.PropertyMock(return_value=auth_ref) - type(self.app.client_manager).auth_ref = self.ar_mock + self.app.client_manager.auth_ref = auth_ref arglist = [] verifylist = [] @@ -114,7 +99,7 @@ class TestTokenIssue(TestToken): self.assertEqual(datalist, data) -class TestTokenRevoke(TestToken): +class TestTokenRevoke(identity_fakes.TestIdentityv3): TOKEN = 'fob' def setUp(self): diff --git a/openstackclient/tests/unit/identity/v3/test_trust.py b/openstackclient/tests/unit/identity/v3/test_trust.py index fb7ac9b..07776fa 100644 --- a/openstackclient/tests/unit/identity/v3/test_trust.py +++ b/openstackclient/tests/unit/identity/v3/test_trust.py @@ -11,58 +11,36 @@ # under the License. # -import copy from unittest import mock from osc_lib import exceptions -from osc_lib import utils + +from openstack import exceptions as sdk_exceptions +from openstack.identity.v3 import project as _project +from openstack.identity.v3 import role as _role +from openstack.identity.v3 import trust as _trust +from openstack.identity.v3 import user as _user +from openstack.test import fakes as sdk_fakes from openstackclient.identity.v3 import trust -from openstackclient.tests.unit import fakes from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes -class TestTrust(identity_fakes.TestIdentityv3): +class TestTrustCreate(identity_fakes.TestIdentityv3): def setUp(self): super().setUp() - self.trusts_mock = self.identity_client.trusts - self.trusts_mock.reset_mock() - self.projects_mock = self.identity_client.projects - self.projects_mock.reset_mock() - self.users_mock = self.identity_client.users - self.users_mock.reset_mock() - self.roles_mock = self.identity_client.roles - self.roles_mock.reset_mock() - + self.trust = sdk_fakes.generate_fake_resource(_trust.Trust) + self.identity_sdk_client.create_trust.return_value = self.trust -class TestTrustCreate(TestTrust): - def setUp(self): - super().setUp() + self.project = sdk_fakes.generate_fake_resource(_project.Project) + self.identity_sdk_client.find_project.return_value = self.project - self.projects_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.PROJECT), - loaded=True, - ) + self.user = sdk_fakes.generate_fake_resource(_user.User) + self.identity_sdk_client.find_user.return_value = self.user - self.users_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.USER), - loaded=True, - ) - - self.roles_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ROLE), - loaded=True, - ) - - self.trusts_mock.create.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.TRUST), - loaded=True, - ) + self.role = sdk_fakes.generate_fake_resource(_role.Role) + self.identity_sdk_client.find_role.return_value = self.role # Get the command object to test self.cmd = trust.CreateTrust(self.app, None) @@ -70,18 +48,17 @@ class TestTrustCreate(TestTrust): def test_trust_create_basic(self): arglist = [ '--project', - identity_fakes.project_id, + self.project.id, '--role', - identity_fakes.role_id, - identity_fakes.user_id, - identity_fakes.user_id, + self.role.id, + self.user.id, + self.user.id, ] verifylist = [ - ('project', identity_fakes.project_id), - ('impersonate', False), - ('role', [identity_fakes.role_id]), - ('trustor', identity_fakes.user_id), - ('trustee', identity_fakes.user_id), + ('project', self.project.id), + ('roles', [self.role.id]), + ('trustor', self.user.id), + ('trustee', self.user.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -92,76 +69,71 @@ class TestTrustCreate(TestTrust): # Set expected values kwargs = { - 'impersonation': False, - 'project': identity_fakes.project_id, - 'role_ids': [identity_fakes.role_id], - 'expires_at': None, + 'project_id': self.project.id, + 'roles': [self.role.id], } # TrustManager.create(trustee_id, trustor_id, impersonation=, # project=, role_names=, expires_at=) - self.trusts_mock.create.assert_called_with( - identity_fakes.user_id, identity_fakes.user_id, **kwargs + self.identity_sdk_client.create_trust.assert_called_with( + trustor_id=self.user.id, trustee_id=self.user.id, **kwargs ) collist = ( 'expires_at', 'id', - 'impersonation', + 'is_impersonation', 'project_id', + 'redelegated_trust_id', + 'redelegation_count', + 'remaining_uses', 'roles', 'trustee_user_id', 'trustor_user_id', ) self.assertEqual(collist, columns) datalist = ( - identity_fakes.trust_expires, - identity_fakes.trust_id, - identity_fakes.trust_impersonation, - identity_fakes.project_id, - identity_fakes.role_name, - identity_fakes.user_id, - identity_fakes.user_id, + self.trust.expires_at, + self.trust.id, + self.trust.is_impersonation, + self.trust.project_id, + self.trust.redelegated_trust_id, + self.trust.redelegation_count, + self.trust.remaining_uses, + self.trust.roles, + self.trust.trustee_user_id, + self.trust.trustor_user_id, ) self.assertEqual(datalist, data) -class TestTrustDelete(TestTrust): +class TestTrustDelete(identity_fakes.TestIdentityv3): def setUp(self): super().setUp() - # This is the return value for utils.find_resource() - self.trusts_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.TRUST), - loaded=True, - ) - self.trusts_mock.delete.return_value = None + self.trust = sdk_fakes.generate_fake_resource(_trust.Trust) + self.identity_sdk_client.delete_trust.return_value = None + self.identity_sdk_client.find_trust.return_value = self.trust # Get the command object to test self.cmd = trust.DeleteTrust(self.app, None) def test_trust_delete(self): arglist = [ - identity_fakes.trust_id, + self.trust.id, ] - verifylist = [('trust', [identity_fakes.trust_id])] + verifylist = [('trust', [self.trust.id])] parsed_args = self.check_parser(self.cmd, arglist, verifylist) result = self.cmd.take_action(parsed_args) - self.trusts_mock.delete.assert_called_with( - identity_fakes.trust_id, + self.identity_sdk_client.delete_trust.assert_called_with( + self.trust.id, ) self.assertIsNone(result) - @mock.patch.object(utils, 'find_resource') - def test_delete_multi_trusts_with_exception(self, find_mock): - find_mock.side_effect = [ - self.trusts_mock.get.return_value, - exceptions.CommandError, - ] + def test_delete_multi_trusts_with_exception(self): arglist = [ - identity_fakes.trust_id, + self.trust.id, 'unexist_trust', ] verifylist = [ @@ -169,32 +141,37 @@ class TestTrustDelete(TestTrust): ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.identity_sdk_client.find_trust.side_effect = [ + self.trust, + sdk_exceptions.ResourceNotFound, + ] + try: self.cmd.take_action(parsed_args) self.fail('CommandError should be raised.') except exceptions.CommandError as e: self.assertEqual('1 of 2 trusts failed to delete.', str(e)) - find_mock.assert_any_call(self.trusts_mock, identity_fakes.trust_id) - find_mock.assert_any_call(self.trusts_mock, 'unexist_trust') - - self.assertEqual(2, find_mock.call_count) - self.trusts_mock.delete.assert_called_once_with( - identity_fakes.trust_id + self.identity_sdk_client.find_trust.assert_has_calls( + [ + mock.call(self.trust.id, ignore_missing=False), + mock.call('unexist_trust', ignore_missing=False), + ] + ) + self.identity_sdk_client.delete_trust.assert_called_once_with( + self.trust.id ) -class TestTrustList(TestTrust): +class TestTrustList(identity_fakes.TestIdentityv3): def setUp(self): super().setUp() - self.trusts_mock.list.return_value = [ - fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.TRUST), - loaded=True, - ), - ] + self.trust = sdk_fakes.generate_fake_resource(_trust.Trust) + self.identity_sdk_client.trusts.return_value = [self.trust] + + self.user = sdk_fakes.generate_fake_resource(_user.User) + self.identity_sdk_client.find_user.return_value = self.user # Get the command object to test self.cmd = trust.ListTrust(self.app, None) @@ -209,9 +186,9 @@ class TestTrustList(TestTrust): # containing the data to be listed. columns, data = self.cmd.take_action(parsed_args) - self.trusts_mock.list.assert_called_with( - trustor_user=None, - trustee_user=None, + self.identity_sdk_client.trusts.assert_called_with( + trustor_user_id=None, + trustee_user_id=None, ) collist = ( @@ -225,19 +202,19 @@ class TestTrustList(TestTrust): self.assertEqual(collist, columns) datalist = ( ( - identity_fakes.trust_id, - identity_fakes.trust_expires, - identity_fakes.trust_impersonation, - identity_fakes.project_id, - identity_fakes.user_id, - identity_fakes.user_id, + self.trust.id, + self.trust.expires_at, + self.trust.is_impersonation, + self.trust.project_id, + self.trust.trustee_user_id, + self.trust.trustor_user_id, ), ) self.assertEqual(datalist, tuple(data)) def test_trust_list_auth_user(self): - auth_ref = self.app.client_manager.auth_ref = mock.Mock() - auth_ref.user_id.return_value = identity_fakes.user_id + self.app.client_manager.auth_ref = mock.Mock() + auth_ref = self.app.client_manager.auth_ref arglist = ['--auth-user'] verifylist = [ @@ -252,11 +229,11 @@ class TestTrustList(TestTrust): # containing the data to be listed. columns, data = self.cmd.take_action(parsed_args) - self.trusts_mock.list.assert_any_call( - trustor_user=self.users_mock.get() - ) - self.trusts_mock.list.assert_any_call( - trustee_user=self.users_mock.get() + self.identity_sdk_client.trusts.assert_has_calls( + [ + mock.call(trustor_user_id=auth_ref.user_id), + mock.call(trustee_user_id=auth_ref.user_id), + ] ) collist = ( @@ -270,21 +247,21 @@ class TestTrustList(TestTrust): self.assertEqual(collist, columns) datalist = ( ( - identity_fakes.trust_id, - identity_fakes.trust_expires, - identity_fakes.trust_impersonation, - identity_fakes.project_id, - identity_fakes.user_id, - identity_fakes.user_id, + self.trust.id, + self.trust.expires_at, + self.trust.is_impersonation, + self.trust.project_id, + self.trust.trustee_user_id, + self.trust.trustor_user_id, ), ) self.assertEqual(datalist, tuple(data)) def test_trust_list_trustee(self): - arglist = ['--trustee', identity_fakes.user_name] + arglist = ['--trustee', self.user.name] verifylist = [ ('trustor', None), - ('trustee', identity_fakes.user_name), + ('trustee', self.user.name), ('authuser', False), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -294,9 +271,9 @@ class TestTrustList(TestTrust): # containing the data to be listed. columns, data = self.cmd.take_action(parsed_args) - self.trusts_mock.list.assert_any_call( - trustee_user=self.users_mock.get(), - trustor_user=None, + self.identity_sdk_client.trusts.assert_called_with( + trustee_user_id=self.user.id, + trustor_user_id=None, ) collist = ( @@ -310,21 +287,21 @@ class TestTrustList(TestTrust): self.assertEqual(collist, columns) datalist = ( ( - identity_fakes.trust_id, - identity_fakes.trust_expires, - identity_fakes.trust_impersonation, - identity_fakes.project_id, - identity_fakes.user_id, - identity_fakes.user_id, + self.trust.id, + self.trust.expires_at, + self.trust.is_impersonation, + self.trust.project_id, + self.trust.trustee_user_id, + self.trust.trustor_user_id, ), ) self.assertEqual(datalist, tuple(data)) def test_trust_list_trustor(self): - arglist = ['--trustor', identity_fakes.user_name] + arglist = ['--trustor', self.user.name] verifylist = [ ('trustee', None), - ('trustor', identity_fakes.user_name), + ('trustor', self.user.name), ('authuser', False), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -334,9 +311,9 @@ class TestTrustList(TestTrust): # containing the data to be listed. columns, data = self.cmd.take_action(parsed_args) - self.trusts_mock.list.assert_any_call( - trustor_user=self.users_mock.get(), - trustee_user=None, + self.identity_sdk_client.trusts.assert_called_once_with( + trustor_user_id=self.user.id, + trustee_user_id=None, ) collist = ( @@ -350,36 +327,33 @@ class TestTrustList(TestTrust): self.assertEqual(collist, columns) datalist = ( ( - identity_fakes.trust_id, - identity_fakes.trust_expires, - identity_fakes.trust_impersonation, - identity_fakes.project_id, - identity_fakes.user_id, - identity_fakes.user_id, + self.trust.id, + self.trust.expires_at, + self.trust.is_impersonation, + self.trust.project_id, + self.trust.trustee_user_id, + self.trust.trustor_user_id, ), ) self.assertEqual(datalist, tuple(data)) -class TestTrustShow(TestTrust): +class TestTrustShow(identity_fakes.TestIdentityv3): def setUp(self): super().setUp() - self.trusts_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.TRUST), - loaded=True, - ) + self.trust = sdk_fakes.generate_fake_resource(_trust.Trust) + self.identity_sdk_client.find_trust.return_value = self.trust # Get the command object to test self.cmd = trust.ShowTrust(self.app, None) def test_trust_show(self): arglist = [ - identity_fakes.trust_id, + self.trust.id, ] verifylist = [ - ('trust', identity_fakes.trust_id), + ('trust', self.trust.id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -388,25 +362,33 @@ class TestTrustShow(TestTrust): # data to be shown. columns, data = self.cmd.take_action(parsed_args) - self.trusts_mock.get.assert_called_with(identity_fakes.trust_id) + self.identity_sdk_client.find_trust.assert_called_with( + self.trust.id, ignore_missing=False + ) collist = ( 'expires_at', 'id', - 'impersonation', + 'is_impersonation', 'project_id', + 'redelegated_trust_id', + 'redelegation_count', + 'remaining_uses', 'roles', 'trustee_user_id', 'trustor_user_id', ) self.assertEqual(collist, columns) datalist = ( - identity_fakes.trust_expires, - identity_fakes.trust_id, - identity_fakes.trust_impersonation, - identity_fakes.project_id, - identity_fakes.role_name, - identity_fakes.user_id, - identity_fakes.user_id, + self.trust.expires_at, + self.trust.id, + self.trust.is_impersonation, + self.trust.project_id, + self.trust.redelegated_trust_id, + self.trust.redelegation_count, + self.trust.remaining_uses, + self.trust.roles, + self.trust.trustee_user_id, + self.trust.trustor_user_id, ) self.assertEqual(datalist, data) diff --git a/openstackclient/tests/unit/image/v2/test_image.py b/openstackclient/tests/unit/image/v2/test_image.py index e8aafa8..69a65a5 100644 --- a/openstackclient/tests/unit/image/v2/test_image.py +++ b/openstackclient/tests/unit/image/v2/test_image.py @@ -55,6 +55,7 @@ class TestImageCreate(TestImage): self.new_image = image_fakes.create_one_image() self.image_client.create_image.return_value = self.new_image self.image_client.update_image.return_value = self.new_image + self.image_client.get_image.return_value = self.new_image self.project_mock.get.return_value = self.project @@ -89,6 +90,7 @@ class TestImageCreate(TestImage): container_format=_image.DEFAULT_CONTAINER_FORMAT, disk_format=_image.DEFAULT_DISK_FORMAT, ) + self.image_client.get_image.assert_called_once_with(self.new_image) self.assertEqual(self.expected_columns, columns) self.assertCountEqual(self.expected_data, data) @@ -146,6 +148,7 @@ class TestImageCreate(TestImage): is_protected=self.new_image.is_protected, visibility=self.new_image.visibility, ) + self.image_client.get_image.assert_called_once_with(self.new_image) self.assertEqual(self.expected_columns, columns) self.assertCountEqual(self.expected_data, data) @@ -243,6 +246,7 @@ class TestImageCreate(TestImage): tags=self.new_image.tags, filename=imagefile.name, ) + self.image_client.get_image.assert_called_once_with(self.new_image) self.assertEqual(self.expected_columns, columns) self.assertCountEqual(self.expected_data, data) @@ -275,6 +279,7 @@ class TestImageCreate(TestImage): data=fake_stdin, validate_checksum=False, ) + self.image_client.get_image.assert_called_once_with(self.new_image) self.assertEqual(self.expected_columns, columns) self.assertCountEqual(self.expected_data, data) @@ -315,6 +320,7 @@ class TestImageCreate(TestImage): disk_format=_image.DEFAULT_DISK_FORMAT, use_import=True, ) + self.image_client.get_image.assert_called_once_with(self.new_image) @mock.patch('osc_lib.utils.find_resource') @mock.patch('openstackclient.image.v2.image.get_data_from_stdin') diff --git a/openstackclient/tests/unit/network/v2/fakes.py b/openstackclient/tests/unit/network/v2/fakes.py index 999e102..d0b1c1e 100644 --- a/openstackclient/tests/unit/network/v2/fakes.py +++ b/openstackclient/tests/unit/network/v2/fakes.py @@ -1419,6 +1419,7 @@ def create_one_network(attrs=None): 'availability_zone_hints': [], 'is_default': False, 'is_vlan_transparent': True, + 'is_vlan_qinq': False, 'port_security_enabled': True, 'qos_policy_id': 'qos-policy-id-' + uuid.uuid4().hex, 'ipv4_address_scope': 'ipv4' + uuid.uuid4().hex, @@ -1676,8 +1677,10 @@ def create_one_port(attrs=None): 'qos_network_policy_id': 'qos-policy-id-' + uuid.uuid4().hex, 'qos_policy_id': 'qos-policy-id-' + uuid.uuid4().hex, 'tags': [], + 'trusted': None, 'propagate_uplink_status': False, 'location': 'MUNCHMUNCHMUNCH', + 'trunk_details': {}, } # Overwrite default attributes. diff --git a/openstackclient/tests/unit/network/v2/test_network.py b/openstackclient/tests/unit/network/v2/test_network.py index 33fe5be..0222be6 100644 --- a/openstackclient/tests/unit/network/v2/test_network.py +++ b/openstackclient/tests/unit/network/v2/test_network.py @@ -63,6 +63,7 @@ class TestCreateNetworkIdentityV3(TestNetwork): 'ipv6_address_scope', 'is_default', 'is_vlan_transparent', + 'is_vlan_qinq', 'mtu', 'name', 'port_security_enabled', @@ -103,6 +104,7 @@ class TestCreateNetworkIdentityV3(TestNetwork): network.RouterExternalColumn(_network.is_router_external), _network.is_shared, _network.is_vlan_transparent, + _network.is_vlan_qinq, _network.status, _network.segments, format_columns.ListColumn(_network.subnet_ids), @@ -190,6 +192,7 @@ class TestCreateNetworkIdentityV3(TestNetwork): "--qos-policy", self.qos_policy.id, "--transparent-vlan", + "--no-qinq-vlan", "--enable-port-security", "--dns-domain", "example.org.", @@ -210,6 +213,7 @@ class TestCreateNetworkIdentityV3(TestNetwork): ('segmentation_id', '400'), ('qos_policy', self.qos_policy.id), ('transparent_vlan', True), + ('qinq_vlan', False), ('enable_port_security', True), ('name', self._network.name), ('dns_domain', 'example.org.'), @@ -234,6 +238,7 @@ class TestCreateNetworkIdentityV3(TestNetwork): 'provider:segmentation_id': '400', 'qos_policy_id': self.qos_policy.id, 'vlan_transparent': True, + 'vlan_qinq': False, 'port_security_enabled': True, 'dns_domain': 'example.org.', } @@ -246,6 +251,7 @@ class TestCreateNetworkIdentityV3(TestNetwork): "--enable", "--no-share", "--disable-port-security", + "--qinq-vlan", self._network.name, ] verifylist = [ @@ -253,6 +259,7 @@ class TestCreateNetworkIdentityV3(TestNetwork): ('no_share', True), ('name', self._network.name), ('external', False), + ('qinq_vlan', True), ('disable_port_security', True), ] @@ -264,6 +271,7 @@ class TestCreateNetworkIdentityV3(TestNetwork): 'admin_state_up': True, 'name': self._network.name, 'shared': False, + 'vlan_qinq': True, 'port_security_enabled': False, } ) @@ -309,6 +317,19 @@ class TestCreateNetworkIdentityV3(TestNetwork): def test_create_with_no_tag(self): self._test_create_with_tag(add_tags=False) + def test_create_with_vlan_qinq_and_transparency_enabled(self): + arglist = [ + "--transparent-vlan", + "--qinq-vlan", + self._network.name, + ] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.assertRaises( + exceptions.CommandError, self.cmd.take_action, parsed_args + ) + class TestCreateNetworkIdentityV2( identity_fakes_v2.FakeClientMixin, @@ -332,6 +353,7 @@ class TestCreateNetworkIdentityV2( 'ipv6_address_scope', 'is_default', 'is_vlan_transparent', + 'is_vlan_qinq', 'mtu', 'name', 'port_security_enabled', @@ -372,6 +394,7 @@ class TestCreateNetworkIdentityV2( network.RouterExternalColumn(_network.is_router_external), _network.is_shared, _network.is_vlan_transparent, + _network.is_vlan_qinq, _network.status, _network.segments, format_columns.ListColumn(_network.subnet_ids), @@ -1149,6 +1172,7 @@ class TestShowNetwork(TestNetwork): 'ipv6_address_scope', 'is_default', 'is_vlan_transparent', + 'is_vlan_qinq', 'mtu', 'name', 'port_security_enabled', @@ -1189,6 +1213,7 @@ class TestShowNetwork(TestNetwork): network.RouterExternalColumn(_network.is_router_external), _network.is_shared, _network.is_vlan_transparent, + _network.is_vlan_qinq, _network.status, _network.segments, format_columns.ListColumn(_network.subnet_ids), diff --git a/openstackclient/tests/unit/network/v2/test_network_flavor_profile.py b/openstackclient/tests/unit/network/v2/test_network_flavor_profile.py index 44cc4f4..d94926c 100644 --- a/openstackclient/tests/unit/network/v2/test_network_flavor_profile.py +++ b/openstackclient/tests/unit/network/v2/test_network_flavor_profile.py @@ -23,14 +23,11 @@ class TestFlavorProfile(network_fakes.TestNetworkV2): def setUp(self): super().setUp() - # Get the ProjectManager Mock - self.projects_mock = self.identity_client.projects # Get the DomainManager Mock self.domains_mock = self.identity_client.domains class TestCreateFlavorProfile(TestFlavorProfile): - project = identity_fakes_v3.FakeProject.create_one_project() domain = identity_fakes_v3.FakeDomain.create_one_domain() new_flavor_profile = network_fakes.create_one_service_profile() @@ -40,7 +37,6 @@ class TestCreateFlavorProfile(TestFlavorProfile): 'enabled', 'id', 'meta_info', - 'project_id', ) data = ( @@ -49,7 +45,6 @@ class TestCreateFlavorProfile(TestFlavorProfile): new_flavor_profile.is_enabled, new_flavor_profile.id, new_flavor_profile.meta_info, - new_flavor_profile.project_id, ) def setUp(self): @@ -57,7 +52,6 @@ class TestCreateFlavorProfile(TestFlavorProfile): self.network_client.create_service_profile = mock.Mock( return_value=self.new_flavor_profile ) - self.projects_mock.get.return_value = self.project # Get the command object to test self.cmd = network_flavor_profile.CreateNetworkFlavorProfile( self.app, None @@ -67,10 +61,6 @@ class TestCreateFlavorProfile(TestFlavorProfile): arglist = [ "--description", self.new_flavor_profile.description, - "--project", - self.new_flavor_profile.project_id, - '--project-domain', - self.domain.name, "--enable", "--driver", self.new_flavor_profile.driver, @@ -80,8 +70,6 @@ class TestCreateFlavorProfile(TestFlavorProfile): verifylist = [ ('description', self.new_flavor_profile.description), - ('project', self.new_flavor_profile.project_id), - ('project_domain', self.domain.name), ('enable', True), ('driver', self.new_flavor_profile.driver), ('metainfo', self.new_flavor_profile.meta_info), @@ -93,7 +81,6 @@ class TestCreateFlavorProfile(TestFlavorProfile): self.network_client.create_service_profile.assert_called_once_with( **{ 'description': self.new_flavor_profile.description, - 'project_id': self.project.id, 'enabled': self.new_flavor_profile.is_enabled, 'driver': self.new_flavor_profile.driver, 'metainfo': self.new_flavor_profile.meta_info, @@ -106,10 +93,6 @@ class TestCreateFlavorProfile(TestFlavorProfile): arglist = [ "--description", self.new_flavor_profile.description, - "--project", - self.new_flavor_profile.project_id, - '--project-domain', - self.domain.name, "--enable", "--metainfo", self.new_flavor_profile.meta_info, @@ -117,8 +100,6 @@ class TestCreateFlavorProfile(TestFlavorProfile): verifylist = [ ('description', self.new_flavor_profile.description), - ('project', self.new_flavor_profile.project_id), - ('project_domain', self.domain.name), ('enable', True), ('metainfo', self.new_flavor_profile.meta_info), ] @@ -129,7 +110,6 @@ class TestCreateFlavorProfile(TestFlavorProfile): self.network_client.create_service_profile.assert_called_once_with( **{ 'description': self.new_flavor_profile.description, - 'project_id': self.project.id, 'enabled': self.new_flavor_profile.is_enabled, 'metainfo': self.new_flavor_profile.meta_info, } @@ -141,10 +121,6 @@ class TestCreateFlavorProfile(TestFlavorProfile): arglist = [ "--description", self.new_flavor_profile.description, - "--project", - self.new_flavor_profile.project_id, - '--project-domain', - self.domain.name, "--enable", "--driver", self.new_flavor_profile.driver, @@ -152,8 +128,6 @@ class TestCreateFlavorProfile(TestFlavorProfile): verifylist = [ ('description', self.new_flavor_profile.description), - ('project', self.new_flavor_profile.project_id), - ('project_domain', self.domain.name), ('enable', True), ('driver', self.new_flavor_profile.driver), ] @@ -164,7 +138,6 @@ class TestCreateFlavorProfile(TestFlavorProfile): self.network_client.create_service_profile.assert_called_once_with( **{ 'description': self.new_flavor_profile.description, - 'project_id': self.project.id, 'enabled': self.new_flavor_profile.is_enabled, 'driver': self.new_flavor_profile.driver, } @@ -176,17 +149,11 @@ class TestCreateFlavorProfile(TestFlavorProfile): arglist = [ "--description", self.new_flavor_profile.description, - "--project", - self.new_flavor_profile.project_id, - '--project-domain', - self.domain.name, "--enable", ] verifylist = [ ('description', self.new_flavor_profile.description), - ('project', self.new_flavor_profile.project_id), - ('project_domain', self.domain.name), ('enable', True), ] @@ -377,7 +344,6 @@ class TestShowFlavorProfile(TestFlavorProfile): 'enabled', 'id', 'meta_info', - 'project_id', ) data = ( network_flavor_profile.description, @@ -385,7 +351,6 @@ class TestShowFlavorProfile(TestFlavorProfile): network_flavor_profile.is_enabled, network_flavor_profile.id, network_flavor_profile.meta_info, - network_flavor_profile.project_id, ) def setUp(self): diff --git a/openstackclient/tests/unit/network/v2/test_port.py b/openstackclient/tests/unit/network/v2/test_port.py index 81f3cd7..3f521a4 100644 --- a/openstackclient/tests/unit/network/v2/test_port.py +++ b/openstackclient/tests/unit/network/v2/test_port.py @@ -12,6 +12,7 @@ from unittest import mock from unittest.mock import call +import uuid from osc_lib.cli import format_columns from osc_lib import exceptions @@ -23,8 +24,13 @@ from openstackclient.tests.unit.network.v2 import fakes as network_fakes from openstackclient.tests.unit import utils as test_utils -LIST_FIELDS_TO_RETRIEVE = ('id', 'name', 'mac_address', 'fixed_ips', 'status') -LIST_FIELDS_TO_RETRIEVE_LONG = ('security_group_ids', 'device_owner', 'tags') +LIST_FIELDS_TO_RETRIEVE = ['id', 'name', 'mac_address', 'fixed_ips', 'status'] +LIST_FIELDS_TO_RETRIEVE_LONG = [ + 'security_groups', + 'device_owner', + 'tags', + 'trunk_details', +] class TestPort(network_fakes.TestNetworkV2): @@ -73,6 +79,7 @@ class TestPort(network_fakes.TestNetworkV2): 'security_group_ids', 'status', 'tags', + 'trusted', 'trunk_details', 'updated_at', ) @@ -114,6 +121,7 @@ class TestPort(network_fakes.TestNetworkV2): format_columns.ListColumn(fake_port.security_group_ids), fake_port.status, format_columns.ListColumn(fake_port.tags), + fake_port.trusted, fake_port.trunk_details, fake_port.updated_at, ) @@ -330,7 +338,7 @@ class TestCreatePort(TestPort): self._port.network_id, ), ('enable', True), - ('security_group', [secgroup.id]), + ('security_groups', [secgroup.id]), ('name', 'test-port'), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -403,7 +411,7 @@ class TestCreatePort(TestPort): self._port.network_id, ), ('enable', True), - ('security_group', [sg_1.id, sg_2.id]), + ('security_groups', [sg_1.id, sg_2.id]), ('name', 'test-port'), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -432,7 +440,7 @@ class TestCreatePort(TestPort): verifylist = [ ('network', self._port.network_id), ('enable', True), - ('no_security_group', True), + ('security_groups', []), ('name', 'test-port'), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -1111,6 +1119,50 @@ class TestCreatePort(TestPort): def test_create_with_hardware_offload_type_null(self): self._test_create_with_hardware_offload_type() + def _test_create_with_trusted_field(self, trusted): + arglist = [ + '--network', + self._port.network_id, + 'test-port', + ] + if trusted: + arglist += ['--trusted'] + else: + arglist += ['--not-trusted'] + + verifylist = [ + ( + 'network', + self._port.network_id, + ), + ('name', 'test-port'), + ] + if trusted: + verifylist.append(('trusted', True)) + else: + verifylist.append(('trusted', False)) + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + create_args = { + 'admin_state_up': True, + 'network_id': self._port.network_id, + 'name': 'test-port', + } + create_args['trusted'] = trusted + self.network_client.create_port.assert_called_once_with(**create_args) + + self.assertEqual(set(self.columns), set(columns)) + self.assertCountEqual(self.data, data) + + def test_create_with_trusted_true(self): + self._test_create_with_trusted_field(True) + + def test_create_with_trusted_false(self): + self._test_create_with_trusted_field(False) + class TestDeletePort(TestPort): # Ports to delete. @@ -1190,17 +1242,47 @@ class TestDeletePort(TestPort): class TestListPort(compute_fakes.FakeClientMixin, TestPort): - _ports = network_fakes.create_ports(count=3) + _project = identity_fakes.FakeProject.create_one_project() + _networks = network_fakes.create_networks(count=3) + _sport1 = network_fakes.create_one_port( + attrs={'project_id': _project.id, 'network_id': _networks[1]['id']} + ) + _sport2 = network_fakes.create_one_port( + attrs={'project_id': _project.id, 'network_id': _networks[2]['id']} + ) + _trunk_details = { + 'trunk_id': str(uuid.uuid4()), + 'sub_ports': [ + { + 'segmentation_id': 100, + 'segmentation_type': 'vlan', + 'port_id': _sport1.id, + }, + { + 'segmentation_id': 102, + 'segmentation_type': 'vlan', + 'port_id': _sport2.id, + }, + ], + } + _pport = network_fakes.create_one_port( + attrs={ + 'project_id': _project.id, + 'network_id': _networks[0]['id'], + 'trunk_details': _trunk_details, + } + ) + _ports = (_pport, _sport1, _sport2) - columns = ( + columns = [ 'ID', 'Name', 'MAC Address', 'Fixed IP Addresses', 'Status', - ) + ] - columns_long = ( + columns_long = [ 'ID', 'Name', 'MAC Address', @@ -1209,7 +1291,8 @@ class TestListPort(compute_fakes.FakeClientMixin, TestPort): 'Security Groups', 'Device Owner', 'Tags', - ) + 'Trunk subports', + ] data = [] for prt in _ports: @@ -1235,6 +1318,7 @@ class TestListPort(compute_fakes.FakeClientMixin, TestPort): format_columns.ListColumn(prt.security_group_ids), prt.device_owner, format_columns.ListColumn(prt.tags), + port.SubPortColumn(prt.trunk_details), ) ) @@ -2021,7 +2105,7 @@ class TestSetPort(TestPort): self._port.name, ] verifylist = [ - ('security_group', [sg.id]), + ('security_groups', [sg.id]), ('port', self._port.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -2054,7 +2138,7 @@ class TestSetPort(TestPort): _testport.name, ] verifylist = [ - ('security_group', [sg_2.id, sg_3.id]), + ('security_groups', [sg_2.id, sg_3.id]), ('port', _testport.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -2103,7 +2187,7 @@ class TestSetPort(TestPort): _testport.name, ] verifylist = [ - ('security_group', [sg2.id]), + ('security_groups', [sg2.id]), ('no_security_group', True), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -2520,6 +2604,64 @@ class TestSetPort(TestPort): ) self.assertIsNone(result) + def _test_set_trusted_field(self, trusted): + arglist = [self._port.id] + if trusted: + arglist += ['--trusted'] + else: + arglist += ['--not-trusted'] + + verifylist = [ + ('port', self._port.id), + ] + if trusted: + verifylist.append(('trusted', True)) + else: + verifylist.append(('trusted', False)) + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + self.network_client.update_port.assert_called_once_with( + self._port, **{'trusted': trusted} + ) + self.assertIsNone(result) + + def test_set_trusted_true(self): + self._test_set_trusted_field(True) + + def test_set_trusted_false(self): + self._test_set_trusted_field(False) + + def _test_set_uplink_status_propagation(self, uspropagation): + arglist = [self._port.id] + if uspropagation: + arglist += ['--enable-uplink-status-propagation'] + else: + arglist += ['--disable-uplink-status-propagation'] + + verifylist = [ + ('port', self._port.id), + ] + if uspropagation: + verifylist.append(('enable_uplink_status_propagation', True)) + else: + verifylist.append(('enable_uplink_status_propagation', False)) + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + self.network_client.update_port.assert_called_once_with( + self._port, **{'propagate_uplink_status': uspropagation} + ) + self.assertIsNone(result) + + def test_set_uplink_status_propagation_true(self): + self._test_set_uplink_status_propagation(True) + + def test_set_uplink_status_propagation_false(self): + self._test_set_uplink_status_propagation(False) + class TestShowPort(TestPort): # The port to show. @@ -2695,7 +2837,7 @@ class TestUnsetPort(TestPort): _fake_port.name, ] verifylist = [ - ('security_group_ids', [_fake_sg2.id]), + ('security_groups', [_fake_sg2.id]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -2722,7 +2864,7 @@ class TestUnsetPort(TestPort): _fake_port.name, ] verifylist = [ - ('security_group_ids', [_fake_sg2.id]), + ('security_groups', [_fake_sg2.id]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) diff --git a/openstackclient/tests/unit/network/v2/test_router.py b/openstackclient/tests/unit/network/v2/test_router.py index e420f80..aa6de7d 100644 --- a/openstackclient/tests/unit/network/v2/test_router.py +++ b/openstackclient/tests/unit/network/v2/test_router.py @@ -384,7 +384,7 @@ class TestCreateRouter(TestRouter): def test_create_with_no_tag(self): self._test_create_with_tag(add_tags=False) - def test_create_with_flavor_id_or_name(self): + def test_create_with_flavor_id_id(self): _flavor = network_fakes.create_one_network_flavor() self.network_client.find_flavor = mock.Mock(return_value=_flavor) arglist = [ @@ -392,7 +392,6 @@ class TestCreateRouter(TestRouter): '--flavor-id', _flavor.id, ] - arglist_with_name = [self.new_router.name, '--flavor-id', _flavor.name] verifylist = [ ('name', self.new_router.name), ('enable', True), @@ -412,18 +411,69 @@ class TestCreateRouter(TestRouter): self.assertEqual(self.columns, columns) self.assertCountEqual(self.data, data) - self.network_client.create_router.reset_mock() - verifylist_w_name = [ + def test_create_with_flavor_id_name(self): + _flavor = network_fakes.create_one_network_flavor() + self.network_client.find_flavor = mock.Mock(return_value=_flavor) + arglist = [self.new_router.name, '--flavor-id', _flavor.name] + verifylist = [ ('name', self.new_router.name), ('enable', True), ('distributed', False), ('ha', False), ('flavor_id', _flavor.name), ] - parsed_args_w_name = self.check_parser( - self.cmd, arglist_with_name, verifylist_w_name + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + self.network_client.create_router.assert_called_once_with( + **{ + 'admin_state_up': True, + 'name': self.new_router.name, + 'flavor_id': _flavor.id, + } + ) + self.assertEqual(self.columns, columns) + self.assertCountEqual(self.data, data) + + def test_create_with_flavor_id(self): + _flavor = network_fakes.create_one_network_flavor() + self.network_client.find_flavor = mock.Mock(return_value=_flavor) + arglist = [ + self.new_router.name, + '--flavor', + _flavor.id, + ] + verifylist = [ + ('name', self.new_router.name), + ('enable', True), + ('distributed', False), + ('ha', False), + ('flavor', _flavor.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + self.network_client.create_router.assert_called_once_with( + **{ + 'admin_state_up': True, + 'name': self.new_router.name, + 'flavor_id': _flavor.id, + } ) - columns, data = self.cmd.take_action(parsed_args_w_name) + self.assertEqual(self.columns, columns) + self.assertCountEqual(self.data, data) + + def test_create_with_flavor_name(self): + _flavor = network_fakes.create_one_network_flavor() + self.network_client.find_flavor = mock.Mock(return_value=_flavor) + arglist = [self.new_router.name, '--flavor', _flavor.name] + verifylist = [ + ('name', self.new_router.name), + ('enable', True), + ('distributed', False), + ('ha', False), + ('flavor', _flavor.name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) self.network_client.create_router.assert_called_once_with( **{ 'admin_state_up': True, diff --git a/openstackclient/tests/unit/utils.py b/openstackclient/tests/unit/utils.py index 2a39ca4..607047f 100644 --- a/openstackclient/tests/unit/utils.py +++ b/openstackclient/tests/unit/utils.py @@ -93,8 +93,14 @@ class TestCommand(TestCase): f"Argument parse failed: {stderr.getvalue()}" ) for av in verify_args: - attr, value = av + attr, expected_value = av if attr: + actual_value = getattr(parsed_args, attr) self.assertIn(attr, parsed_args) - self.assertEqual(value, getattr(parsed_args, attr)) + self.assertEqual( + expected_value, + actual_value, + f'args.{attr}: expected: {expected_value}, got: ' + f'{actual_value}', + ) return parsed_args diff --git a/openstackclient/tests/unit/volume/v2/test_volume_backup.py b/openstackclient/tests/unit/volume/v2/test_volume_backup.py index 483ca24..faf2489 100644 --- a/openstackclient/tests/unit/volume/v2/test_volume_backup.py +++ b/openstackclient/tests/unit/volume/v2/test_volume_backup.py @@ -364,16 +364,28 @@ class TestBackupRestore(volume_fakes.TestVolume): attrs={'volume_id': volume.id}, ) + columns = ( + "id", + "volume_id", + "volume_name", + ) + + data = ( + backup.id, + volume.id, + volume.name, + ) + def setUp(self): super().setUp() self.volume_sdk_client.find_backup.return_value = self.backup self.volume_sdk_client.find_volume.return_value = self.volume - self.volume_sdk_client.restore_backup.return_value = ( - volume_fakes.create_one_volume( - {'id': self.volume['id']}, - ) - ) + self.volume_sdk_client.restore_backup.return_value = { + 'id': self.backup['id'], + 'volume_id': self.volume['id'], + 'volume_name': self.volume['name'], + } # Get the command object to mock self.cmd = volume_backup.RestoreVolumeBackup(self.app, None) @@ -389,13 +401,15 @@ class TestBackupRestore(volume_fakes.TestVolume): ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - result = self.cmd.take_action(parsed_args) + columns, data = self.cmd.take_action(parsed_args) self.volume_sdk_client.restore_backup.assert_called_with( self.backup.id, volume_id=None, name=None, ) - self.assertIsNotNone(result) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) def test_backup_restore_with_volume(self): self.volume_sdk_client.find_volume.side_effect = ( @@ -411,13 +425,15 @@ class TestBackupRestore(volume_fakes.TestVolume): ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - result = self.cmd.take_action(parsed_args) + columns, data = self.cmd.take_action(parsed_args) self.volume_sdk_client.restore_backup.assert_called_with( self.backup.id, volume_id=None, name=self.backup.volume_id, ) - self.assertIsNotNone(result) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) def test_backup_restore_with_volume_force(self): arglist = [ @@ -432,13 +448,15 @@ class TestBackupRestore(volume_fakes.TestVolume): ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - result = self.cmd.take_action(parsed_args) + columns, data = self.cmd.take_action(parsed_args) self.volume_sdk_client.restore_backup.assert_called_with( self.backup.id, volume_id=self.volume.id, name=None, ) - self.assertIsNotNone(result) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) def test_backup_restore_with_volume_existing(self): arglist = [ @@ -544,7 +562,7 @@ class TestBackupShow(volume_fakes.TestVolume): def setUp(self): super().setUp() - self.volume_sdk_client.get_backup.return_value = self.backup + self.volume_sdk_client.find_backup.return_value = self.backup # Get the command object to test self.cmd = volume_backup.ShowVolumeBackup(self.app, None) @@ -554,7 +572,7 @@ class TestBackupShow(volume_fakes.TestVolume): parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) - self.volume_sdk_client.get_backup.assert_called_with(self.backup.id) + self.volume_sdk_client.find_backup.assert_called_with(self.backup.id) self.assertEqual(self.columns, columns) self.assertEqual(self.data, data) diff --git a/openstackclient/tests/unit/volume/v3/test_volume_backup.py b/openstackclient/tests/unit/volume/v3/test_volume_backup.py index d4e7e79..fb0a465 100644 --- a/openstackclient/tests/unit/volume/v3/test_volume_backup.py +++ b/openstackclient/tests/unit/volume/v3/test_volume_backup.py @@ -333,6 +333,7 @@ class TestBackupList(volume_fakes.TestVolume): 'Status', 'Size', 'Incremental', + 'Created At', ) columns_long = columns + ( 'Availability Zone', @@ -350,6 +351,7 @@ class TestBackupList(volume_fakes.TestVolume): b.status, b.size, b.is_incremental, + b.created_at, ) ) data_long = [] @@ -362,6 +364,7 @@ class TestBackupList(volume_fakes.TestVolume): b.status, b.size, b.is_incremental, + b.created_at, b.availability_zone, volume_backup.VolumeIdColumn(b.volume_id), b.container, @@ -459,16 +462,28 @@ class TestBackupRestore(volume_fakes.TestVolume): attrs={'volume_id': volume.id}, ) + columns = ( + "id", + "volume_id", + "volume_name", + ) + + data = ( + backup.id, + volume.id, + volume.name, + ) + def setUp(self): super().setUp() self.volume_sdk_client.find_backup.return_value = self.backup self.volume_sdk_client.find_volume.return_value = self.volume - self.volume_sdk_client.restore_backup.return_value = ( - volume_fakes.create_one_volume( - {'id': self.volume['id']}, - ) - ) + self.volume_sdk_client.restore_backup.return_value = { + 'id': self.backup['id'], + 'volume_id': self.volume['id'], + 'volume_name': self.volume['name'], + } # Get the command object to mock self.cmd = volume_backup.RestoreVolumeBackup(self.app, None) @@ -484,13 +499,15 @@ class TestBackupRestore(volume_fakes.TestVolume): ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - result = self.cmd.take_action(parsed_args) + columns, data = self.cmd.take_action(parsed_args) self.volume_sdk_client.restore_backup.assert_called_with( self.backup.id, volume_id=None, name=None, ) - self.assertIsNotNone(result) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) def test_backup_restore_with_volume(self): self.volume_sdk_client.find_volume.side_effect = ( @@ -506,13 +523,15 @@ class TestBackupRestore(volume_fakes.TestVolume): ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - result = self.cmd.take_action(parsed_args) + columns, data = self.cmd.take_action(parsed_args) self.volume_sdk_client.restore_backup.assert_called_with( self.backup.id, volume_id=None, name=self.backup.volume_id, ) - self.assertIsNotNone(result) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) def test_backup_restore_with_volume_force(self): arglist = [ @@ -527,13 +546,15 @@ class TestBackupRestore(volume_fakes.TestVolume): ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - result = self.cmd.take_action(parsed_args) + columns, data = self.cmd.take_action(parsed_args) self.volume_sdk_client.restore_backup.assert_called_with( self.backup.id, volume_id=self.volume.id, name=None, ) - self.assertIsNotNone(result) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) def test_backup_restore_with_volume_existing(self): arglist = [ @@ -876,7 +897,7 @@ class TestBackupShow(volume_fakes.TestVolume): def setUp(self): super().setUp() - self.volume_sdk_client.get_backup.return_value = self.backup + self.volume_sdk_client.find_backup.return_value = self.backup # Get the command object to test self.cmd = volume_backup.ShowVolumeBackup(self.app, None) @@ -886,7 +907,7 @@ class TestBackupShow(volume_fakes.TestVolume): parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) - self.volume_sdk_client.get_backup.assert_called_with(self.backup.id) + self.volume_sdk_client.find_backup.assert_called_with(self.backup.id) self.assertEqual(self.columns, columns) self.assertEqual(self.data, data) diff --git a/openstackclient/volume/v2/volume_backup.py b/openstackclient/volume/v2/volume_backup.py index fd59c0c..3c7b42e 100644 --- a/openstackclient/volume/v2/volume_backup.py +++ b/openstackclient/volume/v2/volume_backup.py @@ -359,6 +359,12 @@ class RestoreVolumeBackup(command.ShowOne): ignore_missing=False, ) + columns = ( + 'id', + 'volume_id', + 'volume_name', + ) + volume_name = None volume_id = None try: @@ -378,12 +384,15 @@ class RestoreVolumeBackup(command.ShowOne): ) raise exceptions.CommandError(msg % parsed_args.volume) - return volume_client.restore_backup( + restore = volume_client.restore_backup( backup.id, volume_id=volume_id, name=volume_name, ) + data = utils.get_dict_properties(restore, columns) + return (columns, data) + class SetVolumeBackup(command.Command): _description = _("Set volume backup properties") @@ -439,7 +448,7 @@ class ShowVolumeBackup(command.ShowOne): def take_action(self, parsed_args): volume_client = self.app.client_manager.sdk_connection.volume - backup = volume_client.get_backup(parsed_args.backup) + backup = volume_client.find_backup(parsed_args.backup) columns = ( "availability_zone", "container", diff --git a/openstackclient/volume/v3/volume_backup.py b/openstackclient/volume/v3/volume_backup.py index 471b4ce..dce5646 100644 --- a/openstackclient/volume/v3/volume_backup.py +++ b/openstackclient/volume/v3/volume_backup.py @@ -305,6 +305,7 @@ class ListVolumeBackup(command.Lister): 'status', 'size', 'is_incremental', + 'created_at', ) column_headers = ( 'ID', @@ -313,6 +314,7 @@ class ListVolumeBackup(command.Lister): 'Status', 'Size', 'Incremental', + 'Created At', ) if parsed_args.long: columns += ('availability_zone', 'volume_id', 'container') @@ -410,6 +412,12 @@ class RestoreVolumeBackup(command.ShowOne): def take_action(self, parsed_args): volume_client = self.app.client_manager.sdk_connection.volume + columns = ( + 'id', + 'volume_id', + 'volume_name', + ) + backup = volume_client.find_backup( parsed_args.backup, ignore_missing=False, @@ -434,12 +442,15 @@ class RestoreVolumeBackup(command.ShowOne): ) raise exceptions.CommandError(msg % parsed_args.volume) - return volume_client.restore_backup( + restore = volume_client.restore_backup( backup.id, volume_id=volume_id, name=volume_name, ) + data = utils.get_dict_properties(restore, columns) + return (columns, data) + class SetVolumeBackup(command.Command): _description = _("Set volume backup properties") @@ -643,7 +654,7 @@ class ShowVolumeBackup(command.ShowOne): def take_action(self, parsed_args): volume_client = self.app.client_manager.sdk_connection.volume - backup = volume_client.get_backup(parsed_args.backup) + backup = volume_client.find_backup(parsed_args.backup) columns = ( "availability_zone", "container", diff --git a/python_openstackclient.egg-info/PKG-INFO b/python_openstackclient.egg-info/PKG-INFO index 5b0b4cc..619eb75 100644 --- a/python_openstackclient.egg-info/PKG-INFO +++ b/python_openstackclient.egg-info/PKG-INFO @@ -1,152 +1,10 @@ -Metadata-Version: 1.2 +Metadata-Version: 2.1 Name: python-openstackclient -Version: 7.2.1 +Version: 7.4.0 Summary: OpenStack Command-line Client Home-page: https://docs.openstack.org/python-openstackclient/latest/ Author: OpenStack Author-email: openstack-discuss@lists.openstack.org -License: UNKNOWN -Description: ======================== - Team and repository tags - ======================== - - .. image:: https://governance.openstack.org/tc/badges/python-openstackclient.svg - :target: https://governance.openstack.org/tc/reference/tags/index.html - - .. Change things from this point on - - =============== - OpenStackClient - =============== - - .. image:: https://img.shields.io/pypi/v/python-openstackclient.svg - :target: https://pypi.org/project/python-openstackclient/ - :alt: Latest Version - - OpenStackClient (aka OSC) is a command-line client for OpenStack that brings - the command set for Compute, Identity, Image, Network, Object Store and Block - Storage APIs together in a single shell with a uniform command structure. - - The primary goal is to provide a unified shell command structure and a common - language to describe operations in OpenStack. - - * `PyPi`_ - package installation - * `Online Documentation`_ - * `Launchpad project`_ - bugs and feature requests - * `Blueprints`_ - feature specifications (historical only) - * `Source`_ - * `Developer`_ - getting started as a developer - * `Contributing`_ - contributing code - * `Testing`_ - testing code - * IRC: #openstack-sdks on OFTC (irc.oftc.net) - * License: Apache 2.0 - - .. _PyPi: https://pypi.org/project/python-openstackclient - .. _Online Documentation: https://docs.openstack.org/python-openstackclient/latest/ - .. _Blueprints: https://blueprints.launchpad.net/python-openstackclient - .. _`Launchpad project`: https://bugs.launchpad.net/python-openstackclient - .. _Source: https://opendev.org/openstack/python-openstackclient - .. _Developer: https://docs.openstack.org/project-team-guide/project-setup/python.html - .. _Contributing: https://docs.openstack.org/infra/manual/developers.html - .. _Testing: https://docs.openstack.org/python-openstackclient/latest/contributor/developing.html#testing - .. _Release Notes: https://docs.openstack.org/releasenotes/python-openstackclient - - Getting Started - =============== - - OpenStack Client can be installed from PyPI using pip:: - - pip install python-openstackclient - - There are a few variants on getting help. A list of global options and supported - commands is shown with ``--help``:: - - openstack --help - - There is also a ``help`` command that can be used to get help text for a specific - command:: - - openstack help - openstack help server create - - If you want to make changes to the OpenStackClient for testing and contribution, - make any changes and then run:: - - python setup.py develop - - or:: - - pip install -e . - - Configuration - ============= - - The CLI is configured via environment variables and command-line - options as listed in https://docs.openstack.org/python-openstackclient/latest/cli/authentication.html. - - Authentication using username/password is most commonly used: - - - For a local user, your configuration will look like the one below:: - - export OS_AUTH_URL=<url-to-openstack-identity> - export OS_IDENTITY_API_VERSION=3 - export OS_PROJECT_NAME=<project-name> - export OS_PROJECT_DOMAIN_NAME=<project-domain-name> - export OS_USERNAME=<username> - export OS_USER_DOMAIN_NAME=<user-domain-name> - export OS_PASSWORD=<password> # (optional) - - The corresponding command-line options look very similar:: - - --os-auth-url <url> - --os-identity-api-version 3 - --os-project-name <project-name> - --os-project-domain-name <project-domain-name> - --os-username <username> - --os-user-domain-name <user-domain-name> - [--os-password <password>] - - - For a federated user, your configuration will look the so:: - - export OS_PROJECT_NAME=<project-name> - export OS_PROJECT_DOMAIN_NAME=<project-domain-name> - export OS_AUTH_URL=<url-to-openstack-identity> - export OS_IDENTITY_API_VERSION=3 - export OS_AUTH_PLUGIN=openid - export OS_AUTH_TYPE=v3oidcpassword - export OS_USERNAME=<username-in-idp> - export OS_PASSWORD=<password-in-idp> - export OS_IDENTITY_PROVIDER=<the-desired-idp-in-keystone> - export OS_CLIENT_ID=<the-client-id-configured-in-the-idp> - export OS_CLIENT_SECRET=<the-client-secred-configured-in-the-idp> - export OS_OPENID_SCOPE=<the-scopes-of-desired-attributes-to-claim-from-idp> - export OS_PROTOCOL=<the-protocol-used-in-the-apache2-oidc-proxy> - export OS_ACCESS_TOKEN_TYPE=<the-access-token-type-used-by-your-idp> - export OS_DISCOVERY_ENDPOINT=<the-well-known-endpoint-of-the-idp> - - The corresponding command-line options look very similar:: - - --os-project-name <project-name> - --os-project-domain-name <project-domain-name> - --os-auth-url <url-to-openstack-identity> - --os-identity-api-version 3 - --os-auth-plugin openid - --os-auth-type v3oidcpassword - --os-username <username-in-idp> - --os-password <password-in-idp> - --os-identity-provider <the-desired-idp-in-keystone> - --os-client-id <the-client-id-configured-in-the-idp> - --os-client-secret <the-client-secred-configured-in-the-idp> - --os-openid-scope <the-scopes-of-desired-attributes-to-claim-from-idp> - --os-protocol <the-protocol-used-in-the-apache2-oidc-proxy> - --os-access-token-type <the-access-token-type-used-by-your-idp> - --os-discovery-endpoint <the-well-known-endpoint-of-the-idp> - - If a password is not provided above (in plaintext), you will be interactively - prompted to provide one securely. - - -Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators @@ -159,3 +17,155 @@ Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Requires-Python: >=3.9 +License-File: LICENSE +Requires-Dist: pbr!=2.1.0,>=2.0.0 +Requires-Dist: cryptography>=2.7 +Requires-Dist: cliff>=3.5.0 +Requires-Dist: iso8601>=0.1.11 +Requires-Dist: openstacksdk>=3.3.0 +Requires-Dist: osc-lib>=2.3.0 +Requires-Dist: oslo.i18n>=3.15.3 +Requires-Dist: python-keystoneclient>=3.22.0 +Requires-Dist: python-cinderclient>=3.3.0 +Requires-Dist: requests>=2.27.0 +Requires-Dist: stevedore>=2.0.1 + +======================== +Team and repository tags +======================== + +.. image:: https://governance.openstack.org/tc/badges/python-openstackclient.svg + :target: https://governance.openstack.org/tc/reference/tags/index.html + +.. Change things from this point on + +=============== +OpenStackClient +=============== + +.. image:: https://img.shields.io/pypi/v/python-openstackclient.svg + :target: https://pypi.org/project/python-openstackclient/ + :alt: Latest Version + +OpenStackClient (aka OSC) is a command-line client for OpenStack that brings +the command set for Compute, Identity, Image, Network, Object Store and Block +Storage APIs together in a single shell with a uniform command structure. + +The primary goal is to provide a unified shell command structure and a common +language to describe operations in OpenStack. + +* `PyPi`_ - package installation +* `Online Documentation`_ +* `Launchpad project`_ - bugs and feature requests +* `Blueprints`_ - feature specifications (historical only) +* `Source`_ +* `Developer`_ - getting started as a developer +* `Contributing`_ - contributing code +* `Testing`_ - testing code +* IRC: #openstack-sdks on OFTC (irc.oftc.net) +* License: Apache 2.0 + +.. _PyPi: https://pypi.org/project/python-openstackclient +.. _Online Documentation: https://docs.openstack.org/python-openstackclient/latest/ +.. _Blueprints: https://blueprints.launchpad.net/python-openstackclient +.. _`Launchpad project`: https://bugs.launchpad.net/python-openstackclient +.. _Source: https://opendev.org/openstack/python-openstackclient +.. _Developer: https://docs.openstack.org/project-team-guide/project-setup/python.html +.. _Contributing: https://docs.openstack.org/infra/manual/developers.html +.. _Testing: https://docs.openstack.org/python-openstackclient/latest/contributor/developing.html#testing +.. _Release Notes: https://docs.openstack.org/releasenotes/python-openstackclient + +Getting Started +=============== + +OpenStack Client can be installed from PyPI using pip:: + + pip install python-openstackclient + +There are a few variants on getting help. A list of global options and supported +commands is shown with ``--help``:: + + openstack --help + +There is also a ``help`` command that can be used to get help text for a specific +command:: + + openstack help + openstack help server create + +If you want to make changes to the OpenStackClient for testing and contribution, +make any changes and then run:: + + python setup.py develop + +or:: + + pip install -e . + +Configuration +============= + +The CLI is configured via environment variables and command-line +options as listed in https://docs.openstack.org/python-openstackclient/latest/cli/authentication.html. + +Authentication using username/password is most commonly used: + +- For a local user, your configuration will look like the one below:: + + export OS_AUTH_URL=<url-to-openstack-identity> + export OS_IDENTITY_API_VERSION=3 + export OS_PROJECT_NAME=<project-name> + export OS_PROJECT_DOMAIN_NAME=<project-domain-name> + export OS_USERNAME=<username> + export OS_USER_DOMAIN_NAME=<user-domain-name> + export OS_PASSWORD=<password> # (optional) + + The corresponding command-line options look very similar:: + + --os-auth-url <url> + --os-identity-api-version 3 + --os-project-name <project-name> + --os-project-domain-name <project-domain-name> + --os-username <username> + --os-user-domain-name <user-domain-name> + [--os-password <password>] + +- For a federated user, your configuration will look the so:: + + export OS_PROJECT_NAME=<project-name> + export OS_PROJECT_DOMAIN_NAME=<project-domain-name> + export OS_AUTH_URL=<url-to-openstack-identity> + export OS_IDENTITY_API_VERSION=3 + export OS_AUTH_PLUGIN=openid + export OS_AUTH_TYPE=v3oidcpassword + export OS_USERNAME=<username-in-idp> + export OS_PASSWORD=<password-in-idp> + export OS_IDENTITY_PROVIDER=<the-desired-idp-in-keystone> + export OS_CLIENT_ID=<the-client-id-configured-in-the-idp> + export OS_CLIENT_SECRET=<the-client-secred-configured-in-the-idp> + export OS_OPENID_SCOPE=<the-scopes-of-desired-attributes-to-claim-from-idp> + export OS_PROTOCOL=<the-protocol-used-in-the-apache2-oidc-proxy> + export OS_ACCESS_TOKEN_TYPE=<the-access-token-type-used-by-your-idp> + export OS_DISCOVERY_ENDPOINT=<the-well-known-endpoint-of-the-idp> + + The corresponding command-line options look very similar:: + + --os-project-name <project-name> + --os-project-domain-name <project-domain-name> + --os-auth-url <url-to-openstack-identity> + --os-identity-api-version 3 + --os-auth-plugin openid + --os-auth-type v3oidcpassword + --os-username <username-in-idp> + --os-password <password-in-idp> + --os-identity-provider <the-desired-idp-in-keystone> + --os-client-id <the-client-id-configured-in-the-idp> + --os-client-secret <the-client-secred-configured-in-the-idp> + --os-openid-scope <the-scopes-of-desired-attributes-to-claim-from-idp> + --os-protocol <the-protocol-used-in-the-apache2-oidc-proxy> + --os-access-token-type <the-access-token-type-used-by-your-idp> + --os-discovery-endpoint <the-well-known-endpoint-of-the-idp> + +If a password is not provided above (in plaintext), you will be interactively +prompted to provide one securely. + diff --git a/python_openstackclient.egg-info/SOURCES.txt b/python_openstackclient.egg-info/SOURCES.txt index 62b5bf9..85e7038 100644 --- a/python_openstackclient.egg-info/SOURCES.txt +++ b/python_openstackclient.egg-info/SOURCES.txt @@ -712,6 +712,7 @@ python_openstackclient.egg-info/requires.txt python_openstackclient.egg-info/top_level.txt releasenotes/notes/.placeholder releasenotes/notes/Add-default-security-group-rule-CRUD-2916568f829ea38c.yaml +releasenotes/notes/Add-trusted-vif-to-the-port-0a0c76d9da8f3da0.yaml releasenotes/notes/L3-conntrack-helper-bd0d9da041747e84.yaml releasenotes/notes/Router-flavor-accepts-name-or-id-e9cecafcddf81cb2.yaml releasenotes/notes/add-auto-and-none-as-nic-parameter-ed23a6e7f99f250d.yaml @@ -830,6 +831,7 @@ releasenotes/notes/add-tag-support-server-add-port-7e30aa38202d0839.yaml releasenotes/notes/add-tag-support-server-add-volume-278e79a22dd482f4.yaml releasenotes/notes/add-trusted-certs-option-server-create-a660488407300f22.yaml releasenotes/notes/add-virtio-forwarder-vnic-type-bad939c6a868b9e9.yaml +releasenotes/notes/add-vlan_qinq-to-the-network-3556c094aeedc0de.yaml releasenotes/notes/add-vol-service-get-set-log-commands-f9420e5061d994b5.yaml releasenotes/notes/add-volume-attachment-commands-db2974c6460fa3bc.yaml releasenotes/notes/add-volume-group-commands-b121d6ec7da9779a.yaml @@ -1191,6 +1193,8 @@ releasenotes/notes/fix-flavor-props-formatting-d21e97745543caa7.yaml releasenotes/notes/fix-image-create-from-volume-c573e553161605c4.yaml releasenotes/notes/fix-network-rbac-create-d1f4de77ad2dd421.yaml releasenotes/notes/fix-openstak-image-save-sdk-port-eb160e8ffc92e514.yaml +releasenotes/notes/fix-restore-resp-e664a643a723cd2e.yaml +releasenotes/notes/fix-show-backup-by-name-0759c55396be77a3.yaml releasenotes/notes/fix-story-2007890-0974f3e69f26801e.yaml releasenotes/notes/fix-story-2010775-953dbdf03b2b6746.yaml releasenotes/notes/flavor-add-description-b618abd4a7fb6545.yaml @@ -1229,9 +1233,11 @@ releasenotes/notes/migrate-agent-commands-1c50ffcb75f91418.yaml releasenotes/notes/migrate-application-credential-to-sdk-c79d8dfc3c8e1d9f.yaml releasenotes/notes/migrate-backup-commands-0becc8f18cf9737b.yaml releasenotes/notes/migrate-create-server-image-to-sdk-e3d8077ffe05bb3d.yaml +releasenotes/notes/migrate-credential-to-sdk-33a841847fe7d568.yaml releasenotes/notes/migrate-host-list-show-to-sdk-9b80cd9b4196ab01.yaml releasenotes/notes/migrate-host-set-438997eb6f81f2b1.yaml releasenotes/notes/migrate-limits-show-f586c9762dfd7d0c.yaml +releasenotes/notes/migrate-region-to-sdk-fbd27bceaa1db9dc.yaml releasenotes/notes/migrate-resource-filter-commands-2a353edb965723d1.yaml releasenotes/notes/migrate-role-assignment-to-sdk-e6e52bef467b4e4c.yaml releasenotes/notes/migrate-server-add-network-add-port-to-sdk-7d81b25f59cfbec9.yaml @@ -1248,7 +1254,9 @@ releasenotes/notes/migrate-server-start-stop-to-sdk-55edd4e1ff5e6ac7.yaml releasenotes/notes/migrate-server-suspend-resume-to-sdk-fd1709336607b496.yaml releasenotes/notes/migrate-server-volume-list-update-to-sdk-95b1d3063e46f813.yaml releasenotes/notes/migrate-service-list-delete-set-to-sdk-920cbe0d210af565.yaml +releasenotes/notes/migrate-service-provider-to-sdk-74dc48b227f21a05.yaml releasenotes/notes/migrate-service-to-sdk-6ff62ebf7e41db7c.yaml +releasenotes/notes/migrate-trust-to-sdk-9397c9cfddcb636a.yaml releasenotes/notes/migrate-volume-attachment-commands-4309409bca1ca5d4.yaml releasenotes/notes/migrate-volume-backend-commands-259e553e213c71b0.yaml releasenotes/notes/migrate-volume-revert-to-sdk-1e399853d80ba5f8.yaml @@ -1279,6 +1287,7 @@ releasenotes/notes/osc4-volume-470422e5a453310e.yaml releasenotes/notes/pass_ssh_args-cf26a2ce26ccddaf.yaml releasenotes/notes/port-device-profile-4a3bf800da21c778.yaml releasenotes/notes/port-list-security-group-4af5d2e789174ff9.yaml +releasenotes/notes/port_uplink_status_propagation_updatable-d1e155c19247b666.yaml releasenotes/notes/project-cleanup-skip-resource-option-4f80db0d8cf36fdb.yaml releasenotes/notes/properties-with-image-property-field.yaml-c51bf37c3106d6ff.yaml releasenotes/notes/qos-min-pps-rule-bfe22cea1966c4a0.yaml @@ -1313,6 +1322,7 @@ releasenotes/notes/router-subnet-469d095ae0bac884.yaml releasenotes/notes/security-grp-json-fix.yaml-2af1f48a48034d64.yaml releasenotes/notes/server-add-tag-63f9cd01dbd82d1b.yaml releasenotes/notes/server-changes-3962541b6ebdbbd8.yaml +releasenotes/notes/server-create-no-security-group-option-627697bddae429b1.yaml releasenotes/notes/server-create-server-group-a5b630f2a64de28d.yaml releasenotes/notes/server-description-ae9618fc09544cac.yaml releasenotes/notes/server-group-create_rule_option-9f84e52f35e7c3ba.yaml @@ -1368,6 +1378,7 @@ releasenotes/notes/use_sdk_for_image-f49d2df38e7d9f81.yaml releasenotes/notes/versions-show-12a2443624c83048.yaml releasenotes/notes/volume-attachment-create-output-fix-56515b8fcdd260b9.yaml releasenotes/notes/volume-backend-c5faae0b31556a24.yaml +releasenotes/notes/volume-backup-created-at-list-v3-47400b31be5143bc.yaml releasenotes/notes/volume-backup-record-9f5987c45e294dc6.yaml releasenotes/notes/volume-migrate-command-52cf6edd62fe17a7.yaml releasenotes/notes/volume-type-extra-specs-22a22fcb6e269832.yaml diff --git a/python_openstackclient.egg-info/entry_points.txt b/python_openstackclient.egg-info/entry_points.txt index 630118f..45d6347 100644 --- a/python_openstackclient.egg-info/entry_points.txt +++ b/python_openstackclient.egg-info/entry_points.txt @@ -715,4 +715,3 @@ volume_type_set = openstackclient.volume.v3.volume_type:SetVolumeType volume_type_show = openstackclient.volume.v3.volume_type:ShowVolumeType volume_type_unset = openstackclient.volume.v3.volume_type:UnsetVolumeType volume_unset = openstackclient.volume.v3.volume:UnsetVolume - diff --git a/python_openstackclient.egg-info/pbr.json b/python_openstackclient.egg-info/pbr.json index c62adec..4bf5247 100644 --- a/python_openstackclient.egg-info/pbr.json +++ b/python_openstackclient.egg-info/pbr.json @@ -1 +1 @@ -{"git_version": "7c6b47b4", "is_release": true}
\ No newline at end of file +{"git_version": "4b7e32ca", "is_release": true}
\ No newline at end of file diff --git a/python_openstackclient.egg-info/requires.txt b/python_openstackclient.egg-info/requires.txt index b79129e..66146e4 100644 --- a/python_openstackclient.egg-info/requires.txt +++ b/python_openstackclient.egg-info/requires.txt @@ -1,11 +1,11 @@ -cliff>=3.5.0 +pbr!=2.1.0,>=2.0.0 cryptography>=2.7 +cliff>=3.5.0 iso8601>=0.1.11 openstacksdk>=3.3.0 osc-lib>=2.3.0 oslo.i18n>=3.15.3 -pbr!=2.1.0,>=2.0.0 -python-cinderclient>=3.3.0 python-keystoneclient>=3.22.0 +python-cinderclient>=3.3.0 requests>=2.27.0 stevedore>=2.0.1 diff --git a/releasenotes/notes/Add-trusted-vif-to-the-port-0a0c76d9da8f3da0.yaml b/releasenotes/notes/Add-trusted-vif-to-the-port-0a0c76d9da8f3da0.yaml new file mode 100644 index 0000000..ffa9669 --- /dev/null +++ b/releasenotes/notes/Add-trusted-vif-to-the-port-0a0c76d9da8f3da0.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + Add ``trusted`` attribute to the ``port create`` and ``port set`` commands. + It can be set to ``true`` with ``--trusted`` and to ``false`` with + ``--not-trusted`` CLI arguments passed to the ``port create`` and ``port + set`` commands`` diff --git a/releasenotes/notes/add-vlan_qinq-to-the-network-3556c094aeedc0de.yaml b/releasenotes/notes/add-vlan_qinq-to-the-network-3556c094aeedc0de.yaml new file mode 100644 index 0000000..f89575b --- /dev/null +++ b/releasenotes/notes/add-vlan_qinq-to-the-network-3556c094aeedc0de.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + Add ``qinq-vlan`` and ``no-qinq-vlan`` arguments to the ``network create`` + command. It will enable/disable QinQ feature for the created network. + This new argument is mutually exclusive with the ``transparent-vlan`` - only + one of them can be set to ``True`` for the network. diff --git a/releasenotes/notes/fix-restore-resp-e664a643a723cd2e.yaml b/releasenotes/notes/fix-restore-resp-e664a643a723cd2e.yaml new file mode 100644 index 0000000..2ee8f21 --- /dev/null +++ b/releasenotes/notes/fix-restore-resp-e664a643a723cd2e.yaml @@ -0,0 +1,4 @@ +--- +fixes: + - | + Fixed the output of ``volume backup restore`` command. diff --git a/releasenotes/notes/fix-show-backup-by-name-0759c55396be77a3.yaml b/releasenotes/notes/fix-show-backup-by-name-0759c55396be77a3.yaml new file mode 100644 index 0000000..7ed9d72 --- /dev/null +++ b/releasenotes/notes/fix-show-backup-by-name-0759c55396be77a3.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fixed the ``openstack volume backup show`` command + to show a backup by name. diff --git a/releasenotes/notes/migrate-credential-to-sdk-33a841847fe7d568.yaml b/releasenotes/notes/migrate-credential-to-sdk-33a841847fe7d568.yaml new file mode 100644 index 0000000..e830012 --- /dev/null +++ b/releasenotes/notes/migrate-credential-to-sdk-33a841847fe7d568.yaml @@ -0,0 +1,10 @@ +--- +upgrade: + - | + The following commands have been migrated to SDK: + + - ``credential create`` + - ``credential delete`` + - ``credential list`` + - ``credential set`` + - ``credential show`` diff --git a/releasenotes/notes/migrate-region-to-sdk-fbd27bceaa1db9dc.yaml b/releasenotes/notes/migrate-region-to-sdk-fbd27bceaa1db9dc.yaml new file mode 100644 index 0000000..31a5e6d --- /dev/null +++ b/releasenotes/notes/migrate-region-to-sdk-fbd27bceaa1db9dc.yaml @@ -0,0 +1,10 @@ +--- +upgrade: + - | + The following commands have been migrated to SDK: + + - ``region create`` + - ``region list`` + - ``region delete`` + - ``region set`` + - ``region show`` diff --git a/releasenotes/notes/migrate-service-provider-to-sdk-74dc48b227f21a05.yaml b/releasenotes/notes/migrate-service-provider-to-sdk-74dc48b227f21a05.yaml new file mode 100644 index 0000000..d9914cf --- /dev/null +++ b/releasenotes/notes/migrate-service-provider-to-sdk-74dc48b227f21a05.yaml @@ -0,0 +1,10 @@ +--- +upgrade: + - | + The following commands have been migrated to SDK: + + - ``service provider create`` + - ``service provider delete`` + - ``service provider set`` + - ``service provider list`` + - ``service provider show`` diff --git a/releasenotes/notes/migrate-trust-to-sdk-9397c9cfddcb636a.yaml b/releasenotes/notes/migrate-trust-to-sdk-9397c9cfddcb636a.yaml new file mode 100644 index 0000000..e45218f --- /dev/null +++ b/releasenotes/notes/migrate-trust-to-sdk-9397c9cfddcb636a.yaml @@ -0,0 +1,9 @@ +--- +upgrade: + - | + The following commands have been migrated to SDK: + + - ``trust create`` + - ``trust list`` + - ``trust delete`` + - ``trust show`` diff --git a/releasenotes/notes/port_uplink_status_propagation_updatable-d1e155c19247b666.yaml b/releasenotes/notes/port_uplink_status_propagation_updatable-d1e155c19247b666.yaml new file mode 100644 index 0000000..0e7b776 --- /dev/null +++ b/releasenotes/notes/port_uplink_status_propagation_updatable-d1e155c19247b666.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Add ``--enable-uplink-status-propagation`` option and + ``--disable-uplink-status-propagation`` option to ``port update`` command. diff --git a/releasenotes/notes/server-create-no-security-group-option-627697bddae429b1.yaml b/releasenotes/notes/server-create-no-security-group-option-627697bddae429b1.yaml new file mode 100644 index 0000000..b2169d3 --- /dev/null +++ b/releasenotes/notes/server-create-no-security-group-option-627697bddae429b1.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + The ``server create`` command now supports a ``--no-security-group`` + option. When provided, no security groups will be associated with ports + created and attached to the server during server creation. This does not + affect pre-created ports. diff --git a/releasenotes/notes/volume-backup-created-at-list-v3-47400b31be5143bc.yaml b/releasenotes/notes/volume-backup-created-at-list-v3-47400b31be5143bc.yaml new file mode 100644 index 0000000..88aa714 --- /dev/null +++ b/releasenotes/notes/volume-backup-created-at-list-v3-47400b31be5143bc.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Listing volume backups now shows the created_at column when + volume v3 API is used. diff --git a/releasenotes/source/2023.1.rst b/releasenotes/source/2023.1.rst index d123847..2c9a36f 100644 --- a/releasenotes/source/2023.1.rst +++ b/releasenotes/source/2023.1.rst @@ -3,4 +3,4 @@ =========================== .. release-notes:: - :branch: stable/2023.1 + :branch: unmaintained/2023.1 diff --git a/test-requirements.txt b/test-requirements.txt index 275c2ff..c9c1b28 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,7 +1,5 @@ coverage!=4.4,>=4.0 # Apache-2.0 fixtures>=3.0.0 # Apache-2.0/BSD -oslotest>=3.2.0 # Apache-2.0 -requests>=2.14.2 # Apache-2.0 requests-mock>=1.2.0 # Apache-2.0 stestr>=1.0.0 # Apache-2.0 testtools>=2.2.0 # MIT |
