diff options
| author | Corey Bryant <corey.bryant@canonical.com> | 2016-03-01 14:20:39 -0500 |
|---|---|---|
| committer | git-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com> | 2016-03-01 19:45:09 +0000 |
| commit | ba815ad57e1f5a7b71261c4a7b8bee142c75b5db (patch) | |
| tree | 1def0d24a7ba397c9e4538a3c4ee9a6a65c364ef | |
| parent | 52574c696d01ea4b4eb469dce0b01dcb7e7ca8c2 (diff) | |
| parent | 1fed399182555cb88ec582a864a480e278ecc52f (diff) | |
2.1.0-0ubuntu1 (patches applied)applied/2.1.0-0ubuntu1
Imported using git-ubuntu import.
202 files changed, 6780 insertions, 4865 deletions
diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index aeabc0d..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,14 +0,0 @@ -include AUTHORS -include babel.cfg -include ChangeLog -include LICENSE -include README.rst - -recursive-include doc * -recursive-include tests * -recursive-include python-openstackclient *.po *.pot - -exclude .gitignore -exclude .gitreview - -global-exclude *.pyc @@ -11,8 +11,8 @@ OpenStackClient :alt: Downloads OpenStackClient (aka OSC) is a command-line client for OpenStack that brings -the command set for Compute, Identity, Image, Object Store and Volume APIs -together in a single shell with a uniform command structure. +the command set for Compute, Identity, Image, 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. diff --git a/debian/changelog b/debian/changelog index 6932dbf..46771e7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +python-openstackclient (2.1.0-0ubuntu1) xenial; urgency=medium + + * New upstream release. + * Align (Build-)Depends with upstream. + + -- Corey Bryant <corey.bryant@canonical.com> Tue, 01 Mar 2016 14:20:39 -0500 + python-openstackclient (2.0.0-3) experimental; urgency=medium * Blacklist 3 failed unit tests in Jessie (works in Sid): diff --git a/debian/control b/debian/control index 40d806e..a9cd36e 100644 --- a/debian/control +++ b/debian/control @@ -1,7 +1,8 @@ Source: python-openstackclient Section: python Priority: optional -Maintainer: PKG OpenStack <openstack-devel@lists.alioth.debian.org> +Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com> +XSBC-Original-Maintainer: PKG OpenStack <openstack-devel@lists.alioth.debian.org> Uploaders: gustavo panizzo <gfa@zumbi.com.ar>, Thomas Goirand <zigo@debian.org>, Build-Depends: debhelper (>= 9), @@ -23,10 +24,10 @@ Build-Depends-Indep: python-babel, python-crypto, python-designateclient (>= 1.5.0), python-fixtures (>= 1.3.1), - python-glanceclient (>= 1:0.18.0), + python-glanceclient (>= 1:1.2.0), python-hacking (>= 0.10.0), python-heatclient (>= 0.6.0), - python-ironicclient (>= 0.8.0), + python-ironicclient (>= 1.1.0), python-keyring, python-keystoneauth1 (>= 2.1.0), python-keystoneclient (>= 1:1.6.0), @@ -34,20 +35,21 @@ Build-Depends-Indep: python-babel, python-mock (>= 1.3), python-neutronclient (>= 1:2.6.0), python-novaclient (>= 2:2.30.0), - python-os-client-config (>= 1.4.0), + python-openstacksdk (>= 0.7.4), + python-os-client-config (>= 1.13.1), python-os-testr (>= 0.4.2), - python-oslo.config (>= 1:3.2.0), - python-oslo.i18n (>= 1.5.0), + python-oslo.config (>= 1:3.4.0), + python-oslo.i18n (>= 2.1.0), python-oslo.serialization (>= 1.2.0), - python-oslo.utils (>= 3.3.0), + python-oslo.utils (>= 3.4.0), python-oslosphinx (>= 2.5.0), python-oslotest (>= 1.10.0), python-requests (>= 2.8.1), - python-requests-mock (>= 0.6.0), + python-requests-mock (>= 0.7.0), python-saharaclient (>= 0.10.0), python-six (>= 1.9.0), python-stevedore (>= 1.5.0), - python-tempest-lib (>= 0.11.0), + python-tempest-lib (>= 0.13.0), python-testtools (>= 1.4.0), python-webob, python-zaqarclient (>= 0.3.0), @@ -57,26 +59,30 @@ Build-Depends-Indep: python-babel, python3-coverage, python3-crypto, python3-fixtures (>= 1.3.1), - python3-glanceclient (>= 1:0.18.0), + python3-glanceclient (>= 1:1.2.0), + python3-ironicclient (>= 1.1.0), python3-keyring, python3-keystoneauth1 (>= 2.1.0), python3-keystoneclient (>= 1:1.6.0), + python3-mistralclient (>= 1.0.0), python3-mock (>= 1.3), python3-neutronclient (>= 1:2.6.0), python3-novaclient (>= 2:2.30.0), - python3-os-client-config (>= 1.4.0), + python3-openstacksdk (>= 0.7.4), + python3-os-client-config (>= 1.13.1), python3-os-testr (>= 0.4.2), - python3-oslo.config (>= 1:3.2.0), - python3-oslo.i18n (>= 1.5.0), + python3-oslo.config (>= 1:3.4.0), + python3-oslo.i18n (>= 2.1.0), python3-oslo.serialization (>= 1.2.0), - python3-oslo.utils (>= 3.3.0), + python3-oslo.utils (>= 3.4.0), python3-oslotest (>= 1.10.0), python3-requests (>= 2.8.1), - python3-requests-mock (>= 0.6.0), + python3-requests-mock (>= 0.7.0), + python3-saharaclient (>= 0.10.0), python3-six (>= 1.9.0), python3-stevedore (>= 1.5.0), python3-subunit, - python3-tempest-lib (>= 0.11.0), + python3-tempest-lib (>= 0.13.0), python3-testtools (>= 1.4.0), python3-webob, subunit, @@ -92,17 +98,18 @@ Depends: python-babel, python-cinderclient (>= 1:1.3.1), python-cliff (>= 1.15.0), python-crypto, - python-glanceclient (>= 1:0.18.0), + python-glanceclient (>= 1:1.2.0), python-keyring, python-keystoneauth1 (>= 2.1.0), python-keystoneclient (>= 1:1.6.0), python-neutronclient (>= 1:2.6.0), python-novaclient (>= 2:2.30.0), - python-os-client-config (>= 1.4.0), - python-oslo.config (>= 1:3.2.0), - python-oslo.i18n (>= 1.5.0), + python-openstacksdk (>= 0.7.4), + python-os-client-config (>= 1.13.1), + python-oslo.config (>= 1:3.4.0), + python-oslo.i18n (>= 2.1.0), python-oslo.serialization (>= 1.2.0), - python-oslo.utils (>= 3.3.0), + python-oslo.utils (>= 3.4.0), python-pbr (>= 1.8), python-requests (>= 2.8.1), python-six (>= 1.9.0), @@ -129,17 +136,18 @@ Depends: python3-babel, python3-cinderclient (>= 1:1.3.1), python3-cliff (>= 1.15.0), python3-crypto, - python3-glanceclient (>= 1:0.18.0), + python3-glanceclient (>= 1:1.2.0), python3-keyring, python3-keystoneauth1 (>= 2.1.0), python3-keystoneclient (>= 1:1.6.0), python3-neutronclient (>= 1:2.6.0), python3-novaclient (>= 2:2.30.0), - python3-os-client-config (>= 1.4.0), - python3-oslo.config (>= 1:3.2.0), - python3-oslo.i18n (>= 1.5.0), + python3-openstacksdk (>= 0.7.4), + python3-os-client-config (>= 1.13.1), + python3-oslo.config (>= 1:3.4.0), + python3-oslo.i18n (>= 2.1.0), python3-oslo.serialization (>= 1.2.0), - python3-oslo.utils (>= 3.3.0), + python3-oslo.utils (>= 3.4.0), python3-pbr (>= 1.8), python3-requests (>= 2.8.1), python3-six (>= 1.9.0), diff --git a/doc/source/command-objects/availability-zone.rst b/doc/source/command-objects/availability-zone.rst index 3743523..1f56843 100644 --- a/doc/source/command-objects/availability-zone.rst +++ b/doc/source/command-objects/availability-zone.rst @@ -2,7 +2,7 @@ availability zone ================= -Compute v2 +Block Storage v2, Compute v2, Network v2 availability zone list ---------------------- @@ -13,8 +13,23 @@ List availability zones and their status .. code:: bash os availability zone list + [--compute] + [--network] + [--volume] [--long] +.. option:: --compute + + List compute availability zones + +.. option:: --network + + List network availability zones + +.. option:: --volume + + List volume availability zones + .. option:: --long List additional fields in output diff --git a/doc/source/command-objects/backup.rst b/doc/source/command-objects/backup.rst index ec201aa..9d7fb95 100644 --- a/doc/source/command-objects/backup.rst +++ b/doc/source/command-objects/backup.rst @@ -2,7 +2,7 @@ backup ====== -Volume v1 +Block Storage v1 backup create ------------- diff --git a/doc/source/command-objects/compute-service.rst b/doc/source/command-objects/compute-service.rst index 95a77bd..7bcab4d 100644 --- a/doc/source/command-objects/compute-service.rst +++ b/doc/source/command-objects/compute-service.rst @@ -57,7 +57,7 @@ Set service command .. _compute-service-set: .. describe:: --enable - Enable service + Enable service (default) .. describe:: --disable diff --git a/doc/source/command-objects/extension.rst b/doc/source/command-objects/extension.rst index 8f39a62..dff30fa 100644 --- a/doc/source/command-objects/extension.rst +++ b/doc/source/command-objects/extension.rst @@ -34,7 +34,7 @@ List API extensions .. option:: --volume - List extensions for the Volume API + List extensions for the Block Storage API .. option:: --long diff --git a/doc/source/command-objects/image.rst b/doc/source/command-objects/image.rst index d4b9916..61872ec 100644 --- a/doc/source/command-objects/image.rst +++ b/doc/source/command-objects/image.rst @@ -19,7 +19,6 @@ Create/upload an image [--store <store>] [--container-format <container-format>] [--disk-format <disk-format>] - [--owner <project>] [--size <size>] [--min-disk <disk-gb>] [--min-ram <ram-mb>] @@ -33,6 +32,7 @@ Create/upload an image [--public | --private] [--property <key=value> [...] ] [--tag <tag> [...] ] + [--project <project> [--project-domain <project-domain>]] <image-name> .. option:: --id <id> @@ -53,10 +53,6 @@ Create/upload an image Image disk format (default: raw) -.. option:: --owner <project> - - Image owner project name or ID - .. option:: --size <size> Image size, in bytes (only used with --location and --copy-from) @@ -127,6 +123,18 @@ Create/upload an image .. versionadded:: 2 +.. option:: --project <project> + + Set an alternate project on this image (name or ID). + Previously known as `--owner`. + +.. option:: --project-domain <project-domain> + + Domain the project belongs to (name or ID). + This can be used in case collisions between project names exist. + + .. versionadded:: 2 + .. describe:: <image-name> New image name @@ -159,6 +167,8 @@ List available images [--property <key=value>] [--long] [--sort <key>[:<direction>]] + [--limit <limit>] + [--marker <marker>] .. option:: --public @@ -187,6 +197,15 @@ List available images Sort output by selected keys and directions(asc or desc) (default: asc), multiple keys and directions can be specified separated by comma +.. option:: --limit <limit> + + Maximum number of images to display. + +.. option:: --marker <marker> + + The last image (name or ID) of the previous page. Display list of images + after marker. Display all images if not specified. + image save ---------- @@ -219,7 +238,6 @@ Set image properties os image set [--name <name>] - [--owner <project>] [--min-disk <disk-gb>] [--min-ram <disk-ram>] [--container-format <container-format>] @@ -243,16 +261,14 @@ Set image properties [--os-distro <os-distro>] [--os-version <os-version>] [--ramdisk-id <ramdisk-id>] + [--activate|--deactivate] + [--project <project> [--project-domain <project-domain>]] <image> .. option:: --name <name> New image name -.. option:: --owner <project> - - New image owner project (name or ID) - .. option:: --min-disk <disk-gb> Minimum disk size needed to boot image, in gigabytes @@ -387,6 +403,30 @@ Set image properties .. versionadded:: 2 +.. option:: --activate + + Activate the image. + + .. versionadded:: 2 + +.. option:: --deactivate + + Deactivate the image. + + .. versionadded:: 2 + +.. option:: --project <project> + + Set an alternate project on this image (name or ID). + Previously known as `--owner`. + +.. option:: --project-domain <project-domain> + + Domain the project belongs to (name or ID). + This can be used in case collisions between project names exist. + + .. versionadded:: 2 + .. describe:: <image> Image to modify (name or ID) diff --git a/doc/source/command-objects/limits.rst b/doc/source/command-objects/limits.rst index 0d466af..6a7509f 100644 --- a/doc/source/command-objects/limits.rst +++ b/doc/source/command-objects/limits.rst @@ -2,14 +2,14 @@ limits ====== -The Compute and Volume APIs have resource usage limits. +The Compute and Block Storage APIs have resource usage limits. -Compute v2, Volume v1 +Compute v2, Block Storage v1 limits show ----------- -Show compute and volume limits +Show compute and block storage limits .. program:: limits show .. code:: bash diff --git a/doc/source/command-objects/network.rst b/doc/source/command-objects/network.rst index 6b63c35..bb36667 100644 --- a/doc/source/command-objects/network.rst +++ b/doc/source/command-objects/network.rst @@ -16,6 +16,7 @@ Create new network [--project <project> [--project-domain <project-domain>]] [--enable | --disable] [--share | --no-share] + [--availability-zone-hint <availability-zone>] <name> .. option:: --project <project> @@ -43,6 +44,11 @@ Create new network Do not share the network between projects +.. option:: --availability-zone-hint <availability-zone> + + Availability Zone in which to create this network (requires the Network + Availability Zone extension, this option can be repeated). + .. _network_create-name: .. describe:: <name> @@ -59,10 +65,10 @@ Delete network(s) os network delete <network> [<network> ...] -.. _network_delete-project: +.. _network_delete-network: .. describe:: <network> - Network to delete (name or ID) + Network(s) to delete (name or ID) network list ------------ @@ -74,17 +80,12 @@ List networks os network list [--external] - [--dhcp <dhcp-id>] [--long] .. option:: --external List external networks -.. option:: --dhcp <dhcp-id> - - DHCP agent ID - .. option:: --long List additional fields in output @@ -123,7 +124,7 @@ Set network properties Do not share the network between projects -.. _network_set-name: +.. _network_set-network: .. describe:: <network> Network to modify (name or ID) @@ -139,7 +140,7 @@ Display network details os network show <network> -.. _network_show-name: +.. _network_show-network: .. describe:: <network> Network to display (name or ID) diff --git a/doc/source/command-objects/port.rst b/doc/source/command-objects/port.rst new file mode 100644 index 0000000..414b743 --- /dev/null +++ b/doc/source/command-objects/port.rst @@ -0,0 +1,37 @@ +==== +port +==== + +Network v2 + +port delete +----------- + +Delete port(s) + +.. program:: port delete +.. code:: bash + + os port delete + <port> [<port> ...] + +.. _port_delete-port: +.. describe:: <port> + + Port(s) to delete (name or ID) + +port show +--------- + +Display port details + +.. program:: port show +.. code:: bash + + os port show + <port> + +.. _port_show-port: +.. describe:: <port> + + Port to display (name or ID) diff --git a/doc/source/command-objects/project.rst b/doc/source/command-objects/project.rst index a342115..f76f79f 100644 --- a/doc/source/command-objects/project.rst +++ b/doc/source/command-objects/project.rst @@ -156,6 +156,8 @@ Set project properties Set a property on :ref:`\<project\> <project_set-project>` (repeat option to set multiple properties) + *Identity version 2 only* + .. _project_set-project: .. describe:: <project> @@ -195,3 +197,25 @@ Display project details .. describe:: <project> Project to display (name or ID) + +project unset +------------- + +Unset project properties + +*Identity version 2 only* + +.. program:: project unset +.. code:: bash + + os project unset + --property <key> [--property <key> ...] + <project> + +.. option:: --property <key> + + Property key to remove from project (repeat option to remove multiple properties) + +.. describe:: <project> + + Project to modify (name or ID) diff --git a/doc/source/command-objects/quota.rst b/doc/source/command-objects/quota.rst index 5ea49f8..98e6df3 100644 --- a/doc/source/command-objects/quota.rst +++ b/doc/source/command-objects/quota.rst @@ -4,7 +4,7 @@ quota Resource quotas appear in multiple APIs, OpenStackClient presents them as a single object with multiple properties. -Compute v2, Volume v1 +Compute v2, Block Storage v1 quota set --------- @@ -26,7 +26,7 @@ Set quotas for project [--properties <num-properties>] [--ram <ram-mb>] - # Volume settings + # Block Storage settings [--gigabytes <new-gigabytes>] [--snapshots <new-snapshots>] [--volumes <new-volumes>] @@ -51,7 +51,7 @@ Set quotas for class [--properties <num-properties>] [--ram <ram-mb>] - # Volume settings + # Block Storage settings [--gigabytes <new-gigabytes>] [--snapshots <new-snapshots>] [--volumes <new-volumes>] @@ -161,4 +161,4 @@ Show quotas for project .. _quota_show-class: .. describe:: <class> - Class to show
\ No newline at end of file + Class to show diff --git a/doc/source/command-objects/router.rst b/doc/source/command-objects/router.rst new file mode 100644 index 0000000..2a5bf05 --- /dev/null +++ b/doc/source/command-objects/router.rst @@ -0,0 +1,137 @@ +====== +router +====== + +Network v2 + +router create +------------- + +Create new router + +.. program:: router create +.. code:: bash + + os router create + [--project <project> [--project-domain <project-domain>]] + [--enable | --disable] + [--distributed] + [--availability-zone-hint <availability-zone>] + <name> + +.. option:: --project <project> + + Owner's project (name or ID) + +.. option:: --project-domain <project-domain> + + Domain the project belongs to (name or ID). + This can be used in case collisions between project names exist. + +.. option:: --enable + + Enable router (default) + +.. option:: --disable + + Disable router + +.. option:: --distributed + + Create a distributed router + +.. option:: --availability-zone-hint <availability-zone> + + Availability Zone in which to create this router (requires the Router + Availability Zone extension, this option can be repeated). + +.. _router_create-name: +.. describe:: <name> + + New router name + +router delete +------------- + +Delete router(s) + +.. program:: router delete +.. code:: bash + + os router delete + <router> [<router> ...] + +.. _router_delete-router: +.. describe:: <router> + + Router(s) to delete (name or ID) + +router list +----------- + +List routers + +.. program:: router list +.. code:: bash + + os router list + [--long] + +.. option:: --long + + List additional fields in output + +router set +---------- + +Set router properties + +.. program:: router set +.. code:: bash + + os router set + [--name <name>] + [--enable | --disable] + [--distributed | --centralized] + <router> + +.. option:: --name <name> + + Set router name + +.. option:: --enable + + Enable router + +.. option:: --disable + + Disable router + +.. option:: --distributed + + Set router to distributed mode (disabled router only) + +.. option:: --centralized + + Set router to centralized mode (disabled router only) + +.. _router_set-router: +.. describe:: <router> + + Router to modify (name or ID) + +router show +----------- + +Display router details + +.. program:: router show +.. code:: bash + + os router show + <router> + +.. _router_show-router: +.. describe:: <router> + + Router to display (name or ID) diff --git a/doc/source/command-objects/security-group-rule.rst b/doc/source/command-objects/security-group-rule.rst index 8bd0d06..50bc64a 100644 --- a/doc/source/command-objects/security-group-rule.rst +++ b/doc/source/command-objects/security-group-rule.rst @@ -2,7 +2,7 @@ security group rule =================== -Compute v2 +Compute v2, Network v2 security group rule create -------------------------- @@ -14,7 +14,7 @@ Create a new security group rule os security group rule create [--proto <proto>] - [--src-ip <ip-address>] + [--src-ip <ip-address> | --src-group <group>] [--dst-port <port-range>] <group> @@ -24,7 +24,11 @@ Create a new security group rule .. option:: --src-ip <ip-address> - Source IP (may use CIDR notation; default: 0.0.0.0/0) + Source IP address block (may use CIDR notation; default: 0.0.0.0/0) + +.. option:: --src-group <group> + + Source security group (ID only) .. option:: --dst-port <port-range> @@ -58,7 +62,7 @@ List security group rules .. code:: bash os security group rule list - <group> + [<group>] .. describe:: <group> diff --git a/doc/source/command-objects/security-group.rst b/doc/source/command-objects/security-group.rst index 60de41d..cf86bda 100644 --- a/doc/source/command-objects/security-group.rst +++ b/doc/source/command-objects/security-group.rst @@ -2,7 +2,7 @@ security group ============== -Compute v2 +Compute v2, Network v2 security group create --------------------- diff --git a/doc/source/command-objects/server.rst b/doc/source/command-objects/server.rst index 506a82d..fc27597 100644 --- a/doc/source/command-objects/server.rst +++ b/doc/source/command-objects/server.rst @@ -77,19 +77,20 @@ Create a new server .. option:: --image <image> - Create server from this image + Create server from this image (name or ID) .. option:: --volume <volume> - Create server from this volume + Create server from this volume (name or ID) .. option:: --flavor <flavor> - Create server with this flavor + Create server with this flavor (name or ID) .. option:: --security-group <security-group-name> - Security group to assign to this server (repeat for multiple groups) + Security group to assign to this server (name or ID) + (repeat for multiple groups) .. option:: --key-name <key-name> @@ -216,11 +217,11 @@ List servers .. option:: --flavor <flavor> - Search by flavor ID + Search by flavor (name or ID) .. option:: --image <image> - Search by image ID + Search by image (name or ID) .. option:: --host <hostname> @@ -374,14 +375,15 @@ Rebuild server .. code:: bash os server rebuild - --image <image> + [--image <image>] [--password <password>] [--wait] <server> .. option:: --image <image> - Recreate server from this image + Recreate server from the specified image (name or ID). Defaults to the + currently used one. .. option:: --password <password> diff --git a/doc/source/command-objects/snapshot.rst b/doc/source/command-objects/snapshot.rst index e05673b..b483868 100644 --- a/doc/source/command-objects/snapshot.rst +++ b/doc/source/command-objects/snapshot.rst @@ -2,7 +2,7 @@ snapshot ======== -Volume v1 +Block Storage v1 snapshot create --------------- diff --git a/doc/source/command-objects/subnet.rst b/doc/source/command-objects/subnet.rst new file mode 100644 index 0000000..70a0eed --- /dev/null +++ b/doc/source/command-objects/subnet.rst @@ -0,0 +1,20 @@ +====== +subnet +====== + +Network v2 + +subnet list +----------- + +List subnets + +.. program:: subnet list +.. code:: bash + + os subnet list + [--long] + +.. option:: --long + + List additional fields in output diff --git a/doc/source/command-objects/volume-qos.rst b/doc/source/command-objects/volume-qos.rst index d0fe36f..2d9d14a 100644 --- a/doc/source/command-objects/volume-qos.rst +++ b/doc/source/command-objects/volume-qos.rst @@ -2,7 +2,7 @@ volume qos ========== -volume v1, v2 +Block Storage v1, v2 volume qos associate -------------------- diff --git a/doc/source/command-objects/volume-type.rst b/doc/source/command-objects/volume-type.rst index 0edd742..8a11384 100644 --- a/doc/source/command-objects/volume-type.rst +++ b/doc/source/command-objects/volume-type.rst @@ -2,7 +2,7 @@ volume type =========== -Volume v1, v2 +Block Storage v1, v2 volume type create ------------------ diff --git a/doc/source/command-objects/volume.rst b/doc/source/command-objects/volume.rst index cb52c56..bf89dc4 100644 --- a/doc/source/command-objects/volume.rst +++ b/doc/source/command-objects/volume.rst @@ -2,7 +2,7 @@ volume ====== -Volume v1, v2 +Block Storage v1, v2 volume create ------------- diff --git a/doc/source/command-options.rst b/doc/source/command-options.rst index edafb15..458c56b 100644 --- a/doc/source/command-options.rst +++ b/doc/source/command-options.rst @@ -19,7 +19,7 @@ Boolean Options Boolean options for any command that sets a resource state, such as 'enabled' or 'public', shall always have both positive and negative options defined. -The names of those options shall either be a naturally occuring pair of +The names of those options shall either be a naturally occurring pair of words (in English) or a positive option and a negative option with `no-` prepended (such as in the traditional GNU option usage) like `--share` and `--no-share`. diff --git a/doc/source/commands.rst b/doc/source/commands.rst index 6069895..1c4f84b 100644 --- a/doc/source/commands.rst +++ b/doc/source/commands.rst @@ -70,7 +70,7 @@ the API resources will be merged, as in the ``quota`` object that has options referring to both Compute and Volume quotas. * ``access token``: (**Identity**) long-lived OAuth-based token -* ``availability zone``: (**Compute**) a logical partition of hosts or volume services +* ``availability zone``: (**Compute**, **Network**, **Volume**) a logical partition of hosts or block storage or network services * ``aggregate``: (**Compute**) a grouping of servers * ``backup``: (**Volume**) a volume copy * ``catalog``: (**Identity**) service catalog @@ -82,7 +82,7 @@ referring to both Compute and Volume quotas. * ``domain``: (**Identity**) a grouping of projects * ``ec2 credentials``: (**Identity**) AWS EC2-compatible credentials * ``endpoint``: (**Identity**) the base URL used to contact a specific service -* ``extension``: (**Compute**, **Identity**, **Volume**) OpenStack server API extensions +* ``extension``: (**Compute**, **Identity**, **Network**, **Volume**) OpenStack server API extensions * ``federation protocol``: (**Identity**) the underlying protocol used while federating identities * ``flavor``: (**Compute**) predefined server configurations: ram, root disk, etc * ``group``: (**Identity**) a grouping of users @@ -101,12 +101,14 @@ referring to both Compute and Volume quotas. * ``network``: (**Network**) - a virtual network for connecting servers and other resources * ``object``: (**Object Storage**) a single file in the Object Storage * ``policy``: (**Identity**) determines authorization +* ``port``: (**Network**) - a virtual port for connecting servers and other resources to a network * ``project``: (**Identity**) owns a group of resources * ``quota``: (**Compute**, **Volume**) resource usage restrictions * ``region``: (**Identity**) a subset of an OpenStack deployment * ``request token``: (**Identity**) temporary OAuth-based token * ``role``: (**Identity**) a policy object used to determine authorization * ``role assignment``: (**Identity**) a relationship between roles, users or groups, and domains or projects +* ``router``: (**Network**) - a virtual router * ``security group``: (**Compute**, **Network**) - groups of network access rules * ``security group rule``: (**Compute**, **Network**) - the individual rules that define protocol/IP/port access * ``server``: (**Compute**) virtual machine instance @@ -114,6 +116,7 @@ referring to both Compute and Volume quotas. * ``service``: (**Identity**) a cloud service * ``service provider``: (**Identity**) a resource that consumes assertions from an ``identity provider`` * ``snapshot``: (**Volume**) a point-in-time copy of a volume +* ``subnet``: (**Network**) - a contiguous range of IP addresses assigned to a network * ``token``: (**Identity**) a bearer token managed by Identity service * ``usage``: (**Compute**) display host resources being consumed * ``user``: (**Identity**) individual cloud resources users @@ -129,17 +132,18 @@ The following are known `Objects` used by OpenStack :doc:`plugins`. These are listed here to avoid name conflicts when creating new plugins. For a complete list check out :doc:`plugin-commands`. +* ``action definition``: (**Workflow Engine (Mistral)**) +* ``action execution``: (**Workflow Engine (Mistral)**) * ``baremetal``: (**Baremetal (Ironic)**) * ``congress datasource``: (**Policy (Congress)**) * ``congress driver``: (**Policy (Congress)**) * ``congress policy``: (**Policy (Congress)**) * ``congress policy rule``: (**Policy (Congress)**) +* ``cron trigger``: (**Workflow Engine (Mistral)**) * ``dataprocessing data source``: (**Data Processing (Sahara)**) * ``dataprocessing image``: (**Data Processing (Sahara)**) * ``dataprocessing image tags``: (**Data Processing (Sahara)**) * ``dataprocessing plugin``: (**Data Processing (Sahara)**) -* ``management plan``: (**Management (Tuskar)**) -* ``management role``: (**Management (Tuskar)**) * ``message-broker cluster``: (**Message Broker (Cue)**) * ``message flavor``: (**Messaging (Zaqar)**) * ``pool``: (**Messaging (Zaqar)**) @@ -150,7 +154,11 @@ list check out :doc:`plugin-commands`. * ``secret container``: (**Key Manager (Barbican)**) * ``secret order``: (**Key Manager (Barbican)**) * ``stack``: (**Orchestration (Heat)**) +* ``task exeuction``: (**Workflow Engine (Mistral)**) * ``tld``: (**DNS (Designate)**) +* ``workbook``: (**Workflow Engine (Mistral)**) +* ``workflow``: (**Workflow Engine (Mistral)**) +* ``workflow execution``: (**Workflow Engine (Mistral)**) * ``zone``: (**DNS (Designate)**) * ``zone blacklist``: (**DNS (Designate)**) * ``zone transfer``: (**DNS (Designate)**) diff --git a/doc/source/index.rst b/doc/source/index.rst index 4992997..cb38d84 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -3,8 +3,9 @@ OpenStackClient =============== OpenStackClient (aka OSC) is a command-line client for OpenStack that -brings the command set for Compute, Identity, Image, Object Storage and Volume -APIs together in a single shell with a uniform command structure. +brings the command set for Compute, Identity, Image, Object Storage and +Block Storage APIs together in a single shell with a uniform command +structure. User Documentation ------------------ diff --git a/doc/source/man/openstack.rst b/doc/source/man/openstack.rst index 3e47635..a33b189 100644 --- a/doc/source/man/openstack.rst +++ b/doc/source/man/openstack.rst @@ -171,7 +171,7 @@ project support. The object names may consist of multiple words to compose a unique name. Occasionally when multiple APIs have a common name with common overlapping purposes there will be options to select which object to use, or the API resources will be merged, as in the ``quota`` object that has options -referring to both Compute and Volume quotas. +referring to both Compute and Block Storage quotas. Command Actions --------------- diff --git a/doc/source/plugins.rst b/doc/source/plugins.rst index 5f82cc6..0c838ec 100644 --- a/doc/source/plugins.rst +++ b/doc/source/plugins.rst @@ -11,8 +11,9 @@ Adoption ======== OpenStackClient promises to provide first class support for the following -OpenStack services: Compute, Identity, Image, Storage, Volume and Network. -These services are considered essential to any OpenStack deployment. +OpenStack services: Compute, Identity, Image, Object Storage, Block Storage +and Network. These services are considered essential to any OpenStack +deployment. Other OpenStack services, such as Orchestration or Telemetry may create an OpenStackClient plugin. The source code will not be hosted by @@ -33,11 +34,10 @@ python-heatclient patch in progress (https://review.openstack.org/# python-ironicclient Using OpenStackClient python-magnumclient using argparse python-manilaclient using argparse -python-mistralclient using cliff +python-mistralclient using OpenStackClient python-muranoclient using argparse python-saharaclient using OpenStackClient python-troveclient using argparse -python-tuskarclient using OpenStackClient python-zaqarclient using OpenStackClient ============================= ====================================== diff --git a/doc/source/releases.rst b/doc/source/releases.rst index 853ef95..063066a 100644 --- a/doc/source/releases.rst +++ b/doc/source/releases.rst @@ -137,12 +137,12 @@ As of release 2.0 the release notes can be found on the OpenStack `Release Notes * Add ``--log-file`` option support -* Set default Volume API version to ``2`` +* Set default Block Storage API version to ``2`` 1.6.0 (10 Aug 2015) =================== -* Added support for Volume v2 APIs +* Added support for Block Storage v2 APIs Blueprint `volume-v2 <https://blueprints.launchpad.net/python-openstackclient/+spec/volume-v2>`_ * Backup diff --git a/functional/tests/common/test_availability_zone.py b/functional/tests/common/test_availability_zone.py new file mode 100644 index 0000000..9296db2 --- /dev/null +++ b/functional/tests/common/test_availability_zone.py @@ -0,0 +1,25 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from functional.common import test + + +class AvailabilityZoneTests(test.TestCase): + """Functional tests for availability zone. """ + HEADERS = ["'Zone Name'"] + # So far, all components have the same default availability zone name. + DEFAULT_AZ_NAME = 'nova' + + def test_availability_zone_list(self): + opts = self.get_list_opts(self.HEADERS) + raw_output = self.openstack('availability zone list' + opts) + self.assertIn(self.DEFAULT_AZ_NAME, raw_output) diff --git a/functional/tests/compute/v2/test_security_group_rule.py b/functional/tests/compute/v2/test_security_group_rule.py new file mode 100644 index 0000000..e864b08 --- /dev/null +++ b/functional/tests/compute/v2/test_security_group_rule.py @@ -0,0 +1,59 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import uuid + +from functional.common import test + + +class SecurityGroupRuleTests(test.TestCase): + """Functional tests for security group rule. """ + SECURITY_GROUP_NAME = uuid.uuid4().hex + SECURITY_GROUP_RULE_ID = None + NAME_FIELD = ['name'] + ID_FIELD = ['id'] + ID_HEADER = ['ID'] + + @classmethod + def setUpClass(cls): + # Create the security group to hold the rule. + opts = cls.get_show_opts(cls.NAME_FIELD) + raw_output = cls.openstack('security group create ' + + cls.SECURITY_GROUP_NAME + + opts) + expected = cls.SECURITY_GROUP_NAME + '\n' + cls.assertOutput(expected, raw_output) + + # Create the security group rule. + opts = cls.get_show_opts(cls.ID_FIELD) + raw_output = cls.openstack('security group rule create ' + + cls.SECURITY_GROUP_NAME + + ' --proto tcp --dst-port 80:80' + + opts) + cls.SECURITY_GROUP_RULE_ID = raw_output.strip('\n') + + @classmethod + def tearDownClass(cls): + raw_output = cls.openstack('security group rule delete ' + + cls.SECURITY_GROUP_RULE_ID) + cls.assertOutput('', raw_output) + + raw_output = cls.openstack('security group delete ' + + cls.SECURITY_GROUP_NAME) + cls.assertOutput('', raw_output) + + def test_security_group_rule_list(self): + opts = self.get_list_opts(self.ID_HEADER) + raw_output = self.openstack('security group rule list ' + + self.SECURITY_GROUP_NAME + + opts) + self.assertIn(self.SECURITY_GROUP_RULE_ID, raw_output) diff --git a/functional/tests/identity/v2/test_project.py b/functional/tests/identity/v2/test_project.py index 88b282e..3a5e8e8 100644 --- a/functional/tests/identity/v2/test_project.py +++ b/functional/tests/identity/v2/test_project.py @@ -68,12 +68,12 @@ class ProjectTests(test_identity.IdentityTests): ) items = self.parse_show(raw_output) fields = list(self.PROJECT_FIELDS) - fields.extend(['k0']) + fields.extend(['properties']) self.assert_show_fields(items, fields) project = self.parse_show_as_object(raw_output) self.assertEqual(new_project_name, project['name']) self.assertEqual('False', project['enabled']) - self.assertEqual('v0', project['k0']) + self.assertEqual("k0='v0'", project['properties']) def test_project_show(self): project_name = self._create_dummy_project() @@ -81,4 +81,6 @@ class ProjectTests(test_identity.IdentityTests): 'project show %s' % project_name ) items = self.parse_show(raw_output) - self.assert_show_fields(items, self.PROJECT_FIELDS) + fields = list(self.PROJECT_FIELDS) + fields.extend(['properties']) + self.assert_show_fields(items, fields) diff --git a/functional/tests/network/v2/test_network.py b/functional/tests/network/v2/test_network.py index 0b2f35e..5cc461b 100644 --- a/functional/tests/network/v2/test_network.py +++ b/functional/tests/network/v2/test_network.py @@ -40,9 +40,9 @@ class NetworkTests(test.TestCase): def test_network_set(self): raw_output = self.openstack('network set --disable ' + self.NAME) - opts = self.get_show_opts(['name', 'state']) + opts = self.get_show_opts(['name', 'admin_state_up']) raw_output = self.openstack('network show ' + self.NAME + opts) - self.assertEqual(self.NAME + "\nDOWN\n", raw_output) + self.assertEqual("DOWN\n" + self.NAME + "\n", raw_output) def test_network_show(self): opts = self.get_show_opts(self.FIELDS) diff --git a/functional/tests/network/v2/test_router.py b/functional/tests/network/v2/test_router.py new file mode 100644 index 0000000..ceb7625 --- /dev/null +++ b/functional/tests/network/v2/test_router.py @@ -0,0 +1,50 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import uuid + +from functional.common import test + + +class RouterTests(test.TestCase): + """Functional tests for router. """ + NAME = uuid.uuid4().hex + HEADERS = ['Name'] + FIELDS = ['name'] + + @classmethod + def setUpClass(cls): + opts = cls.get_show_opts(cls.FIELDS) + raw_output = cls.openstack('router create ' + cls.NAME + opts) + expected = cls.NAME + '\n' + cls.assertOutput(expected, raw_output) + + @classmethod + def tearDownClass(cls): + raw_output = cls.openstack('router delete ' + cls.NAME) + cls.assertOutput('', raw_output) + + def test_router_list(self): + opts = self.get_list_opts(self.HEADERS) + raw_output = self.openstack('router list' + opts) + self.assertIn(self.NAME, raw_output) + + def test_router_set(self): + self.openstack('router set --disable ' + self.NAME) + opts = self.get_show_opts(['name', 'admin_state_up']) + raw_output = self.openstack('router show ' + self.NAME + opts) + self.assertEqual("DOWN\n" + self.NAME + "\n", raw_output) + + def test_router_show(self): + opts = self.get_show_opts(self.FIELDS) + raw_output = self.openstack('router show ' + self.NAME + opts) + self.assertEqual(self.NAME + "\n", raw_output) diff --git a/openstackclient/api/network_v2.py b/openstackclient/api/network_v2.py deleted file mode 100644 index 90be523..0000000 --- a/openstackclient/api/network_v2.py +++ /dev/null @@ -1,59 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# - -"""Network v2 API Library""" - -from openstackclient.api import api - - -class APIv2(api.BaseAPI): - """Network v2 API""" - - def __init__(self, **kwargs): - super(APIv2, self).__init__(**kwargs) - - def dhcp_agent_list( - self, - dhcp_id=None, - **filter - ): - """List DHCP agents - - :param string dhcp_id: - DHCP Agent ID - :param filter: - used to create the query string filters - http://docs.openstack.org/api/openstack-network/2.0/content/filtering.html - """ - - return self.list('dhcp-networks', **filter)['dhcp-networks'] - - def network_list( - self, - external=False, - **filter - ): - """List external networks - - :param string dhcp_id: - DHCP agent ID - :param bool external: - Return external networks if True - :param filter: - used to create the query string filters - http://docs.openstack.org/api/openstack-network/2.0/content/filtering.html - """ - - if external: - filter = {'router:external': True} - return self.list('networks', **filter)['networks'] diff --git a/openstackclient/api/object_store_v1.py b/openstackclient/api/object_store_v1.py index ab75a78..d9f130b 100644 --- a/openstackclient/api/object_store_v1.py +++ b/openstackclient/api/object_store_v1.py @@ -570,6 +570,6 @@ class APIv1(api.BaseAPI): # OSC commands properties = {} for k, v in six.iteritems(headers): - if k.startswith(header_tag): + if k.lower().startswith(header_tag): properties[k[len(header_tag):]] = v return properties diff --git a/openstackclient/api/utils.py b/openstackclient/api/utils.py index b7ff7f2..fa759cd 100644 --- a/openstackclient/api/utils.py +++ b/openstackclient/api/utils.py @@ -27,11 +27,11 @@ def simple_filter( be changed if any filtering occurs. :param string attr: The name of the attribute to filter. If attr does not exist no - match will succeed and no rows will be retrurned. If attr is + match will succeed and no rows will be returned. If attr is None no filtering will be performed and all rows will be returned. :param sring value: The value to filter. None is considered to be a 'no filter' value. - '' matches agains a Python empty string. + '' matches against a Python empty string. :param string property_field: The name of the data field containing a property dict to filter. If property_field is None, attr is a field name. If property_field diff --git a/openstackclient/common/availability_zone.py b/openstackclient/common/availability_zone.py new file mode 100644 index 0000000..a941418 --- /dev/null +++ b/openstackclient/common/availability_zone.py @@ -0,0 +1,191 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +"""Availability Zone action implementations""" + +import copy + +from novaclient import exceptions as nova_exceptions +import six + +from openstackclient.common import command +from openstackclient.common import utils +from openstackclient.i18n import _ # noqa + + +def _xform_common_availability_zone(az, zone_info): + if hasattr(az, 'zoneState'): + zone_info['zone_status'] = ('available' if az.zoneState['available'] + else 'not available') + if hasattr(az, 'zoneName'): + zone_info['zone_name'] = az.zoneName + + zone_info['zone_resource'] = '' + + +def _xform_compute_availability_zone(az, include_extra): + result = [] + zone_info = {} + _xform_common_availability_zone(az, zone_info) + + if not include_extra: + result.append(zone_info) + return result + + if hasattr(az, 'hosts') and az.hosts: + for host, services in six.iteritems(az.hosts): + host_info = copy.deepcopy(zone_info) + host_info['host_name'] = host + + for svc, state in six.iteritems(services): + info = copy.deepcopy(host_info) + info['service_name'] = svc + info['service_status'] = '%s %s %s' % ( + 'enabled' if state['active'] else 'disabled', + ':-)' if state['available'] else 'XXX', + state['updated_at']) + result.append(info) + else: + zone_info['host_name'] = '' + zone_info['service_name'] = '' + zone_info['service_status'] = '' + result.append(zone_info) + return result + + +def _xform_volume_availability_zone(az): + result = [] + zone_info = {} + _xform_common_availability_zone(az, zone_info) + result.append(zone_info) + return result + + +def _xform_network_availability_zone(az): + result = [] + zone_info = {} + zone_info['zone_name'] = getattr(az, 'name', '') + zone_info['zone_status'] = getattr(az, 'state', '') + if 'unavailable' == zone_info['zone_status']: + zone_info['zone_status'] = 'not available' + zone_info['zone_resource'] = getattr(az, 'resource', '') + result.append(zone_info) + return result + + +class ListAvailabilityZone(command.Lister): + """List availability zones and their status""" + + def get_parser(self, prog_name): + parser = super(ListAvailabilityZone, self).get_parser(prog_name) + parser.add_argument( + '--compute', + action='store_true', + default=False, + help='List compute availability zones') + parser.add_argument( + '--network', + action='store_true', + default=False, + help='List network availability zones') + parser.add_argument( + '--volume', + action='store_true', + default=False, + help='List volume availability zones') + parser.add_argument( + '--long', + action='store_true', + default=False, + help=_('List additional fields in output'), + ) + return parser + + def _get_compute_availability_zones(self, parsed_args): + compute_client = self.app.client_manager.compute + try: + data = compute_client.availability_zones.list() + except nova_exceptions.Forbidden as e: # policy doesn't allow + try: + data = compute_client.availability_zones.list(detailed=False) + except Exception: + raise e + + # Argh, the availability zones are not iterable... + result = [] + for zone in data: + result += _xform_compute_availability_zone(zone, parsed_args.long) + return result + + def _get_volume_availability_zones(self, parsed_args): + volume_client = self.app.client_manager.volume + data = [] + try: + data = volume_client.availability_zones.list() + except Exception as e: + self.log.debug('Volume availability zone exception: ' + str(e)) + if parsed_args.volume: + message = "Availability zones list not supported by " \ + "Block Storage API" + self.log.warning(message) + + result = [] + for zone in data: + result += _xform_volume_availability_zone(zone) + return result + + def _get_network_availability_zones(self, parsed_args): + network_client = self.app.client_manager.network + data = [] + try: + # Verify that the extension exists. + network_client.find_extension('Availability Zone', + ignore_missing=False) + data = network_client.availability_zones() + except Exception as e: + self.log.debug('Network availability zone exception: ' + str(e)) + if parsed_args.network: + message = "Availability zones list not supported by " \ + "Network API" + self.log.warning(message) + + result = [] + for zone in data: + result += _xform_network_availability_zone(zone) + return result + + def take_action(self, parsed_args): + + if parsed_args.long: + columns = ('Zone Name', 'Zone Status', 'Zone Resource', + 'Host Name', 'Service Name', 'Service Status') + else: + columns = ('Zone Name', 'Zone Status') + + # Show everything by default. + show_all = (not parsed_args.compute and + not parsed_args.volume and + not parsed_args.network) + + result = [] + if parsed_args.compute or show_all: + result += self._get_compute_availability_zones(parsed_args) + if parsed_args.volume or show_all: + result += self._get_volume_availability_zones(parsed_args) + if parsed_args.network or show_all: + result += self._get_network_availability_zones(parsed_args) + + return (columns, + (utils.get_dict_properties( + s, columns + ) for s in result)) diff --git a/openstackclient/common/clientmanager.py b/openstackclient/common/clientmanager.py index edabf65..dce1972 100644 --- a/openstackclient/common/clientmanager.py +++ b/openstackclient/common/clientmanager.py @@ -191,6 +191,26 @@ class ClientManager(object): self._auth_ref = self.auth.get_auth_ref(self.session) return self._auth_ref + def is_network_endpoint_enabled(self): + """Check if the network endpoint is enabled""" + # Trigger authentication necessary to determine if the network + # endpoint is enabled. + if self.auth_ref: + service_catalog = self.auth_ref.service_catalog + else: + service_catalog = None + # Assume that the network endpoint is enabled. + network_endpoint_enabled = True + if service_catalog: + if 'network' in service_catalog.get_endpoints(): + LOG.debug("Network endpoint in service catalog") + else: + LOG.debug("No network endpoint in service catalog") + network_endpoint_enabled = False + else: + LOG.debug("No service catalog, assuming network endpoint enabled") + return network_endpoint_enabled + def get_endpoint_for_service_type(self, service_type, region_name=None, interface='public'): """Return the endpoint URL for the service type.""" diff --git a/openstackclient/common/command.py b/openstackclient/common/command.py new file mode 100644 index 0000000..13b0bcc --- /dev/null +++ b/openstackclient/common/command.py @@ -0,0 +1,45 @@ +# Copyright 2016 NEC Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import abc +import logging + +from cliff import command +from cliff import lister +from cliff import show +import six + + +class CommandMeta(abc.ABCMeta): + def __new__(mcs, name, bases, cls_dict): + if 'log' not in cls_dict: + cls_dict['log'] = logging.getLogger( + cls_dict['__module__'] + '.' + name) + return super(CommandMeta, mcs).__new__(mcs, name, bases, cls_dict) + + +@six.add_metaclass(CommandMeta) +class Command(command.Command): + + def run(self, parsed_args): + self.log.debug('run(%s)', parsed_args) + return super(Command, self).run(parsed_args) + + +class Lister(Command, lister.Lister): + pass + + +class ShowOne(Command, show.ShowOne): + pass diff --git a/openstackclient/common/commandmanager.py b/openstackclient/common/commandmanager.py index b34bf7d..b809d63 100644 --- a/openstackclient/common/commandmanager.py +++ b/openstackclient/common/commandmanager.py @@ -15,15 +15,11 @@ """Modify cliff.CommandManager""" -import logging import pkg_resources import cliff.commandmanager -LOG = logging.getLogger(__name__) - - class CommandManager(cliff.commandmanager.CommandManager): """Add additional functionality to cliff.CommandManager diff --git a/openstackclient/common/configuration.py b/openstackclient/common/configuration.py index ac2792d..a70e4d1 100644 --- a/openstackclient/common/configuration.py +++ b/openstackclient/common/configuration.py @@ -13,21 +13,16 @@ """Configuration action implementations""" -import logging - -from cliff import show import six -from openstackclient.common import utils +from openstackclient.common import command REDACTED = "<redacted>" -class ShowConfiguration(show.ShowOne): +class ShowConfiguration(command.ShowOne): """Display configuration details""" - log = logging.getLogger(__name__ + '.ShowConfiguration') - def get_parser(self, prog_name): parser = super(ShowConfiguration, self).get_parser(prog_name) mask_group = parser.add_mutually_exclusive_group() @@ -46,7 +41,6 @@ class ShowConfiguration(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): info = self.app.client_manager.get_configuration() diff --git a/openstackclient/common/extension.py b/openstackclient/common/extension.py index dad7ed6..8b556b4 100644 --- a/openstackclient/common/extension.py +++ b/openstackclient/common/extension.py @@ -16,18 +16,14 @@ """Extension action implementations""" import itertools -import logging - -from cliff import lister +from openstackclient.common import command from openstackclient.common import utils -class ListExtension(lister.Lister): +class ListExtension(command.Lister): """List API extensions""" - log = logging.getLogger(__name__ + '.ListExtension') - def get_parser(self, prog_name): parser = super(ListExtension, self).get_parser(prog_name) parser.add_argument( @@ -49,7 +45,7 @@ class ListExtension(lister.Lister): '--volume', action='store_true', default=False, - help='List extensions for the Volume API') + help='List extensions for the Block Storage API') parser.add_argument( '--long', action='store_true', @@ -58,8 +54,6 @@ class ListExtension(lister.Lister): return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) - if parsed_args.long: columns = ('Name', 'Namespace', 'Description', 'Alias', 'Updated', 'Links') @@ -95,7 +89,7 @@ class ListExtension(lister.Lister): try: data += volume_client.list_extensions.show_all() except Exception: - message = "Extensions list not supported by Volume API" + message = "Extensions list not supported by Block Storage API" self.log.warning(message) # Resource classes for the above @@ -111,9 +105,9 @@ class ListExtension(lister.Lister): if parsed_args.network or show_all: network_client = self.app.client_manager.network try: - data = network_client.list_extensions()['extensions'] + data = network_client.extensions() dict_tuples = ( - utils.get_dict_properties( + utils.get_item_properties( s, columns, formatters={}, diff --git a/openstackclient/common/limits.py b/openstackclient/common/limits.py index 582f70c..bd546c0 100644 --- a/openstackclient/common/limits.py +++ b/openstackclient/common/limits.py @@ -16,18 +16,14 @@ """Limits Action Implementation""" import itertools -import logging - -from cliff import lister +from openstackclient.common import command from openstackclient.common import utils from openstackclient.identity import common as identity_common -class ShowLimits(lister.Lister): - """Show compute and volume limits""" - - log = logging.getLogger(__name__ + '.ShowLimits') +class ShowLimits(command.Lister): + """Show compute and block storage limits""" def get_parser(self, prog_name): parser = super(ShowLimits, self).get_parser(prog_name) @@ -64,7 +60,6 @@ class ShowLimits(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute diff --git a/openstackclient/common/module.py b/openstackclient/common/module.py index f0ed23b..a3dea5d 100644 --- a/openstackclient/common/module.py +++ b/openstackclient/common/module.py @@ -15,23 +15,17 @@ """Module action implementation""" -import logging import six import sys -from cliff import lister -from cliff import show +from openstackclient.common import command -from openstackclient.common import utils - -class ListCommand(lister.Lister): +class ListCommand(command.Lister): """List recognized commands by group""" auth_required = False - log = logging.getLogger(__name__ + '.ListCommand') - @utils.log_method(log) def take_action(self, parsed_args): cm = self.app.command_manager groups = cm.get_command_groups() @@ -40,11 +34,10 @@ class ListCommand(lister.Lister): return (columns, ((c, cm.get_command_names(group=c)) for c in groups)) -class ListModule(show.ShowOne): +class ListModule(command.ShowOne): """List module versions""" auth_required = False - log = logging.getLogger(__name__ + '.ListModule') def get_parser(self, prog_name): parser = super(ListModule, self).get_parser(prog_name) @@ -56,7 +49,6 @@ class ListModule(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): data = {} diff --git a/openstackclient/common/quota.py b/openstackclient/common/quota.py index 8a9b910..f208948 100644 --- a/openstackclient/common/quota.py +++ b/openstackclient/common/quota.py @@ -16,13 +16,10 @@ """Quota action implementations""" import itertools -import logging import six import sys -from cliff import command -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils @@ -60,8 +57,6 @@ NETWORK_QUOTAS = { class SetQuota(command.Command): """Set quotas for project or class""" - log = logging.getLogger(__name__ + '.SetQuota') - def get_parser(self, prog_name): parser = super(SetQuota, self).get_parser(prog_name) parser.add_argument( @@ -92,7 +87,6 @@ class SetQuota(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -143,11 +137,9 @@ class SetQuota(command.Command): **volume_kwargs) -class ShowQuota(show.ShowOne): +class ShowQuota(command.ShowOne): """Show quotas for project or class""" - log = logging.getLogger(__name__ + '.ShowQuota') - def get_parser(self, prog_name): parser = super(ShowQuota, self).get_parser(prog_name) parser.add_argument( @@ -196,14 +188,16 @@ class ShowQuota(show.ShowOne): def get_network_quota(self, parsed_args): if parsed_args.quota_class or parsed_args.default: return {} - service_catalog = self.app.client_manager.auth_ref.service_catalog - if 'network' in service_catalog.get_endpoints(): - network_client = self.app.client_manager.network - return network_client.show_quota(parsed_args.project)['quota'] + if self.app.client_manager.is_network_endpoint_enabled(): + identity_client = self.app.client_manager.identity + project = utils.find_resource( + identity_client.projects, + parsed_args.project, + ).id + return self.app.client_manager.network.get_quota(project) else: return {} - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute diff --git a/openstackclient/common/timing.py b/openstackclient/common/timing.py index d13c86e..5f62875 100644 --- a/openstackclient/common/timing.py +++ b/openstackclient/common/timing.py @@ -13,19 +13,13 @@ """Timing Implementation""" -import logging +from openstackclient.common import command -from cliff import lister - -class Timing(lister.Lister): +class Timing(command.Lister): """Show timing data""" - log = logging.getLogger(__name__ + '.Timing') - def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) - column_headers = ( 'URL', 'Seconds', diff --git a/openstackclient/common/utils.py b/openstackclient/common/utils.py index 42630d9..4142f83 100644 --- a/openstackclient/common/utils.py +++ b/openstackclient/common/utils.py @@ -26,29 +26,6 @@ from oslo_utils import importutils from openstackclient.common import exceptions -def log_method(log, level=logging.DEBUG): - """Logs a method and its arguments when entered.""" - - def decorator(func): - func_name = func.__name__ - - @six.wraps(func) - def wrapper(self, *args, **kwargs): - if log.isEnabledFor(level): - pretty_args = [] - if args: - pretty_args.extend(str(a) for a in args) - if kwargs: - pretty_args.extend( - "%s=%s" % (k, v) for k, v in six.iteritems(kwargs)) - log.log(level, "%s(%s)", func_name, ", ".join(pretty_args)) - return func(self, *args, **kwargs) - - return wrapper - - return decorator - - def find_resource(manager, name_or_id, **kwargs): """Helper for the _find_* methods. @@ -154,14 +131,25 @@ def format_dict(data): return output[:-2] -def format_list(data): +def format_list(data, separator=', '): """Return a formatted strings :param data: a list of strings - :rtype: a string formatted to a,b,c + :param separator: the separator to use between strings (default: ', ') + :rtype: a string formatted based on separator """ - return ', '.join(sorted(data)) + return separator.join(sorted(data)) + + +def format_list_of_dicts(data): + """Return a formatted string of key value pairs for each dict + + :param data: a list of dicts + :rtype: a string formatted to key='value' with dicts separated by new line + """ + + return '\n'.join(format_dict(i) for i in data) def get_field(item, field): @@ -258,10 +246,6 @@ def sort_items(items, sort_str): return items -def string_to_bool(arg): - return arg.strip().lower() in ('t', 'true', 'yes', '1') - - def env(*vars, **kwargs): """Search for the first defined of possibly many env vars @@ -330,6 +314,8 @@ def wait_for_status(status_f, def wait_for_delete(manager, res_id, status_field='status', + error_status=['error'], + exception_name=['NotFound'], sleep_time=5, timeout=300, callback=None): @@ -340,6 +326,8 @@ def wait_for_delete(manager, :param status_field: the status attribute in the returned resource object, this is used to check for error states while the resource is being deleted + :param error_status: a list of status strings for error + :param exception_name: a list of exception strings for deleted case :param sleep_time: wait this long between checks (seconds) :param timeout: check until this long (seconds) :param callback: called per sleep cycle, useful to display progress; this @@ -356,12 +344,12 @@ def wait_for_delete(manager, # handle a NotFound exception here without parsing the message res = manager.get(res_id) except Exception as ex: - if type(ex).__name__ == 'NotFound': + if type(ex).__name__ in exception_name: return True raise status = getattr(res, status_field, '').lower() - if status == 'error': + if status in error_status: return False if callback: diff --git a/openstackclient/compute/v2/agent.py b/openstackclient/compute/v2/agent.py index 14c4b2c..59d7dc6 100644 --- a/openstackclient/compute/v2/agent.py +++ b/openstackclient/compute/v2/agent.py @@ -15,21 +15,15 @@ """Agent action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils -class CreateAgent(show.ShowOne): +class CreateAgent(command.ShowOne): """Create compute agent command""" - log = logging.getLogger(__name__ + ".CreateAgent") - def get_parser(self, prog_name): parser = super(CreateAgent, self).get_parser(prog_name) parser.add_argument( @@ -60,7 +54,6 @@ class CreateAgent(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute args = ( parsed_args.os, @@ -77,8 +70,6 @@ class CreateAgent(show.ShowOne): class DeleteAgent(command.Command): """Delete compute agent command""" - log = logging.getLogger(__name__ + ".DeleteAgent") - def get_parser(self, prog_name): parser = super(DeleteAgent, self).get_parser(prog_name) parser.add_argument( @@ -88,17 +79,13 @@ class DeleteAgent(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute compute_client.agents.delete(parsed_args.id) - return -class ListAgent(lister.Lister): +class ListAgent(command.Lister): """List compute agent command""" - log = logging.getLogger(__name__ + ".ListAgent") - def get_parser(self, prog_name): parser = super(ListAgent, self).get_parser(prog_name) parser.add_argument( @@ -108,7 +95,6 @@ class ListAgent(lister.Lister): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute columns = ( "Agent ID", @@ -126,11 +112,9 @@ class ListAgent(lister.Lister): ) for s in data)) -class SetAgent(show.ShowOne): +class SetAgent(command.ShowOne): """Set compute agent command""" - log = logging.getLogger(__name__ + ".SetAgent") - def get_parser(self, prog_name): parser = super(SetAgent, self).get_parser(prog_name) parser.add_argument( @@ -152,7 +136,6 @@ class SetAgent(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute args = ( parsed_args.id, diff --git a/openstackclient/compute/v2/aggregate.py b/openstackclient/compute/v2/aggregate.py index a1ba618..5f29725 100644 --- a/openstackclient/compute/v2/aggregate.py +++ b/openstackclient/compute/v2/aggregate.py @@ -16,22 +16,16 @@ """Compute v2 Aggregate action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils -class AddAggregateHost(show.ShowOne): +class AddAggregateHost(command.ShowOne): """Add host to aggregate""" - log = logging.getLogger(__name__ + '.AddAggregateHost') - def get_parser(self, prog_name): parser = super(AddAggregateHost, self).get_parser(prog_name) parser.add_argument( @@ -47,8 +41,6 @@ class AddAggregateHost(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - compute_client = self.app.client_manager.compute aggregate = utils.find_resource( @@ -62,11 +54,9 @@ class AddAggregateHost(show.ShowOne): return zip(*sorted(six.iteritems(info))) -class CreateAggregate(show.ShowOne): +class CreateAggregate(command.ShowOne): """Create a new aggregate""" - log = logging.getLogger(__name__ + ".CreateAggregate") - def get_parser(self, prog_name): parser = super(CreateAggregate, self).get_parser(prog_name) parser.add_argument( @@ -89,8 +79,6 @@ class CreateAggregate(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - compute_client = self.app.client_manager.compute info = {} @@ -112,8 +100,6 @@ class CreateAggregate(show.ShowOne): class DeleteAggregate(command.Command): """Delete an existing aggregate""" - log = logging.getLogger(__name__ + '.DeleteAggregate') - def get_parser(self, prog_name): parser = super(DeleteAggregate, self).get_parser(prog_name) parser.add_argument( @@ -123,7 +109,6 @@ class DeleteAggregate(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -132,14 +117,11 @@ class DeleteAggregate(command.Command): parsed_args.aggregate, ) compute_client.aggregates.delete(data.id) - return -class ListAggregate(lister.Lister): +class ListAggregate(command.Lister): """List all aggregates""" - log = logging.getLogger(__name__ + ".ListAggregate") - def get_parser(self, prog_name): parser = super(ListAggregate, self).get_parser(prog_name) parser.add_argument( @@ -150,8 +132,6 @@ class ListAggregate(lister.Lister): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - compute_client = self.app.client_manager.compute data = compute_client.aggregates.list() @@ -187,11 +167,9 @@ class ListAggregate(lister.Lister): ) for s in data)) -class RemoveAggregateHost(show.ShowOne): +class RemoveAggregateHost(command.ShowOne): """Remove host from aggregate""" - log = logging.getLogger(__name__ + '.RemoveAggregateHost') - def get_parser(self, prog_name): parser = super(RemoveAggregateHost, self).get_parser(prog_name) parser.add_argument( @@ -207,8 +185,6 @@ class RemoveAggregateHost(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - compute_client = self.app.client_manager.compute aggregate = utils.find_resource( @@ -225,11 +201,9 @@ class RemoveAggregateHost(show.ShowOne): return zip(*sorted(six.iteritems(info))) -class SetAggregate(show.ShowOne): +class SetAggregate(command.ShowOne): """Set aggregate properties""" - log = logging.getLogger(__name__ + '.SetAggregate') - def get_parser(self, prog_name): parser = super(SetAggregate, self).get_parser(prog_name) parser.add_argument( @@ -256,7 +230,6 @@ class SetAggregate(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -289,11 +262,9 @@ class SetAggregate(show.ShowOne): return ({}, {}) -class ShowAggregate(show.ShowOne): +class ShowAggregate(command.ShowOne): """Display aggregate details""" - log = logging.getLogger(__name__ + '.ShowAggregate') - def get_parser(self, prog_name): parser = super(ShowAggregate, self).get_parser(prog_name) parser.add_argument( @@ -303,7 +274,6 @@ class ShowAggregate(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute diff --git a/openstackclient/compute/v2/availability_zone.py b/openstackclient/compute/v2/availability_zone.py deleted file mode 100644 index 0fe6c73..0000000 --- a/openstackclient/compute/v2/availability_zone.py +++ /dev/null @@ -1,102 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# - -"""Compute v2 Availability Zone action implementations""" - -import copy -import logging - -from cliff import lister -from novaclient import exceptions as nova_exceptions -import six - -from openstackclient.common import utils -from openstackclient.i18n import _ # noqa - - -def _xform_availability_zone(az, include_extra): - result = [] - zone_info = {} - if hasattr(az, 'zoneState'): - zone_info['zone_status'] = ('available' if az.zoneState['available'] - else 'not available') - if hasattr(az, 'zoneName'): - zone_info['zone_name'] = az.zoneName - - if not include_extra: - result.append(zone_info) - return result - - if hasattr(az, 'hosts') and az.hosts: - for host, services in six.iteritems(az.hosts): - host_info = copy.deepcopy(zone_info) - host_info['host_name'] = host - - for svc, state in six.iteritems(services): - info = copy.deepcopy(host_info) - info['service_name'] = svc - info['service_status'] = '%s %s %s' % ( - 'enabled' if state['active'] else 'disabled', - ':-)' if state['available'] else 'XXX', - state['updated_at']) - result.append(info) - else: - zone_info['host_name'] = '' - zone_info['service_name'] = '' - zone_info['service_status'] = '' - result.append(zone_info) - return result - - -class ListAvailabilityZone(lister.Lister): - """List availability zones and their status""" - - log = logging.getLogger(__name__ + '.ListAvailabilityZone') - - def get_parser(self, prog_name): - parser = super(ListAvailabilityZone, self).get_parser(prog_name) - parser.add_argument( - '--long', - action='store_true', - default=False, - help=_('List additional fields in output'), - ) - return parser - - @utils.log_method(log) - def take_action(self, parsed_args): - - if parsed_args.long: - columns = ('Zone Name', 'Zone Status', - 'Host Name', 'Service Name', 'Service Status') - else: - columns = ('Zone Name', 'Zone Status') - - compute_client = self.app.client_manager.compute - try: - data = compute_client.availability_zones.list() - except nova_exceptions.Forbidden as e: # policy doesn't allow - try: - data = compute_client.availability_zones.list(detailed=False) - except Exception: - raise e - - # Argh, the availability zones are not iterable... - result = [] - for zone in data: - result += _xform_availability_zone(zone, parsed_args.long) - - return (columns, - (utils.get_dict_properties( - s, columns - ) for s in result)) diff --git a/openstackclient/compute/v2/console.py b/openstackclient/compute/v2/console.py index aafa5d4..6c0ec31 100644 --- a/openstackclient/compute/v2/console.py +++ b/openstackclient/compute/v2/console.py @@ -15,13 +15,10 @@ """Compute v2 Console action implementations""" -import logging import six import sys -from cliff import command -from cliff import show - +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils @@ -29,8 +26,6 @@ from openstackclient.common import utils class ShowConsoleLog(command.Command): """Show server's console output""" - log = logging.getLogger(__name__ + '.ShowConsoleLog') - def get_parser(self, prog_name): parser = super(ShowConsoleLog, self).get_parser(prog_name) parser.add_argument( @@ -49,7 +44,6 @@ class ShowConsoleLog(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -65,14 +59,11 @@ class ShowConsoleLog(command.Command): data = server.get_console_output(length=length) sys.stdout.write(data) - return -class ShowConsoleURL(show.ShowOne): +class ShowConsoleURL(command.ShowOne): """Show server's remote console URL""" - log = logging.getLogger(__name__ + '.ShowConsoleURL') - def get_parser(self, prog_name): parser = super(ShowConsoleURL, self).get_parser(prog_name) parser.add_argument( @@ -105,7 +96,6 @@ class ShowConsoleURL(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute server = utils.find_resource( diff --git a/openstackclient/compute/v2/fixedip.py b/openstackclient/compute/v2/fixedip.py index da9d85c..daac97d 100644 --- a/openstackclient/compute/v2/fixedip.py +++ b/openstackclient/compute/v2/fixedip.py @@ -15,18 +15,13 @@ """Fixed IP action implementations""" -import logging - -from cliff import command - +from openstackclient.common import command from openstackclient.common import utils class AddFixedIP(command.Command): """Add fixed IP address to server""" - log = logging.getLogger(__name__ + ".AddFixedIP") - def get_parser(self, prog_name): parser = super(AddFixedIP, self).get_parser(prog_name) parser.add_argument( @@ -42,7 +37,6 @@ class AddFixedIP(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute network = utils.find_resource( @@ -52,14 +46,11 @@ class AddFixedIP(command.Command): compute_client.servers, parsed_args.server) server.add_fixed_ip(network.id) - return class RemoveFixedIP(command.Command): """Remove fixed IP address from server""" - log = logging.getLogger(__name__ + ".RemoveFixedIP") - def get_parser(self, prog_name): parser = super(RemoveFixedIP, self).get_parser(prog_name) parser.add_argument( @@ -75,11 +66,9 @@ class RemoveFixedIP(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute server = utils.find_resource( compute_client.servers, parsed_args.server) server.remove_fixed_ip(parsed_args.ip_address) - return diff --git a/openstackclient/compute/v2/flavor.py b/openstackclient/compute/v2/flavor.py index 7474580..093592c 100644 --- a/openstackclient/compute/v2/flavor.py +++ b/openstackclient/compute/v2/flavor.py @@ -15,22 +15,16 @@ """Flavor action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils -class CreateFlavor(show.ShowOne): +class CreateFlavor(command.ShowOne): """Create new flavor""" - log = logging.getLogger(__name__ + ".CreateFlavor") - def get_parser(self, prog_name): parser = super(CreateFlavor, self).get_parser(prog_name) parser.add_argument( @@ -104,7 +98,6 @@ class CreateFlavor(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute args = ( @@ -128,8 +121,6 @@ class CreateFlavor(show.ShowOne): class DeleteFlavor(command.Command): """Delete flavor""" - log = logging.getLogger(__name__ + ".DeleteFlavor") - def get_parser(self, prog_name): parser = super(DeleteFlavor, self).get_parser(prog_name) parser.add_argument( @@ -140,19 +131,15 @@ class DeleteFlavor(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute flavor = utils.find_resource(compute_client.flavors, parsed_args.flavor) compute_client.flavors.delete(flavor.id) - return -class ListFlavor(lister.Lister): +class ListFlavor(command.Lister): """List flavors""" - log = logging.getLogger(__name__ + ".ListFlavor") - def get_parser(self, prog_name): parser = super(ListFlavor, self).get_parser(prog_name) public_group = parser.add_mutually_exclusive_group() @@ -193,7 +180,6 @@ class ListFlavor(lister.Lister): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute columns = ( "ID", @@ -232,11 +218,9 @@ class ListFlavor(lister.Lister): ) for s in data)) -class ShowFlavor(show.ShowOne): +class ShowFlavor(command.ShowOne): """Display flavor details""" - log = logging.getLogger(__name__ + ".ShowFlavor") - def get_parser(self, prog_name): parser = super(ShowFlavor, self).get_parser(prog_name) parser.add_argument( @@ -247,7 +231,6 @@ class ShowFlavor(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute resource_flavor = utils.find_resource(compute_client.flavors, parsed_args.flavor) @@ -259,11 +242,9 @@ class ShowFlavor(show.ShowOne): return zip(*sorted(six.iteritems(flavor))) -class SetFlavor(show.ShowOne): +class SetFlavor(command.ShowOne): """Set flavor properties""" - log = logging.getLogger(__name__ + ".SetFlavor") - def get_parser(self, prog_name): parser = super(SetFlavor, self).get_parser(prog_name) parser.add_argument( @@ -281,7 +262,6 @@ class SetFlavor(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute resource_flavor = compute_client.flavors.find(name=parsed_args.flavor) @@ -293,11 +273,9 @@ class SetFlavor(show.ShowOne): return zip(*sorted(six.iteritems(flavor))) -class UnsetFlavor(show.ShowOne): +class UnsetFlavor(command.ShowOne): """Unset flavor properties""" - log = logging.getLogger(__name__ + ".UnsetFlavor") - def get_parser(self, prog_name): parser = super(UnsetFlavor, self).get_parser(prog_name) parser.add_argument( @@ -316,7 +294,6 @@ class UnsetFlavor(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute resource_flavor = compute_client.flavors.find(name=parsed_args.flavor) diff --git a/openstackclient/compute/v2/floatingip.py b/openstackclient/compute/v2/floatingip.py index 65fe591..29ecbc9 100644 --- a/openstackclient/compute/v2/floatingip.py +++ b/openstackclient/compute/v2/floatingip.py @@ -15,21 +15,15 @@ """Floating IP action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils class AddFloatingIP(command.Command): """Add floating IP address to server""" - log = logging.getLogger(__name__ + ".AddFloatingIP") - def get_parser(self, prog_name): parser = super(AddFloatingIP, self).get_parser(prog_name) parser.add_argument( @@ -45,21 +39,17 @@ class AddFloatingIP(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute server = utils.find_resource( compute_client.servers, parsed_args.server) server.add_floating_ip(parsed_args.ip_address) - return -class CreateFloatingIP(show.ShowOne): +class CreateFloatingIP(command.ShowOne): """Create new floating IP address""" - log = logging.getLogger(__name__ + '.CreateFloatingIP') - def get_parser(self, prog_name): parser = super(CreateFloatingIP, self).get_parser(prog_name) parser.add_argument( @@ -69,7 +59,6 @@ class CreateFloatingIP(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute floating_ip = compute_client.floating_ips.create(parsed_args.pool) @@ -82,8 +71,6 @@ class CreateFloatingIP(show.ShowOne): class DeleteFloatingIP(command.Command): """Delete a floating IP address""" - log = logging.getLogger(__name__ + '.DeleteFloatingIP') - def get_parser(self, prog_name): parser = super(DeleteFloatingIP, self).get_parser(prog_name) parser.add_argument( @@ -93,7 +80,6 @@ class DeleteFloatingIP(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -103,15 +89,11 @@ class DeleteFloatingIP(command.Command): ) compute_client.floating_ips.delete(floating_ip) - return -class ListFloatingIP(lister.Lister): +class ListFloatingIP(command.Lister): """List floating IP addresses""" - log = logging.getLogger(__name__ + '.ListFloatingIP') - - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -129,8 +111,6 @@ class ListFloatingIP(lister.Lister): class RemoveFloatingIP(command.Command): """Remove floating IP address from server""" - log = logging.getLogger(__name__ + ".RemoveFloatingIP") - def get_parser(self, prog_name): parser = super(RemoveFloatingIP, self).get_parser(prog_name) parser.add_argument( @@ -146,11 +126,9 @@ class RemoveFloatingIP(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute server = utils.find_resource( compute_client.servers, parsed_args.server) server.remove_floating_ip(parsed_args.ip_address) - return diff --git a/openstackclient/compute/v2/floatingippool.py b/openstackclient/compute/v2/floatingippool.py index 39a2d8f..997e032 100644 --- a/openstackclient/compute/v2/floatingippool.py +++ b/openstackclient/compute/v2/floatingippool.py @@ -15,19 +15,13 @@ """Floating IP Pool action implementations""" -import logging - -from cliff import lister - +from openstackclient.common import command from openstackclient.common import utils -class ListFloatingIPPool(lister.Lister): +class ListFloatingIPPool(command.Lister): """List pools of floating IP addresses""" - log = logging.getLogger(__name__ + '.ListFloatingIPPool') - - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute diff --git a/openstackclient/compute/v2/host.py b/openstackclient/compute/v2/host.py index 4f72738..f2257d1 100644 --- a/openstackclient/compute/v2/host.py +++ b/openstackclient/compute/v2/host.py @@ -15,18 +15,13 @@ """Host action implementations""" -import logging - -from cliff import lister - +from openstackclient.common import command from openstackclient.common import utils -class ListHost(lister.Lister): +class ListHost(command.Lister): """List host command""" - log = logging.getLogger(__name__ + ".ListHost") - def get_parser(self, prog_name): parser = super(ListHost, self).get_parser(prog_name) parser.add_argument( @@ -36,7 +31,6 @@ class ListHost(lister.Lister): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute columns = ( "Host Name", @@ -50,11 +44,9 @@ class ListHost(lister.Lister): ) for s in data)) -class ShowHost(lister.Lister): +class ShowHost(command.Lister): """Show host command""" - log = logging.getLogger(__name__ + ".ShowHost") - def get_parser(self, prog_name): parser = super(ShowHost, self).get_parser(prog_name) parser.add_argument( @@ -64,7 +56,6 @@ class ShowHost(lister.Lister): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute columns = ( "Host", diff --git a/openstackclient/compute/v2/hypervisor.py b/openstackclient/compute/v2/hypervisor.py index f33beb0..f5288a3 100644 --- a/openstackclient/compute/v2/hypervisor.py +++ b/openstackclient/compute/v2/hypervisor.py @@ -15,21 +15,16 @@ """Hypervisor action implementations""" -import logging import re import six -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils -class ListHypervisor(lister.Lister): +class ListHypervisor(command.Lister): """List hypervisors""" - log = logging.getLogger(__name__ + ".ListHypervisor") - def get_parser(self, prog_name): parser = super(ListHypervisor, self).get_parser(prog_name) parser.add_argument( @@ -40,7 +35,6 @@ class ListHypervisor(lister.Lister): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute columns = ( "ID", @@ -58,11 +52,9 @@ class ListHypervisor(lister.Lister): ) for s in data)) -class ShowHypervisor(show.ShowOne): +class ShowHypervisor(command.ShowOne): """Display hypervisor details""" - log = logging.getLogger(__name__ + ".ShowHypervisor") - def get_parser(self, prog_name): parser = super(ShowHypervisor, self).get_parser(prog_name) parser.add_argument( @@ -72,7 +64,6 @@ class ShowHypervisor(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute hypervisor = utils.find_resource(compute_client.hypervisors, parsed_args.hypervisor)._info.copy() diff --git a/openstackclient/compute/v2/hypervisor_stats.py b/openstackclient/compute/v2/hypervisor_stats.py index 43ba9fc..290f541 100644 --- a/openstackclient/compute/v2/hypervisor_stats.py +++ b/openstackclient/compute/v2/hypervisor_stats.py @@ -14,19 +14,15 @@ """Hypervisor Stats action implementations""" -import logging import six -from cliff import show +from openstackclient.common import command -class ShowHypervisorStats(show.ShowOne): +class ShowHypervisorStats(command.ShowOne): """Display hypervisor stats details""" - log = logging.getLogger(__name__ + ".ShowHypervisorStats") - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute hypervisor_stats = compute_client.hypervisors.statistics().to_dict() diff --git a/openstackclient/compute/v2/keypair.py b/openstackclient/compute/v2/keypair.py index 5c627c5..71c9d67 100644 --- a/openstackclient/compute/v2/keypair.py +++ b/openstackclient/compute/v2/keypair.py @@ -15,24 +15,18 @@ """Keypair action implementations""" -import logging import os import six import sys -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import exceptions from openstackclient.common import utils -class CreateKeypair(show.ShowOne): +class CreateKeypair(command.ShowOne): """Create new public key""" - log = logging.getLogger(__name__ + '.CreateKeypair') - def get_parser(self, prog_name): parser = super(CreateKeypair, self).get_parser(prog_name) parser.add_argument( @@ -47,7 +41,6 @@ class CreateKeypair(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -82,8 +75,6 @@ class CreateKeypair(show.ShowOne): class DeleteKeypair(command.Command): """Delete public key""" - log = logging.getLogger(__name__ + '.DeleteKeypair') - def get_parser(self, prog_name): parser = super(DeleteKeypair, self).get_parser(prog_name) parser.add_argument( @@ -93,20 +84,15 @@ class DeleteKeypair(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute compute_client.keypairs.delete(parsed_args.name) - return -class ListKeypair(lister.Lister): +class ListKeypair(command.Lister): """List public key fingerprints""" - log = logging.getLogger(__name__ + ".ListKeypair") - def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute columns = ( "Name", @@ -120,11 +106,9 @@ class ListKeypair(lister.Lister): ) for s in data)) -class ShowKeypair(show.ShowOne): +class ShowKeypair(command.ShowOne): """Display public key details""" - log = logging.getLogger(__name__ + '.ShowKeypair') - def get_parser(self, prog_name): parser = super(ShowKeypair, self).get_parser(prog_name) parser.add_argument( @@ -140,7 +124,6 @@ class ShowKeypair(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute keypair = utils.find_resource(compute_client.keypairs, diff --git a/openstackclient/compute/v2/security_group.py b/openstackclient/compute/v2/security_group.py index 6d38195..2a8908d 100644 --- a/openstackclient/compute/v2/security_group.py +++ b/openstackclient/compute/v2/security_group.py @@ -16,13 +16,8 @@ """Compute v2 Security Group action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - from keystoneauth1 import exceptions as ks_exc try: @@ -30,6 +25,7 @@ try: except ImportError: from novaclient.v1_1 import security_group_rules +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils @@ -54,13 +50,33 @@ def _xform_security_group_rule(sgroup): info['ip_protocol'] = '' elif info['ip_protocol'].lower() == 'icmp': info['port_range'] = '' + group = info.pop('group') + if 'name' in group: + info['remote_security_group'] = group['name'] + else: + info['remote_security_group'] = '' return info -class CreateSecurityGroup(show.ShowOne): - """Create a new security group""" +def _xform_and_trim_security_group_rule(sgroup): + info = _xform_security_group_rule(sgroup) + # Trim parent security group ID since caller has this information. + info.pop('parent_group_id', None) + # Trim keys with empty string values. + keys_to_trim = [ + 'ip_protocol', + 'ip_range', + 'port_range', + 'remote_security_group', + ] + for key in keys_to_trim: + if key in info and not info[key]: + info.pop(key) + return info - log = logging.getLogger(__name__ + ".CreateSecurityGroup") + +class CreateSecurityGroup(command.ShowOne): + """Create a new security group""" def get_parser(self, prog_name): parser = super(CreateSecurityGroup, self).get_parser(prog_name) @@ -77,8 +93,6 @@ class CreateSecurityGroup(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - compute_client = self.app.client_manager.compute description = parsed_args.description or parsed_args.name @@ -93,11 +107,9 @@ class CreateSecurityGroup(show.ShowOne): return zip(*sorted(six.iteritems(info))) -class CreateSecurityGroupRule(show.ShowOne): +class CreateSecurityGroupRule(command.ShowOne): """Create a new security group rule""" - log = logging.getLogger(__name__ + ".CreateSecurityGroupRule") - def get_parser(self, prog_name): parser = super(CreateSecurityGroupRule, self).get_parser(prog_name) parser.add_argument( @@ -111,11 +123,18 @@ class CreateSecurityGroupRule(show.ShowOne): default="tcp", help="IP protocol (icmp, tcp, udp; default: tcp)", ) - parser.add_argument( + source_group = parser.add_mutually_exclusive_group() + source_group.add_argument( "--src-ip", metavar="<ip-address>", default="0.0.0.0/0", - help="Source IP (may use CIDR notation; default: 0.0.0.0/0)", + help="Source IP address block (may use CIDR notation; default: " + "0.0.0.0/0)", + ) + source_group.add_argument( + "--src-group", + metavar="<group>", + help="Source security group (ID only)", ) parser.add_argument( "--dst-port", @@ -128,8 +147,6 @@ class CreateSecurityGroupRule(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - compute_client = self.app.client_manager.compute group = utils.find_resource( compute_client.security_groups, @@ -145,43 +162,16 @@ class CreateSecurityGroupRule(show.ShowOne): from_port, to_port, parsed_args.src_ip, + parsed_args.src_group, ) info = _xform_security_group_rule(data._info) return zip(*sorted(six.iteritems(info))) -class DeleteSecurityGroup(command.Command): - """Delete a security group""" - - log = logging.getLogger(__name__ + '.DeleteSecurityGroup') - - def get_parser(self, prog_name): - parser = super(DeleteSecurityGroup, self).get_parser(prog_name) - parser.add_argument( - 'group', - metavar='<group>', - help='Security group to delete (name or ID)', - ) - return parser - - @utils.log_method(log) - def take_action(self, parsed_args): - - compute_client = self.app.client_manager.compute - data = utils.find_resource( - compute_client.security_groups, - parsed_args.group, - ) - compute_client.security_groups.delete(data.id) - return - - class DeleteSecurityGroupRule(command.Command): """Delete a security group rule""" - log = logging.getLogger(__name__ + '.DeleteSecurityGroupRule') - def get_parser(self, prog_name): parser = super(DeleteSecurityGroupRule, self).get_parser(prog_name) parser.add_argument( @@ -191,19 +181,15 @@ class DeleteSecurityGroupRule(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute compute_client.security_group_rules.delete(parsed_args.rule) - return -class ListSecurityGroup(lister.Lister): +class ListSecurityGroup(command.Lister): """List security groups""" - log = logging.getLogger(__name__ + ".ListSecurityGroup") - def get_parser(self, prog_name): parser = super(ListSecurityGroup, self).get_parser(prog_name) parser.add_argument( @@ -222,8 +208,6 @@ class ListSecurityGroup(lister.Lister): except KeyError: return project_id - self.log.debug("take_action(%s)", parsed_args) - compute_client = self.app.client_manager.compute columns = ( "ID", @@ -255,54 +239,59 @@ class ListSecurityGroup(lister.Lister): ) for s in data)) -class ListSecurityGroupRule(lister.Lister): +class ListSecurityGroupRule(command.Lister): """List security group rules""" - log = logging.getLogger(__name__ + ".ListSecurityGroupRule") - def get_parser(self, prog_name): parser = super(ListSecurityGroupRule, self).get_parser(prog_name) parser.add_argument( 'group', metavar='<group>', + nargs='?', help='List all rules in this security group (name or ID)', ) return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - compute_client = self.app.client_manager.compute - group = utils.find_resource( - compute_client.security_groups, - parsed_args.group, + columns = column_headers = ( + "ID", + "IP Protocol", + "IP Range", + "Port Range", + "Remote Security Group", ) + rules_to_list = [] + if parsed_args.group: + group = utils.find_resource( + compute_client.security_groups, + parsed_args.group, + ) + rules_to_list = group.rules + else: + columns = columns + ('parent_group_id',) + column_headers = column_headers + ('Security Group',) + for group in compute_client.security_groups.list(): + rules_to_list.extend(group.rules) + # Argh, the rules are not Resources... rules = [] - for rule in group.rules: + for rule in rules_to_list: rules.append(security_group_rules.SecurityGroupRule( compute_client.security_group_rules, _xform_security_group_rule(rule), )) - columns = column_headers = ( - "ID", - "IP Protocol", - "IP Range", - "Port Range", - ) return (column_headers, (utils.get_item_properties( s, columns, ) for s in rules)) -class SetSecurityGroup(show.ShowOne): +class SetSecurityGroup(command.ShowOne): """Set security group properties""" - log = logging.getLogger(__name__ + '.SetSecurityGroup') - def get_parser(self, prog_name): parser = super(SetSecurityGroup, self).get_parser(prog_name) parser.add_argument( @@ -322,7 +311,6 @@ class SetSecurityGroup(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -349,11 +337,9 @@ class SetSecurityGroup(show.ShowOne): return ({}, {}) -class ShowSecurityGroup(show.ShowOne): +class ShowSecurityGroup(command.ShowOne): """Display security group details""" - log = logging.getLogger(__name__ + '.ShowSecurityGroup') - def get_parser(self, prog_name): parser = super(ShowSecurityGroup, self).get_parser(prog_name) parser.add_argument( @@ -363,7 +349,6 @@ class ShowSecurityGroup(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -374,11 +359,12 @@ class ShowSecurityGroup(show.ShowOne): )._info) rules = [] for r in info['rules']: - rules.append(utils.format_dict(_xform_security_group_rule(r))) + formatted_rule = _xform_and_trim_security_group_rule(r) + rules.append(utils.format_dict(formatted_rule)) # Format rules into a list of strings info.update( - {'rules': rules} + {'rules': utils.format_list(rules, separator='\n')} ) # Map 'tenant_id' column to 'project_id' info.update( diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index 9dca784..dd7bc47 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -18,14 +18,11 @@ import argparse import getpass import io -import logging import os import six import sys -from cliff import command -from cliff import lister -from cliff import show +from openstackclient.common import command try: from novaclient.v2 import servers @@ -37,7 +34,6 @@ from openstackclient.common import parseractions from openstackclient.common import utils from openstackclient.i18n import _ # noqa from openstackclient.identity import common as identity_common -from openstackclient.network import common def _format_servers_list_networks(networks): @@ -174,8 +170,6 @@ def _show_progress(progress): class AddServerSecurityGroup(command.Command): """Add security group to server""" - log = logging.getLogger(__name__ + '.AddServerSecurityGroup') - def get_parser(self, prog_name): parser = super(AddServerSecurityGroup, self).get_parser(prog_name) parser.add_argument( @@ -191,8 +185,6 @@ class AddServerSecurityGroup(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - compute_client = self.app.client_manager.compute server = utils.find_resource( @@ -205,14 +197,11 @@ class AddServerSecurityGroup(command.Command): ) server.add_security_group(security_group.name) - return class AddServerVolume(command.Command): """Add volume to server""" - log = logging.getLogger(__name__ + '.AddServerVolume') - def get_parser(self, prog_name): parser = super(AddServerVolume, self).get_parser(prog_name) parser.add_argument( @@ -233,8 +222,6 @@ class AddServerVolume(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - compute_client = self.app.client_manager.compute volume_client = self.app.client_manager.volume @@ -254,15 +241,9 @@ class AddServerVolume(command.Command): ) -class CreateServer(show.ShowOne): +class CreateServer(command.ShowOne): """Create a new server""" - log = logging.getLogger(__name__ + '.CreateServer') - - def _is_neutron_enabled(self): - service_catalog = self.app.client_manager.auth_ref.service_catalog - return 'network' in service_catalog.get_endpoints() - def get_parser(self, prog_name): parser = super(CreateServer, self).get_parser(prog_name) parser.add_argument( @@ -276,25 +257,25 @@ class CreateServer(show.ShowOne): disk_group.add_argument( '--image', metavar='<image>', - help=_('Create server from this image'), + help=_('Create server from this image (name or ID)'), ) disk_group.add_argument( '--volume', metavar='<volume>', - help=_('Create server from this volume'), + help=_('Create server from this volume (name or ID)'), ) parser.add_argument( '--flavor', metavar='<flavor>', required=True, - help=_('Create server with this flavor'), + help=_('Create server with this flavor (name or ID)'), ) parser.add_argument( '--security-group', metavar='<security-group-name>', action='append', default=[], - help=_('Security group to assign to this server ' + help=_('Security group to assign to this server (name or ID) ' '(repeat for multiple groups)'), ) parser.add_argument( @@ -385,7 +366,6 @@ class CreateServer(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute volume_client = self.app.client_manager.volume @@ -462,8 +442,6 @@ class CreateServer(show.ShowOne): block_device_mapping.update({dev_key: block_volume}) nics = [] - if parsed_args.nic: - neutron_enabled = self._is_neutron_enabled() for nic_str in parsed_args.nic: nic_info = {"net-id": "", "v4-fixed-ip": "", "v6-fixed-ip": "", "port-id": ""} @@ -473,18 +451,16 @@ class CreateServer(show.ShowOne): msg = _("either net-id or port-id should be specified " "but not both") raise exceptions.CommandError(msg) - if neutron_enabled: + if self.app.client_manager.is_network_endpoint_enabled(): network_client = self.app.client_manager.network if nic_info["net-id"]: - nic_info["net-id"] = common.find(network_client, - 'network', - 'networks', - nic_info["net-id"]) + net = network_client.find_network( + nic_info["net-id"], ignore_missing=False) + nic_info["net-id"] = net.id if nic_info["port-id"]: - nic_info["port-id"] = common.find(network_client, - 'port', - 'ports', - nic_info["port-id"]) + port = network_client.find_port( + nic_info["port-id"], ignore_missing=False) + nic_info["port-id"] = port.id else: if nic_info["net-id"]: nic_info["net-id"] = utils.find_resource( @@ -493,7 +469,7 @@ class CreateServer(show.ShowOne): ).id if nic_info["port-id"]: msg = _("can't create server with port specified " - "since neutron not enabled") + "since network endpoint not enabled") raise exceptions.CommandError(msg) nics.append(nic_info) @@ -566,11 +542,9 @@ class CreateServer(show.ShowOne): return zip(*sorted(six.iteritems(details))) -class CreateServerImage(show.ShowOne): +class CreateServerImage(command.ShowOne): """Create a new disk image from a running server""" - log = logging.getLogger(__name__ + '.CreateServerImage') - def get_parser(self, prog_name): parser = super(CreateServerImage, self).get_parser(prog_name) parser.add_argument( @@ -590,7 +564,6 @@ class CreateServerImage(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute image_client = self.app.client_manager.image @@ -632,8 +605,6 @@ class CreateServerImage(show.ShowOne): class DeleteServer(command.Command): """Delete server(s)""" - log = logging.getLogger(__name__ + '.DeleteServer') - def get_parser(self, prog_name): parser = super(DeleteServer, self).get_parser(prog_name) parser.add_argument( @@ -649,7 +620,6 @@ class DeleteServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute for server in parsed_args.server: @@ -668,14 +638,11 @@ class DeleteServer(command.Command): server_obj.id) sys.stdout.write(_('\nError deleting server')) raise SystemExit - return -class ListServer(lister.Lister): +class ListServer(command.Lister): """List servers""" - log = logging.getLogger(__name__ + '.ListServer') - def get_parser(self, prog_name): parser = super(ListServer, self).get_parser(prog_name) parser.add_argument( @@ -712,12 +679,12 @@ class ListServer(lister.Lister): parser.add_argument( '--flavor', metavar='<flavor>', - help=_('Search by flavor'), + help=_('Search by flavor (name or ID)'), ) parser.add_argument( '--image', metavar='<image>', - help=_('Search by image'), + help=_('Search by image (name or ID)'), ) parser.add_argument( '--host', @@ -767,7 +734,6 @@ class ListServer(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute identity_client = self.app.client_manager.identity @@ -789,6 +755,20 @@ class ListServer(lister.Lister): parsed_args.user_domain, ).id + # Nova only supports list servers searching by flavor ID. So if a + # flavor name is given, map it to ID. + flavor_id = None + if parsed_args.flavor: + flavor_id = utils.find_resource(compute_client.flavors, + parsed_args.flavor).id + + # Nova only supports list servers searching by image ID. So if a + # image name is given, map it to ID. + image_id = None + if parsed_args.image: + image_id = utils.find_resource(compute_client.images, + parsed_args.image).id + search_opts = { 'reservation_id': parsed_args.reservation_id, 'ip': parsed_args.ip, @@ -796,8 +776,8 @@ class ListServer(lister.Lister): 'name': parsed_args.name, 'instance_name': parsed_args.instance_name, 'status': parsed_args.status, - 'flavor': parsed_args.flavor, - 'image': parsed_args.image, + 'flavor': flavor_id, + 'image': image_id, 'host': parsed_args.host, 'tenant_id': project_id, 'all_tenants': parsed_args.all_projects, @@ -874,8 +854,6 @@ class LockServer(command.Command): """Lock server(s). A non-admin user will not be able to execute actions""" - log = logging.getLogger(__name__ + '.LockServer') - def get_parser(self, prog_name): parser = super(LockServer, self).get_parser(prog_name) parser.add_argument( @@ -886,7 +864,6 @@ class LockServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -910,8 +887,6 @@ class LockServer(command.Command): class MigrateServer(command.Command): """Migrate server to different host""" - log = logging.getLogger(__name__ + '.MigrateServer') - def get_parser(self, prog_name): parser = super(MigrateServer, self).get_parser(prog_name) parser.add_argument( @@ -960,7 +935,6 @@ class MigrateServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -993,8 +967,6 @@ class MigrateServer(command.Command): class PauseServer(command.Command): """Pause server(s)""" - log = logging.getLogger(__name__ + '.PauseServer') - def get_parser(self, prog_name): parser = super(PauseServer, self).get_parser(prog_name) parser.add_argument( @@ -1005,7 +977,6 @@ class PauseServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute for server in parsed_args.server: @@ -1018,8 +989,6 @@ class PauseServer(command.Command): class RebootServer(command.Command): """Perform a hard or soft server reboot""" - log = logging.getLogger(__name__ + '.RebootServer') - def get_parser(self, prog_name): parser = super(RebootServer, self).get_parser(prog_name) parser.add_argument( @@ -1051,7 +1020,6 @@ class RebootServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute server = utils.find_resource( @@ -1070,11 +1038,9 @@ class RebootServer(command.Command): raise SystemExit -class RebuildServer(show.ShowOne): +class RebuildServer(command.ShowOne): """Rebuild server""" - log = logging.getLogger(__name__ + '.RebuildServer') - def get_parser(self, prog_name): parser = super(RebuildServer, self).get_parser(prog_name) parser.add_argument( @@ -1085,8 +1051,8 @@ class RebuildServer(show.ShowOne): parser.add_argument( '--image', metavar='<image>', - required=True, - help=_('Recreate server from this image'), + help=_('Recreate server from the specified image (name or ID).' + ' Defaults to the currently used one.'), ) parser.add_argument( '--password', @@ -1100,16 +1066,16 @@ class RebuildServer(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute - # Lookup parsed_args.image - image = utils.find_resource(compute_client.images, parsed_args.image) - server = utils.find_resource( compute_client.servers, parsed_args.server) + # If parsed_args.image is not set, default to the currently used one. + image_id = parsed_args.image or server._info.get('image', {}).get('id') + image = utils.find_resource(compute_client.images, image_id) + server = server.rebuild(image, parsed_args.password) if parsed_args.wait: if utils.wait_for_status( @@ -1129,8 +1095,6 @@ class RebuildServer(show.ShowOne): class RemoveServerSecurityGroup(command.Command): """Remove security group from server""" - log = logging.getLogger(__name__ + '.RemoveServerSecurityGroup') - def get_parser(self, prog_name): parser = super(RemoveServerSecurityGroup, self).get_parser(prog_name) parser.add_argument( @@ -1146,8 +1110,6 @@ class RemoveServerSecurityGroup(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - compute_client = self.app.client_manager.compute server = utils.find_resource( @@ -1165,8 +1127,6 @@ class RemoveServerSecurityGroup(command.Command): class RemoveServerVolume(command.Command): """Remove volume from server""" - log = logging.getLogger(__name__ + '.RemoveServerVolume') - def get_parser(self, prog_name): parser = super(RemoveServerVolume, self).get_parser(prog_name) parser.add_argument( @@ -1182,8 +1142,6 @@ class RemoveServerVolume(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - compute_client = self.app.client_manager.compute volume_client = self.app.client_manager.volume @@ -1202,11 +1160,9 @@ class RemoveServerVolume(command.Command): ) -class RescueServer(show.ShowOne): +class RescueServer(command.ShowOne): """Put server in rescue mode""" - log = logging.getLogger(__name__ + '.RescueServer') - def get_parser(self, prog_name): parser = super(RescueServer, self).get_parser(prog_name) parser.add_argument( @@ -1216,7 +1172,6 @@ class RescueServer(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -1230,8 +1185,6 @@ class RescueServer(show.ShowOne): class ResizeServer(command.Command): """Scale server to a new flavor""" - log = logging.getLogger(__name__ + '.ResizeServer') - def get_parser(self, prog_name): parser = super(ResizeServer, self).get_parser(prog_name) phase_group = parser.add_mutually_exclusive_group() @@ -1262,7 +1215,6 @@ class ResizeServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -1296,8 +1248,6 @@ class ResizeServer(command.Command): class ResumeServer(command.Command): """Resume server(s)""" - log = logging.getLogger(__name__ + '.ResumeServer') - def get_parser(self, prog_name): parser = super(ResumeServer, self).get_parser(prog_name) parser.add_argument( @@ -1308,7 +1258,6 @@ class ResumeServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -1322,8 +1271,6 @@ class ResumeServer(command.Command): class SetServer(command.Command): """Set server properties""" - log = logging.getLogger(__name__ + '.SetServer') - def get_parser(self, prog_name): parser = super(SetServer, self).get_parser(prog_name) parser.add_argument( @@ -1350,7 +1297,6 @@ class SetServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -1381,8 +1327,6 @@ class SetServer(command.Command): class ShelveServer(command.Command): """Shelve server(s)""" - log = logging.getLogger(__name__ + '.ShelveServer') - def get_parser(self, prog_name): parser = super(ShelveServer, self).get_parser(prog_name) parser.add_argument( @@ -1393,7 +1337,6 @@ class ShelveServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute for server in parsed_args.server: @@ -1403,11 +1346,9 @@ class ShelveServer(command.Command): ).shelve() -class ShowServer(show.ShowOne): +class ShowServer(command.ShowOne): """Show server details""" - log = logging.getLogger(__name__ + '.ShowServer') - def get_parser(self, prog_name): parser = super(ShowServer, self).get_parser(prog_name) parser.add_argument( @@ -1423,7 +1364,6 @@ class ShowServer(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute server = utils.find_resource(compute_client.servers, @@ -1443,8 +1383,6 @@ class ShowServer(show.ShowOne): class SshServer(command.Command): """Ssh to server""" - log = logging.getLogger(__name__ + '.SshServer') - def get_parser(self, prog_name): parser = super(SshServer, self).get_parser(prog_name) parser.add_argument( @@ -1546,7 +1484,6 @@ class SshServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -1590,8 +1527,6 @@ class SshServer(command.Command): class StartServer(command.Command): """Start server(s).""" - log = logging.getLogger(__name__ + '.StartServer') - def get_parser(self, prog_name): parser = super(StartServer, self).get_parser(prog_name) parser.add_argument( @@ -1602,7 +1537,6 @@ class StartServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute for server in parsed_args.server: @@ -1615,8 +1549,6 @@ class StartServer(command.Command): class StopServer(command.Command): """Stop server(s).""" - log = logging.getLogger(__name__ + '.StopServer') - def get_parser(self, prog_name): parser = super(StopServer, self).get_parser(prog_name) parser.add_argument( @@ -1627,7 +1559,6 @@ class StopServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute for server in parsed_args.server: @@ -1640,8 +1571,6 @@ class StopServer(command.Command): class SuspendServer(command.Command): """Suspend server(s)""" - log = logging.getLogger(__name__ + '.SuspendServer') - def get_parser(self, prog_name): parser = super(SuspendServer, self).get_parser(prog_name) parser.add_argument( @@ -1652,7 +1581,6 @@ class SuspendServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -1666,8 +1594,6 @@ class SuspendServer(command.Command): class UnlockServer(command.Command): """Unlock server(s)""" - log = logging.getLogger(__name__ + '.UnlockServer') - def get_parser(self, prog_name): parser = super(UnlockServer, self).get_parser(prog_name) parser.add_argument( @@ -1678,7 +1604,6 @@ class UnlockServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -1692,8 +1617,6 @@ class UnlockServer(command.Command): class UnpauseServer(command.Command): """Unpause server(s)""" - log = logging.getLogger(__name__ + '.UnpauseServer') - def get_parser(self, prog_name): parser = super(UnpauseServer, self).get_parser(prog_name) parser.add_argument( @@ -1704,7 +1627,6 @@ class UnpauseServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -1718,8 +1640,6 @@ class UnpauseServer(command.Command): class UnrescueServer(command.Command): """Restore server from rescue mode""" - log = logging.getLogger(__name__ + '.UnrescueServer') - def get_parser(self, prog_name): parser = super(UnrescueServer, self).get_parser(prog_name) parser.add_argument( @@ -1729,7 +1649,6 @@ class UnrescueServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute @@ -1742,8 +1661,6 @@ class UnrescueServer(command.Command): class UnsetServer(command.Command): """Unset server properties""" - log = logging.getLogger(__name__ + '.UnsetServer') - def get_parser(self, prog_name): parser = super(UnsetServer, self).get_parser(prog_name) parser.add_argument( @@ -1761,7 +1678,6 @@ class UnsetServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute server = utils.find_resource( @@ -1779,8 +1695,6 @@ class UnsetServer(command.Command): class UnshelveServer(command.Command): """Unshelve server(s)""" - log = logging.getLogger(__name__ + '.UnshelveServer') - def get_parser(self, prog_name): parser = super(UnshelveServer, self).get_parser(prog_name) parser.add_argument( @@ -1791,7 +1705,6 @@ class UnshelveServer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): compute_client = self.app.client_manager.compute for server in parsed_args.server: diff --git a/openstackclient/compute/v2/service.py b/openstackclient/compute/v2/service.py index c2d51c2..3c06272 100644 --- a/openstackclient/compute/v2/service.py +++ b/openstackclient/compute/v2/service.py @@ -15,19 +15,13 @@ """Service action implementations""" -import logging - -from cliff import command -from cliff import lister - +from openstackclient.common import command from openstackclient.common import utils class DeleteService(command.Command): """Delete service command""" - log = logging.getLogger(__name__ + ".DeleteService") - def get_parser(self, prog_name): parser = super(DeleteService, self).get_parser(prog_name) parser.add_argument( @@ -37,18 +31,14 @@ class DeleteService(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute compute_client.services.delete(parsed_args.service) - return -class ListService(lister.Lister): +class ListService(command.Lister): """List service command""" - log = logging.getLogger(__name__ + ".ListService") - def get_parser(self, prog_name): parser = super(ListService, self).get_parser(prog_name) parser.add_argument( @@ -62,7 +52,6 @@ class ListService(lister.Lister): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute columns = ( "Id", @@ -81,11 +70,9 @@ class ListService(lister.Lister): ) for s in data)) -class SetService(lister.Lister): +class SetService(command.Command): """Set service command""" - log = logging.getLogger(__name__ + ".SetService") - def get_parser(self, prog_name): parser = super(SetService, self).get_parser(prog_name) parser.add_argument( @@ -101,7 +88,7 @@ class SetService(lister.Lister): "--enable", dest="enabled", default=True, - help="Enable a service", + help="Enable a service (default)", action="store_true") enabled_group.add_argument( "--disable", @@ -111,21 +98,11 @@ class SetService(lister.Lister): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) compute_client = self.app.client_manager.compute - columns = ( - "Host", - "Service", - "Disabled" - ) if parsed_args.enabled: action = compute_client.services.enable else: action = compute_client.services.disable - data = action(parsed_args.host, parsed_args.service) - return (columns, - (utils.get_item_properties( - s, columns, - ) for s in data)) + action(parsed_args.host, parsed_args.service) diff --git a/openstackclient/compute/v2/usage.py b/openstackclient/compute/v2/usage.py index 4e7cf10..baa5017 100644 --- a/openstackclient/compute/v2/usage.py +++ b/openstackclient/compute/v2/usage.py @@ -16,21 +16,17 @@ """Usage action implementations""" import datetime -import logging import sys -from cliff import lister -from cliff import show import six +from openstackclient.common import command from openstackclient.common import utils -class ListUsage(lister.Lister): +class ListUsage(command.Lister): """List resource usage per project""" - log = logging.getLogger(__name__ + ".ListUsage") - def get_parser(self, prog_name): parser = super(ListUsage, self).get_parser(prog_name) parser.add_argument( @@ -49,7 +45,6 @@ class ListUsage(lister.Lister): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) def _format_project(project): if not project: @@ -118,11 +113,9 @@ class ListUsage(lister.Lister): ) for s in usage_list)) -class ShowUsage(show.ShowOne): +class ShowUsage(command.ShowOne): """Show resource usage for a single project""" - log = logging.getLogger(__name__ + ".ShowUsage") - def get_parser(self, prog_name): parser = super(ShowUsage, self).get_parser(prog_name) parser.add_argument( @@ -147,8 +140,6 @@ class ShowUsage(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - identity_client = self.app.client_manager.identity compute_client = self.app.client_manager.compute dateformat = "%Y-%m-%d" diff --git a/openstackclient/i18n.py b/openstackclient/i18n.py index 3a11c1d..1d09772 100644 --- a/openstackclient/i18n.py +++ b/openstackclient/i18n.py @@ -15,7 +15,7 @@ import oslo_i18n -_translators = oslo_i18n.TranslatorFactory(domain='python-openstackclient') +_translators = oslo_i18n.TranslatorFactory(domain='openstackclient') # The primary translation function using the well-known name "_" _ = _translators.primary diff --git a/openstackclient/identity/common.py b/openstackclient/identity/common.py index d0edb0b..2afa41f 100644 --- a/openstackclient/identity/common.py +++ b/openstackclient/identity/common.py @@ -41,6 +41,11 @@ def find_service(identity_client, name_type_or_id): msg = ("No service with a type, name or ID of '%s' exists." % name_type_or_id) raise exceptions.CommandError(msg) + except identity_exc.NoUniqueMatch: + msg = ("Multiple service matches found for '%s', " + "use an ID to be more specific." + % name_type_or_id) + raise exceptions.CommandError(msg) def _get_domain_id_if_requested(identity_client, domain_name_or_id): diff --git a/openstackclient/identity/v2_0/catalog.py b/openstackclient/identity/v2_0/catalog.py index 9bc2755..c927943 100644 --- a/openstackclient/identity/v2_0/catalog.py +++ b/openstackclient/identity/v2_0/catalog.py @@ -13,12 +13,9 @@ """Identity v2 Service Catalog action implementations""" -import logging import six -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils from openstackclient.i18n import _ # noqa @@ -37,12 +34,9 @@ def _format_endpoints(eps=None): return ret -class ListCatalog(lister.Lister): +class ListCatalog(command.Lister): """List services in the service catalog""" - log = logging.getLogger(__name__ + '.ListCatalog') - - @utils.log_method(log) def take_action(self, parsed_args): # This is ugly because if auth hasn't happened yet we need @@ -62,11 +56,9 @@ class ListCatalog(lister.Lister): ) for s in data)) -class ShowCatalog(show.ShowOne): +class ShowCatalog(command.ShowOne): """Display service catalog details""" - log = logging.getLogger(__name__ + '.ShowCatalog') - def get_parser(self, prog_name): parser = super(ShowCatalog, self).get_parser(prog_name) parser.add_argument( @@ -76,7 +68,6 @@ class ShowCatalog(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): # This is ugly because if auth hasn't happened yet we need diff --git a/openstackclient/identity/v2_0/ec2creds.py b/openstackclient/identity/v2_0/ec2creds.py index a7730ce..a16b3d9 100644 --- a/openstackclient/identity/v2_0/ec2creds.py +++ b/openstackclient/identity/v2_0/ec2creds.py @@ -16,22 +16,16 @@ """Identity v2 EC2 Credentials action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils from openstackclient.i18n import _ # noqa -class CreateEC2Creds(show.ShowOne): +class CreateEC2Creds(command.ShowOne): """Create EC2 credentials""" - log = logging.getLogger(__name__ + ".CreateEC2Creds") - def get_parser(self, prog_name): parser = super(CreateEC2Creds, self).get_parser(prog_name) parser.add_argument( @@ -52,7 +46,6 @@ class CreateEC2Creds(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -89,8 +82,6 @@ class CreateEC2Creds(show.ShowOne): class DeleteEC2Creds(command.Command): """Delete EC2 credentials""" - log = logging.getLogger(__name__ + '.DeleteEC2Creds') - def get_parser(self, prog_name): parser = super(DeleteEC2Creds, self).get_parser(prog_name) parser.add_argument( @@ -105,7 +96,6 @@ class DeleteEC2Creds(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -121,11 +111,9 @@ class DeleteEC2Creds(command.Command): identity_client.ec2.delete(user, parsed_args.access_key) -class ListEC2Creds(lister.Lister): +class ListEC2Creds(command.Lister): """List EC2 credentials""" - log = logging.getLogger(__name__ + '.ListEC2Creds') - def get_parser(self, prog_name): parser = super(ListEC2Creds, self).get_parser(prog_name) parser.add_argument( @@ -135,7 +123,6 @@ class ListEC2Creds(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -159,11 +146,9 @@ class ListEC2Creds(lister.Lister): ) for s in data)) -class ShowEC2Creds(show.ShowOne): +class ShowEC2Creds(command.ShowOne): """Display EC2 credentials details""" - log = logging.getLogger(__name__ + '.ShowEC2Creds') - def get_parser(self, prog_name): parser = super(ShowEC2Creds, self).get_parser(prog_name) parser.add_argument( @@ -178,7 +163,6 @@ class ShowEC2Creds(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity diff --git a/openstackclient/identity/v2_0/endpoint.py b/openstackclient/identity/v2_0/endpoint.py index 1744cc7..08c0956 100644 --- a/openstackclient/identity/v2_0/endpoint.py +++ b/openstackclient/identity/v2_0/endpoint.py @@ -15,23 +15,17 @@ """Endpoint action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils from openstackclient.i18n import _ # noqa from openstackclient.identity import common -class CreateEndpoint(show.ShowOne): +class CreateEndpoint(command.ShowOne): """Create new endpoint""" - log = logging.getLogger(__name__ + '.CreateEndpoint') - def get_parser(self, prog_name): parser = super(CreateEndpoint, self).get_parser(prog_name) parser.add_argument( @@ -62,7 +56,6 @@ class CreateEndpoint(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity service = common.find_service(identity_client, parsed_args.service) @@ -83,8 +76,6 @@ class CreateEndpoint(show.ShowOne): class DeleteEndpoint(command.Command): """Delete endpoint""" - log = logging.getLogger(__name__ + '.DeleteEndpoint') - def get_parser(self, prog_name): parser = super(DeleteEndpoint, self).get_parser(prog_name) parser.add_argument( @@ -93,18 +84,15 @@ class DeleteEndpoint(command.Command): help=_('Endpoint ID to delete')) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity identity_client.endpoints.delete(parsed_args.endpoint) return -class ListEndpoint(lister.Lister): +class ListEndpoint(command.Lister): """List endpoints""" - log = logging.getLogger(__name__ + '.ListEndpoint') - def get_parser(self, prog_name): parser = super(ListEndpoint, self).get_parser(prog_name) parser.add_argument( @@ -115,7 +103,6 @@ class ListEndpoint(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity if parsed_args.long: @@ -136,11 +123,9 @@ class ListEndpoint(lister.Lister): ) for s in data)) -class ShowEndpoint(show.ShowOne): +class ShowEndpoint(command.ShowOne): """Display endpoint details""" - log = logging.getLogger(__name__ + '.ShowEndpoint') - def get_parser(self, prog_name): parser = super(ShowEndpoint, self).get_parser(prog_name) parser.add_argument( @@ -150,7 +135,6 @@ class ShowEndpoint(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity data = identity_client.endpoints.list() diff --git a/openstackclient/identity/v2_0/project.py b/openstackclient/identity/v2_0/project.py index 065f0ad..9e26c30 100644 --- a/openstackclient/identity/v2_0/project.py +++ b/openstackclient/identity/v2_0/project.py @@ -15,24 +15,19 @@ """Identity v2 Project action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show from keystoneauth1 import exceptions as ks_exc +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils from openstackclient.i18n import _ # noqa -class CreateProject(show.ShowOne): +class CreateProject(command.ShowOne): """Create new project""" - log = logging.getLogger(__name__ + '.CreateProject') - def get_parser(self, prog_name): parser = super(CreateProject, self).get_parser(prog_name) parser.add_argument( @@ -70,7 +65,6 @@ class CreateProject(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -106,8 +100,6 @@ class CreateProject(show.ShowOne): class DeleteProject(command.Command): """Delete project(s)""" - log = logging.getLogger(__name__ + '.DeleteProject') - def get_parser(self, prog_name): parser = super(DeleteProject, self).get_parser(prog_name) parser.add_argument( @@ -118,7 +110,6 @@ class DeleteProject(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -131,11 +122,9 @@ class DeleteProject(command.Command): return -class ListProject(lister.Lister): +class ListProject(command.Lister): """List projects""" - log = logging.getLogger(__name__ + '.ListProject') - def get_parser(self, prog_name): parser = super(ListProject, self).get_parser(prog_name) parser.add_argument( @@ -146,7 +135,6 @@ class ListProject(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): if parsed_args.long: columns = ('ID', 'Name', 'Description', 'Enabled') @@ -163,8 +151,6 @@ class ListProject(lister.Lister): class SetProject(command.Command): """Set project properties""" - log = logging.getLogger(__name__ + '.SetProject') - def get_parser(self, prog_name): parser = super(SetProject, self).get_parser(prog_name) parser.add_argument( @@ -202,7 +188,6 @@ class SetProject(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -240,11 +225,9 @@ class SetProject(command.Command): return -class ShowProject(show.ShowOne): +class ShowProject(command.ShowOne): """Display project details""" - log = logging.getLogger(__name__ + '.ShowProject') - def get_parser(self, prog_name): parser = super(ShowProject, self).get_parser(prog_name) parser.add_argument( @@ -253,7 +236,6 @@ class ShowProject(show.ShowOne): help=_('Project to display (name or ID)')) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -282,4 +264,57 @@ class ShowProject(show.ShowOne): # TODO(stevemar): Remove the line below when we support multitenancy info.pop('parent_id', None) + + # NOTE(stevemar): Property handling isn't really supported in Keystone + # and needs a lot of extra handling. Let's reserve the properties that + # the API has and handle the extra top level properties. + reserved = ('name', 'id', 'enabled', 'description') + properties = {} + for k, v in info.items(): + if k not in reserved: + # If a key is not in `reserved` it's a property, pop it + info.pop(k) + # If a property has been "unset" it's `None`, so don't show it + if v is not None: + properties[k] = v + + info['properties'] = utils.format_dict(properties) return zip(*sorted(six.iteritems(info))) + + +class UnsetProject(command.Command): + """Unset project properties""" + + def get_parser(self, prog_name): + parser = super(UnsetProject, self).get_parser(prog_name) + parser.add_argument( + 'project', + metavar='<project>', + help=_('Project to modify (name or ID)'), + ) + parser.add_argument( + '--property', + metavar='<key>', + action='append', + default=[], + help=_('Unset a project property ' + '(repeat option to unset multiple properties)'), + required=True, + ) + return parser + + def take_action(self, parsed_args): + identity_client = self.app.client_manager.identity + project = utils.find_resource( + identity_client.tenants, + parsed_args.project, + ) + if not parsed_args.property: + self.app.log.error("No changes requested\n") + else: + kwargs = project._info + for key in parsed_args.property: + if key in kwargs: + kwargs[key] = None + identity_client.tenants.update(project.id, **kwargs) + return diff --git a/openstackclient/identity/v2_0/role.py b/openstackclient/identity/v2_0/role.py index cab6b4a..892ce00 100644 --- a/openstackclient/identity/v2_0/role.py +++ b/openstackclient/identity/v2_0/role.py @@ -15,24 +15,19 @@ """Identity v2 Role action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show from keystoneauth1 import exceptions as ks_exc +from openstackclient.common import command from openstackclient.common import exceptions from openstackclient.common import utils from openstackclient.i18n import _ # noqa -class AddRole(show.ShowOne): +class AddRole(command.ShowOne): """Add role to project:user""" - log = logging.getLogger(__name__ + '.AddRole') - def get_parser(self, prog_name): parser = super(AddRole, self).get_parser(prog_name) parser.add_argument( @@ -54,7 +49,6 @@ class AddRole(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity role = utils.find_resource(identity_client.roles, parsed_args.role) @@ -74,11 +68,9 @@ class AddRole(show.ShowOne): return zip(*sorted(six.iteritems(info))) -class CreateRole(show.ShowOne): +class CreateRole(command.ShowOne): """Create new role""" - log = logging.getLogger(__name__ + '.CreateRole') - def get_parser(self, prog_name): parser = super(CreateRole, self).get_parser(prog_name) parser.add_argument( @@ -93,7 +85,6 @@ class CreateRole(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity try: @@ -116,8 +107,6 @@ class CreateRole(show.ShowOne): class DeleteRole(command.Command): """Delete role(s)""" - log = logging.getLogger(__name__ + '.DeleteRole') - def get_parser(self, prog_name): parser = super(DeleteRole, self).get_parser(prog_name) parser.add_argument( @@ -128,7 +117,6 @@ class DeleteRole(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -141,11 +129,9 @@ class DeleteRole(command.Command): return -class ListRole(lister.Lister): +class ListRole(command.Lister): """List roles""" - log = logging.getLogger(__name__ + '.ListRole') - def get_parser(self, prog_name): parser = super(ListRole, self).get_parser(prog_name) parser.add_argument( @@ -160,7 +146,6 @@ class ListRole(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity auth_ref = self.app.client_manager.auth_ref @@ -222,11 +207,9 @@ class ListRole(lister.Lister): ) for s in data)) -class ListUserRole(lister.Lister): +class ListUserRole(command.Lister): """List user-role assignments""" - log = logging.getLogger(__name__ + '.ListUserRole') - def get_parser(self, prog_name): parser = super(ListUserRole, self).get_parser(prog_name) parser.add_argument( @@ -242,7 +225,6 @@ class ListUserRole(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity auth_ref = self.app.client_manager.auth_ref @@ -293,8 +275,6 @@ class ListUserRole(lister.Lister): class RemoveRole(command.Command): """Remove role from project : user""" - log = logging.getLogger(__name__ + '.RemoveRole') - def get_parser(self, prog_name): parser = super(RemoveRole, self).get_parser(prog_name) parser.add_argument( @@ -316,7 +296,6 @@ class RemoveRole(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity role = utils.find_resource(identity_client.roles, parsed_args.role) @@ -331,11 +310,9 @@ class RemoveRole(command.Command): project.id) -class ShowRole(show.ShowOne): +class ShowRole(command.ShowOne): """Display role details""" - log = logging.getLogger(__name__ + '.ShowRole') - def get_parser(self, prog_name): parser = super(ShowRole, self).get_parser(prog_name) parser.add_argument( @@ -345,7 +322,6 @@ class ShowRole(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity role = utils.find_resource(identity_client.roles, parsed_args.role) diff --git a/openstackclient/identity/v2_0/service.py b/openstackclient/identity/v2_0/service.py index c9d4844..3af85d7 100644 --- a/openstackclient/identity/v2_0/service.py +++ b/openstackclient/identity/v2_0/service.py @@ -16,24 +16,18 @@ """Service action implementations""" import argparse -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import exceptions from openstackclient.common import utils from openstackclient.i18n import _ # noqa from openstackclient.identity import common -class CreateService(show.ShowOne): +class CreateService(command.ShowOne): """Create new service""" - log = logging.getLogger(__name__ + '.CreateService') - def get_parser(self, prog_name): parser = super(CreateService, self).get_parser(prog_name) parser.add_argument( @@ -59,7 +53,6 @@ class CreateService(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -95,8 +88,6 @@ class CreateService(show.ShowOne): class DeleteService(command.Command): """Delete service""" - log = logging.getLogger(__name__ + '.DeleteService') - def get_parser(self, prog_name): parser = super(DeleteService, self).get_parser(prog_name) parser.add_argument( @@ -106,7 +97,6 @@ class DeleteService(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity service = common.find_service(identity_client, parsed_args.service) @@ -114,11 +104,9 @@ class DeleteService(command.Command): return -class ListService(lister.Lister): +class ListService(command.Lister): """List services""" - log = logging.getLogger(__name__ + '.ListService') - def get_parser(self, prog_name): parser = super(ListService, self).get_parser(prog_name) parser.add_argument( @@ -129,7 +117,6 @@ class ListService(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): if parsed_args.long: @@ -143,11 +130,9 @@ class ListService(lister.Lister): ) -class ShowService(show.ShowOne): +class ShowService(command.ShowOne): """Display service details""" - log = logging.getLogger(__name__ + '.ShowService') - def get_parser(self, prog_name): parser = super(ShowService, self).get_parser(prog_name) parser.add_argument( @@ -163,7 +148,6 @@ class ShowService(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity auth_ref = self.app.client_manager.auth_ref diff --git a/openstackclient/identity/v2_0/token.py b/openstackclient/identity/v2_0/token.py index 5fed58e..db38fae 100644 --- a/openstackclient/identity/v2_0/token.py +++ b/openstackclient/identity/v2_0/token.py @@ -15,26 +15,19 @@ """Identity v2 Token action implementations""" -import logging import six -from cliff import command -from cliff import show - -from openstackclient.common import utils +from openstackclient.common import command from openstackclient.i18n import _ # noqa -class IssueToken(show.ShowOne): +class IssueToken(command.ShowOne): """Issue new token""" - log = logging.getLogger(__name__ + '.IssueToken') - def get_parser(self, prog_name): parser = super(IssueToken, self).get_parser(prog_name) return parser - @utils.log_method(log) def take_action(self, parsed_args): token = self.app.client_manager.auth_ref.service_catalog.get_token() @@ -45,8 +38,6 @@ class IssueToken(show.ShowOne): class RevokeToken(command.Command): """Revoke existing token""" - log = logging.getLogger(__name__ + '.RevokeToken') - def get_parser(self, prog_name): parser = super(RevokeToken, self).get_parser(prog_name) parser.add_argument( @@ -57,7 +48,6 @@ class RevokeToken(command.Command): return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) identity_client = self.app.client_manager.identity identity_client.tokens.delete(parsed_args.token) diff --git a/openstackclient/identity/v2_0/user.py b/openstackclient/identity/v2_0/user.py index e2b285b..3d84873 100644 --- a/openstackclient/identity/v2_0/user.py +++ b/openstackclient/identity/v2_0/user.py @@ -15,23 +15,18 @@ """Identity v2.0 User action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show from keystoneauth1 import exceptions as ks_exc +from openstackclient.common import command from openstackclient.common import utils from openstackclient.i18n import _ # noqa -class CreateUser(show.ShowOne): +class CreateUser(command.ShowOne): """Create new user""" - log = logging.getLogger(__name__ + '.CreateUser') - def get_parser(self, prog_name): parser = super(CreateUser, self).get_parser(prog_name) parser.add_argument( @@ -78,7 +73,6 @@ class CreateUser(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -130,8 +124,6 @@ class CreateUser(show.ShowOne): class DeleteUser(command.Command): """Delete user(s)""" - log = logging.getLogger(__name__ + '.DeleteUser') - def get_parser(self, prog_name): parser = super(DeleteUser, self).get_parser(prog_name) parser.add_argument( @@ -142,7 +134,6 @@ class DeleteUser(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -155,11 +146,9 @@ class DeleteUser(command.Command): return -class ListUser(lister.Lister): +class ListUser(command.Lister): """List users""" - log = logging.getLogger(__name__ + '.ListUser') - def get_parser(self, prog_name): parser = super(ListUser, self).get_parser(prog_name) parser.add_argument( @@ -174,7 +163,6 @@ class ListUser(lister.Lister): help=_('List additional fields in output')) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -248,8 +236,6 @@ class ListUser(lister.Lister): class SetUser(command.Command): """Set user properties""" - log = logging.getLogger(__name__ + '.SetUser') - def get_parser(self, prog_name): parser = super(SetUser, self).get_parser(prog_name) parser.add_argument( @@ -296,7 +282,6 @@ class SetUser(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -348,11 +333,9 @@ class SetUser(command.Command): return -class ShowUser(show.ShowOne): +class ShowUser(command.ShowOne): """Display user details""" - log = logging.getLogger(__name__ + '.ShowUser') - def get_parser(self, prog_name): parser = super(ShowUser, self).get_parser(prog_name) parser.add_argument( @@ -362,7 +345,6 @@ class ShowUser(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity diff --git a/openstackclient/identity/v3/catalog.py b/openstackclient/identity/v3/catalog.py index 76f7da5..795f5d5 100644 --- a/openstackclient/identity/v3/catalog.py +++ b/openstackclient/identity/v3/catalog.py @@ -13,12 +13,9 @@ """Identity v3 Service Catalog action implementations""" -import logging - -from cliff import lister -from cliff import show import six +from openstackclient.common import command from openstackclient.common import utils from openstackclient.i18n import _ # noqa @@ -34,12 +31,9 @@ def _format_endpoints(eps=None): return ret -class ListCatalog(lister.Lister): +class ListCatalog(command.Lister): """List services in the service catalog""" - log = logging.getLogger(__name__ + '.ListCatalog') - - @utils.log_method(log) def take_action(self, parsed_args): # This is ugly because if auth hasn't happened yet we need @@ -59,11 +53,9 @@ class ListCatalog(lister.Lister): ) for s in data)) -class ShowCatalog(show.ShowOne): +class ShowCatalog(command.ShowOne): """Display service catalog details""" - log = logging.getLogger(__name__ + '.ShowCatalog') - def get_parser(self, prog_name): parser = super(ShowCatalog, self).get_parser(prog_name) parser.add_argument( @@ -73,7 +65,6 @@ class ShowCatalog(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): # This is ugly because if auth hasn't happened yet we need diff --git a/openstackclient/identity/v3/consumer.py b/openstackclient/identity/v3/consumer.py index 0a6ade6..7298398 100644 --- a/openstackclient/identity/v3/consumer.py +++ b/openstackclient/identity/v3/consumer.py @@ -15,22 +15,16 @@ """Identity v3 Consumer action implementations""" -import logging import six import sys -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils -class CreateConsumer(show.ShowOne): +class CreateConsumer(command.ShowOne): """Create new consumer""" - log = logging.getLogger(__name__ + '.CreateConsumer') - def get_parser(self, prog_name): parser = super(CreateConsumer, self).get_parser(prog_name) parser.add_argument( @@ -40,7 +34,6 @@ class CreateConsumer(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity consumer = identity_client.oauth1.consumers.create( @@ -53,8 +46,6 @@ class CreateConsumer(show.ShowOne): class DeleteConsumer(command.Command): """Delete consumer""" - log = logging.getLogger(__name__ + '.DeleteConsumer') - def get_parser(self, prog_name): parser = super(DeleteConsumer, self).get_parser(prog_name) parser.add_argument( @@ -64,7 +55,6 @@ class DeleteConsumer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity consumer = utils.find_resource( @@ -73,12 +63,9 @@ class DeleteConsumer(command.Command): return -class ListConsumer(lister.Lister): +class ListConsumer(command.Lister): """List consumers""" - log = logging.getLogger(__name__ + '.ListConsumer') - - @utils.log_method(log) def take_action(self, parsed_args): columns = ('ID', 'Description') data = self.app.client_manager.identity.oauth1.consumers.list() @@ -92,8 +79,6 @@ class ListConsumer(lister.Lister): class SetConsumer(command.Command): """Set consumer properties""" - log = logging.getLogger(__name__ + '.SetConsumer') - def get_parser(self, prog_name): parser = super(SetConsumer, self).get_parser(prog_name) parser.add_argument( @@ -108,7 +93,6 @@ class SetConsumer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity consumer = utils.find_resource( @@ -126,11 +110,9 @@ class SetConsumer(command.Command): return -class ShowConsumer(show.ShowOne): +class ShowConsumer(command.ShowOne): """Display consumer details""" - log = logging.getLogger(__name__ + '.ShowConsumer') - def get_parser(self, prog_name): parser = super(ShowConsumer, self).get_parser(prog_name) parser.add_argument( @@ -140,7 +122,6 @@ class ShowConsumer(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity consumer = utils.find_resource( diff --git a/openstackclient/identity/v3/credential.py b/openstackclient/identity/v3/credential.py index f22092d..6208b32 100644 --- a/openstackclient/identity/v3/credential.py +++ b/openstackclient/identity/v3/credential.py @@ -15,21 +15,15 @@ """Identity v3 Credential action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils -class CreateCredential(show.ShowOne): +class CreateCredential(command.ShowOne): """Create credential command""" - log = logging.getLogger(__name__ + '.CreateCredential') - def get_parser(self, prog_name): parser = super(CreateCredential, self).get_parser(prog_name) parser.add_argument( @@ -56,7 +50,6 @@ class CreateCredential(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity user_id = utils.find_resource(identity_client.users, @@ -79,8 +72,6 @@ class CreateCredential(show.ShowOne): class DeleteCredential(command.Command): """Delete credential command""" - log = logging.getLogger(__name__ + '.DeleteCredential') - def get_parser(self, prog_name): parser = super(DeleteCredential, self).get_parser(prog_name) parser.add_argument( @@ -90,19 +81,15 @@ class DeleteCredential(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity identity_client.credentials.delete(parsed_args.credential) return -class ListCredential(lister.Lister): +class ListCredential(command.Lister): """List credential command""" - log = logging.getLogger(__name__ + '.ListCredential') - - @utils.log_method(log) def take_action(self, parsed_args): columns = ('ID', 'Type', 'User ID', 'Blob', 'Project ID') column_headers = ('ID', 'Type', 'User ID', 'Data', 'Project ID') @@ -117,8 +104,6 @@ class ListCredential(lister.Lister): class SetCredential(command.Command): """Set credential command""" - log = logging.getLogger(__name__ + '.SetCredential') - def get_parser(self, prog_name): parser = super(SetCredential, self).get_parser(prog_name) parser.add_argument( @@ -152,7 +137,6 @@ class SetCredential(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -174,11 +158,9 @@ class SetCredential(command.Command): return -class ShowCredential(show.ShowOne): +class ShowCredential(command.ShowOne): """Show credential command""" - log = logging.getLogger(__name__ + '.ShowCredential') - def get_parser(self, prog_name): parser = super(ShowCredential, self).get_parser(prog_name) parser.add_argument( @@ -188,7 +170,6 @@ class ShowCredential(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity credential = utils.find_resource(identity_client.credentials, diff --git a/openstackclient/identity/v3/domain.py b/openstackclient/identity/v3/domain.py index 8278a30..cec967b 100644 --- a/openstackclient/identity/v3/domain.py +++ b/openstackclient/identity/v3/domain.py @@ -15,24 +15,19 @@ """Identity v3 Domain action implementations""" -import logging import six import sys -from cliff import command -from cliff import lister -from cliff import show from keystoneauth1 import exceptions as ks_exc +from openstackclient.common import command from openstackclient.common import utils from openstackclient.i18n import _ # noqa -class CreateDomain(show.ShowOne): +class CreateDomain(command.ShowOne): """Create new domain""" - log = logging.getLogger(__name__ + '.CreateDomain') - def get_parser(self, prog_name): parser = super(CreateDomain, self).get_parser(prog_name) parser.add_argument( @@ -63,7 +58,6 @@ class CreateDomain(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -92,8 +86,6 @@ class CreateDomain(show.ShowOne): class DeleteDomain(command.Command): """Delete domain""" - log = logging.getLogger(__name__ + '.DeleteDomain') - def get_parser(self, prog_name): parser = super(DeleteDomain, self).get_parser(prog_name) parser.add_argument( @@ -103,7 +95,6 @@ class DeleteDomain(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity domain = utils.find_resource(identity_client.domains, @@ -112,12 +103,9 @@ class DeleteDomain(command.Command): return -class ListDomain(lister.Lister): +class ListDomain(command.Lister): """List domains""" - log = logging.getLogger(__name__ + '.ListDomain') - - @utils.log_method(log) def take_action(self, parsed_args): columns = ('ID', 'Name', 'Enabled', 'Description') data = self.app.client_manager.identity.domains.list() @@ -131,8 +119,6 @@ class ListDomain(lister.Lister): class SetDomain(command.Command): """Set domain properties""" - log = logging.getLogger(__name__ + '.SetDomain') - def get_parser(self, prog_name): parser = super(SetDomain, self).get_parser(prog_name) parser.add_argument( @@ -163,7 +149,6 @@ class SetDomain(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity domain = utils.find_resource(identity_client.domains, @@ -186,11 +171,9 @@ class SetDomain(command.Command): return -class ShowDomain(show.ShowOne): +class ShowDomain(command.ShowOne): """Display domain details""" - log = logging.getLogger(__name__ + '.ShowDomain') - def get_parser(self, prog_name): parser = super(ShowDomain, self).get_parser(prog_name) parser.add_argument( @@ -200,7 +183,6 @@ class ShowDomain(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity domain = utils.find_resource(identity_client.domains, diff --git a/openstackclient/identity/v3/ec2creds.py b/openstackclient/identity/v3/ec2creds.py index a12ee25..777c043 100644 --- a/openstackclient/identity/v3/ec2creds.py +++ b/openstackclient/identity/v3/ec2creds.py @@ -12,13 +12,9 @@ """Identity v3 EC2 Credentials action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils from openstackclient.i18n import _ # noqa from openstackclient.identity import common @@ -52,11 +48,9 @@ def _determine_ec2_user(parsed_args, client_manager): return user -class CreateEC2Creds(show.ShowOne): +class CreateEC2Creds(command.ShowOne): """Create EC2 credentials""" - log = logging.getLogger(__name__ + ".CreateEC2Creds") - def get_parser(self, prog_name): parser = super(CreateEC2Creds, self).get_parser(prog_name) parser.add_argument( @@ -79,7 +73,6 @@ class CreateEC2Creds(show.ShowOne): common.add_project_domain_option_to_parser(parser) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity client_manager = self.app.client_manager @@ -119,8 +112,6 @@ class CreateEC2Creds(show.ShowOne): class DeleteEC2Creds(command.Command): """Delete EC2 credentials""" - log = logging.getLogger(__name__ + '.DeleteEC2Creds') - def get_parser(self, prog_name): parser = super(DeleteEC2Creds, self).get_parser(prog_name) parser.add_argument( @@ -136,18 +127,15 @@ class DeleteEC2Creds(command.Command): common.add_user_domain_option_to_parser(parser) return parser - @utils.log_method(log) def take_action(self, parsed_args): client_manager = self.app.client_manager user = _determine_ec2_user(parsed_args, client_manager) client_manager.identity.ec2.delete(user, parsed_args.access_key) -class ListEC2Creds(lister.Lister): +class ListEC2Creds(command.Lister): """List EC2 credentials""" - log = logging.getLogger(__name__ + '.ListEC2Creds') - def get_parser(self, prog_name): parser = super(ListEC2Creds, self).get_parser(prog_name) parser.add_argument( @@ -158,7 +146,6 @@ class ListEC2Creds(lister.Lister): common.add_user_domain_option_to_parser(parser) return parser - @utils.log_method(log) def take_action(self, parsed_args): client_manager = self.app.client_manager user = _determine_ec2_user(parsed_args, client_manager) @@ -174,11 +161,9 @@ class ListEC2Creds(lister.Lister): ) for s in data)) -class ShowEC2Creds(show.ShowOne): +class ShowEC2Creds(command.ShowOne): """Display EC2 credentials details""" - log = logging.getLogger(__name__ + '.ShowEC2Creds') - def get_parser(self, prog_name): parser = super(ShowEC2Creds, self).get_parser(prog_name) parser.add_argument( @@ -194,7 +179,6 @@ class ShowEC2Creds(show.ShowOne): common.add_user_domain_option_to_parser(parser) return parser - @utils.log_method(log) def take_action(self, parsed_args): client_manager = self.app.client_manager user = _determine_ec2_user(parsed_args, client_manager) diff --git a/openstackclient/identity/v3/endpoint.py b/openstackclient/identity/v3/endpoint.py index 3d1c6f5..1eff3b3 100644 --- a/openstackclient/identity/v3/endpoint.py +++ b/openstackclient/identity/v3/endpoint.py @@ -15,14 +15,10 @@ """Identity v3 Endpoint action implementations""" -import logging import six import sys -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils from openstackclient.identity import common @@ -34,11 +30,9 @@ def get_service_name(service): return '' -class CreateEndpoint(show.ShowOne): +class CreateEndpoint(command.ShowOne): """Create new endpoint""" - log = logging.getLogger(__name__ + '.CreateEndpoint') - def get_parser(self, prog_name): parser = super(CreateEndpoint, self).get_parser(prog_name) parser.add_argument( @@ -78,7 +72,6 @@ class CreateEndpoint(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity service = common.find_service(identity_client, parsed_args.service) @@ -102,8 +95,6 @@ class CreateEndpoint(show.ShowOne): class DeleteEndpoint(command.Command): """Delete endpoint""" - log = logging.getLogger(__name__ + '.DeleteEndpoint') - def get_parser(self, prog_name): parser = super(DeleteEndpoint, self).get_parser(prog_name) parser.add_argument( @@ -113,7 +104,6 @@ class DeleteEndpoint(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity endpoint_id = utils.find_resource(identity_client.endpoints, @@ -122,11 +112,9 @@ class DeleteEndpoint(command.Command): return -class ListEndpoint(lister.Lister): +class ListEndpoint(command.Lister): """List endpoints""" - log = logging.getLogger(__name__ + '.ListEndpoint') - def get_parser(self, prog_name): parser = super(ListEndpoint, self).get_parser(prog_name) parser.add_argument( @@ -147,7 +135,6 @@ class ListEndpoint(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity columns = ('ID', 'Region', 'Service Name', 'Service Type', @@ -176,8 +163,6 @@ class ListEndpoint(lister.Lister): class SetEndpoint(command.Command): """Set endpoint properties""" - log = logging.getLogger(__name__ + '.SetEndpoint') - def get_parser(self, prog_name): parser = super(SetEndpoint, self).get_parser(prog_name) parser.add_argument( @@ -221,7 +206,6 @@ class SetEndpoint(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity endpoint = utils.find_resource(identity_client.endpoints, @@ -256,11 +240,9 @@ class SetEndpoint(command.Command): return -class ShowEndpoint(show.ShowOne): +class ShowEndpoint(command.ShowOne): """Display endpoint details""" - log = logging.getLogger(__name__ + '.ShowEndpoint') - def get_parser(self, prog_name): parser = super(ShowEndpoint, self).get_parser(prog_name) parser.add_argument( @@ -270,7 +252,6 @@ class ShowEndpoint(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity endpoint = utils.find_resource(identity_client.endpoints, diff --git a/openstackclient/identity/v3/federation_protocol.py b/openstackclient/identity/v3/federation_protocol.py index 20877fc..2d7ab15 100644 --- a/openstackclient/identity/v3/federation_protocol.py +++ b/openstackclient/identity/v3/federation_protocol.py @@ -14,21 +14,15 @@ """Identity v3 Protocols actions implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils -class CreateProtocol(show.ShowOne): +class CreateProtocol(command.ShowOne): """Create new federation protocol""" - log = logging.getLogger(__name__ + 'CreateProtocol') - def get_parser(self, prog_name): parser = super(CreateProtocol, self).get_parser(prog_name) parser.add_argument( @@ -50,7 +44,6 @@ class CreateProtocol(show.ShowOne): return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity protocol = identity_client.federation.protocols.create( @@ -71,8 +64,6 @@ class CreateProtocol(show.ShowOne): class DeleteProtocol(command.Command): """Delete federation protocol""" - log = logging.getLogger(__name__ + '.DeleteProtocol') - def get_parser(self, prog_name): parser = super(DeleteProtocol, self).get_parser(prog_name) parser.add_argument( @@ -88,7 +79,6 @@ class DeleteProtocol(command.Command): return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity identity_client.federation.protocols.delete( @@ -96,11 +86,9 @@ class DeleteProtocol(command.Command): return -class ListProtocols(lister.Lister): +class ListProtocols(command.Lister): """List federation protocols""" - log = logging.getLogger(__name__ + '.ListProtocols') - def get_parser(self, prog_name): parser = super(ListProtocols, self).get_parser(prog_name) parser.add_argument( @@ -126,8 +114,6 @@ class ListProtocols(lister.Lister): class SetProtocol(command.Command): """Set federation protocol properties""" - log = logging.getLogger(__name__ + '.SetProtocol') - def get_parser(self, prog_name): parser = super(SetProtocol, self).get_parser(prog_name) parser.add_argument( @@ -166,11 +152,9 @@ class SetProtocol(command.Command): return zip(*sorted(six.iteritems(info))) -class ShowProtocol(show.ShowOne): +class ShowProtocol(command.ShowOne): """Display federation protocol details""" - log = logging.getLogger(__name__ + '.ShowProtocol') - def get_parser(self, prog_name): parser = super(ShowProtocol, self).get_parser(prog_name) parser.add_argument( diff --git a/openstackclient/identity/v3/group.py b/openstackclient/identity/v3/group.py index d503a6b..b3d893c 100644 --- a/openstackclient/identity/v3/group.py +++ b/openstackclient/identity/v3/group.py @@ -15,15 +15,12 @@ """Group action implementations""" -import logging import six import sys -from cliff import command -from cliff import lister -from cliff import show from keystoneauth1 import exceptions as ks_exc +from openstackclient.common import command from openstackclient.common import utils from openstackclient.i18n import _ # noqa from openstackclient.identity import common @@ -32,8 +29,6 @@ from openstackclient.identity import common class AddUserToGroup(command.Command): """Add user to group""" - log = logging.getLogger(__name__ + '.AddUserToGroup') - def get_parser(self, prog_name): parser = super(AddUserToGroup, self).get_parser(prog_name) parser.add_argument( @@ -50,7 +45,6 @@ class AddUserToGroup(command.Command): common.add_user_domain_option_to_parser(parser) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -74,8 +68,6 @@ class AddUserToGroup(command.Command): class CheckUserInGroup(command.Command): """Check user membership in group""" - log = logging.getLogger(__name__ + '.CheckUserInGroup') - def get_parser(self, prog_name): parser = super(CheckUserInGroup, self).get_parser(prog_name) parser.add_argument( @@ -92,7 +84,6 @@ class CheckUserInGroup(command.Command): common.add_user_domain_option_to_parser(parser) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -113,11 +104,9 @@ class CheckUserInGroup(command.Command): (parsed_args.user, parsed_args.group)) -class CreateGroup(show.ShowOne): +class CreateGroup(command.ShowOne): """Create new group""" - log = logging.getLogger(__name__ + '.CreateGroup') - def get_parser(self, prog_name): parser = super(CreateGroup, self).get_parser(prog_name) parser.add_argument( @@ -142,7 +131,6 @@ class CreateGroup(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -172,8 +160,6 @@ class CreateGroup(show.ShowOne): class DeleteGroup(command.Command): """Delete group(s)""" - log = logging.getLogger(__name__ + '.DeleteGroup') - def get_parser(self, prog_name): parser = super(DeleteGroup, self).get_parser(prog_name) parser.add_argument( @@ -188,7 +174,6 @@ class DeleteGroup(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -200,11 +185,9 @@ class DeleteGroup(command.Command): return -class ListGroup(lister.Lister): +class ListGroup(command.Lister): """List groups""" - log = logging.getLogger(__name__ + '.ListGroup') - def get_parser(self, prog_name): parser = super(ListGroup, self).get_parser(prog_name) parser.add_argument( @@ -226,7 +209,6 @@ class ListGroup(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -266,8 +248,6 @@ class ListGroup(lister.Lister): class RemoveUserFromGroup(command.Command): """Remove user from group""" - log = logging.getLogger(__name__ + '.RemoveUserFromGroup') - def get_parser(self, prog_name): parser = super(RemoveUserFromGroup, self).get_parser(prog_name) parser.add_argument( @@ -284,7 +264,6 @@ class RemoveUserFromGroup(command.Command): common.add_user_domain_option_to_parser(parser) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -308,8 +287,6 @@ class RemoveUserFromGroup(command.Command): class SetGroup(command.Command): """Set group properties""" - log = logging.getLogger(__name__ + '.SetGroup') - def get_parser(self, prog_name): parser = super(SetGroup, self).get_parser(prog_name) parser.add_argument( @@ -331,7 +308,6 @@ class SetGroup(command.Command): help='New group description') return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity group = common.find_group(identity_client, parsed_args.group, @@ -349,11 +325,9 @@ class SetGroup(command.Command): return -class ShowGroup(show.ShowOne): +class ShowGroup(command.ShowOne): """Display group details""" - log = logging.getLogger(__name__ + '.ShowGroup') - def get_parser(self, prog_name): parser = super(ShowGroup, self).get_parser(prog_name) parser.add_argument( @@ -368,7 +342,6 @@ class ShowGroup(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity diff --git a/openstackclient/identity/v3/identity_provider.py b/openstackclient/identity/v3/identity_provider.py index 4e086b6..0ff8acb 100644 --- a/openstackclient/identity/v3/identity_provider.py +++ b/openstackclient/identity/v3/identity_provider.py @@ -13,21 +13,15 @@ """Identity v3 IdentityProvider action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils -class CreateIdentityProvider(show.ShowOne): +class CreateIdentityProvider(command.ShowOne): """Create new identity provider""" - log = logging.getLogger(__name__ + '.CreateIdentityProvider') - def get_parser(self, prog_name): parser = super(CreateIdentityProvider, self).get_parser(prog_name) parser.add_argument( @@ -70,7 +64,6 @@ class CreateIdentityProvider(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity if parsed_args.remote_id_file: @@ -96,8 +89,6 @@ class CreateIdentityProvider(show.ShowOne): class DeleteIdentityProvider(command.Command): """Delete identity provider""" - log = logging.getLogger(__name__ + '.DeleteIdentityProvider') - def get_parser(self, prog_name): parser = super(DeleteIdentityProvider, self).get_parser(prog_name) parser.add_argument( @@ -107,7 +98,6 @@ class DeleteIdentityProvider(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity identity_client.federation.identity_providers.delete( @@ -115,12 +105,9 @@ class DeleteIdentityProvider(command.Command): return -class ListIdentityProvider(lister.Lister): +class ListIdentityProvider(command.Lister): """List identity providers""" - log = logging.getLogger(__name__ + '.ListIdentityProvider') - - @utils.log_method(log) def take_action(self, parsed_args): columns = ('ID', 'Enabled', 'Description') identity_client = self.app.client_manager.identity @@ -135,8 +122,6 @@ class ListIdentityProvider(lister.Lister): class SetIdentityProvider(command.Command): """Set identity provider properties""" - log = logging.getLogger(__name__ + '.SetIdentityProvider') - def get_parser(self, prog_name): parser = super(SetIdentityProvider, self).get_parser(prog_name) parser.add_argument( @@ -176,7 +161,6 @@ class SetIdentityProvider(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): federation_client = self.app.client_manager.identity.federation @@ -215,11 +199,9 @@ class SetIdentityProvider(command.Command): return zip(*sorted(six.iteritems(identity_provider._info))) -class ShowIdentityProvider(show.ShowOne): +class ShowIdentityProvider(command.ShowOne): """Display identity provider details""" - log = logging.getLogger(__name__ + '.ShowIdentityProvider') - def get_parser(self, prog_name): parser = super(ShowIdentityProvider, self).get_parser(prog_name) parser.add_argument( @@ -229,7 +211,6 @@ class ShowIdentityProvider(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity idp = utils.find_resource( diff --git a/openstackclient/identity/v3/mapping.py b/openstackclient/identity/v3/mapping.py index c79331e..422d66b 100644 --- a/openstackclient/identity/v3/mapping.py +++ b/openstackclient/identity/v3/mapping.py @@ -16,13 +16,10 @@ """Identity v3 federation mapping action implementations""" import json -import logging -from cliff import command -from cliff import lister -from cliff import show import six +from openstackclient.common import command from openstackclient.common import exceptions from openstackclient.common import utils @@ -79,11 +76,9 @@ class _RulesReader(object): return rules -class CreateMapping(show.ShowOne, _RulesReader): +class CreateMapping(command.ShowOne, _RulesReader): """Create new mapping""" - log = logging.getLogger(__name__ + '.CreateMapping') - def get_parser(self, prog_name): parser = super(CreateMapping, self).get_parser(prog_name) parser.add_argument( @@ -99,7 +94,6 @@ class CreateMapping(show.ShowOne, _RulesReader): return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) identity_client = self.app.client_manager.identity rules = self._read_rules(parsed_args.rules) @@ -114,8 +108,6 @@ class CreateMapping(show.ShowOne, _RulesReader): class DeleteMapping(command.Command): """Delete mapping""" - log = logging.getLogger(__name__ + '.DeleteMapping') - def get_parser(self, prog_name): parser = super(DeleteMapping, self).get_parser(prog_name) parser.add_argument( @@ -126,19 +118,16 @@ class DeleteMapping(command.Command): return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) identity_client = self.app.client_manager.identity identity_client.federation.mappings.delete(parsed_args.mapping) return -class ListMapping(lister.Lister): +class ListMapping(command.Lister): """List mappings""" - log = logging.getLogger(__name__ + '.ListMapping') def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) # NOTE(marek-denis): Since rules can be long and tedious I have decided # to only list ids of the mappings. If somebody wants to check the # rules, (s)he should show specific ones. @@ -152,8 +141,6 @@ class ListMapping(lister.Lister): class SetMapping(command.Command, _RulesReader): """Set mapping properties""" - log = logging.getLogger(__name__ + '.SetMapping') - def get_parser(self, prog_name): parser = super(SetMapping, self).get_parser(prog_name) parser.add_argument( @@ -169,7 +156,6 @@ class SetMapping(command.Command, _RulesReader): return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) identity_client = self.app.client_manager.identity if not parsed_args.rules: @@ -186,11 +172,9 @@ class SetMapping(command.Command, _RulesReader): return zip(*sorted(six.iteritems(mapping._info))) -class ShowMapping(show.ShowOne): +class ShowMapping(command.ShowOne): """Display mapping details""" - log = logging.getLogger(__name__ + '.ShowMapping') - def get_parser(self, prog_name): parser = super(ShowMapping, self).get_parser(prog_name) parser.add_argument( @@ -201,7 +185,6 @@ class ShowMapping(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) identity_client = self.app.client_manager.identity mapping = identity_client.federation.mappings.get(parsed_args.mapping) diff --git a/openstackclient/identity/v3/policy.py b/openstackclient/identity/v3/policy.py index 9da9486..503df37 100644 --- a/openstackclient/identity/v3/policy.py +++ b/openstackclient/identity/v3/policy.py @@ -15,22 +15,16 @@ """Identity v3 Policy action implementations""" -import logging import six import sys -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils -class CreatePolicy(show.ShowOne): +class CreatePolicy(command.ShowOne): """Create new policy""" - log = logging.getLogger(__name__ + '.CreatePolicy') - def get_parser(self, prog_name): parser = super(CreatePolicy, self).get_parser(prog_name) parser.add_argument( @@ -47,7 +41,6 @@ class CreatePolicy(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): blob = utils.read_blob_file_contents(parsed_args.rules) @@ -64,8 +57,6 @@ class CreatePolicy(show.ShowOne): class DeletePolicy(command.Command): """Delete policy""" - log = logging.getLogger(__name__ + '.DeletePolicy') - def get_parser(self, prog_name): parser = super(DeletePolicy, self).get_parser(prog_name) parser.add_argument( @@ -75,18 +66,15 @@ class DeletePolicy(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity identity_client.policies.delete(parsed_args.policy) return -class ListPolicy(lister.Lister): +class ListPolicy(command.Lister): """List policies""" - log = logging.getLogger(__name__ + '.ListPolicy') - def get_parser(self, prog_name): parser = super(ListPolicy, self).get_parser(prog_name) parser.add_argument( @@ -97,7 +85,6 @@ class ListPolicy(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): if parsed_args.long: columns = ('ID', 'Type', 'Blob') @@ -116,8 +103,6 @@ class ListPolicy(lister.Lister): class SetPolicy(command.Command): """Set policy properties""" - log = logging.getLogger(__name__ + '.SetPolicy') - def get_parser(self, prog_name): parser = super(SetPolicy, self).get_parser(prog_name) parser.add_argument( @@ -137,7 +122,6 @@ class SetPolicy(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity blob = None @@ -158,11 +142,9 @@ class SetPolicy(command.Command): return -class ShowPolicy(show.ShowOne): +class ShowPolicy(command.ShowOne): """Display policy details""" - log = logging.getLogger(__name__ + '.ShowPolicy') - def get_parser(self, prog_name): parser = super(ShowPolicy, self).get_parser(prog_name) parser.add_argument( @@ -172,7 +154,6 @@ class ShowPolicy(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity policy = utils.find_resource(identity_client.policies, diff --git a/openstackclient/identity/v3/project.py b/openstackclient/identity/v3/project.py index f87105d..61db861 100644 --- a/openstackclient/identity/v3/project.py +++ b/openstackclient/identity/v3/project.py @@ -15,25 +15,20 @@ """Project action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show from keystoneauth1 import exceptions as ks_exc +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils from openstackclient.i18n import _ # noqa from openstackclient.identity import common -class CreateProject(show.ShowOne): +class CreateProject(command.ShowOne): """Create new project""" - log = logging.getLogger(__name__ + '.CreateProject') - def get_parser(self, prog_name): parser = super(CreateProject, self).get_parser(prog_name) parser.add_argument( @@ -81,7 +76,6 @@ class CreateProject(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -129,8 +123,6 @@ class CreateProject(show.ShowOne): class DeleteProject(command.Command): """Delete project(s)""" - log = logging.getLogger(__name__ + '.DeleteProject') - def get_parser(self, prog_name): parser = super(DeleteProject, self).get_parser(prog_name) parser.add_argument( @@ -146,7 +138,6 @@ class DeleteProject(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -165,11 +156,9 @@ class DeleteProject(command.Command): return -class ListProject(lister.Lister): +class ListProject(command.Lister): """List projects""" - log = logging.getLogger(__name__ + '.ListProject') - def get_parser(self, prog_name): parser = super(ListProject, self).get_parser(prog_name) parser.add_argument( @@ -190,7 +179,6 @@ class ListProject(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity if parsed_args.long: @@ -227,8 +215,6 @@ class ListProject(lister.Lister): class SetProject(command.Command): """Set project properties""" - log = logging.getLogger(__name__ + '.SetProject') - def get_parser(self, prog_name): parser = super(SetProject, self).get_parser(prog_name) parser.add_argument( @@ -271,7 +257,6 @@ class SetProject(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -283,16 +268,12 @@ class SetProject(command.Command): and not parsed_args.disable): return - project = utils.find_resource( - identity_client.projects, - parsed_args.project, - ) + project = common.find_project(identity_client, parsed_args.project, + parsed_args.domain) kwargs = {} if parsed_args.name: kwargs['name'] = parsed_args.name - if parsed_args.domain: - kwargs['domain'] = parsed_args.domain if parsed_args.description: kwargs['description'] = parsed_args.description if parsed_args.enable: @@ -306,11 +287,9 @@ class SetProject(command.Command): return -class ShowProject(show.ShowOne): +class ShowProject(command.ShowOne): """Display project details""" - log = logging.getLogger(__name__ + '.ShowProject') - def get_parser(self, prog_name): parser = super(ShowProject, self).get_parser(prog_name) parser.add_argument( @@ -337,7 +316,6 @@ class ShowProject(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity diff --git a/openstackclient/identity/v3/region.py b/openstackclient/identity/v3/region.py index 1ff0b8c..1e15fd2 100644 --- a/openstackclient/identity/v3/region.py +++ b/openstackclient/identity/v3/region.py @@ -13,22 +13,16 @@ """Identity v3 Region action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils from openstackclient.i18n import _ # noqa -class CreateRegion(show.ShowOne): +class CreateRegion(command.ShowOne): """Create new region""" - log = logging.getLogger(__name__ + '.CreateRegion') - def get_parser(self, prog_name): parser = super(CreateRegion, self).get_parser(prog_name) # NOTE(stevemar): The API supports an optional region ID, but that @@ -50,7 +44,6 @@ class CreateRegion(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -69,8 +62,6 @@ class CreateRegion(show.ShowOne): class DeleteRegion(command.Command): """Delete region""" - log = logging.getLogger(__name__ + '.DeleteRegion') - def get_parser(self, prog_name): parser = super(DeleteRegion, self).get_parser(prog_name) parser.add_argument( @@ -80,7 +71,6 @@ class DeleteRegion(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -88,11 +78,9 @@ class DeleteRegion(command.Command): return -class ListRegion(lister.Lister): +class ListRegion(command.Lister): """List regions""" - log = logging.getLogger(__name__ + '.ListRegion') - def get_parser(self, prog_name): parser = super(ListRegion, self).get_parser(prog_name) parser.add_argument( @@ -102,7 +90,6 @@ class ListRegion(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -124,8 +111,6 @@ class ListRegion(lister.Lister): class SetRegion(command.Command): """Set region properties""" - log = logging.getLogger(__name__ + '.SetRegion') - def get_parser(self, prog_name): parser = super(SetRegion, self).get_parser(prog_name) parser.add_argument( @@ -145,7 +130,6 @@ class SetRegion(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -162,11 +146,9 @@ class SetRegion(command.Command): return -class ShowRegion(show.ShowOne): +class ShowRegion(command.ShowOne): """Display region details""" - log = logging.getLogger(__name__ + '.ShowRegion') - def get_parser(self, prog_name): parser = super(ShowRegion, self).get_parser(prog_name) parser.add_argument( @@ -176,7 +158,6 @@ class ShowRegion(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity diff --git a/openstackclient/identity/v3/role.py b/openstackclient/identity/v3/role.py index 66f1896..4cced61 100644 --- a/openstackclient/identity/v3/role.py +++ b/openstackclient/identity/v3/role.py @@ -15,15 +15,12 @@ """Identity v3 Role action implementations""" -import logging import six import sys -from cliff import command -from cliff import lister -from cliff import show from keystoneauth1 import exceptions as ks_exc +from openstackclient.common import command from openstackclient.common import utils from openstackclient.i18n import _ # noqa from openstackclient.identity import common @@ -110,8 +107,6 @@ def _process_identity_and_resource_options(parsed_args, class AddRole(command.Command): """Adds a role to a user or group on a domain or project""" - log = logging.getLogger(__name__ + '.AddRole') - def get_parser(self, prog_name): parser = super(AddRole, self).get_parser(prog_name) parser.add_argument( @@ -122,7 +117,6 @@ class AddRole(command.Command): _add_identity_and_resource_options_to_parser(parser) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -147,11 +141,9 @@ class AddRole(command.Command): return -class CreateRole(show.ShowOne): +class CreateRole(command.ShowOne): """Create new role""" - log = logging.getLogger(__name__ + '.CreateRole') - def get_parser(self, prog_name): parser = super(CreateRole, self).get_parser(prog_name) parser.add_argument( @@ -166,7 +158,6 @@ class CreateRole(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -187,8 +178,6 @@ class CreateRole(show.ShowOne): class DeleteRole(command.Command): """Delete role(s)""" - log = logging.getLogger(__name__ + '.DeleteRole') - def get_parser(self, prog_name): parser = super(DeleteRole, self).get_parser(prog_name) parser.add_argument( @@ -199,7 +188,6 @@ class DeleteRole(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -212,18 +200,15 @@ class DeleteRole(command.Command): return -class ListRole(lister.Lister): +class ListRole(command.Lister): """List roles""" - log = logging.getLogger(__name__ + '.ListRole') - def get_parser(self, prog_name): parser = super(ListRole, self).get_parser(prog_name) _add_identity_and_resource_options_to_parser(parser) return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) identity_client = self.app.client_manager.identity if parsed_args.user: @@ -318,8 +303,6 @@ class ListRole(lister.Lister): class RemoveRole(command.Command): """Remove role from domain/project : user/group""" - log = logging.getLogger(__name__ + '.RemoveRole') - def get_parser(self, prog_name): parser = super(RemoveRole, self).get_parser(prog_name) parser.add_argument( @@ -330,7 +313,6 @@ class RemoveRole(command.Command): _add_identity_and_resource_options_to_parser(parser) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -357,8 +339,6 @@ class RemoveRole(command.Command): class SetRole(command.Command): """Set role properties""" - log = logging.getLogger(__name__ + '.SetRole') - def get_parser(self, prog_name): parser = super(SetRole, self).get_parser(prog_name) parser.add_argument( @@ -373,7 +353,6 @@ class SetRole(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -389,11 +368,9 @@ class SetRole(command.Command): return -class ShowRole(show.ShowOne): +class ShowRole(command.ShowOne): """Display role details""" - log = logging.getLogger(__name__ + '.ShowRole') - def get_parser(self, prog_name): parser = super(ShowRole, self).get_parser(prog_name) parser.add_argument( @@ -403,7 +380,6 @@ class ShowRole(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity diff --git a/openstackclient/identity/v3/role_assignment.py b/openstackclient/identity/v3/role_assignment.py index 169c6cb..d766be6 100644 --- a/openstackclient/identity/v3/role_assignment.py +++ b/openstackclient/identity/v3/role_assignment.py @@ -13,19 +13,14 @@ """Identity v3 Assignment action implementations """ -import logging - -from cliff import lister - +from openstackclient.common import command from openstackclient.common import utils from openstackclient.identity import common -class ListRoleAssignment(lister.Lister): +class ListRoleAssignment(command.Lister): """List role assignments""" - log = logging.getLogger(__name__ + '.ListRoleAssignment') - def get_parser(self, prog_name): parser = super(ListRoleAssignment, self).get_parser(prog_name) parser.add_argument( @@ -72,7 +67,6 @@ class ListRoleAssignment(lister.Lister): assignment.project, assignment.domain, assignment.inherited) def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) identity_client = self.app.client_manager.identity role = None @@ -114,7 +108,6 @@ class ListRoleAssignment(lister.Lister): ) effective = True if parsed_args.effective else False - self.log.debug('take_action(%s)' % parsed_args) columns = ('Role', 'User', 'Group', 'Project', 'Domain', 'Inherited') inherited_to = 'projects' if parsed_args.inherited else None diff --git a/openstackclient/identity/v3/service.py b/openstackclient/identity/v3/service.py index 85081aa..42117c8 100644 --- a/openstackclient/identity/v3/service.py +++ b/openstackclient/identity/v3/service.py @@ -15,22 +15,16 @@ """Identity v3 Service action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils from openstackclient.identity import common -class CreateService(show.ShowOne): +class CreateService(command.ShowOne): """Create new service""" - log = logging.getLogger(__name__ + '.CreateService') - def get_parser(self, prog_name): parser = super(CreateService, self).get_parser(prog_name) parser.add_argument( @@ -61,7 +55,6 @@ class CreateService(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -83,8 +76,6 @@ class CreateService(show.ShowOne): class DeleteService(command.Command): """Delete service""" - log = logging.getLogger(__name__ + '.DeleteService') - def get_parser(self, prog_name): parser = super(DeleteService, self).get_parser(prog_name) parser.add_argument( @@ -94,7 +85,6 @@ class DeleteService(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -104,11 +94,9 @@ class DeleteService(command.Command): return -class ListService(lister.Lister): +class ListService(command.Lister): """List services""" - log = logging.getLogger(__name__ + '.ListService') - def get_parser(self, prog_name): parser = super(ListService, self).get_parser(prog_name) parser.add_argument( @@ -119,7 +107,6 @@ class ListService(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): if parsed_args.long: @@ -136,8 +123,6 @@ class ListService(lister.Lister): class SetService(command.Command): """Set service properties""" - log = logging.getLogger(__name__ + '.SetService') - def get_parser(self, prog_name): parser = super(SetService, self).get_parser(prog_name) parser.add_argument( @@ -173,7 +158,6 @@ class SetService(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -205,11 +189,9 @@ class SetService(command.Command): return -class ShowService(show.ShowOne): +class ShowService(command.ShowOne): """Display service details""" - log = logging.getLogger(__name__ + '.ShowService') - def get_parser(self, prog_name): parser = super(ShowService, self).get_parser(prog_name) parser.add_argument( @@ -219,7 +201,6 @@ class ShowService(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity diff --git a/openstackclient/identity/v3/service_provider.py b/openstackclient/identity/v3/service_provider.py index 838ad4a..6016928 100644 --- a/openstackclient/identity/v3/service_provider.py +++ b/openstackclient/identity/v3/service_provider.py @@ -13,22 +13,16 @@ """Service Provider action implementations""" -import logging import six import sys -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils -class CreateServiceProvider(show.ShowOne): +class CreateServiceProvider(command.ShowOne): """Create new service provider""" - log = logging.getLogger(__name__ + '.CreateServiceProvider') - def get_parser(self, prog_name): parser = super(CreateServiceProvider, self).get_parser(prog_name) parser.add_argument( @@ -73,7 +67,6 @@ class CreateServiceProvider(show.ShowOne): return parser - @utils.log_method(log) def take_action(self, parsed_args): service_client = self.app.client_manager.identity sp = service_client.federation.service_providers.create( @@ -90,8 +83,6 @@ class CreateServiceProvider(show.ShowOne): class DeleteServiceProvider(command.Command): """Delete service provider""" - log = logging.getLogger(__name__ + '.DeleteServiceProvider') - def get_parser(self, prog_name): parser = super(DeleteServiceProvider, self).get_parser(prog_name) parser.add_argument( @@ -101,7 +92,6 @@ class DeleteServiceProvider(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): service_client = self.app.client_manager.identity service_client.federation.service_providers.delete( @@ -109,12 +99,9 @@ class DeleteServiceProvider(command.Command): return -class ListServiceProvider(lister.Lister): +class ListServiceProvider(command.Lister): """List service providers""" - log = logging.getLogger(__name__ + '.ListServiceProvider') - - @utils.log_method(log) def take_action(self, parsed_args): service_client = self.app.client_manager.identity data = service_client.federation.service_providers.list() @@ -130,8 +117,6 @@ class ListServiceProvider(lister.Lister): class SetServiceProvider(command.Command): """Set service provider properties""" - log = logging.getLogger(__name__ + '.SetServiceProvider') - def get_parser(self, prog_name): parser = super(SetServiceProvider, self).get_parser(prog_name) parser.add_argument( @@ -168,7 +153,6 @@ class SetServiceProvider(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): federation_client = self.app.client_manager.identity.federation @@ -193,11 +177,9 @@ class SetServiceProvider(command.Command): return zip(*sorted(six.iteritems(service_provider._info))) -class ShowServiceProvider(show.ShowOne): +class ShowServiceProvider(command.ShowOne): """Display service provider details""" - log = logging.getLogger(__name__ + '.ShowServiceProvider') - def get_parser(self, prog_name): parser = super(ShowServiceProvider, self).get_parser(prog_name) parser.add_argument( @@ -207,7 +189,6 @@ class ShowServiceProvider(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): service_client = self.app.client_manager.identity service_provider = utils.find_resource( diff --git a/openstackclient/identity/v3/token.py b/openstackclient/identity/v3/token.py index cd3dc79..588c521 100644 --- a/openstackclient/identity/v3/token.py +++ b/openstackclient/identity/v3/token.py @@ -15,20 +15,16 @@ """Identity v3 Token action implementations""" -import logging import six -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils from openstackclient.identity import common -class AuthorizeRequestToken(show.ShowOne): +class AuthorizeRequestToken(command.ShowOne): """Authorize a request token""" - log = logging.getLogger(__name__ + '.AuthorizeRequestToken') - def get_parser(self, prog_name): parser = super(AuthorizeRequestToken, self).get_parser(prog_name) parser.add_argument( @@ -49,7 +45,6 @@ class AuthorizeRequestToken(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) identity_client = self.app.client_manager.identity # NOTE(stevemar): We want a list of role ids @@ -68,11 +63,9 @@ class AuthorizeRequestToken(show.ShowOne): return zip(*sorted(six.iteritems(verifier_pin._info))) -class CreateAccessToken(show.ShowOne): +class CreateAccessToken(command.ShowOne): """Create an access token""" - log = logging.getLogger(__name__ + '.CreateAccessToken') - def get_parser(self, prog_name): parser = super(CreateAccessToken, self).get_parser(prog_name) parser.add_argument( @@ -108,7 +101,6 @@ class CreateAccessToken(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) token_client = self.app.client_manager.identity.oauth1.access_tokens access_token = token_client.create( parsed_args.consumer_key, parsed_args.consumer_secret, @@ -117,11 +109,9 @@ class CreateAccessToken(show.ShowOne): return zip(*sorted(six.iteritems(access_token._info))) -class CreateRequestToken(show.ShowOne): +class CreateRequestToken(command.ShowOne): """Create a request token""" - log = logging.getLogger(__name__ + '.CreateRequestToken') - def get_parser(self, prog_name): parser = super(CreateRequestToken, self).get_parser(prog_name) parser.add_argument( @@ -151,8 +141,6 @@ class CreateRequestToken(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) - identity_client = self.app.client_manager.identity if parsed_args.domain: @@ -173,16 +161,13 @@ class CreateRequestToken(show.ShowOne): return zip(*sorted(six.iteritems(request_token._info))) -class IssueToken(show.ShowOne): +class IssueToken(command.ShowOne): """Issue new token""" - log = logging.getLogger(__name__ + '.IssueToken') - def get_parser(self, prog_name): parser = super(IssueToken, self).get_parser(prog_name) return parser - @utils.log_method(log) def take_action(self, parsed_args): token = self.app.client_manager.auth_ref.service_catalog.get_token() if 'tenant_id' in token: diff --git a/openstackclient/identity/v3/trust.py b/openstackclient/identity/v3/trust.py index 2c3cf53..26fb833 100644 --- a/openstackclient/identity/v3/trust.py +++ b/openstackclient/identity/v3/trust.py @@ -14,22 +14,16 @@ """Identity v3 Trust action implementations""" import datetime -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils from openstackclient.identity import common -class CreateTrust(show.ShowOne): +class CreateTrust(command.ShowOne): """Create new trust""" - log = logging.getLogger(__name__ + '.CreateTrust') - def get_parser(self, prog_name): parser = super(CreateTrust, self).get_parser(prog_name) parser.add_argument( @@ -85,7 +79,6 @@ class CreateTrust(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) identity_client = self.app.client_manager.identity # NOTE(stevemar): Find the two users, project and roles that @@ -138,8 +131,6 @@ class CreateTrust(show.ShowOne): class DeleteTrust(command.Command): """Delete trust(s)""" - log = logging.getLogger(__name__ + '.DeleteTrust') - def get_parser(self, prog_name): parser = super(DeleteTrust, self).get_parser(prog_name) parser.add_argument( @@ -151,20 +142,16 @@ class DeleteTrust(command.Command): return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) identity_client = self.app.client_manager.identity for t in parsed_args.trust: trust_obj = utils.find_resource(identity_client.trusts, t) identity_client.trusts.delete(trust_obj.id) -class ListTrust(lister.Lister): +class ListTrust(command.Lister): """List trusts""" - log = logging.getLogger(__name__ + '.ListTrust') - def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) columns = ('ID', 'Expires At', 'Impersonation', 'Project ID', 'Trustee User ID', 'Trustor User ID') data = self.app.client_manager.identity.trusts.list() @@ -175,11 +162,9 @@ class ListTrust(lister.Lister): ) for s in data)) -class ShowTrust(show.ShowOne): +class ShowTrust(command.ShowOne): """Display trust details""" - log = logging.getLogger(__name__ + '.ShowTrust') - def get_parser(self, prog_name): parser = super(ShowTrust, self).get_parser(prog_name) parser.add_argument( @@ -190,7 +175,6 @@ class ShowTrust(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) identity_client = self.app.client_manager.identity trust = utils.find_resource(identity_client.trusts, parsed_args.trust) diff --git a/openstackclient/identity/v3/unscoped_saml.py b/openstackclient/identity/v3/unscoped_saml.py index e659e75..a42637d 100644 --- a/openstackclient/identity/v3/unscoped_saml.py +++ b/openstackclient/identity/v3/unscoped_saml.py @@ -17,10 +17,7 @@ The first step of federated auth is to fetch an unscoped token. From there, the user can list domains and projects they are allowed to access, and request a scoped token.""" -import logging - -from cliff import lister - +from openstackclient.common import command from openstackclient.common import exceptions from openstackclient.common import utils @@ -43,13 +40,10 @@ def auth_with_unscoped_saml(func): return _decorated -class ListAccessibleDomains(lister.Lister): +class ListAccessibleDomains(command.Lister): """List accessible domains""" - log = logging.getLogger(__name__ + '.ListAccessibleDomains') - @auth_with_unscoped_saml - @utils.log_method(log) def take_action(self, parsed_args): columns = ('ID', 'Enabled', 'Name', 'Description') identity_client = self.app.client_manager.identity @@ -61,13 +55,10 @@ class ListAccessibleDomains(lister.Lister): ) for s in data)) -class ListAccessibleProjects(lister.Lister): +class ListAccessibleProjects(command.Lister): """List accessible projects""" - log = logging.getLogger(__name__ + '.ListAccessibleProjects') - @auth_with_unscoped_saml - @utils.log_method(log) def take_action(self, parsed_args): columns = ('ID', 'Domain ID', 'Enabled', 'Name') identity_client = self.app.client_manager.identity diff --git a/openstackclient/identity/v3/user.py b/openstackclient/identity/v3/user.py index eaef8f0..c694c6a 100644 --- a/openstackclient/identity/v3/user.py +++ b/openstackclient/identity/v3/user.py @@ -16,24 +16,19 @@ """Identity v3 User action implementations""" import copy -import logging import six -from cliff import command -from cliff import lister -from cliff import show from keystoneauth1 import exceptions as ks_exc +from openstackclient.common import command from openstackclient.common import utils from openstackclient.i18n import _ # noqa from openstackclient.identity import common -class CreateUser(show.ShowOne): +class CreateUser(command.ShowOne): """Create new user""" - log = logging.getLogger(__name__ + '.CreateUser') - def get_parser(self, prog_name): parser = super(CreateUser, self).get_parser(prog_name) parser.add_argument( @@ -91,7 +86,6 @@ class CreateUser(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -138,8 +132,6 @@ class CreateUser(show.ShowOne): class DeleteUser(command.Command): """Delete user(s)""" - log = logging.getLogger(__name__ + '.DeleteUser') - def get_parser(self, prog_name): parser = super(DeleteUser, self).get_parser(prog_name) parser.add_argument( @@ -155,7 +147,6 @@ class DeleteUser(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -174,11 +165,9 @@ class DeleteUser(command.Command): return -class ListUser(lister.Lister): +class ListUser(command.Lister): """List users""" - log = logging.getLogger(__name__ + '.ListUser') - def get_parser(self, prog_name): parser = super(ListUser, self).get_parser(prog_name) parser.add_argument( @@ -205,7 +194,6 @@ class ListUser(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -280,8 +268,6 @@ class ListUser(lister.Lister): class SetUser(command.Command): """Set user properties""" - log = logging.getLogger(__name__ + '.SetUser') - def get_parser(self, prog_name): parser = super(SetUser, self).get_parser(prog_name) parser.add_argument( @@ -334,7 +320,6 @@ class SetUser(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -383,8 +368,6 @@ class SetUser(command.Command): class SetPasswordUser(command.Command): """Change current user password""" - log = logging.getLogger(__name__ + '.SetPasswordUser') - def get_parser(self, prog_name): parser = super(SetPasswordUser, self).get_parser(prog_name) parser.add_argument( @@ -392,14 +375,40 @@ class SetPasswordUser(command.Command): metavar='<new-password>', help='New user password' ) + parser.add_argument( + '--original-password', + metavar='<original-password>', + help='Original user password' + ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity - current_password = utils.get_password( - self.app.stdin, prompt="Current Password:", confirm=False) + # FIXME(gyee): there are two scenarios: + # + # 1. user update password for himself + # 2. admin update password on behalf of the user. This is an unlikely + # scenario because that will require admin knowing the user's + # original password which is forbidden under most security + # policies. + # + # Of the two scenarios above, user either authenticate using its + # original password or an authentication token. For scenario #1, + # if user is authenticating with its original password (i.e. passing + # --os-password argument), we can just make use of it instead of using + # --original-password or prompting. For scenario #2, admin will need + # to specify --original-password option or this won't work because + # --os-password is the admin's own password. In the future if we stop + # supporting scenario #2 then we can just do this. + # + # current_password = (parsed_args.original_password or + # self.app.cloud.password) + # + current_password = parsed_args.original_password + if current_password is None: + current_password = utils.get_password( + self.app.stdin, prompt="Current Password:", confirm=False) password = parsed_args.password if password is None: @@ -409,11 +418,9 @@ class SetPasswordUser(command.Command): identity_client.users.update_password(current_password, password) -class ShowUser(show.ShowOne): +class ShowUser(command.ShowOne): """Display user details""" - log = logging.getLogger(__name__ + '.ShowUser') - def get_parser(self, prog_name): parser = super(ShowUser, self).get_parser(prog_name) parser.add_argument( @@ -428,7 +435,6 @@ class ShowUser(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity diff --git a/openstackclient/image/v1/image.py b/openstackclient/image/v1/image.py index 4ebc8f9..9cc5fac 100644 --- a/openstackclient/image/v1/image.py +++ b/openstackclient/image/v1/image.py @@ -17,7 +17,6 @@ import argparse import io -import logging import os import six import sys @@ -27,14 +26,12 @@ if os.name == "nt": else: msvcrt = None -from cliff import command -from cliff import lister -from cliff import show - from glanceclient.common import utils as gc_utils from openstackclient.api import utils as api_utils +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils +from openstackclient.i18n import _ # noqa DEFAULT_CONTAINER_FORMAT = 'bare' @@ -56,11 +53,9 @@ def _format_visibility(data): return 'private' -class CreateImage(show.ShowOne): +class CreateImage(command.ShowOne): """Create/upload an image""" - log = logging.getLogger(__name__ + ".CreateImage") - def get_parser(self, prog_name): parser = super(CreateImage, self).get_parser(prog_name) parser.add_argument( @@ -93,11 +88,6 @@ class CreateImage(show.ShowOne): "(default: %s)" % DEFAULT_DISK_FORMAT, ) parser.add_argument( - "--owner", - metavar="<project>", - help="Image owner project name or ID", - ) - parser.add_argument( "--size", metavar="<size>", help="Image size, in bytes (only used with --location and" @@ -178,12 +168,31 @@ class CreateImage(show.ShowOne): help="Set a property on this image " "(repeat option to set multiple properties)", ) + # NOTE(dtroyer): --owner is deprecated in Jan 2016 in an early + # 2.x release. Do not remove before Jan 2017 + # and a 3.x release. + project_group = parser.add_mutually_exclusive_group() + project_group.add_argument( + "--project", + metavar="<project>", + help="Set an alternate project on this image (name or ID)", + ) + project_group.add_argument( + "--owner", + metavar="<project>", + help=argparse.SUPPRESS, + ) return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) image_client = self.app.client_manager.image + if getattr(parsed_args, 'owner', None) is not None: + self.log.warning(_( + 'The --owner option is deprecated, ' + 'please use --project instead.' + )) + # Build an attribute dict from the parsed args, only include # attributes that were actually set on the command line kwargs = {} @@ -198,6 +207,12 @@ class CreateImage(show.ShowOne): # Only include a value in kwargs for attributes that are # actually present on the command line kwargs[attr] = val + + # Special case project option back to API attribute name 'owner' + val = getattr(parsed_args, 'project', None) + if val: + kwargs['owner'] = val + # Handle exclusive booleans with care # Avoid including attributes in kwargs if an option is not # present on the command line. These exclusive booleans are not @@ -261,8 +276,6 @@ class CreateImage(show.ShowOne): class DeleteImage(command.Command): """Delete image(s)""" - log = logging.getLogger(__name__ + ".DeleteImage") - def get_parser(self, prog_name): parser = super(DeleteImage, self).get_parser(prog_name) parser.add_argument( @@ -274,8 +287,6 @@ class DeleteImage(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - image_client = self.app.client_manager.image for image in parsed_args.images: image_obj = utils.find_resource( @@ -285,11 +296,9 @@ class DeleteImage(command.Command): image_client.images.delete(image_obj.id) -class ListImage(lister.Lister): +class ListImage(command.Lister): """List available images""" - log = logging.getLogger(__name__ + ".ListImage") - def get_parser(self, prog_name): parser = super(ListImage, self).get_parser(prog_name) public_group = parser.add_mutually_exclusive_group() @@ -345,8 +354,6 @@ class ListImage(lister.Lister): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - image_client = self.app.client_manager.image kwargs = {} @@ -383,7 +390,7 @@ class ListImage(lister.Lister): 'Status', 'Visibility', 'Protected', - 'Owner', + 'Project', 'Properties', ) else: @@ -430,8 +437,6 @@ class ListImage(lister.Lister): class SaveImage(command.Command): """Save an image locally""" - log = logging.getLogger(__name__ + ".SaveImage") - def get_parser(self, prog_name): parser = super(SaveImage, self).get_parser(prog_name) parser.add_argument( @@ -447,8 +452,6 @@ class SaveImage(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - image_client = self.app.client_manager.image image = utils.find_resource( image_client.images, @@ -462,8 +465,6 @@ class SaveImage(command.Command): class SetImage(command.Command): """Set image properties""" - log = logging.getLogger(__name__ + ".SetImage") - def get_parser(self, prog_name): parser = super(SetImage, self).get_parser(prog_name) parser.add_argument( @@ -477,11 +478,6 @@ class SetImage(command.Command): help="New image name", ) parser.add_argument( - "--owner", - metavar="<project>", - help="New image owner project (name or ID)", - ) - parser.add_argument( "--min-disk", metavar="<disk-gb>", type=int, @@ -590,12 +586,31 @@ class SetImage(command.Command): metavar="<checksum>", help="Image hash used for verification", ) + # NOTE(dtroyer): --owner is deprecated in Jan 2016 in an early + # 2.x release. Do not remove before Jan 2017 + # and a 3.x release. + project_group = parser.add_mutually_exclusive_group() + project_group.add_argument( + "--project", + metavar="<project>", + help="Set an alternate project on this image (name or ID)", + ) + project_group.add_argument( + "--owner", + metavar="<project>", + help=argparse.SUPPRESS, + ) return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) image_client = self.app.client_manager.image + if getattr(parsed_args, 'owner', None) is not None: + self.log.warning(_( + 'The --owner option is deprecated, ' + 'please use --project instead.' + )) + kwargs = {} copy_attrs = ('name', 'owner', 'min_disk', 'min_ram', 'properties', 'container_format', 'disk_format', 'size', 'store', @@ -607,6 +622,12 @@ class SetImage(command.Command): # Only include a value in kwargs for attributes that are # actually present on the command line kwargs[attr] = val + + # Special case project option back to API attribute name 'owner' + val = getattr(parsed_args, 'project', None) + if val: + kwargs['owner'] = val + # Handle exclusive booleans with care # Avoid including attributes in kwargs if an option is not # present on the command line. These exclusive booleans are not @@ -679,14 +700,10 @@ class SetImage(command.Command): kwargs['data'] != sys.stdin): kwargs['data'].close() - return - -class ShowImage(show.ShowOne): +class ShowImage(command.ShowOne): """Display image details""" - log = logging.getLogger(__name__ + ".ShowImage") - def get_parser(self, prog_name): parser = super(ShowImage, self).get_parser(prog_name) parser.add_argument( @@ -697,8 +714,6 @@ class ShowImage(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - image_client = self.app.client_manager.image image = utils.find_resource( image_client.images, diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py index c0fb5b5..3f16218 100644 --- a/openstackclient/image/v2/image.py +++ b/openstackclient/image/v2/image.py @@ -16,18 +16,16 @@ """Image V2 Action Implementations""" import argparse -import logging import six -from cliff import command -from cliff import lister -from cliff import show from glanceclient.common import utils as gc_utils from openstackclient.api import utils as api_utils +from openstackclient.common import command from openstackclient.common import exceptions from openstackclient.common import parseractions from openstackclient.common import utils +from openstackclient.i18n import _ # noqa from openstackclient.identity import common @@ -66,11 +64,9 @@ def _format_image(image): return info -class AddProjectToImage(show.ShowOne): +class AddProjectToImage(command.ShowOne): """Associate project with image""" - log = logging.getLogger(__name__ + ".AddProjectToImage") - def get_parser(self, prog_name): parser = super(AddProjectToImage, self).get_parser(prog_name) parser.add_argument( @@ -87,8 +83,6 @@ class AddProjectToImage(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - image_client = self.app.client_manager.image identity_client = self.app.client_manager.identity @@ -108,15 +102,13 @@ class AddProjectToImage(show.ShowOne): return zip(*sorted(six.iteritems(image_member))) -class CreateImage(show.ShowOne): +class CreateImage(command.ShowOne): """Create/upload an image""" - log = logging.getLogger(__name__ + ".CreateImage") deadopts = ('size', 'location', 'copy-from', 'checksum', 'store') def get_parser(self, prog_name): parser = super(CreateImage, self).get_parser(prog_name) - # TODO(mordred): add --volume and --force parameters and support # TODO(bunting): There are additional arguments that v1 supported # that v2 either doesn't support or supports weirdly. # --checksum - could be faked clientside perhaps? @@ -149,11 +141,6 @@ class CreateImage(show.ShowOne): "(default: %s)" % DEFAULT_DISK_FORMAT, ) parser.add_argument( - "--owner", - metavar="<owner>", - help="Image owner project name or ID", - ) - parser.add_argument( "--min-disk", metavar="<disk-gb>", type=int, @@ -170,6 +157,19 @@ class CreateImage(show.ShowOne): metavar="<file>", help="Upload image from local file", ) + parser.add_argument( + "--volume", + metavar="<volume>", + help="Create image from a volume", + ) + parser.add_argument( + "--force", + dest='force', + action='store_true', + default=False, + help="Force image creation if volume is in use " + "(only meaningful with --volume)", + ) protected_group = parser.add_mutually_exclusive_group() protected_group.add_argument( "--protected", @@ -208,6 +208,21 @@ class CreateImage(show.ShowOne): help="Set a tag on this image " "(repeat option to set multiple tags)", ) + # NOTE(dtroyer): --owner is deprecated in Jan 2016 in an early + # 2.x release. Do not remove before Jan 2017 + # and a 3.x release. + project_group = parser.add_mutually_exclusive_group() + project_group.add_argument( + "--project", + metavar="<project>", + help="Set an alternate project on this image (name or ID)", + ) + project_group.add_argument( + "--owner", + metavar="<project>", + help=argparse.SUPPRESS, + ) + common.add_project_domain_option_to_parser(parser) for deadopt in self.deadopts: parser.add_argument( "--%s" % deadopt, @@ -218,7 +233,7 @@ class CreateImage(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) + identity_client = self.app.client_manager.identity image_client = self.app.client_manager.image for deadopt in self.deadopts: @@ -232,8 +247,7 @@ class CreateImage(show.ShowOne): kwargs = {} copy_attrs = ('name', 'id', 'container_format', 'disk_format', - 'min_disk', 'min_ram', - 'tags', 'owner') + 'min_disk', 'min_ram', 'tags') for attr in copy_attrs: if attr in parsed_args: val = getattr(parsed_args, attr, None) @@ -241,10 +255,12 @@ class CreateImage(show.ShowOne): # Only include a value in kwargs for attributes that # are actually present on the command line kwargs[attr] = val + # properties should get flattened into the general kwargs if getattr(parsed_args, 'properties', None): for k, v in six.iteritems(parsed_args.properties): kwargs[k] = str(v) + # Handle exclusive booleans with care # Avoid including attributes in kwargs if an option is not # present on the command line. These exclusive booleans are not @@ -260,15 +276,58 @@ class CreateImage(show.ShowOne): if parsed_args.private: kwargs['visibility'] = 'private' + # Handle deprecated --owner option + project_arg = parsed_args.project + if parsed_args.owner: + project_arg = parsed_args.owner + self.log.warning(_( + 'The --owner option is deprecated, ' + 'please use --project instead.' + )) + if project_arg: + kwargs['owner'] = common.find_project( + identity_client, + project_arg, + parsed_args.project_domain, + ).id + # open the file first to ensure any failures are handled before the # image is created fp = gc_utils.get_data_file(parsed_args) + info = {} + if fp is not None and parsed_args.volume: + raise exceptions.CommandError("Uploading data and using container " + "are not allowed at the same time") if fp is None and parsed_args.file: self.log.warning("Failed to get an image file.") return {}, {} - image = image_client.images.create(**kwargs) + if parsed_args.owner: + kwargs['owner'] = common.find_project( + identity_client, + parsed_args.owner, + parsed_args.project_domain, + ).id + + # If a volume is specified. + if parsed_args.volume: + volume_client = self.app.client_manager.volume + source_volume = utils.find_resource( + volume_client.volumes, + parsed_args.volume, + ) + response, body = volume_client.volumes.upload_to_image( + source_volume.id, + parsed_args.force, + parsed_args.name, + parsed_args.container_format, + parsed_args.disk_format, + ) + info = body['os-volume_upload_image'] + info['volume_type'] = info['volume_type']['name'] + else: + image = image_client.images.create(**kwargs) if fp is not None: with fp: @@ -289,15 +348,15 @@ class CreateImage(show.ShowOne): # update the image after the data has been uploaded image = image_client.images.get(image.id) - info = _format_image(image) + if not info: + info = _format_image(image) + return zip(*sorted(six.iteritems(info))) class DeleteImage(command.Command): """Delete image(s)""" - log = logging.getLogger(__name__ + ".DeleteImage") - def get_parser(self, prog_name): parser = super(DeleteImage, self).get_parser(prog_name) parser.add_argument( @@ -309,8 +368,6 @@ class DeleteImage(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - image_client = self.app.client_manager.image for image in parsed_args.images: image_obj = utils.find_resource( @@ -320,11 +377,9 @@ class DeleteImage(command.Command): image_client.images.delete(image_obj.id) -class ListImage(lister.Lister): +class ListImage(command.Lister): """List available images""" - log = logging.getLogger(__name__ + ".ListImage") - def get_parser(self, prog_name): parser = super(ListImage, self).get_parser(prog_name) public_group = parser.add_mutually_exclusive_group() @@ -376,11 +431,23 @@ class ListImage(lister.Lister): "(default: asc), multiple keys and directions can be " "specified separated by comma", ) + parser.add_argument( + "--limit", + metavar="<limit>", + type=int, + help="Maximum number of images to display.", + ) + parser.add_argument( + '--marker', + metavar='<marker>', + default=None, + help="The last image (name or ID) of the previous page. Display " + "list of images after marker. Display all images if not " + "specified." + ) return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - image_client = self.app.client_manager.image kwargs = {} @@ -390,6 +457,11 @@ class ListImage(lister.Lister): kwargs['private'] = True if parsed_args.shared: kwargs['shared'] = True + if parsed_args.limit: + kwargs['limit'] = parsed_args.limit + if parsed_args.marker: + kwargs['marker'] = utils.find_resource(image_client.images, + parsed_args.marker).id if parsed_args.long: columns = ( @@ -413,7 +485,7 @@ class ListImage(lister.Lister): 'Status', 'Visibility', 'Protected', - 'Owner', + 'Project', 'Tags', ) else: @@ -421,16 +493,7 @@ class ListImage(lister.Lister): column_headers = columns # List of image data received - data = [] - # No pages received yet, so start the page marker at None. - marker = None - while True: - page = image_client.api.image_list(marker=marker, **kwargs) - if not page: - break - data.extend(page) - # Set the marker to the id of the last item we received - marker = page[-1]['id'] + data = image_client.api.image_list(**kwargs) if parsed_args.property: # NOTE(dtroyer): coerce to a list to subscript it in py3 @@ -459,8 +522,6 @@ class ListImage(lister.Lister): class RemoveProjectImage(command.Command): """Disassociate project with image""" - log = logging.getLogger(__name__ + ".RemoveProjectImage") - def get_parser(self, prog_name): parser = super(RemoveProjectImage, self).get_parser(prog_name) parser.add_argument( @@ -477,8 +538,6 @@ class RemoveProjectImage(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - image_client = self.app.client_manager.image identity_client = self.app.client_manager.identity @@ -496,8 +555,6 @@ class RemoveProjectImage(command.Command): class SaveImage(command.Command): """Save an image locally""" - log = logging.getLogger(__name__ + ".SaveImage") - def get_parser(self, prog_name): parser = super(SaveImage, self).get_parser(prog_name) parser.add_argument( @@ -513,8 +570,6 @@ class SaveImage(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - image_client = self.app.client_manager.image image = utils.find_resource( image_client.images, @@ -528,7 +583,6 @@ class SaveImage(command.Command): class SetImage(command.Command): """Set image properties""" - log = logging.getLogger(__name__ + ".SetImage") deadopts = ('visibility',) def get_parser(self, prog_name): @@ -539,8 +593,8 @@ class SetImage(command.Command): # --location - maybe location add? # --copy-from - does not exist in v2 # --file - should be able to upload file - # --volume - needs adding - # --force - needs adding + # --volume - not possible with v2 as can't change id + # --force - see `--volume` # --checksum - maybe could be done client side # --stdin - could be implemented parser.add_argument( @@ -554,11 +608,6 @@ class SetImage(command.Command): help="New image name" ) parser.add_argument( - "--owner", - metavar="<project>", - help="New image owner project (name or ID)", - ) - parser.add_argument( "--min-disk", type=int, metavar="<disk-gb>", @@ -657,6 +706,32 @@ class SetImage(command.Command): metavar="<ramdisk-id>", help="ID of ramdisk image used to boot this disk image", ) + deactivate_group = parser.add_mutually_exclusive_group() + deactivate_group.add_argument( + "--deactivate", + action="store_true", + help="Deactivate the image", + ) + deactivate_group.add_argument( + "--activate", + action="store_true", + help="Activate the image", + ) + # NOTE(dtroyer): --owner is deprecated in Jan 2016 in an early + # 2.x release. Do not remove before Jan 2017 + # and a 3.x release. + project_group = parser.add_mutually_exclusive_group() + project_group.add_argument( + "--project", + metavar="<project>", + help="Set an alternate project on this image (name or ID)", + ) + project_group.add_argument( + "--owner", + metavar="<project>", + help=argparse.SUPPRESS, + ) + common.add_project_domain_option_to_parser(parser) for deadopt in self.deadopts: parser.add_argument( "--%s" % deadopt, @@ -667,7 +742,7 @@ class SetImage(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) + identity_client = self.app.client_manager.identity image_client = self.app.client_manager.image for deadopt in self.deadopts: @@ -680,7 +755,7 @@ class SetImage(command.Command): copy_attrs = ('architecture', 'container_format', 'disk_format', 'file', 'instance_id', 'kernel_id', 'locations', 'min_disk', 'min_ram', 'name', 'os_distro', 'os_version', - 'owner', 'prefix', 'progress', 'ramdisk_id', 'tags') + 'prefix', 'progress', 'ramdisk_id', 'tags') for attr in copy_attrs: if attr in parsed_args: val = getattr(parsed_args, attr, None) @@ -709,25 +784,56 @@ class SetImage(command.Command): if parsed_args.private: kwargs['visibility'] = 'private' - if not kwargs: + # Handle deprecated --owner option + project_arg = parsed_args.project + if parsed_args.owner: + project_arg = parsed_args.owner + self.log.warning(_( + 'The --owner option is deprecated, ' + 'please use --project instead.' + )) + if project_arg: + kwargs['owner'] = common.find_project( + identity_client, + project_arg, + parsed_args.project_domain, + ).id + + # Checks if anything that requires getting the image + if not (kwargs or parsed_args.deactivate or parsed_args.activate): self.log.warning("No arguments specified") return {}, {} image = utils.find_resource( image_client.images, parsed_args.image) + activation_status = None + if parsed_args.deactivate: + image_client.images.deactivate(image.id) + activation_status = "deactivated" + if parsed_args.activate: + image_client.images.reactivate(image.id) + activation_status = "activated" + + # Check if need to do the actual update + if not kwargs: + return {}, {} + if parsed_args.tags: # Tags should be extended, but duplicates removed kwargs['tags'] = list(set(image.tags).union(set(parsed_args.tags))) - image = image_client.images.update(image.id, **kwargs) + try: + image = image_client.images.update(image.id, **kwargs) + except Exception as e: + if activation_status is not None: + print("Image %s was %s." % (image.id, activation_status)) + raise e -class ShowImage(show.ShowOne): +class ShowImage(command.ShowOne): """Display image details""" - log = logging.getLogger(__name__ + ".ShowImage") - def get_parser(self, prog_name): parser = super(ShowImage, self).get_parser(prog_name) parser.add_argument( @@ -738,8 +844,6 @@ class ShowImage(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - image_client = self.app.client_manager.image image = utils.find_resource( image_client.images, diff --git a/python-openstackclient/locale/de/LC_MESSAGES/python-openstackclient.po b/openstackclient/locale/de/LC_MESSAGES/openstackclient.po index 983abdb..1c94b9d 100644 --- a/python-openstackclient/locale/de/LC_MESSAGES/python-openstackclient.po +++ b/openstackclient/locale/de/LC_MESSAGES/openstackclient.po @@ -1,4 +1,4 @@ -# German translations for python-openstackclient. +# Translations template for python-openstackclient. # Copyright (C) 2015 ORGANIZATION # This file is distributed under the same license as the # python-openstackclient project. @@ -9,18 +9,19 @@ # OpenStack Infra <zanata@openstack.org>, 2015. #zanata msgid "" msgstr "" -"Project-Id-Version: python-openstackclient 1.8.1.dev15\n" +"Project-Id-Version: python-openstackclient 2.0.1.dev168\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2015-11-04 06:04+0000\n" +"POT-Creation-Date: 2016-01-19 02:20+0000\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2015-09-19 07:10+0000\n" "Last-Translator: Andreas Jaeger <jaegerandi@gmail.com>\n" "Language: de\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Generated-By: Babel 2.0\n" +"X-Generator: Zanata 3.7.3\n" "Language-Team: German\n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.1.1\n" msgid "" "\n" @@ -126,15 +127,6 @@ msgstr "" "Anmeldedaten in Projekt erstellen (Name oder Kennung; Standard: aktuell " "authentifiziertes Projekt)" -msgid "Create server from this image" -msgstr "Server aus diesem Abbild erstellen" - -msgid "Create server from this volume" -msgstr "Server aus diesem Datenträger erstellen" - -msgid "Create server with this flavor" -msgstr "Server mit dieser Variante erstellen" - msgid "Credentials access key" msgstr "Anmeldedaten-Zugriffsschlüssel" @@ -358,9 +350,6 @@ msgstr "" "Zu hinzufügende/ändernde Eigenschaft für diesen Server (wiederholen Sie die " "Option, um mehrere Eigenschaften festzulegen)" -msgid "Recreate server from this image" -msgstr "Server aus diesem Abbild neu erstellen" - msgid "Region ID to delete" msgstr "Zu löschende Regionskennung" @@ -419,15 +408,9 @@ msgstr "Zu entfernende Rolle (Name oder Kennung)" msgid "Role(s) to delete (name or ID)" msgstr "Zu löschende Rolle(n) (Name oder Kennung)" -msgid "Search by flavor" -msgstr "Nach Variante suchen" - msgid "Search by hostname" msgstr "Nach Hostname suchen" -msgid "Search by image" -msgstr "Nach Bild suchen" - msgid "Search by server status" msgstr "Nach Serverstatus suchen" @@ -437,11 +420,6 @@ msgstr "Nach Benutzer suchen (nur Administrator) (Name oder Kennung)" msgid "Security group to add (name or ID)" msgstr "Zu hinzufügende Sicherheitsgruppe (Name oder Kennung)" -msgid "Security group to assign to this server (repeat for multiple groups)" -msgstr "" -"Zu diesem Server zuweisende Sicherheitsgruppe (für mehrere Gruppen " -"wiederholen)" - msgid "Select an availability zone for the server" msgstr "Wählen Sie eine Verfügbarkeitszone für den Server aus" @@ -609,11 +587,6 @@ msgstr "Warten Sie, bis die Wiederherstellung abgeschlossen ist" msgid "Wait for resize to complete" msgstr "Warten Sie, bis die Größenänderung abgeschlossen ist" -msgid "can't create server with port specified since neutron not enabled" -msgstr "" -"Server mit dem angegebenen Port kann nicht erstellt werden, da Neutron nicht " -"aktiviert ist" - msgid "either net-id or port-id should be specified but not both" msgstr "entweder net-id oder port-id sollten angegeben sein, aber nicht beide" diff --git a/python-openstackclient/locale/python-openstackclient.pot b/openstackclient/locale/openstackclient.pot index cc4f1a1..afc8926 100644 --- a/python-openstackclient/locale/python-openstackclient.pot +++ b/openstackclient/locale/openstackclient.pot @@ -1,22 +1,22 @@ # Translations template for python-openstackclient. -# Copyright (C) 2015 ORGANIZATION +# Copyright (C) 2016 ORGANIZATION # This file is distributed under the same license as the # python-openstackclient project. -# FIRST AUTHOR <EMAIL@ADDRESS>, 2015. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2016. # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: python-openstackclient 1.8.1.dev15\n" +"Project-Id-Version: python-openstackclient 2.0.1.dev168\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2015-11-04 06:04+0000\n" +"POT-Creation-Date: 2016-01-19 06:03+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.1.1\n" +"Generated-By: Babel 2.2.0\n" #: openstackclient/api/auth.py:144 msgid "Set a username with --os-username, OS_USERNAME, or auth.username\n" @@ -48,7 +48,7 @@ msgid "Set a service URL, with --os-url, OS_URL or auth.url\n" msgstr "" #: openstackclient/compute/v2/availability_zone.py:72 -#: openstackclient/compute/v2/server.py:718 +#: openstackclient/compute/v2/server.py:737 #: openstackclient/identity/v2_0/endpoint.py:114 #: openstackclient/identity/v2_0/project.py:145 #: openstackclient/identity/v2_0/service.py:128 @@ -56,89 +56,85 @@ msgstr "" msgid "List additional fields in output" msgstr "" -#: openstackclient/compute/v2/server.py:161 -#: openstackclient/compute/v2/server.py:198 -#: openstackclient/compute/v2/server.py:549 -#: openstackclient/compute/v2/server.py:810 -#: openstackclient/compute/v2/server.py:844 -#: openstackclient/compute/v2/server.py:927 -#: openstackclient/compute/v2/server.py:951 -#: openstackclient/compute/v2/server.py:1006 -#: openstackclient/compute/v2/server.py:1098 -#: openstackclient/compute/v2/server.py:1138 -#: openstackclient/compute/v2/server.py:1164 -#: openstackclient/compute/v2/server.py:1229 -#: openstackclient/compute/v2/server.py:1253 -#: openstackclient/compute/v2/server.py:1312 -#: openstackclient/compute/v2/server.py:1349 -#: openstackclient/compute/v2/server.py:1496 -#: openstackclient/compute/v2/server.py:1520 -#: openstackclient/compute/v2/server.py:1544 -#: openstackclient/compute/v2/server.py:1568 -#: openstackclient/compute/v2/server.py:1592 +#: openstackclient/compute/v2/server.py:183 +#: openstackclient/compute/v2/server.py:219 +#: openstackclient/compute/v2/server.py:569 +#: openstackclient/compute/v2/server.py:923 +#: openstackclient/compute/v2/server.py:1031 +#: openstackclient/compute/v2/server.py:1086 +#: openstackclient/compute/v2/server.py:1179 +#: openstackclient/compute/v2/server.py:1219 +#: openstackclient/compute/v2/server.py:1245 +#: openstackclient/compute/v2/server.py:1336 +#: openstackclient/compute/v2/server.py:1420 +#: openstackclient/compute/v2/server.py:1457 +#: openstackclient/compute/v2/server.py:1732 +#: openstackclient/compute/v2/server.py:1756 msgid "Server (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:166 +#: openstackclient/compute/v2/server.py:188 msgid "Security group to add (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:203 +#: openstackclient/compute/v2/server.py:224 msgid "Volume to add (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:208 +#: openstackclient/compute/v2/server.py:229 msgid "Server internal device name for volume" msgstr "" -#: openstackclient/compute/v2/server.py:248 -#: openstackclient/compute/v2/server.py:1258 +#: openstackclient/compute/v2/server.py:265 +#: openstackclient/compute/v2/server.py:1341 msgid "New server name" msgstr "" -#: openstackclient/compute/v2/server.py:256 -msgid "Create server from this image" +#: openstackclient/compute/v2/server.py:273 +msgid "Create server from this image (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:261 -msgid "Create server from this volume" +#: openstackclient/compute/v2/server.py:278 +msgid "Create server from this volume (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:267 -msgid "Create server with this flavor" +#: openstackclient/compute/v2/server.py:284 +msgid "Create server with this flavor (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:274 -msgid "Security group to assign to this server (repeat for multiple groups)" +#: openstackclient/compute/v2/server.py:291 +msgid "" +"Security group to assign to this server (name or ID) (repeat for multiple" +" groups)" msgstr "" -#: openstackclient/compute/v2/server.py:280 +#: openstackclient/compute/v2/server.py:297 msgid "Keypair to inject into this server (optional extension)" msgstr "" -#: openstackclient/compute/v2/server.py:286 +#: openstackclient/compute/v2/server.py:303 msgid "Set a property on this server (repeat for multiple values)" msgstr "" -#: openstackclient/compute/v2/server.py:294 +#: openstackclient/compute/v2/server.py:311 msgid "File to inject into image before boot (repeat for multiple files)" msgstr "" -#: openstackclient/compute/v2/server.py:300 +#: openstackclient/compute/v2/server.py:317 msgid "User data file to serve from the metadata server" msgstr "" -#: openstackclient/compute/v2/server.py:305 +#: openstackclient/compute/v2/server.py:322 msgid "Select an availability zone for the server" msgstr "" -#: openstackclient/compute/v2/server.py:312 +#: openstackclient/compute/v2/server.py:329 msgid "" "Map block devices; map is <id>:<type>:<size(GB)>:<delete_on_terminate> " "(optional extension)" msgstr "" -#: openstackclient/compute/v2/server.py:322 +#: openstackclient/compute/v2/server.py:339 msgid "" "Create a NIC on the server. Specify option multiple times to create " "multiple NICs. Either net-id or port-id must be provided, but not both. " @@ -147,321 +143,367 @@ msgid "" "-fixed-ip: IPv6 fixed address for NIC (optional)." msgstr "" -#: openstackclient/compute/v2/server.py:335 +#: openstackclient/compute/v2/server.py:352 msgid "Hints for the scheduler (optional extension)" msgstr "" -#: openstackclient/compute/v2/server.py:341 +#: openstackclient/compute/v2/server.py:358 msgid "" "Use specified volume as the config drive, or 'True' to use an ephemeral " "drive" msgstr "" -#: openstackclient/compute/v2/server.py:349 +#: openstackclient/compute/v2/server.py:366 msgid "Minimum number of servers to launch (default=1)" msgstr "" -#: openstackclient/compute/v2/server.py:356 +#: openstackclient/compute/v2/server.py:373 msgid "Maximum number of servers to launch (default=1)" msgstr "" -#: openstackclient/compute/v2/server.py:361 +#: openstackclient/compute/v2/server.py:378 msgid "Wait for build to complete" msgstr "" -#: openstackclient/compute/v2/server.py:401 +#: openstackclient/compute/v2/server.py:418 msgid "min instances should be <= max instances" msgstr "" -#: openstackclient/compute/v2/server.py:404 +#: openstackclient/compute/v2/server.py:421 msgid "min instances should be > 0" msgstr "" -#: openstackclient/compute/v2/server.py:407 +#: openstackclient/compute/v2/server.py:424 msgid "max instances should be > 0" msgstr "" -#: openstackclient/compute/v2/server.py:443 -msgid "either net-id or port-id should be specified but not both" +#: openstackclient/compute/v2/server.py:453 +msgid "Volume name or ID must be specified if --block-device-mapping is specified" msgstr "" #: openstackclient/compute/v2/server.py:465 -msgid "can't create server with port specified since neutron not enabled" +msgid "either net-id or port-id should be specified but not both" +msgstr "" + +#: openstackclient/compute/v2/server.py:485 +msgid "can't create server with port specified since network endpoint not enabled" msgstr "" -#: openstackclient/compute/v2/server.py:530 +#: openstackclient/compute/v2/server.py:550 #, python-format msgid "Error creating server: %s" msgstr "" -#: openstackclient/compute/v2/server.py:532 +#: openstackclient/compute/v2/server.py:552 msgid "" "\n" "Error creating server" msgstr "" -#: openstackclient/compute/v2/server.py:554 +#: openstackclient/compute/v2/server.py:574 msgid "Name of new image (default is server name)" msgstr "" -#: openstackclient/compute/v2/server.py:559 +#: openstackclient/compute/v2/server.py:579 msgid "Wait for image create to complete" msgstr "" -#: openstackclient/compute/v2/server.py:589 +#: openstackclient/compute/v2/server.py:609 #, python-format msgid "Error creating server snapshot: %s" msgstr "" -#: openstackclient/compute/v2/server.py:591 +#: openstackclient/compute/v2/server.py:611 msgid "" "\n" "Error creating server snapshot" msgstr "" -#: openstackclient/compute/v2/server.py:613 +#: openstackclient/compute/v2/server.py:633 msgid "Server(s) to delete (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:618 +#: openstackclient/compute/v2/server.py:638 msgid "Wait for delete to complete" msgstr "" -#: openstackclient/compute/v2/server.py:637 +#: openstackclient/compute/v2/server.py:657 #, python-format msgid "Error deleting server: %s" msgstr "" -#: openstackclient/compute/v2/server.py:639 +#: openstackclient/compute/v2/server.py:659 msgid "" "\n" "Error deleting server" msgstr "" -#: openstackclient/compute/v2/server.py:654 +#: openstackclient/compute/v2/server.py:673 msgid "Only return instances that match the reservation" msgstr "" -#: openstackclient/compute/v2/server.py:659 +#: openstackclient/compute/v2/server.py:678 msgid "Regular expression to match IP addresses" msgstr "" -#: openstackclient/compute/v2/server.py:664 +#: openstackclient/compute/v2/server.py:683 msgid "Regular expression to match IPv6 addresses" msgstr "" -#: openstackclient/compute/v2/server.py:669 +#: openstackclient/compute/v2/server.py:688 msgid "Regular expression to match names" msgstr "" -#: openstackclient/compute/v2/server.py:674 +#: openstackclient/compute/v2/server.py:693 msgid "Regular expression to match instance name (admin only)" msgstr "" -#: openstackclient/compute/v2/server.py:680 +#: openstackclient/compute/v2/server.py:699 msgid "Search by server status" msgstr "" -#: openstackclient/compute/v2/server.py:685 -msgid "Search by flavor" +#: openstackclient/compute/v2/server.py:704 +msgid "Search by flavor (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:690 -msgid "Search by image" +#: openstackclient/compute/v2/server.py:709 +msgid "Search by image (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:695 +#: openstackclient/compute/v2/server.py:714 msgid "Search by hostname" msgstr "" -#: openstackclient/compute/v2/server.py:701 +#: openstackclient/compute/v2/server.py:720 msgid "Include all projects (admin only)" msgstr "" -#: openstackclient/compute/v2/server.py:711 +#: openstackclient/compute/v2/server.py:730 msgid "Search by user (admin only) (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:849 +#: openstackclient/compute/v2/server.py:888 +msgid "Server(s) to lock (name or ID)" +msgstr "" + +#: openstackclient/compute/v2/server.py:928 msgid "Target hostname" msgstr "" -#: openstackclient/compute/v2/server.py:857 +#: openstackclient/compute/v2/server.py:936 msgid "Perform a shared live migration (default)" msgstr "" -#: openstackclient/compute/v2/server.py:863 +#: openstackclient/compute/v2/server.py:942 msgid "Perform a block live migration" msgstr "" -#: openstackclient/compute/v2/server.py:870 +#: openstackclient/compute/v2/server.py:949 msgid "Allow disk over-commit on the destination host" msgstr "" -#: openstackclient/compute/v2/server.py:877 +#: openstackclient/compute/v2/server.py:956 msgid "Do not over-commit disk on the destination host (default)" msgstr "" -#: openstackclient/compute/v2/server.py:883 -#: openstackclient/compute/v2/server.py:1184 +#: openstackclient/compute/v2/server.py:962 +#: openstackclient/compute/v2/server.py:1265 msgid "Wait for resize to complete" msgstr "" -#: openstackclient/compute/v2/server.py:911 -#: openstackclient/compute/v2/server.py:1209 +#: openstackclient/compute/v2/server.py:990 +#: openstackclient/compute/v2/server.py:1290 msgid "Complete\n" msgstr "" -#: openstackclient/compute/v2/server.py:913 +#: openstackclient/compute/v2/server.py:992 msgid "" "\n" "Error migrating server" msgstr "" -#: openstackclient/compute/v2/server.py:960 +#: openstackclient/compute/v2/server.py:1007 +msgid "Server(s) to pause (name or ID)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1040 msgid "Perform a hard reboot" msgstr "" -#: openstackclient/compute/v2/server.py:968 +#: openstackclient/compute/v2/server.py:1048 msgid "Perform a soft reboot" msgstr "" -#: openstackclient/compute/v2/server.py:973 +#: openstackclient/compute/v2/server.py:1053 msgid "Wait for reboot to complete" msgstr "" -#: openstackclient/compute/v2/server.py:990 +#: openstackclient/compute/v2/server.py:1070 msgid "" "\n" "Reboot complete\n" msgstr "" -#: openstackclient/compute/v2/server.py:992 +#: openstackclient/compute/v2/server.py:1072 msgid "" "\n" "Error rebooting server\n" msgstr "" -#: openstackclient/compute/v2/server.py:1012 -msgid "Recreate server from this image" +#: openstackclient/compute/v2/server.py:1091 +msgid "" +"Recreate server from the specified image (name or ID). Defaults to the " +"currently used one." msgstr "" -#: openstackclient/compute/v2/server.py:1022 +#: openstackclient/compute/v2/server.py:1102 msgid "Wait for rebuild to complete" msgstr "" -#: openstackclient/compute/v2/server.py:1043 +#: openstackclient/compute/v2/server.py:1124 msgid "" "\n" "Complete\n" msgstr "" -#: openstackclient/compute/v2/server.py:1045 +#: openstackclient/compute/v2/server.py:1126 msgid "" "\n" "Error rebuilding server" msgstr "" -#: openstackclient/compute/v2/server.py:1062 +#: openstackclient/compute/v2/server.py:1143 msgid "Name or ID of server to use" msgstr "" -#: openstackclient/compute/v2/server.py:1067 +#: openstackclient/compute/v2/server.py:1148 msgid "Name or ID of security group to remove from server" msgstr "" -#: openstackclient/compute/v2/server.py:1103 +#: openstackclient/compute/v2/server.py:1184 msgid "Volume to remove (name or ID)" msgstr "" -#: openstackclient/compute/v2/server.py:1169 +#: openstackclient/compute/v2/server.py:1250 msgid "Resize server to specified flavor" msgstr "" -#: openstackclient/compute/v2/server.py:1174 +#: openstackclient/compute/v2/server.py:1255 msgid "Confirm server resize is complete" msgstr "" -#: openstackclient/compute/v2/server.py:1179 +#: openstackclient/compute/v2/server.py:1260 msgid "Restore server state before resize" msgstr "" -#: openstackclient/compute/v2/server.py:1211 +#: openstackclient/compute/v2/server.py:1292 msgid "" "\n" "Error resizing server" msgstr "" -#: openstackclient/compute/v2/server.py:1263 +#: openstackclient/compute/v2/server.py:1311 +msgid "Server(s) to resume (name or ID)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1346 msgid "Set new root password (interactive only)" msgstr "" -#: openstackclient/compute/v2/server.py:1269 +#: openstackclient/compute/v2/server.py:1352 msgid "" "Property to add/change for this server (repeat option to set multiple " "properties)" msgstr "" -#: openstackclient/compute/v2/server.py:1293 +#: openstackclient/compute/v2/server.py:1376 msgid "New password: " msgstr "" -#: openstackclient/compute/v2/server.py:1294 +#: openstackclient/compute/v2/server.py:1377 msgid "Retype new password: " msgstr "" -#: openstackclient/compute/v2/server.py:1298 +#: openstackclient/compute/v2/server.py:1381 msgid "Passwords do not match, password unchanged" msgstr "" -#: openstackclient/compute/v2/server.py:1318 +#: openstackclient/compute/v2/server.py:1396 +msgid "Server(s) to shelve (name or ID)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1426 msgid "Display server diagnostics information" msgstr "" -#: openstackclient/compute/v2/server.py:1331 +#: openstackclient/compute/v2/server.py:1439 msgid "Error retrieving diagnostics data" msgstr "" -#: openstackclient/compute/v2/server.py:1354 +#: openstackclient/compute/v2/server.py:1462 msgid "Login name (ssh -l option)" msgstr "" -#: openstackclient/compute/v2/server.py:1366 +#: openstackclient/compute/v2/server.py:1474 msgid "Destination port (ssh -p option)" msgstr "" -#: openstackclient/compute/v2/server.py:1378 +#: openstackclient/compute/v2/server.py:1486 msgid "Private key file (ssh -i option)" msgstr "" -#: openstackclient/compute/v2/server.py:1389 +#: openstackclient/compute/v2/server.py:1497 msgid "Options in ssh_config(5) format (ssh -o option)" msgstr "" -#: openstackclient/compute/v2/server.py:1403 +#: openstackclient/compute/v2/server.py:1511 msgid "Use only IPv4 addresses" msgstr "" -#: openstackclient/compute/v2/server.py:1410 +#: openstackclient/compute/v2/server.py:1518 msgid "Use only IPv6 addresses" msgstr "" -#: openstackclient/compute/v2/server.py:1419 +#: openstackclient/compute/v2/server.py:1527 msgid "Use public IP address" msgstr "" -#: openstackclient/compute/v2/server.py:1427 +#: openstackclient/compute/v2/server.py:1535 msgid "Use private IP address" msgstr "" -#: openstackclient/compute/v2/server.py:1434 +#: openstackclient/compute/v2/server.py:1542 msgid "Use other IP address (public, private, etc)" msgstr "" -#: openstackclient/compute/v2/server.py:1599 +#: openstackclient/compute/v2/server.py:1605 +msgid "Server(s) to start (name or ID)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1630 +msgid "Server(s) to stop (name or ID)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1655 +msgid "Server(s) to suspend (name or ID)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1681 +msgid "Server(s) to unlock (name or ID)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1707 +msgid "Server(s) to unpause (name or ID)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1763 msgid "Property key to remove from server (repeat to unset multiple values)" msgstr "" +#: openstackclient/compute/v2/server.py:1794 +msgid "Server(s) to unshelve (name or ID)" +msgstr "" + #: openstackclient/identity/v2_0/catalog.py:75 #: openstackclient/identity/v3/catalog.py:72 msgid "Service to display (type or name)" @@ -562,6 +604,7 @@ msgid "Project(s) to delete (name or ID)" msgstr "" #: openstackclient/identity/v2_0/project.py:173 +#: openstackclient/identity/v2_0/project.py:313 msgid "Project to modify (name or ID)" msgstr "" @@ -585,6 +628,10 @@ msgstr "" msgid "Project to display (name or ID)" msgstr "" +#: openstackclient/identity/v2_0/project.py:320 +msgid "Unset a project property (repeat option to unset multiple properties)" +msgstr "" + #: openstackclient/identity/v2_0/role.py:41 msgid "Role to add to <project>:<user> (name or ID)" msgstr "" diff --git a/python-openstackclient/locale/zh_TW/LC_MESSAGES/python-openstackclient.po b/openstackclient/locale/zh_TW/LC_MESSAGES/openstackclient.po index 301912c..2603266 100644 --- a/python-openstackclient/locale/zh_TW/LC_MESSAGES/python-openstackclient.po +++ b/openstackclient/locale/zh_TW/LC_MESSAGES/openstackclient.po @@ -1,4 +1,4 @@ -# Chinese (Traditional, Taiwan) translations for python-openstackclient. +# Translations template for python-openstackclient. # Copyright (C) 2015 ORGANIZATION # This file is distributed under the same license as the # python-openstackclient project. @@ -7,18 +7,19 @@ # OpenStack Infra <zanata@openstack.org>, 2015. #zanata msgid "" msgstr "" -"Project-Id-Version: python-openstackclient 1.8.1.dev15\n" +"Project-Id-Version: python-openstackclient 2.0.1.dev168\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2015-11-04 06:04+0000\n" +"POT-Creation-Date: 2016-01-19 02:20+0000\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2015-06-14 06:41+0000\n" "Last-Translator: openstackjenkins <jenkins@openstack.org>\n" -"Language: zh_Hant_TW\n" +"Language: zh-TW\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"Generated-By: Babel 2.0\n" +"X-Generator: Zanata 3.7.3\n" "Language-Team: Chinese (Taiwan)\n" -"Plural-Forms: nplurals=1; plural=0\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.1.1\n" msgid "" "\n" @@ -88,15 +89,6 @@ msgstr "完成\n" msgid "Confirm server resize is complete" msgstr "確認調整雲實例容量完成" -msgid "Create server from this image" -msgstr "從此映像檔新增雲實例" - -msgid "Create server from this volume" -msgstr "從此雲硬碟新增雲實例" - -msgid "Create server with this flavor" -msgstr "以這個虛擬硬體樣板新增雲實例" - msgid "Credentials access key" msgstr "憑鑰存取密鑰" @@ -303,9 +295,6 @@ msgid "" "properties)" msgstr "要加入這個雲實例的屬性(重復這選項來設定多個屬性)" -msgid "Recreate server from this image" -msgstr "從此映像檔重建雲實例" - msgid "Region ID to delete" msgstr "要刪除的地區識別號" @@ -363,24 +352,15 @@ msgstr "要移除的角色(名稱或識別號)" msgid "Role(s) to delete (name or ID)" msgstr "要刪除的角色(名稱或識別號)" -msgid "Search by flavor" -msgstr "以虛擬硬體樣板來尋找" - msgid "Search by hostname" msgstr "以主機名稱來尋找" -msgid "Search by image" -msgstr "以映像檔來尋找" - msgid "Search by server status" msgstr "以雲實例狀態來尋找" msgid "Security group to add (name or ID)" msgstr "要加入的安全性群組(名稱或識別號)" -msgid "Security group to assign to this server (repeat for multiple groups)" -msgstr "要指定到此雲實例的安全性群組(為多個群組重復指定)" - msgid "Select an availability zone for the server" msgstr "為雲實例選擇可用的區域。" @@ -502,9 +482,6 @@ msgstr "等待重建完成" msgid "Wait for resize to complete" msgstr "等待調整容量完成" -msgid "can't create server with port specified since neutron not enabled" -msgstr "Neutron 未啟用時,不能以指定的接口來新增雲實例" - msgid "either net-id or port-id should be specified but not both" msgstr "任選網路識別號或接口識別號,但不能兩者都指定" diff --git a/openstackclient/network/client.py b/openstackclient/network/client.py index 69ed11f..7714c52 100644 --- a/openstackclient/network/client.py +++ b/openstackclient/network/client.py @@ -13,6 +13,8 @@ import logging +from openstack import connection + from openstackclient.common import utils @@ -22,62 +24,18 @@ DEFAULT_API_VERSION = '2.0' API_VERSION_OPTION = 'os_network_api_version' API_NAME = "network" API_VERSIONS = { - "2.0": "neutronclient.v2_0.client.Client", - "2": "neutronclient.v2_0.client.Client", -} -# Translate our API version to auth plugin version prefix -API_VERSION_MAP = { - '2.0': 'v2.0', - '2': 'v2.0', -} - -NETWORK_API_TYPE = 'network' -NETWORK_API_VERSIONS = { - '2.0': 'openstackclient.api.network_v2.APIv2', - '2': 'openstackclient.api.network_v2.APIv2', + "2.0": "openstack.connection.Connection", + "2": "openstack.connection.Connection", } def make_client(instance): - """Returns an network service client""" - network_client = utils.get_client_class( - API_NAME, - instance._api_version[API_NAME], - API_VERSIONS) - LOG.debug('Instantiating network client: %s', network_client) - - endpoint = instance.get_endpoint_for_service_type( - API_NAME, - region_name=instance._region_name, - interface=instance._interface, - ) - - # Remember endpoint_type only if it is set - kwargs = utils.build_kwargs_dict('endpoint_type', instance._interface) - - client = network_client( - session=instance.session, - region_name=instance._region_name, - **kwargs - ) - - network_api = utils.get_client_class( - API_NAME, - instance._api_version[API_NAME], - NETWORK_API_VERSIONS) - LOG.debug('Instantiating network api: %s', network_client) - - # v2 is hard-coded until discovery is completed, neutron only has one atm - client.api = network_api( - session=instance.session, - service_type=NETWORK_API_TYPE, - endpoint='/'.join([ - endpoint, - API_VERSION_MAP[instance._api_version[API_NAME]], - ]) - ) - - return client + """Returns a network proxy""" + conn = connection.Connection(authenticator=instance.session.auth) + LOG.debug('Connection: %s', conn) + LOG.debug('Network client initialized using OpenStack SDK: %s', + conn.network) + return conn.network def build_option_parser(parser): diff --git a/openstackclient/network/common.py b/openstackclient/network/common.py index 31faef2..c539dd0 100644 --- a/openstackclient/network/common.py +++ b/openstackclient/network/common.py @@ -11,37 +11,52 @@ # under the License. # -from openstackclient.common import exceptions - - -def find(client, resource, resources, name_or_id, name_attr='name'): - """Find a network resource - - :param client: network client - :param resource: name of the resource - :param resources: plural name of resource - :param name_or_id: name or id of resource user is looking for - :param name_attr: key to the name attribute for the resource - - For example: - n = find(netclient, 'network', 'networks', 'matrix') - """ - list_method = getattr(client, "list_%s" % resources) - - # Search by name - kwargs = {name_attr: name_or_id, 'fields': 'id'} - data = list_method(**kwargs) - info = data[resources] - if len(info) == 1: - return info[0]['id'] - if len(info) > 1: - msg = "More than one %s exists with the name '%s'." - raise exceptions.CommandError(msg % (resource, name_or_id)) - - # Search by id - data = list_method(id=name_or_id, fields='id') - info = data[resources] - if len(info) == 1: - return info[0]['id'] - msg = "No %s with a name or ID of '%s' exists." % (resource, name_or_id) - raise exceptions.CommandError(msg) +import abc +import six + +from openstackclient.common import command + + +@six.add_metaclass(abc.ABCMeta) +class NetworkAndComputeCommand(command.Command): + """Network and Compute Command""" + + def take_action(self, parsed_args): + if self.app.client_manager.is_network_endpoint_enabled(): + return self.take_action_network(self.app.client_manager.network, + parsed_args) + else: + return self.take_action_compute(self.app.client_manager.compute, + parsed_args) + + def get_parser(self, prog_name): + self.log.debug('get_parser(%s)', prog_name) + parser = super(NetworkAndComputeCommand, self).get_parser(prog_name) + parser = self.update_parser_common(parser) + self.log.debug('common parser: %s', parser) + if self.app.client_manager.is_network_endpoint_enabled(): + return self.update_parser_network(parser) + else: + return self.update_parser_compute(parser) + + def update_parser_common(self, parser): + """Default is no updates to parser.""" + return parser + + def update_parser_network(self, parser): + """Default is no updates to parser.""" + return parser + + def update_parser_compute(self, parser): + """Default is no updates to parser.""" + return parser + + @abc.abstractmethod + def take_action_network(self, client, parsed_args): + """Override to do something useful.""" + pass + + @abc.abstractmethod + def take_action_compute(self, client, parsed_args): + """Override to do something useful.""" + pass diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py index 336b308..6123721 100644 --- a/openstackclient/network/v2/network.py +++ b/openstackclient/network/v2/network.py @@ -13,40 +13,69 @@ """Network action implementations""" -import logging -import six - -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import exceptions from openstackclient.common import utils from openstackclient.identity import common as identity_common -from openstackclient.network import common -def _prep_network_detail(net): - """Prepare network object for output""" +def _format_admin_state(item): + return 'UP' if item else 'DOWN' - if 'subnets' in net: - net['subnets'] = utils.format_list(net['subnets']) - if 'admin_state_up' in net: - net['state'] = 'UP' if net['admin_state_up'] else 'DOWN' - net.pop('admin_state_up') - if 'router:external' in net: - net['router_type'] = 'External' if net['router:external'] \ - else 'Internal' - net.pop('router:external') - if 'tenant_id' in net: - net['project_id'] = net.pop('tenant_id') - return net +def _format_router_external(item): + return 'External' if item else 'Internal' -class CreateNetwork(show.ShowOne): - """Create new network""" - log = logging.getLogger(__name__ + '.CreateNetwork') +_formatters = { + 'subnets': utils.format_list, + 'admin_state_up': _format_admin_state, + 'router_external': _format_router_external, + 'availability_zones': utils.format_list, + 'availability_zone_hints': utils.format_list, +} + + +def _get_columns(item): + columns = item.keys() + if 'tenant_id' in columns: + columns.remove('tenant_id') + columns.append('project_id') + if 'router:external' in columns: + columns.remove('router:external') + columns.append('router_external') + return tuple(sorted(columns)) + + +def _get_attrs(client_manager, parsed_args): + attrs = {} + if parsed_args.name is not None: + attrs['name'] = str(parsed_args.name) + if parsed_args.admin_state is not None: + attrs['admin_state_up'] = parsed_args.admin_state + if parsed_args.shared is not None: + attrs['shared'] = parsed_args.shared + + # "network set" command doesn't support setting project. + 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['tenant_id'] = project_id + + # "network set" command doesn't support setting availability zone hints. + if 'availability_zone_hints' in parsed_args and \ + parsed_args.availability_zone_hints is not None: + attrs['availability_zone_hints'] = parsed_args.availability_zone_hints + + return attrs + + +class CreateNetwork(command.ShowOne): + """Create new network""" def get_parser(self, prog_name): parser = super(CreateNetwork, self).get_parser(prog_name) @@ -86,68 +115,55 @@ class CreateNetwork(show.ShowOne): parser.add_argument( '--project', metavar='<project>', - help="Owner's project (name or ID)") + help="Owner's project (name or ID)" + ) identity_common.add_project_domain_option_to_parser(parser) + + parser.add_argument( + '--availability-zone-hint', + action='append', + dest='availability_zone_hints', + metavar='<availability-zone>', + help='Availability Zone in which to create this network ' + '(requires the Network Availability Zone extension, ' + 'this option can be repeated).', + ) return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) client = self.app.client_manager.network - body = self.get_body(parsed_args) - create_method = getattr(client, "create_network") - data = create_method(body)['network'] - if data: - data = _prep_network_detail(data) - else: - data = {'': ''} - return zip(*sorted(six.iteritems(data))) - - def get_body(self, parsed_args): - body = {'name': str(parsed_args.name), - 'admin_state_up': parsed_args.admin_state} - if parsed_args.shared is not None: - body['shared'] = parsed_args.shared - if parsed_args.project is not None: - identity_client = self.app.client_manager.identity - project_id = identity_common.find_project( - identity_client, - parsed_args.project, - parsed_args.project_domain, - ).id - body['tenant_id'] = project_id - return {'network': body} + + attrs = _get_attrs(self.app.client_manager, parsed_args) + obj = client.create_network(**attrs) + columns = _get_columns(obj) + + data = utils.get_item_properties(obj, columns, formatters=_formatters) + return (columns, data) class DeleteNetwork(command.Command): """Delete network(s)""" - log = logging.getLogger(__name__ + '.DeleteNetwork') - def get_parser(self, prog_name): parser = super(DeleteNetwork, self).get_parser(prog_name) parser.add_argument( - 'networks', + 'network', metavar="<network>", nargs="+", - help=("Network to delete (name or ID)") + help=("Network(s) to delete (name or ID)") ) return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) client = self.app.client_manager.network - delete_method = getattr(client, "delete_network") - for network in parsed_args.networks: - _id = common.find(client, 'network', 'networks', network) - delete_method(_id) - return + for network in parsed_args.network: + obj = client.find_network(network) + client.delete_network(obj) -class ListNetwork(lister.Lister): +class ListNetwork(command.Lister): """List networks""" - log = logging.getLogger(__name__ + '.ListNetwork') - def get_parser(self, prog_name): parser = super(ListNetwork, self).get_parser(prog_name) parser.add_argument( @@ -165,22 +181,20 @@ class ListNetwork(lister.Lister): return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) client = self.app.client_manager.network - data = client.api.network_list(external=parsed_args.external) - if parsed_args.long: columns = ( - 'ID', - 'Name', - 'Status', - 'project_id', - 'state', - 'Shared', - 'Subnets', - 'provider:network_type', - 'router_type', + 'id', + 'name', + 'status', + 'tenant_id', + 'admin_state_up', + 'shared', + 'subnets', + 'provider_network_type', + 'router_external', + 'availability_zones', ) column_headers = ( 'ID', @@ -192,26 +206,35 @@ class ListNetwork(lister.Lister): 'Subnets', 'Network Type', 'Router Type', + 'Availability Zones', ) else: - columns = ('ID', 'Name', 'Subnets') - column_headers = columns - - for d in data: - d = _prep_network_detail(d) + columns = ( + 'id', + 'name', + 'subnets' + ) + column_headers = ( + 'ID', + 'Name', + 'Subnets', + ) + if parsed_args.external: + args = {'router:external': True} + else: + args = {} + data = client.networks(**args) return (column_headers, - (utils.get_dict_properties( + (utils.get_item_properties( s, columns, - formatters={'subnets': utils.format_list}, + formatters=_formatters, ) for s in data)) class SetNetwork(command.Command): """Set network properties""" - log = logging.getLogger(__name__ + '.SetNetwork') - def get_parser(self, prog_name): parser = super(SetNetwork, self).get_parser(prog_name) parser.add_argument( @@ -255,30 +278,21 @@ class SetNetwork(command.Command): return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) client = self.app.client_manager.network - _id = common.find(client, 'network', 'networks', - parsed_args.identifier) - body = {} - if parsed_args.name is not None: - body['name'] = str(parsed_args.name) - if parsed_args.admin_state is not None: - body['admin_state_up'] = parsed_args.admin_state - if parsed_args.shared is not None: - body['shared'] = parsed_args.shared - if body == {}: + obj = client.find_network(parsed_args.identifier, ignore_missing=False) + + attrs = _get_attrs(self.app.client_manager, parsed_args) + if attrs == {}: msg = "Nothing specified to be set" raise exceptions.CommandError(msg) - update_method = getattr(client, "update_network") - update_method(_id, {'network': body}) + + client.update_network(obj, **attrs) return -class ShowNetwork(show.ShowOne): +class ShowNetwork(command.ShowOne): """Show network details""" - log = logging.getLogger(__name__ + '.ShowNetwork') - def get_parser(self, prog_name): parser = super(ShowNetwork, self).get_parser(prog_name) parser.add_argument( @@ -289,11 +303,8 @@ class ShowNetwork(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug('take_action(%s)' % parsed_args) client = self.app.client_manager.network - net = client.api.find_attr( - 'networks', - parsed_args.identifier, - ) - data = _prep_network_detail(net) - return zip(*sorted(six.iteritems(data))) + obj = client.find_network(parsed_args.identifier, ignore_missing=False) + columns = _get_columns(obj) + data = utils.get_item_properties(obj, columns, formatters=_formatters) + return (columns, data) diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py new file mode 100644 index 0000000..46cb031 --- /dev/null +++ b/openstackclient/network/v2/port.py @@ -0,0 +1,93 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +"""Port action implementations""" + +from openstackclient.common import command +from openstackclient.common import utils + + +def _format_admin_state(state): + return 'UP' if state else 'DOWN' + + +_formatters = { + 'admin_state_up': _format_admin_state, + 'allowed_address_pairs': utils.format_list_of_dicts, + 'binding_profile': utils.format_dict, + 'binding_vif_details': utils.format_dict, + 'dns_assignment': utils.format_list_of_dicts, + 'extra_dhcp_opts': utils.format_list_of_dicts, + 'fixed_ips': utils.format_list_of_dicts, + 'security_groups': utils.format_list, +} + + +def _get_columns(item): + columns = item.keys() + if 'tenant_id' in columns: + columns.remove('tenant_id') + columns.append('project_id') + binding_columns = [ + 'binding:host_id', + 'binding:profile', + 'binding:vif_details', + 'binding:vif_type', + 'binding:vnic_type', + ] + for binding_column in binding_columns: + if binding_column in columns: + columns.remove(binding_column) + columns.append(binding_column.replace('binding:', 'binding_', 1)) + return sorted(columns) + + +class DeletePort(command.Command): + """Delete port(s)""" + + def get_parser(self, prog_name): + parser = super(DeletePort, self).get_parser(prog_name) + parser.add_argument( + 'port', + metavar="<port>", + nargs="+", + help=("Port(s) to delete (name or ID)") + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + + for port in parsed_args.port: + res = client.find_port(port) + client.delete_port(res) + + +class ShowPort(command.ShowOne): + """Display port details""" + + def get_parser(self, prog_name): + parser = super(ShowPort, self).get_parser(prog_name) + parser.add_argument( + 'port', + metavar="<port>", + help="Port to display (name or ID)" + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + obj = client.find_port(parsed_args.port, ignore_missing=False) + columns = _get_columns(obj) + data = utils.get_item_properties(obj, columns, formatters=_formatters) + return (tuple(columns), data) diff --git a/openstackclient/network/v2/router.py b/openstackclient/network/v2/router.py new file mode 100644 index 0000000..60db816 --- /dev/null +++ b/openstackclient/network/v2/router.py @@ -0,0 +1,295 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +"""Router action implementations""" + +import json + +from openstackclient.common import command +from openstackclient.common import exceptions +from openstackclient.common import utils +from openstackclient.identity import common as identity_common + + +def _format_admin_state(state): + return 'UP' if state else 'DOWN' + + +def _format_external_gateway_info(info): + try: + return json.dumps(info) + except (TypeError, KeyError): + return '' + + +_formatters = { + 'admin_state_up': _format_admin_state, + 'external_gateway_info': _format_external_gateway_info, + 'availability_zones': utils.format_list, + 'availability_zone_hints': utils.format_list, +} + + +def _get_attrs(client_manager, parsed_args): + attrs = {} + if parsed_args.name is not None: + attrs['name'] = str(parsed_args.name) + if parsed_args.admin_state_up is not None: + attrs['admin_state_up'] = parsed_args.admin_state_up + if parsed_args.distributed is not None: + attrs['distributed'] = parsed_args.distributed + if ('availability_zone_hints' in parsed_args + and parsed_args.availability_zone_hints is not None): + attrs['availability_zone_hints'] = parsed_args.availability_zone_hints + # "router set" command doesn't support setting project. + 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['tenant_id'] = project_id + + # TODO(tangchen): Support getting 'ha' property. + # TODO(tangchen): Support getting 'external_gateway_info' property. + # TODO(tangchen): Support getting 'routes' property. + + return attrs + + +class CreateRouter(command.ShowOne): + """Create a new router""" + + def get_parser(self, prog_name): + parser = super(CreateRouter, self).get_parser(prog_name) + parser.add_argument( + 'name', + metavar='<name>', + help="New router name", + ) + admin_group = parser.add_mutually_exclusive_group() + admin_group.add_argument( + '--enable', + dest='admin_state_up', + action='store_true', + default=True, + help="Enable router (default)", + ) + admin_group.add_argument( + '--disable', + dest='admin_state_up', + action='store_false', + help="Disable router", + ) + parser.add_argument( + '--distributed', + dest='distributed', + action='store_true', + default=False, + help="Create a distributed router", + ) + parser.add_argument( + '--project', + metavar='<project>', + help="Owner's project (name or ID)", + ) + parser.add_argument( + '--availability-zone-hint', + metavar='<availability-zone>', + action='append', + dest='availability_zone_hints', + help='Availability Zone in which to create this router ' + '(requires the Router Availability Zone extension, ' + 'this option can be repeated).', + ) + + identity_common.add_project_domain_option_to_parser(parser) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + + attrs = _get_attrs(self.app.client_manager, parsed_args) + obj = client.create_router(**attrs) + + columns = sorted(obj.keys()) + data = utils.get_item_properties(obj, columns, formatters=_formatters) + + if 'tenant_id' in columns: + # Rename "tenant_id" to "project_id". + index = columns.index('tenant_id') + columns[index] = 'project_id' + return (tuple(columns), data) + + +class DeleteRouter(command.Command): + """Delete router(s)""" + + def get_parser(self, prog_name): + parser = super(DeleteRouter, self).get_parser(prog_name) + parser.add_argument( + 'router', + metavar="<router>", + nargs="+", + help=("Router(s) to delete (name or ID)") + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + for router in parsed_args.router: + obj = client.find_router(router) + client.delete_router(obj) + + +class ListRouter(command.Lister): + """List routers""" + + def get_parser(self, prog_name): + parser = super(ListRouter, self).get_parser(prog_name) + parser.add_argument( + '--long', + action='store_true', + default=False, + help='List additional fields in output', + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + + columns = ( + 'id', + 'name', + 'status', + 'admin_state_up', + 'distributed', + 'ha', + 'tenant_id', + ) + column_headers = ( + 'ID', + 'Name', + 'Status', + 'State', + 'Distributed', + 'HA', + 'Project', + ) + if parsed_args.long: + columns = columns + ( + 'routes', + 'external_gateway_info', + 'availability_zones' + ) + column_headers = column_headers + ( + 'Routes', + 'External gateway info', + 'Availability zones' + ) + + data = client.routers() + return (column_headers, + (utils.get_item_properties( + s, columns, + formatters=_formatters, + ) for s in data)) + + +class SetRouter(command.Command): + """Set router properties""" + + def get_parser(self, prog_name): + parser = super(SetRouter, self).get_parser(prog_name) + parser.add_argument( + 'router', + metavar="<router>", + help=("Router to modify (name or ID)") + ) + parser.add_argument( + '--name', + metavar='<name>', + help='Set router name', + ) + admin_group = parser.add_mutually_exclusive_group() + admin_group.add_argument( + '--enable', + dest='admin_state_up', + action='store_true', + default=None, + help='Enable router', + ) + admin_group.add_argument( + '--disable', + dest='admin_state_up', + action='store_false', + help='Disable router', + ) + distribute_group = parser.add_mutually_exclusive_group() + distribute_group.add_argument( + '--distributed', + dest='distributed', + action='store_true', + default=None, + help="Set router to distributed mode (disabled router only)", + ) + distribute_group.add_argument( + '--centralized', + dest='distributed', + action='store_false', + help="Set router to centralized mode (disabled router only)", + ) + + # TODO(tangchen): Support setting 'ha' property in 'router set' + # command. It appears that changing the ha state is supported by + # neutron under certain conditions. + + # TODO(tangchen): Support setting 'external_gateway_info' property in + # 'router set' command. + + # TODO(tangchen): Support setting 'routes' property in 'router set' + # command. + + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + obj = client.find_router(parsed_args.router, ignore_missing=False) + + attrs = _get_attrs(self.app.client_manager, parsed_args) + if attrs == {}: + msg = "Nothing specified to be set" + raise exceptions.CommandError(msg) + + client.update_router(obj, **attrs) + + +class ShowRouter(command.ShowOne): + """Display router details""" + + def get_parser(self, prog_name): + parser = super(ShowRouter, self).get_parser(prog_name) + parser.add_argument( + 'router', + metavar="<router>", + help="Router to display (name or ID)" + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + obj = client.find_router(parsed_args.router, ignore_missing=False) + columns = sorted(obj.keys()) + data = utils.get_item_properties(obj, columns, formatters=_formatters) + return (tuple(columns), data) diff --git a/openstackclient/network/v2/security_group.py b/openstackclient/network/v2/security_group.py new file mode 100644 index 0000000..4e122f2 --- /dev/null +++ b/openstackclient/network/v2/security_group.py @@ -0,0 +1,40 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +"""Security Group action implementations""" + +from openstackclient.common import utils +from openstackclient.network import common + + +class DeleteSecurityGroup(common.NetworkAndComputeCommand): + """Delete a security group""" + + def update_parser_common(self, parser): + parser.add_argument( + 'group', + metavar='<group>', + help='Security group to delete (name or ID)', + ) + return parser + + def take_action_network(self, client, parsed_args): + obj = client.find_security_group(parsed_args.group) + client.delete_security_group(obj) + + def take_action_compute(self, client, parsed_args): + data = utils.find_resource( + client.security_groups, + parsed_args.group, + ) + client.security_groups.delete(data.id) diff --git a/openstackclient/network/v2/subnet.py b/openstackclient/network/v2/subnet.py new file mode 100644 index 0000000..b948c65 --- /dev/null +++ b/openstackclient/network/v2/subnet.py @@ -0,0 +1,63 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +"""Subnet action implementations""" + +from openstackclient.common import command +from openstackclient.common import utils + + +def _format_allocation_pools(data): + pool_formatted = ['%s-%s' % (pool.get('start', ''), pool.get('end', '')) + for pool in data] + return ','.join(pool_formatted) + + +_formatters = { + 'allocation_pools': _format_allocation_pools, + 'dns_nameservers': utils.format_list, + 'host_routes': utils.format_list, +} + + +class ListSubnet(command.Lister): + """List subnets""" + + def get_parser(self, prog_name): + parser = super(ListSubnet, self).get_parser(prog_name) + parser.add_argument( + '--long', + action='store_true', + default=False, + help='List additional fields in output', + ) + return parser + + def take_action(self, parsed_args): + data = self.app.client_manager.network.subnets() + + headers = ('ID', 'Name', 'Network', 'Subnet') + columns = ('id', 'name', 'network_id', 'cidr') + if parsed_args.long: + headers += ('Project', 'DHCP', 'Name Servers', + 'Allocation Pools', 'Host Routes', 'IP Version', + 'Gateway') + columns += ('tenant_id', 'enable_dhcp', 'dns_nameservers', + 'allocation_pools', 'host_routes', 'ip_version', + 'gateway_ip') + + return (headers, + (utils.get_item_properties( + s, columns, + formatters=_formatters, + ) for s in data)) diff --git a/openstackclient/object/client.py b/openstackclient/object/client.py index e758780..3af6f8a 100644 --- a/openstackclient/object/client.py +++ b/openstackclient/object/client.py @@ -15,13 +15,9 @@ """Object client""" -import logging - from openstackclient.api import object_store_v1 from openstackclient.common import utils -LOG = logging.getLogger(__name__) - DEFAULT_API_VERSION = '1' API_VERSION_OPTION = 'os_object_api_version' API_NAME = 'object_store' diff --git a/openstackclient/object/v1/account.py b/openstackclient/object/v1/account.py index aa94ff5..543ce4f 100644 --- a/openstackclient/object/v1/account.py +++ b/openstackclient/object/v1/account.py @@ -13,12 +13,9 @@ """Account v1 action implementations""" -import logging - -from cliff import command -from cliff import show import six +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils @@ -26,8 +23,6 @@ from openstackclient.common import utils class SetAccount(command.Command): """Set account properties""" - log = logging.getLogger(__name__ + '.SetAccount') - def get_parser(self, prog_name): parser = super(SetAccount, self).get_parser(prog_name) parser.add_argument( @@ -40,19 +35,15 @@ class SetAccount(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): self.app.client_manager.object_store.account_set( properties=parsed_args.property, ) -class ShowAccount(show.ShowOne): +class ShowAccount(command.ShowOne): """Display account details""" - log = logging.getLogger(__name__ + '.ShowAccount') - - @utils.log_method(log) def take_action(self, parsed_args): data = self.app.client_manager.object_store.account_show() if 'properties' in data: @@ -63,8 +54,6 @@ class ShowAccount(show.ShowOne): class UnsetAccount(command.Command): """Unset account properties""" - log = logging.getLogger(__name__ + '.UnsetAccount') - def get_parser(self, prog_name): parser = super(UnsetAccount, self).get_parser(prog_name) parser.add_argument( @@ -78,7 +67,6 @@ class UnsetAccount(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): self.app.client_manager.object_store.account_unset( properties=parsed_args.property, diff --git a/openstackclient/object/v1/container.py b/openstackclient/object/v1/container.py index 8c8844e..e70afd9 100644 --- a/openstackclient/object/v1/container.py +++ b/openstackclient/object/v1/container.py @@ -16,22 +16,16 @@ """Container v1 action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils -class CreateContainer(lister.Lister): +class CreateContainer(command.Lister): """Create new container""" - log = logging.getLogger(__name__ + '.CreateContainer') - def get_parser(self, prog_name): parser = super(CreateContainer, self).get_parser(prog_name) parser.add_argument( @@ -42,7 +36,6 @@ class CreateContainer(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): results = [] @@ -63,8 +56,6 @@ class CreateContainer(lister.Lister): class DeleteContainer(command.Command): """Delete container""" - log = logging.getLogger(__name__ + '.DeleteContainer') - def get_parser(self, prog_name): parser = super(DeleteContainer, self).get_parser(prog_name) parser.add_argument( @@ -75,7 +66,6 @@ class DeleteContainer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): for container in parsed_args.containers: @@ -84,11 +74,9 @@ class DeleteContainer(command.Command): ) -class ListContainer(lister.Lister): +class ListContainer(command.Lister): """List containers""" - log = logging.getLogger(__name__ + '.ListContainer') - def get_parser(self, prog_name): parser = super(ListContainer, self).get_parser(prog_name) parser.add_argument( @@ -126,7 +114,6 @@ class ListContainer(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): if parsed_args.long: @@ -160,8 +147,6 @@ class ListContainer(lister.Lister): class SaveContainer(command.Command): """Save container contents locally""" - log = logging.getLogger(__name__ + ".SaveContainer") - def get_parser(self, prog_name): parser = super(SaveContainer, self).get_parser(prog_name) parser.add_argument( @@ -172,8 +157,6 @@ class SaveContainer(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - self.app.client_manager.object_store.container_save( container=parsed_args.container, ) @@ -182,8 +165,6 @@ class SaveContainer(command.Command): class SetContainer(command.Command): """Set container properties""" - log = logging.getLogger(__name__ + '.SetContainer') - def get_parser(self, prog_name): parser = super(SetContainer, self).get_parser(prog_name) parser.add_argument( @@ -201,7 +182,6 @@ class SetContainer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): self.app.client_manager.object_store.container_set( parsed_args.container, @@ -209,11 +189,9 @@ class SetContainer(command.Command): ) -class ShowContainer(show.ShowOne): +class ShowContainer(command.ShowOne): """Display container details""" - log = logging.getLogger(__name__ + '.ShowContainer') - def get_parser(self, prog_name): parser = super(ShowContainer, self).get_parser(prog_name) parser.add_argument( @@ -223,7 +201,6 @@ class ShowContainer(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): data = self.app.client_manager.object_store.container_show( @@ -238,8 +215,6 @@ class ShowContainer(show.ShowOne): class UnsetContainer(command.Command): """Unset container properties""" - log = logging.getLogger(__name__ + '.UnsetContainer') - def get_parser(self, prog_name): parser = super(UnsetContainer, self).get_parser(prog_name) parser.add_argument( @@ -258,7 +233,6 @@ class UnsetContainer(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): self.app.client_manager.object_store.container_unset( parsed_args.container, diff --git a/openstackclient/object/v1/object.py b/openstackclient/object/v1/object.py index 4bd0612..f9a55e9 100644 --- a/openstackclient/object/v1/object.py +++ b/openstackclient/object/v1/object.py @@ -16,22 +16,16 @@ """Object v1 action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils -class CreateObject(lister.Lister): +class CreateObject(command.Lister): """Upload object to container""" - log = logging.getLogger(__name__ + '.CreateObject') - def get_parser(self, prog_name): parser = super(CreateObject, self).get_parser(prog_name) parser.add_argument( @@ -47,7 +41,6 @@ class CreateObject(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): results = [] @@ -69,8 +62,6 @@ class CreateObject(lister.Lister): class DeleteObject(command.Command): """Delete object from container""" - log = logging.getLogger(__name__ + '.DeleteObject') - def get_parser(self, prog_name): parser = super(DeleteObject, self).get_parser(prog_name) parser.add_argument( @@ -86,7 +77,6 @@ class DeleteObject(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): for obj in parsed_args.objects: @@ -96,11 +86,9 @@ class DeleteObject(command.Command): ) -class ListObject(lister.Lister): +class ListObject(command.Lister): """List objects""" - log = logging.getLogger(__name__ + '.ListObject') - def get_parser(self, prog_name): parser = super(ListObject, self).get_parser(prog_name) parser.add_argument( @@ -148,7 +136,6 @@ class ListObject(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): if parsed_args.long: @@ -191,8 +178,6 @@ class ListObject(lister.Lister): class SaveObject(command.Command): """Save object locally""" - log = logging.getLogger(__name__ + ".SaveObject") - def get_parser(self, prog_name): parser = super(SaveObject, self).get_parser(prog_name) parser.add_argument( @@ -213,8 +198,6 @@ class SaveObject(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action(%s)", parsed_args) - self.app.client_manager.object_store.object_save( container=parsed_args.container, object=parsed_args.object, @@ -225,8 +208,6 @@ class SaveObject(command.Command): class SetObject(command.Command): """Set object properties""" - log = logging.getLogger(__name__ + '.SetObject') - def get_parser(self, prog_name): parser = super(SetObject, self).get_parser(prog_name) parser.add_argument( @@ -249,7 +230,6 @@ class SetObject(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): self.app.client_manager.object_store.object_set( parsed_args.container, @@ -258,11 +238,9 @@ class SetObject(command.Command): ) -class ShowObject(show.ShowOne): +class ShowObject(command.ShowOne): """Display object details""" - log = logging.getLogger(__name__ + '.ShowObject') - def get_parser(self, prog_name): parser = super(ShowObject, self).get_parser(prog_name) parser.add_argument( @@ -277,7 +255,6 @@ class ShowObject(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): data = self.app.client_manager.object_store.object_show( @@ -293,8 +270,6 @@ class ShowObject(show.ShowOne): class UnsetObject(command.Command): """Unset object properties""" - log = logging.getLogger(__name__ + '.UnsetObject') - def get_parser(self, prog_name): parser = super(UnsetObject, self).get_parser(prog_name) parser.add_argument( @@ -318,7 +293,6 @@ class UnsetObject(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): self.app.client_manager.object_store.object_unset( parsed_args.container, diff --git a/openstackclient/shell.py b/openstackclient/shell.py index 5b4939a..c84e2b1 100644 --- a/openstackclient/shell.py +++ b/openstackclient/shell.py @@ -116,7 +116,7 @@ class OpenStackShell(app.App): if not logging.getLogger('').handlers: logging.basicConfig() if self.dump_stack_trace: - self.log.error(traceback.format_exc(e)) + self.log.error(traceback.format_exc()) else: self.log.error('Exception raised: ' + str(e)) diff --git a/openstackclient/tests/api/test_network_v2.py b/openstackclient/tests/api/test_network_v2.py deleted file mode 100644 index 80f1d9d..0000000 --- a/openstackclient/tests/api/test_network_v2.py +++ /dev/null @@ -1,52 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# - -"""Network v2 API Library Tests""" - -from requests_mock.contrib import fixture - -from keystoneauth1 import session -from openstackclient.api import network_v2 as network -from openstackclient.tests import utils - - -FAKE_PROJECT = 'xyzpdq' -FAKE_URL = 'http://gopher.com/v2/' + FAKE_PROJECT - - -class TestNetworkAPIv2(utils.TestCase): - - def setUp(self): - super(TestNetworkAPIv2, self).setUp() - sess = session.Session() - self.api = network.APIv2(session=sess, endpoint=FAKE_URL) - self.requests_mock = self.useFixture(fixture.Fixture()) - - -class TestNetwork(TestNetworkAPIv2): - - LIST_NETWORK_RESP = [ - {'id': '1', 'name': 'p1', 'description': 'none', 'enabled': True}, - {'id': '2', 'name': 'p2', 'description': 'none', 'enabled': False}, - {'id': '3', 'name': 'p3', 'description': 'none', 'enabled': True}, - ] - - def test_network_list_no_options(self): - self.requests_mock.register_uri( - 'GET', - FAKE_URL + '/networks', - json={'networks': self.LIST_NETWORK_RESP}, - status_code=200, - ) - ret = self.api.network_list() - self.assertEqual(self.LIST_NETWORK_RESP, ret) diff --git a/openstackclient/tests/api/test_object_store_v1.py b/openstackclient/tests/api/test_object_store_v1.py index 992bf26..8cc3a92 100644 --- a/openstackclient/tests/api/test_object_store_v1.py +++ b/openstackclient/tests/api/test_object_store_v1.py @@ -157,6 +157,7 @@ class TestContainer(TestObjectAPIv1): 'container': 'qaz', 'object_count': '1', 'bytes_used': '577', + 'properties': {'Owner': FAKE_ACCOUNT}, } self.requests_mock.register_uri( 'HEAD', @@ -309,6 +310,7 @@ class TestObject(TestObjectAPIv1): 'etag': 'qaz', 'x-container-meta-owner': FAKE_ACCOUNT, 'x-object-meta-wife': 'Wilma', + 'x-object-meta-Husband': 'fred', 'x-tra-header': 'yabba-dabba-do', } resp = { @@ -319,7 +321,8 @@ class TestObject(TestObjectAPIv1): 'content-length': '577', 'last-modified': '20130101', 'etag': 'qaz', - 'properties': {'wife': 'Wilma'}, + 'properties': {'wife': 'Wilma', + 'Husband': 'fred'}, } self.requests_mock.register_uri( 'HEAD', diff --git a/openstackclient/tests/common/test_availability_zone.py b/openstackclient/tests/common/test_availability_zone.py new file mode 100644 index 0000000..e44455c --- /dev/null +++ b/openstackclient/tests/common/test_availability_zone.py @@ -0,0 +1,257 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import mock +import six + +from openstackclient.common import availability_zone +from openstackclient.tests.compute.v2 import fakes as compute_fakes +from openstackclient.tests import fakes +from openstackclient.tests.network.v2 import fakes as network_fakes +from openstackclient.tests import utils +from openstackclient.tests.volume.v2 import fakes as volume_fakes + + +def _build_compute_az_datalist(compute_az, long_datalist=False): + datalist = () + if not long_datalist: + datalist = ( + compute_az.zoneName, + 'available', + ) + else: + for host, services in six.iteritems(compute_az.hosts): + for service, state in six.iteritems(services): + datalist += ( + compute_az.zoneName, + 'available', + '', + host, + service, + 'enabled :-) ' + state['updated_at'], + ) + return (datalist,) + + +def _build_volume_az_datalist(volume_az, long_datalist=False): + datalist = () + if not long_datalist: + datalist = ( + volume_az.zoneName, + 'available', + ) + else: + datalist = ( + volume_az.zoneName, + 'available', + '', '', '', '', + ) + return (datalist,) + + +def _build_network_az_datalist(network_az, long_datalist=False): + datalist = () + if not long_datalist: + datalist = ( + network_az.name, + network_az.state, + ) + else: + datalist = ( + network_az.name, + network_az.state, + network_az.resource, + '', '', '', + ) + return (datalist,) + + +class TestAvailabilityZone(utils.TestCommand): + + def setUp(self): + super(TestAvailabilityZone, self).setUp() + + compute_client = compute_fakes.FakeComputev2Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) + self.app.client_manager.compute = compute_client + + self.compute_azs_mock = compute_client.availability_zones + self.compute_azs_mock.reset_mock() + + volume_client = volume_fakes.FakeVolumeClient( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) + self.app.client_manager.volume = volume_client + + self.volume_azs_mock = volume_client.availability_zones + self.volume_azs_mock.reset_mock() + + network_client = network_fakes.FakeNetworkV2Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) + self.app.client_manager.network = network_client + + network_client.availability_zones = mock.Mock() + network_client.find_extension = mock.Mock() + self.network_azs_mock = network_client.availability_zones + + +class TestAvailabilityZoneList(TestAvailabilityZone): + + compute_azs = \ + compute_fakes.FakeAvailabilityZone.create_availability_zones() + volume_azs = \ + volume_fakes.FakeAvailabilityZone.create_availability_zones(count=1) + network_azs = \ + network_fakes.FakeAvailabilityZone.create_availability_zones() + + short_columnslist = ('Zone Name', 'Zone Status') + long_columnslist = ( + 'Zone Name', + 'Zone Status', + 'Zone Resource', + 'Host Name', + 'Service Name', + 'Service Status', + ) + + def setUp(self): + super(TestAvailabilityZoneList, self).setUp() + + self.compute_azs_mock.list.return_value = self.compute_azs + self.volume_azs_mock.list.return_value = self.volume_azs + self.network_azs_mock.return_value = self.network_azs + + # Get the command object to test + self.cmd = availability_zone.ListAvailabilityZone(self.app, None) + + def test_availability_zone_list_no_options(self): + arglist = [] + verifylist = [] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + self.compute_azs_mock.list.assert_called_with() + self.volume_azs_mock.list.assert_called_with() + self.network_azs_mock.assert_called_with() + + self.assertEqual(self.short_columnslist, columns) + datalist = () + for compute_az in self.compute_azs: + datalist += _build_compute_az_datalist(compute_az) + for volume_az in self.volume_azs: + datalist += _build_volume_az_datalist(volume_az) + for network_az in self.network_azs: + datalist += _build_network_az_datalist(network_az) + self.assertEqual(datalist, tuple(data)) + + def test_availability_zone_list_long(self): + arglist = [ + '--long', + ] + verifylist = [ + ('long', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + self.compute_azs_mock.list.assert_called_with() + self.volume_azs_mock.list.assert_called_with() + self.network_azs_mock.assert_called_with() + + self.assertEqual(self.long_columnslist, columns) + datalist = () + for compute_az in self.compute_azs: + datalist += _build_compute_az_datalist(compute_az, + long_datalist=True) + for volume_az in self.volume_azs: + datalist += _build_volume_az_datalist(volume_az, + long_datalist=True) + for network_az in self.network_azs: + datalist += _build_network_az_datalist(network_az, + long_datalist=True) + self.assertEqual(datalist, tuple(data)) + + def test_availability_zone_list_compute(self): + arglist = [ + '--compute', + ] + verifylist = [ + ('compute', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + self.compute_azs_mock.list.assert_called_with() + self.volume_azs_mock.list.assert_not_called() + self.network_azs_mock.assert_not_called() + + self.assertEqual(self.short_columnslist, columns) + datalist = () + for compute_az in self.compute_azs: + datalist += _build_compute_az_datalist(compute_az) + self.assertEqual(datalist, tuple(data)) + + def test_availability_zone_list_volume(self): + arglist = [ + '--volume', + ] + verifylist = [ + ('volume', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + self.compute_azs_mock.list.assert_not_called() + self.volume_azs_mock.list.assert_called_with() + self.network_azs_mock.assert_not_called() + + self.assertEqual(self.short_columnslist, columns) + datalist = () + for volume_az in self.volume_azs: + datalist += _build_volume_az_datalist(volume_az) + self.assertEqual(datalist, tuple(data)) + + def test_availability_zone_list_network(self): + arglist = [ + '--network', + ] + verifylist = [ + ('network', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + self.compute_azs_mock.list.assert_not_called() + self.volume_azs_mock.list.assert_not_called() + self.network_azs_mock.assert_called_with() + + self.assertEqual(self.short_columnslist, columns) + datalist = () + for network_az in self.network_azs: + datalist += _build_network_az_datalist(network_az) + self.assertEqual(datalist, tuple(data)) diff --git a/openstackclient/tests/common/test_clientmanager.py b/openstackclient/tests/common/test_clientmanager.py index 29cc59e..523f79a 100644 --- a/openstackclient/tests/common/test_clientmanager.py +++ b/openstackclient/tests/common/test_clientmanager.py @@ -77,6 +77,9 @@ class TestClientManager(utils.TestCase): self.requests = self.useFixture(fixture.Fixture()) # fake v2password token retrieval self.stub_auth(json=fakes.TEST_RESPONSE_DICT) + # fake token and token_endpoint retrieval + self.stub_auth(json=fakes.TEST_RESPONSE_DICT, + url='/'.join([fakes.AUTH_URL, 'v2.0/tokens'])) # fake v3password token retrieval self.stub_auth(json=fakes.TEST_RESPONSE_DICT_V3, url='/'.join([fakes.AUTH_URL, 'auth/tokens'])) @@ -99,6 +102,7 @@ class TestClientManager(utils.TestCase): verify=True ) client_manager.setup_auth() + client_manager.auth_ref self.assertEqual( fakes.AUTH_URL, @@ -114,6 +118,7 @@ class TestClientManager(utils.TestCase): ) self.assertFalse(client_manager._insecure) self.assertTrue(client_manager._verify) + self.assertTrue(client_manager.is_network_endpoint_enabled()) def test_client_manager_token(self): @@ -131,6 +136,7 @@ class TestClientManager(utils.TestCase): verify=True ) client_manager.setup_auth() + client_manager.auth_ref self.assertEqual( fakes.AUTH_URL, @@ -150,6 +156,7 @@ class TestClientManager(utils.TestCase): ) self.assertFalse(client_manager._insecure) self.assertTrue(client_manager._verify) + self.assertTrue(client_manager.is_network_endpoint_enabled()) def test_client_manager_password(self): @@ -166,6 +173,7 @@ class TestClientManager(utils.TestCase): verify=False, ) client_manager.setup_auth() + client_manager.auth_ref self.assertEqual( fakes.AUTH_URL, @@ -195,6 +203,28 @@ class TestClientManager(utils.TestCase): dir(SERVICE_CATALOG), dir(client_manager.auth_ref.service_catalog), ) + self.assertTrue(client_manager.is_network_endpoint_enabled()) + + def test_client_manager_network_endpoint_disabled(self): + + client_manager = clientmanager.ClientManager( + cli_options=FakeOptions( + auth=dict( + auth_url=fakes.AUTH_URL, + username=fakes.USERNAME, + password=fakes.PASSWORD, + project_name=fakes.PROJECT_NAME, + ), + auth_type='v3password', + ), + api_version={"identity": "3"}, + verify=False, + ) + client_manager.setup_auth() + client_manager.auth_ref + + # v3 fake doesn't have network endpoint. + self.assertFalse(client_manager.is_network_endpoint_enabled()) def stub_auth(self, json=None, url=None, verb=None, **kwargs): subject_token = fakes.AUTH_TOKEN @@ -229,10 +259,12 @@ class TestClientManager(utils.TestCase): verify='cafile', ) client_manager.setup_auth() + client_manager.auth_ref self.assertFalse(client_manager._insecure) self.assertTrue(client_manager._verify) self.assertEqual('cafile', client_manager._cacert) + self.assertTrue(client_manager.is_network_endpoint_enabled()) def _select_auth_plugin(self, auth_params, api_version, auth_plugin_name): auth_params['auth_type'] = auth_plugin_name @@ -243,6 +275,7 @@ class TestClientManager(utils.TestCase): verify=True ) client_manager.setup_auth() + client_manager.auth_ref self.assertEqual( auth_plugin_name, diff --git a/openstackclient/tests/network/common.py b/openstackclient/tests/common/test_command.py index 31fde25..1b2584b 100644 --- a/openstackclient/tests/network/common.py +++ b/openstackclient/tests/common/test_command.py @@ -1,3 +1,5 @@ +# Copyright 2016 NEC Corporation +# # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at @@ -9,27 +11,22 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. -# -import argparse import mock -from openstackclient.api import network_v2 -from openstackclient.tests import utils +from openstackclient.common import command +from openstackclient.tests import utils as test_utils -class FakeNetworkClient(object): - pass +class FakeCommand(command.Command): + def take_action(self, parsed_args): + pass -class TestNetworkBase(utils.TestCommand): - def setUp(self): - super(TestNetworkBase, self).setUp() - self.namespace = argparse.Namespace() +class TestCommand(test_utils.TestCase): - self.app.client_manager.network = FakeNetworkClient() - self.app.client_manager.network.api = network_v2.APIv2( - session=mock.Mock(), - service_type="network", - ) - self.api = self.app.client_manager.network.api + def test_command_has_logger(self): + cmd = FakeCommand(mock.Mock(), mock.Mock()) + self.assertTrue(hasattr(cmd, 'log')) + self.assertEqual('openstackclient.tests.common.test_command.' + 'FakeCommand', cmd.log.name) diff --git a/openstackclient/tests/common/test_configuration.py b/openstackclient/tests/common/test_configuration.py index 3b94253..e81550e 100644 --- a/openstackclient/tests/common/test_configuration.py +++ b/openstackclient/tests/common/test_configuration.py @@ -18,6 +18,21 @@ from openstackclient.tests import utils class TestConfiguration(utils.TestCommand): + columns = ( + 'auth.password', + 'auth.token', + 'auth.username', + 'identity_api_version', + 'region', + ) + datalist = ( + configuration.REDACTED, + configuration.REDACTED, + fakes.USERNAME, + fakes.VERSION, + fakes.REGION_NAME, + ) + def test_show(self): arglist = [] verifylist = [('mask', True)] @@ -26,17 +41,8 @@ class TestConfiguration(utils.TestCommand): columns, data = cmd.take_action(parsed_args) - collist = ('auth.password', 'auth.token', 'auth.username', - 'identity_api_version', 'region') - self.assertEqual(collist, columns) - datalist = ( - configuration.REDACTED, - configuration.REDACTED, - fakes.USERNAME, - fakes.VERSION, - fakes.REGION_NAME, - ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_show_unmask(self): arglist = ['--unmask'] @@ -46,9 +52,7 @@ class TestConfiguration(utils.TestCommand): columns, data = cmd.take_action(parsed_args) - collist = ('auth.password', 'auth.token', 'auth.username', - 'identity_api_version', 'region') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( fakes.PASSWORD, fakes.AUTH_TOKEN, @@ -56,7 +60,7 @@ class TestConfiguration(utils.TestCommand): fakes.VERSION, fakes.REGION_NAME, ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(datalist, data) def test_show_mask(self): arglist = ['--mask'] @@ -66,14 +70,5 @@ class TestConfiguration(utils.TestCommand): columns, data = cmd.take_action(parsed_args) - collist = ('auth.password', 'auth.token', 'auth.username', - 'identity_api_version', 'region') - self.assertEqual(collist, columns) - datalist = ( - configuration.REDACTED, - configuration.REDACTED, - fakes.USERNAME, - fakes.VERSION, - fakes.REGION_NAME, - ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) diff --git a/openstackclient/tests/common/test_extension.py b/openstackclient/tests/common/test_extension.py index 6d34bdd..21c2cc2 100644 --- a/openstackclient/tests/common/test_extension.py +++ b/openstackclient/tests/common/test_extension.py @@ -34,14 +34,16 @@ class TestExtension(utils.TestCommand): self.app.client_manager.identity.extensions) self.identity_extensions_mock.reset_mock() - network = network_fakes.FakeNetworkV2Client() - self.app.client_manager.network = network - self.network_extensions_mock = network.list_extensions + network_client = network_fakes.FakeNetworkV2Client() + self.app.client_manager.network = network_client + self.network_extensions_mock = network_client.extensions self.network_extensions_mock.reset_mock() class TestExtensionList(TestExtension): + columns = ('Name', 'Alias', 'Description') + def setUp(self): super(TestExtensionList, self).setUp() @@ -67,8 +69,7 @@ class TestExtensionList(TestExtension): # no args should output from all services self.identity_extensions_mock.list.assert_called_with() - collist = ('Name', 'Alias', 'Description') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( ( identity_fakes.extension_name, @@ -135,8 +136,7 @@ class TestExtensionList(TestExtension): self.identity_extensions_mock.list.assert_called_with() - collist = ('Name', 'Alias', 'Description') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = (( identity_fakes.extension_name, identity_fakes.extension_alias, @@ -157,8 +157,7 @@ class TestExtensionList(TestExtension): self.network_extensions_mock.assert_called_with() - collist = ('Name', 'Alias', 'Description') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( ( network_fakes.extension_name, diff --git a/openstackclient/tests/common/test_logs.py b/openstackclient/tests/common/test_logs.py index fe054a3..a319533 100644 --- a/openstackclient/tests/common/test_logs.py +++ b/openstackclient/tests/common/test_logs.py @@ -137,7 +137,7 @@ class TestLogConfigurator(utils.TestCase): self.cliff_log.setLevel.assert_called_with(logging.ERROR) self.stevedore_log.setLevel.assert_called_with(logging.ERROR) self.iso8601_log.setLevel.assert_called_with(logging.ERROR) - self.assertEqual(False, configurator.dump_trace) + self.assertFalse(configurator.dump_trace) @mock.patch('logging.getLogger') @mock.patch('openstackclient.common.logs.set_warning_filter') @@ -149,7 +149,7 @@ class TestLogConfigurator(utils.TestCase): warning_filter.assert_called_with(logging.DEBUG) self.requests_log.setLevel.assert_called_with(logging.DEBUG) - self.assertEqual(True, configurator.dump_trace) + self.assertTrue(configurator.dump_trace) @mock.patch('logging.FileHandler') @mock.patch('logging.getLogger') @@ -199,4 +199,4 @@ class TestLogConfigurator(utils.TestCase): self.root_logger.addHandler.assert_called_with(file_logger) file_logger.setFormatter.assert_called_with(mock_formatter) file_logger.setLevel.assert_called_with(logging.INFO) - self.assertEqual(False, configurator.dump_trace) + self.assertFalse(configurator.dump_trace) diff --git a/openstackclient/tests/common/test_parseractions.py b/openstackclient/tests/common/test_parseractions.py index b75c481..0109a3f 100644 --- a/openstackclient/tests/common/test_parseractions.py +++ b/openstackclient/tests/common/test_parseractions.py @@ -20,34 +20,14 @@ from openstackclient.tests import utils class TestKeyValueAction(utils.TestCase): - def test_good_values(self): - parser = argparse.ArgumentParser() - - # Set up our typical usage - parser.add_argument( - '--property', - metavar='<key=value>', - action=parseractions.KeyValueAction, - help='Property to store for this volume ' - '(repeat option to set multiple properties)', - ) - - results = parser.parse_args([ - '--property', 'red=', - '--property', 'green=100%', - '--property', 'blue=50%', - ]) - actual = getattr(results, 'property', {}) - # All should pass through unmolested - expect = {'red': '', 'green': '100%', 'blue': '50%'} - self.assertDictEqual(expect, actual) + def setUp(self): + super(TestKeyValueAction, self).setUp() - def test_default_values(self): - parser = argparse.ArgumentParser() + self.parser = argparse.ArgumentParser() # Set up our typical usage - parser.add_argument( + self.parser.add_argument( '--property', metavar='<key=value>', action=parseractions.KeyValueAction, @@ -56,84 +36,55 @@ class TestKeyValueAction(utils.TestCase): '(repeat option to set multiple properties)', ) - results = parser.parse_args([ + def test_good_values(self): + results = self.parser.parse_args([ '--property', 'red=', '--property', 'green=100%', '--property', 'blue=50%', ]) actual = getattr(results, 'property', {}) - # Verify green default is changed, format default is unchanged + # All should pass through unmolested expect = {'red': '', 'green': '100%', 'blue': '50%', 'format': '#rgb'} self.assertDictEqual(expect, actual) def test_error_values(self): - parser = argparse.ArgumentParser() - - # Set up our typical usage - parser.add_argument( - '--property', - metavar='<key=value>', - action=parseractions.KeyValueAction, - default={'green': '20%', 'blue': '40%'}, - help='Property to store for this volume ' - '(repeat option to set multiple properties)', - ) - - results = parser.parse_args([ + results = self.parser.parse_args([ '--property', 'red', '--property', 'green=100%', '--property', 'blue', ]) - failhere = None actual = getattr(results, 'property', {}) - # Verify non-existent red key - try: - failhere = actual['red'] - except Exception as e: - self.assertTrue(type(e) == KeyError) - # Verify removal of blue key - try: - failhere = actual['blue'] - except Exception as e: - self.assertTrue(type(e) == KeyError) # There should be no red or blue - expect = {'green': '100%'} + expect = {'green': '100%', 'format': '#rgb'} self.assertDictEqual(expect, actual) - self.assertEqual(None, failhere) class TestNonNegativeAction(utils.TestCase): - def test_negative_values(self): - parser = argparse.ArgumentParser() + + def setUp(self): + super(TestNonNegativeAction, self).setUp() + + self.parser = argparse.ArgumentParser() # Set up our typical usage - parser.add_argument( + self.parser.add_argument( '--foo', metavar='<foo>', type=int, action=parseractions.NonNegativeAction, ) + def test_negative_values(self): self.assertRaises( argparse.ArgumentTypeError, - parser.parse_args, + self.parser.parse_args, "--foo -1".split() ) def test_zero_values(self): - parser = argparse.ArgumentParser() - - # Set up our typical usage - parser.add_argument( - '--foo', - metavar='<foo>', - type=int, - action=parseractions.NonNegativeAction, - ) - - results = parser.parse_args( + results = self.parser.parse_args( '--foo 0'.split() ) @@ -141,17 +92,7 @@ class TestNonNegativeAction(utils.TestCase): self.assertEqual(actual, 0) def test_positive_values(self): - parser = argparse.ArgumentParser() - - # Set up our typical usage - parser.add_argument( - '--foo', - metavar='<foo>', - type=int, - action=parseractions.NonNegativeAction, - ) - - results = parser.parse_args( + results = self.parser.parse_args( '--foo 1'.split() ) diff --git a/openstackclient/tests/common/test_quota.py b/openstackclient/tests/common/test_quota.py index 485b8a8..edf29c9 100644 --- a/openstackclient/tests/common/test_quota.py +++ b/openstackclient/tests/common/test_quota.py @@ -214,13 +214,15 @@ class TestQuotaShow(TestQuota): loaded=True, ) - self.service_catalog_mock.get_endpoints.return_value = [ - fakes.FakeResource( - None, - copy.deepcopy(identity_fakes.ENDPOINT), - loaded=True, - ) - ] + fake_network_endpoint = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.ENDPOINT), + loaded=True, + ) + + self.service_catalog_mock.get_endpoints.return_value = { + 'network': fake_network_endpoint + } self.quotas_class_mock.get.return_value = FakeQuotaResource( None, @@ -244,6 +246,8 @@ class TestQuotaShow(TestQuota): endpoint=fakes.AUTH_URL, token=fakes.AUTH_TOKEN, ) + self.network = self.app.client_manager.network + self.network.get_quota = mock.Mock(return_value=network_fakes.QUOTA) self.cmd = quota.ShowQuota(self.app, None) @@ -260,6 +264,9 @@ class TestQuotaShow(TestQuota): self.cmd.take_action(parsed_args) self.quotas_mock.get.assert_called_with(identity_fakes.project_id) + self.volume_quotas_mock.get.assert_called_with( + identity_fakes.project_id) + self.network.get_quota.assert_called_with(identity_fakes.project_id) def test_quota_show_with_default(self): arglist = [ @@ -276,6 +283,8 @@ class TestQuotaShow(TestQuota): self.cmd.take_action(parsed_args) self.quotas_mock.defaults.assert_called_with(identity_fakes.project_id) + self.volume_quotas_mock.defaults.assert_called_with( + identity_fakes.project_id) def test_quota_show_with_class(self): arglist = [ @@ -293,3 +302,5 @@ class TestQuotaShow(TestQuota): self.quotas_class_mock.get.assert_called_with( identity_fakes.project_id) + self.volume_quotas_class_mock.get.assert_called_with( + identity_fakes.project_id) diff --git a/openstackclient/tests/common/test_timing.py b/openstackclient/tests/common/test_timing.py index a7f93b5..e7b9a04 100644 --- a/openstackclient/tests/common/test_timing.py +++ b/openstackclient/tests/common/test_timing.py @@ -33,6 +33,11 @@ class FakeGenericClient(object): class TestTiming(utils.TestCommand): + columns = ( + 'URL', + 'Seconds', + ) + def setUp(self): super(TestTiming, self).setUp() @@ -59,8 +64,7 @@ class TestTiming(utils.TestCommand): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) - collist = ('URL', 'Seconds') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = [ ('Total', 0.0,) ] @@ -78,9 +82,7 @@ class TestTiming(utils.TestCommand): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) - - collist = ('URL', 'Seconds') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = [ (timing_url, timing_elapsed), ('Total', timing_elapsed), diff --git a/openstackclient/tests/common/test_utils.py b/openstackclient/tests/common/test_utils.py index b564ffa..0954507 100644 --- a/openstackclient/tests/common/test_utils.py +++ b/openstackclient/tests/common/test_utils.py @@ -212,6 +212,28 @@ class TestUtils(test_utils.TestCase): self.assertFalse(utils.wait_for_delete(manager, res_id)) self.assertFalse(mock_sleep.called) + @mock.patch.object(time, 'sleep') + def test_wait_for_delete_error_with_overrides(self, mock_sleep): + # Tests that we fail if the resource is my_status=failed + resource = mock.MagicMock(my_status='FAILED') + mock_get = mock.Mock(return_value=resource) + manager = mock.MagicMock(get=mock_get) + res_id = str(uuid.uuid4()) + self.assertFalse(utils.wait_for_delete(manager, res_id, + status_field='my_status', + error_status=['failed'])) + self.assertFalse(mock_sleep.called) + + @mock.patch.object(time, 'sleep') + def test_wait_for_delete_error_with_overrides_exception(self, mock_sleep): + # Tests that we succeed if the resource is specific exception + mock_get = mock.Mock(side_effect=Exception) + manager = mock.MagicMock(get=mock_get) + res_id = str(uuid.uuid4()) + self.assertTrue(utils.wait_for_delete(manager, res_id, + exception_name=['Exception'])) + self.assertFalse(mock_sleep.called) + def test_build_kwargs_dict_value_set(self): self.assertEqual({'arg_bla': 'bla'}, utils.build_kwargs_dict('arg_bla', 'bla')) @@ -347,3 +369,19 @@ class TestFindResource(test_utils.TestCase): expected = 'a, b, c' self.assertEqual(expected, utils.format_list(['a', 'b', 'c'])) self.assertEqual(expected, utils.format_list(['c', 'b', 'a'])) + + def test_format_list_of_dicts(self): + expected = "a='b', c='d'\ne='f'" + sorted_data = [{'a': 'b', 'c': 'd'}, {'e': 'f'}] + unsorted_data = [{'c': 'd', 'a': 'b'}, {'e': 'f'}] + self.assertEqual(expected, utils.format_list_of_dicts(sorted_data)) + self.assertEqual(expected, utils.format_list_of_dicts(unsorted_data)) + self.assertEqual('', utils.format_list_of_dicts([])) + self.assertEqual('', utils.format_list_of_dicts([{}])) + + def test_format_list_separator(self): + expected = 'a\nb\nc' + actual_pre_sorted = utils.format_list(['a', 'b', 'c'], separator='\n') + actual_unsorted = utils.format_list(['c', 'b', 'a'], separator='\n') + self.assertEqual(expected, actual_pre_sorted) + self.assertEqual(expected, actual_unsorted) diff --git a/openstackclient/tests/compute/v2/fakes.py b/openstackclient/tests/compute/v2/fakes.py index 91cc2bd..a90c9ee 100644 --- a/openstackclient/tests/compute/v2/fakes.py +++ b/openstackclient/tests/compute/v2/fakes.py @@ -76,8 +76,6 @@ QUOTA = { QUOTA_columns = tuple(sorted(QUOTA)) QUOTA_data = tuple(QUOTA[x] for x in sorted(QUOTA)) -block_device_mapping = 'vda=' + volume_fakes.volume_name + ':::0' - service_host = 'host_test' service_binary = 'compute_test' service_status = 'enabled' @@ -90,6 +88,8 @@ SERVICE = { class FakeComputev2Client(object): def __init__(self, **kwargs): + self.availability_zones = mock.Mock() + self.availability_zones.resource_class = fakes.FakeResource(None, {}) self.images = mock.Mock() self.images.resource_class = fakes.FakeResource(None, {}) self.servers = mock.Mock() @@ -291,3 +291,63 @@ class FakeFlavor(object): if flavors is None: flavors = FakeServer.create_flavors(count) return mock.MagicMock(side_effect=flavors) + + +class FakeAvailabilityZone(object): + """Fake one or more compute availability zones (AZs).""" + + @staticmethod + def create_one_availability_zone(attrs={}, methods={}): + """Create a fake AZ. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :return: + A FakeResource object with zoneName, zoneState, etc. + """ + # Set default attributes. + host_name = uuid.uuid4().hex + service_name = uuid.uuid4().hex + service_updated_at = uuid.uuid4().hex + availability_zone = { + 'zoneName': uuid.uuid4().hex, + 'zoneState': {'available': True}, + 'hosts': {host_name: {service_name: { + 'available': True, + 'active': True, + 'updated_at': service_updated_at, + }}}, + } + + # Overwrite default attributes. + availability_zone.update(attrs) + + availability_zone = fakes.FakeResource( + info=copy.deepcopy(availability_zone), + methods=methods, + loaded=True) + return availability_zone + + @staticmethod + def create_availability_zones(attrs={}, methods={}, count=2): + """Create multiple fake AZs. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :param int count: + The number of AZs to fake + :return: + A list of FakeResource objects faking the AZs + """ + availability_zones = [] + for i in range(0, count): + availability_zone = \ + FakeAvailabilityZone.create_one_availability_zone( + attrs, methods) + availability_zones.append(availability_zone) + + return availability_zones diff --git a/openstackclient/tests/compute/v2/test_flavor.py b/openstackclient/tests/compute/v2/test_flavor.py index 60356ef..3a59020 100644 --- a/openstackclient/tests/compute/v2/test_flavor.py +++ b/openstackclient/tests/compute/v2/test_flavor.py @@ -173,10 +173,10 @@ class TestFlavorList(TestFlavor): def test_flavor_list_private_flavors(self): arglist = [ '--private', - ] + ] verifylist = [ ('public', False), - ] + ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -200,10 +200,10 @@ class TestFlavorList(TestFlavor): def test_flavor_list_public_flavors(self): arglist = [ '--public', - ] + ] verifylist = [ ('public', True), - ] + ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) diff --git a/openstackclient/tests/compute/v2/test_security_group.py b/openstackclient/tests/compute/v2/test_security_group.py index fdb659a..87cc487 100644 --- a/openstackclient/tests/compute/v2/test_security_group.py +++ b/openstackclient/tests/compute/v2/test_security_group.py @@ -56,6 +56,19 @@ class TestSecurityGroup(compute_fakes.TestComputev2): class TestSecurityGroupCreate(TestSecurityGroup): + columns = ( + 'description', + 'id', + 'name', + 'tenant_id', + ) + data = ( + security_group_description, + security_group_id, + security_group_name, + identity_fakes.project_id, + ) + def setUp(self): super(TestSecurityGroupCreate, self).setUp() @@ -86,20 +99,8 @@ class TestSecurityGroupCreate(TestSecurityGroup): security_group_name, ) - collist = ( - 'description', - 'id', - 'name', - 'tenant_id', - ) - self.assertEqual(collist, columns) - datalist = ( - security_group_description, - security_group_id, - security_group_name, - identity_fakes.project_id, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) def test_security_group_create_description(self): arglist = [ @@ -121,20 +122,8 @@ class TestSecurityGroupCreate(TestSecurityGroup): security_group_description, ) - collist = ( - 'description', - 'id', - 'name', - 'tenant_id', - ) - self.assertEqual(collist, columns) - datalist = ( - security_group_description, - security_group_id, - security_group_name, - identity_fakes.project_id, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) class TestSecurityGroupList(TestSecurityGroup): diff --git a/openstackclient/tests/compute/v2/test_security_group_rule.py b/openstackclient/tests/compute/v2/test_security_group_rule.py index 9516f8d..a2f9b10 100644 --- a/openstackclient/tests/compute/v2/test_security_group_rule.py +++ b/openstackclient/tests/compute/v2/test_security_group_rule.py @@ -18,6 +18,7 @@ from openstackclient.compute.v2 import security_group from openstackclient.tests.compute.v2 import fakes as compute_fakes from openstackclient.tests import fakes from openstackclient.tests.identity.v2_0 import fakes as identity_fakes +from openstackclient.tests import utils security_group_id = '11' @@ -25,19 +26,13 @@ security_group_name = 'wide-open' security_group_description = 'nothing but net' security_group_rule_id = '1' - -SECURITY_GROUP = { - 'id': security_group_id, - 'name': security_group_name, - 'description': security_group_description, - 'tenant_id': identity_fakes.project_id, -} +security_group_rule_cidr = '0.0.0.0/0' SECURITY_GROUP_RULE = { 'id': security_group_rule_id, 'group': {}, 'ip_protocol': 'tcp', - 'ip_range': '0.0.0.0/0', + 'ip_range': {'cidr': security_group_rule_cidr}, 'parent_group_id': security_group_id, 'from_port': 0, 'to_port': 0, @@ -47,12 +42,54 @@ SECURITY_GROUP_RULE_ICMP = { 'id': security_group_rule_id, 'group': {}, 'ip_protocol': 'icmp', - 'ip_range': '0.0.0.0/0', + 'ip_range': {'cidr': security_group_rule_cidr}, 'parent_group_id': security_group_id, 'from_port': -1, 'to_port': -1, } +SECURITY_GROUP_RULE_REMOTE_GROUP = { + 'id': security_group_rule_id, + 'group': {"tenant_id": "14", "name": "default"}, + 'ip_protocol': 'tcp', + 'ip_range': {}, + 'parent_group_id': security_group_id, + 'from_port': 80, + 'to_port': 80, +} + +SECURITY_GROUP = { + 'id': security_group_id, + 'name': security_group_name, + 'description': security_group_description, + 'tenant_id': identity_fakes.project_id, + 'rules': [SECURITY_GROUP_RULE, + SECURITY_GROUP_RULE_ICMP, + SECURITY_GROUP_RULE_REMOTE_GROUP], +} + +security_group_2_id = '12' +security_group_2_name = 'he-shoots' +security_group_2_description = 'he scores' + +SECURITY_GROUP_2_RULE = { + 'id': '2', + 'group': {}, + 'ip_protocol': 'tcp', + 'ip_range': {}, + 'parent_group_id': security_group_2_id, + 'from_port': 80, + 'to_port': 80, +} + +SECURITY_GROUP_2 = { + 'id': security_group_2_id, + 'name': security_group_2_name, + 'description': security_group_2_description, + 'tenant_id': identity_fakes.project_id, + 'rules': [SECURITY_GROUP_2_RULE], +} + class FakeSecurityGroupRuleResource(fakes.FakeResource): @@ -79,6 +116,15 @@ class TestSecurityGroupRule(compute_fakes.TestComputev2): class TestSecurityGroupRuleCreate(TestSecurityGroupRule): + columns = ( + 'id', + 'ip_protocol', + 'ip_range', + 'parent_group_id', + 'port_range', + 'remote_security_group', + ) + def setUp(self): super(TestSecurityGroupRuleCreate, self).setUp() @@ -115,25 +161,18 @@ class TestSecurityGroupRuleCreate(TestSecurityGroupRule): 'tcp', 0, 0, - '0.0.0.0/0', + security_group_rule_cidr, + None, ) - collist = ( - 'group', - 'id', - 'ip_protocol', - 'ip_range', - 'parent_group_id', - 'port_range', - ) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( - {}, security_group_rule_id, 'tcp', - '', + security_group_rule_cidr, security_group_id, '0:0', + '', ) self.assertEqual(datalist, data) @@ -166,25 +205,18 @@ class TestSecurityGroupRuleCreate(TestSecurityGroupRule): 'tcp', 20, 21, - '0.0.0.0/0', + security_group_rule_cidr, + None, ) - collist = ( - 'group', - 'id', - 'ip_protocol', - 'ip_range', - 'parent_group_id', - 'port_range', - ) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( - {}, security_group_rule_id, 'tcp', - '', + security_group_rule_cidr, security_group_id, '20:21', + '', ) self.assertEqual(datalist, data) @@ -192,6 +224,8 @@ class TestSecurityGroupRuleCreate(TestSecurityGroupRule): sg_rule = copy.deepcopy(SECURITY_GROUP_RULE) sg_rule['from_port'] = 22 sg_rule['to_port'] = 22 + sg_rule['ip_range'] = {} + sg_rule['group'] = {'name': security_group_name} self.sg_rules_mock.create.return_value = FakeSecurityGroupRuleResource( None, sg_rule, @@ -201,10 +235,12 @@ class TestSecurityGroupRuleCreate(TestSecurityGroupRule): arglist = [ security_group_name, '--dst-port', '22', + '--src-group', security_group_id, ] verifylist = [ ('group', security_group_name), ('dst_port', (22, 22)), + ('src_group', security_group_id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -217,25 +253,18 @@ class TestSecurityGroupRuleCreate(TestSecurityGroupRule): 'tcp', 22, 22, - '0.0.0.0/0', + security_group_rule_cidr, + security_group_id, ) - collist = ( - 'group', - 'id', - 'ip_protocol', - 'ip_range', - 'parent_group_id', - 'port_range', - ) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( - {}, security_group_rule_id, 'tcp', '', security_group_id, '22:22', + security_group_name, ) self.assertEqual(datalist, data) @@ -267,42 +296,40 @@ class TestSecurityGroupRuleCreate(TestSecurityGroupRule): 'udp', 0, 0, - '0.0.0.0/0', + security_group_rule_cidr, + None, ) - collist = ( - 'group', - 'id', - 'ip_protocol', - 'ip_range', - 'parent_group_id', - 'port_range', - ) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( - {}, security_group_rule_id, 'udp', - '', + security_group_rule_cidr, security_group_id, '0:0', + '', ) self.assertEqual(datalist, data) def test_security_group_rule_create_icmp(self): + sg_rule_cidr = '10.0.2.0/24' + sg_rule = copy.deepcopy(SECURITY_GROUP_RULE_ICMP) + sg_rule['ip_range'] = {'cidr': sg_rule_cidr} self.sg_rules_mock.create.return_value = FakeSecurityGroupRuleResource( None, - copy.deepcopy(SECURITY_GROUP_RULE_ICMP), + sg_rule, loaded=True, ) arglist = [ security_group_name, '--proto', 'ICMP', + '--src-ip', sg_rule_cidr, ] verifylist = [ ('group', security_group_name), ('proto', 'ICMP'), + ('src_ip', sg_rule_cidr) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -315,24 +342,143 @@ class TestSecurityGroupRuleCreate(TestSecurityGroupRule): 'ICMP', -1, -1, - '0.0.0.0/0', + sg_rule_cidr, + None, + ) + + self.assertEqual(self.columns, columns) + datalist = ( + security_group_rule_id, + 'icmp', + sg_rule_cidr, + security_group_id, + '', + '', + ) + self.assertEqual(datalist, data) + + def test_security_group_rule_create_src_invalid(self): + arglist = [ + security_group_name, + '--proto', 'ICMP', + '--src-ip', security_group_rule_cidr, + '--src-group', security_group_id, + ] + + self.assertRaises(utils.ParserException, + self.check_parser, self.cmd, arglist, []) + + +class TestSecurityGroupRuleList(TestSecurityGroupRule): + + def setUp(self): + super(TestSecurityGroupRuleList, self).setUp() + + security_group_mock = FakeSecurityGroupRuleResource( + None, + copy.deepcopy(SECURITY_GROUP), + loaded=True, + ) + + security_group_2_mock = FakeSecurityGroupRuleResource( + None, + copy.deepcopy(SECURITY_GROUP_2), + loaded=True, ) + self.secgroups_mock.get.return_value = security_group_mock + self.secgroups_mock.list.return_value = [security_group_mock, + security_group_2_mock] + + # Get the command object to test + self.cmd = security_group.ListSecurityGroupRule(self.app, None) + + def test_security_group_rule_list(self): + + arglist = [ + security_group_name, + ] + verifylist = [ + ('group', security_group_name), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + collist = ( - 'group', - 'id', - 'ip_protocol', - 'ip_range', - 'parent_group_id', - 'port_range', + 'ID', + 'IP Protocol', + 'IP Range', + 'Port Range', + 'Remote Security Group', ) self.assertEqual(collist, columns) - datalist = ( - {}, + datalist = (( + security_group_rule_id, + 'tcp', + security_group_rule_cidr, + '0:0', + '', + ), ( security_group_rule_id, 'icmp', + security_group_rule_cidr, '', - security_group_id, '', + ), ( + security_group_rule_id, + 'tcp', + '', + '80:80', + 'default', + ),) + self.assertEqual(datalist, tuple(data)) + + def test_security_group_rule_list_no_group(self): + + parsed_args = self.check_parser(self.cmd, [], []) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + collist = ( + 'ID', + 'IP Protocol', + 'IP Range', + 'Port Range', + 'Remote Security Group', + 'Security Group', ) - self.assertEqual(datalist, data) + self.assertEqual(collist, columns) + datalist = (( + security_group_rule_id, + 'tcp', + security_group_rule_cidr, + '0:0', + '', + security_group_id, + ), ( + security_group_rule_id, + 'icmp', + security_group_rule_cidr, + '', + '', + security_group_id, + ), ( + security_group_rule_id, + 'tcp', + '', + '80:80', + 'default', + security_group_id, + ), ( + '2', + 'tcp', + '', + '80:80', + '', + security_group_2_id, + ),) + self.assertEqual(datalist, tuple(data)) diff --git a/openstackclient/tests/compute/v2/test_server.py b/openstackclient/tests/compute/v2/test_server.py index 359920f..f6b6229 100644 --- a/openstackclient/tests/compute/v2/test_server.py +++ b/openstackclient/tests/compute/v2/test_server.py @@ -13,16 +13,13 @@ # under the License. # -import copy import mock -import testtools from mock import call from openstackclient.common import exceptions from openstackclient.common import utils as common_utils from openstackclient.compute.v2 import server from openstackclient.tests.compute.v2 import fakes as compute_fakes -from openstackclient.tests import fakes from openstackclient.tests.image.v2 import fakes as image_fakes from openstackclient.tests import utils from openstackclient.tests.volume.v2 import fakes as volume_fakes @@ -33,23 +30,23 @@ class TestServer(compute_fakes.TestComputev2): def setUp(self): super(TestServer, self).setUp() - # Get a shortcut to the ServerManager Mock + # Get a shortcut to the compute client ServerManager Mock self.servers_mock = self.app.client_manager.compute.servers self.servers_mock.reset_mock() - # Get a shortcut to the ImageManager Mock + # Get a shortcut to the compute client ImageManager Mock self.cimages_mock = self.app.client_manager.compute.images self.cimages_mock.reset_mock() - # Get a shortcut to the FlavorManager Mock + # Get a shortcut to the compute client FlavorManager Mock self.flavors_mock = self.app.client_manager.compute.flavors self.flavors_mock.reset_mock() - # Get a shortcut to the ImageManager Mock + # Get a shortcut to the image client ImageManager Mock self.images_mock = self.app.client_manager.image.images self.images_mock.reset_mock() - # Get a shortcut to the VolumeManager Mock + # Get a shortcut to the volume client VolumeManager Mock self.volumes_mock = self.app.client_manager.volume.volumes self.volumes_mock.reset_mock() @@ -92,6 +89,26 @@ class TestServer(compute_fakes.TestComputev2): class TestServerCreate(TestServer): + columns = ( + 'addresses', + 'flavor', + 'id', + 'name', + 'networks', + 'properties', + ) + + def datalist(self): + datalist = ( + '', + self.flavor.name + ' ()', + self.new_server.id, + self.new_server.name, + self.new_server.networks, + '', + ) + return datalist + def setUp(self): super(TestServerCreate, self).setUp() @@ -107,22 +124,15 @@ class TestServerCreate(TestServer): self.servers_mock.create.return_value = self.new_server - self.image = fakes.FakeResource( - None, - copy.deepcopy(image_fakes.IMAGE), - loaded=True, - ) + self.image = image_fakes.FakeImage.create_one_image() self.cimages_mock.get.return_value = self.image self.flavor = compute_fakes.FakeFlavor.create_one_flavor() self.flavors_mock.get.return_value = self.flavor - self.volume = fakes.FakeResource( - None, - copy.deepcopy(volume_fakes.VOLUME), - loaded=True, - ) + self.volume = volume_fakes.FakeVolume.create_one_volume() self.volumes_mock.get.return_value = self.volume + self.block_device_mapping = 'vda=' + self.volume.name + ':::0' # Get the command object to test self.cmd = server.CreateServer(self.app, None) @@ -181,24 +191,8 @@ class TestServerCreate(TestServer): **kwargs ) - collist = ( - 'addresses', - 'flavor', - 'id', - 'name', - 'networks', - 'properties', - ) - self.assertEqual(collist, columns) - datalist = ( - '', - self.flavor.name + ' ()', - self.new_server.id, - self.new_server.name, - self.new_server.networks, - '', - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist(), data) def test_server_create_with_network(self): arglist = [ @@ -224,12 +218,29 @@ class TestServerCreate(TestServer): self.app.client_manager.auth_ref.service_catalog.get_endpoints = ( get_endpoints) - list_networks = mock.Mock() - list_ports = mock.Mock() - self.app.client_manager.network.list_networks = list_networks - self.app.client_manager.network.list_ports = list_ports - list_networks.return_value = {'networks': [{'id': 'net1_uuid'}]} - list_ports.return_value = {'ports': [{'id': 'port1_uuid'}]} + find_network = mock.Mock() + find_port = mock.Mock() + network_client = self.app.client_manager.network + network_client.find_network = find_network + network_client.find_port = find_port + network_resource = mock.Mock() + network_resource.id = 'net1_uuid' + port_resource = mock.Mock() + port_resource.id = 'port1_uuid' + find_network.return_value = network_resource + find_port.return_value = port_resource + + # Mock sdk APIs. + _network = mock.Mock() + _network.id = 'net1_uuid' + _port = mock.Mock() + _port.id = 'port1_uuid' + find_network = mock.Mock() + find_port = mock.Mock() + find_network.return_value = _network + find_port.return_value = _port + self.app.client_manager.network.find_network = find_network + self.app.client_manager.network.find_port = find_port # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) @@ -265,24 +276,8 @@ class TestServerCreate(TestServer): **kwargs ) - collist = ( - 'addresses', - 'flavor', - 'id', - 'name', - 'networks', - 'properties', - ) - self.assertEqual(collist, columns) - datalist = ( - '', - self.flavor.name + ' ()', - self.new_server.id, - self.new_server.name, - self.new_server.networks, - '', - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist(), data) @mock.patch('openstackclient.compute.v2.server.io.open') def test_server_create_userdata(self, mock_open): @@ -338,36 +333,20 @@ class TestServerCreate(TestServer): **kwargs ) - collist = ( - 'addresses', - 'flavor', - 'id', - 'name', - 'networks', - 'properties', - ) - self.assertEqual(collist, columns) - datalist = ( - '', - self.flavor.name + ' ()', - self.new_server.id, - self.new_server.name, - self.new_server.networks, - '', - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist(), data) def test_server_create_with_block_device_mapping(self): arglist = [ '--image', 'image1', '--flavor', self.flavor.id, - '--block-device-mapping', compute_fakes.block_device_mapping, + '--block-device-mapping', self.block_device_mapping, self.new_server.name, ] verifylist = [ ('image', 'image1'), ('flavor', self.flavor.id), - ('block_device_mapping', [compute_fakes.block_device_mapping]), + ('block_device_mapping', [self.block_device_mapping]), ('config_drive', False), ('server_name', self.new_server.name), ] @@ -377,9 +356,9 @@ class TestServerCreate(TestServer): columns, data = self.cmd.take_action(parsed_args) real_volume_mapping = ( - (compute_fakes.block_device_mapping.split('=', 1)[1]).replace( - volume_fakes.volume_name, - volume_fakes.volume_id)) + (self.block_device_mapping.split('=', 1)[1]).replace( + self.volume.name, + self.volume.id)) # Set expected values kwargs = dict( @@ -407,24 +386,8 @@ class TestServerCreate(TestServer): **kwargs ) - collist = ( - 'addresses', - 'flavor', - 'id', - 'name', - 'networks', - 'properties', - ) - self.assertEqual(collist, columns) - datalist = ( - '', - self.flavor.name + ' ()', - self.new_server.id, - self.new_server.name, - self.new_server.networks, - '', - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist(), data) class TestServerDelete(TestServer): @@ -529,6 +492,26 @@ class TestServerDelete(TestServer): class TestServerImageCreate(TestServer): + columns = ( + 'id', + 'name', + 'owner', + 'protected', + 'tags', + 'visibility', + ) + + def datalist(self): + datalist = ( + self.image.id, + self.image.name, + self.image.owner, + self.image.protected, + self.image.tags, + self.image.visibility, + ) + return datalist + def setUp(self): super(TestServerImageCreate, self).setUp() @@ -537,13 +520,9 @@ class TestServerImageCreate(TestServer): # This is the return value for utils.find_resource() self.servers_mock.get.return_value = self.server - self.servers_mock.create_image.return_value = image_fakes.image_id - - self.images_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(image_fakes.IMAGE), - loaded=True, - ) + self.image = image_fakes.FakeImage.create_one_image() + self.images_mock.get.return_value = self.image + self.servers_mock.create_image.return_value = self.image.id # Get the command object to test self.cmd = server.CreateServerImage(self.app, None) @@ -566,17 +545,8 @@ class TestServerImageCreate(TestServer): self.server.name, ) - collist = ('id', 'name', 'owner', 'protected', 'tags', 'visibility') - self.assertEqual(collist, columns) - datalist = ( - image_fakes.image_id, - image_fakes.image_name, - image_fakes.image_owner, - image_fakes.image_protected, - image_fakes.image_tags, - image_fakes.image_visibility, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist(), data) def test_server_image_create_name(self): arglist = [ @@ -598,17 +568,8 @@ class TestServerImageCreate(TestServer): 'img-nam', ) - collist = ('id', 'name', 'owner', 'protected', 'tags', 'visibility') - self.assertEqual(collist, columns) - datalist = ( - image_fakes.image_id, - image_fakes.image_name, - image_fakes.image_owner, - image_fakes.image_protected, - image_fakes.image_tags, - image_fakes.image_visibility, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist(), data) class TestServerList(TestServer): @@ -620,10 +581,17 @@ class TestServerList(TestServer): 'Status', 'Networks', ) - - # Data returned by corresponding Nova API. The elements in this list are - # tuples filled with server attributes. - data = [] + columns_long = ( + 'ID', + 'Name', + 'Status', + 'Task State', + 'Power State', + 'Networks', + 'Availability Zone', + 'Host', + 'Properties', + ) # Default search options, in the case of no commandline option specified. search_opts = { @@ -652,12 +620,18 @@ class TestServerList(TestServer): def setUp(self): super(TestServerList, self).setUp() - # The fake servers' attributes. + # The fake servers' attributes. Use the original attributes names in + # nova, not the ones printed by "server list" command. self.attrs = { 'status': 'ACTIVE', + 'OS-EXT-STS:task_state': 'None', + 'OS-EXT-STS:power_state': 0x01, # Running 'networks': { u'public': [u'10.20.30.40', u'2001:db8::5'] }, + 'OS-EXT-AZ:availability_zone': 'availability-zone-xxx', + 'OS-EXT-SRV-ATTR:host': 'host-name-xxx', + 'Metadata': '', } # The servers to be listed. @@ -669,12 +643,28 @@ class TestServerList(TestServer): self.cmd = server.ListServer(self.app, None) # Prepare data returned by fake Nova API. + self.data = [] + self.data_long = [] + for s in self.servers: self.data.append(( s.id, s.name, s.status, - u'public=10.20.30.40, 2001:db8::5', + server._format_servers_list_networks(s.networks), + )) + self.data_long.append(( + s.id, + s.name, + s.status, + getattr(s, 'OS-EXT-STS:task_state'), + server._format_servers_list_power_state( + getattr(s, 'OS-EXT-STS:power_state') + ), + server._format_servers_list_networks(s.networks), + getattr(s, 'OS-EXT-AZ:availability_zone'), + getattr(s, 'OS-EXT-SRV-ATTR:host'), + s.Metadata, )) def test_server_list_no_option(self): @@ -691,6 +681,22 @@ class TestServerList(TestServer): self.assertEqual(self.columns, columns) self.assertEqual(tuple(self.data), tuple(data)) + def test_server_list_long_option(self): + arglist = [ + '--long', + ] + verifylist = [ + ('all_projects', False), + ('long', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.servers_mock.list.assert_called_with(**self.kwargs) + self.assertEqual(self.columns_long, columns) + self.assertEqual(tuple(self.data_long), tuple(data)) + class TestServerLock(TestServer): @@ -732,6 +738,76 @@ class TestServerPause(TestServer): self.run_method_with_servers('pause', 3) +class TestServerRebuild(TestServer): + + def setUp(self): + super(TestServerRebuild, self).setUp() + + # Return value for utils.find_resource for image + self.image = image_fakes.FakeImage.create_one_image() + self.cimages_mock.get.return_value = self.image + + # Fake the rebuilt new server. + new_server = compute_fakes.FakeServer.create_one_server() + + # Fake the server to be rebuilt. The IDs of them should be the same. + attrs = { + 'id': new_server.id, + 'image': { + 'id': self.image.id + }, + 'networks': {}, + 'adminPass': 'passw0rd', + } + methods = { + 'rebuild': new_server, + } + self.server = compute_fakes.FakeServer.create_one_server( + attrs=attrs, + methods=methods + ) + + # Return value for utils.find_resource for server. + self.servers_mock.get.return_value = self.server + + self.cmd = server.RebuildServer(self.app, None) + + def test_rebuild_with_current_image(self): + arglist = [ + self.server.id, + ] + verifylist = [ + ('server', self.server.id) + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Get the command object to test. + self.cmd.take_action(parsed_args) + + self.servers_mock.get.assert_called_with(self.server.id) + self.cimages_mock.get.assert_called_with(self.image.id) + self.server.rebuild.assert_called_with(self.image, None) + + def test_rebuild_with_current_image_and_password(self): + password = 'password-xxx' + arglist = [ + self.server.id, + '--password', password + ] + verifylist = [ + ('server', self.server.id), + ('password', password) + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Get the command object to test + self.cmd.take_action(parsed_args) + + self.servers_mock.get.assert_called_with(self.server.id) + self.cimages_mock.get.assert_called_with(self.image.id) + self.server.rebuild.assert_called_with(self.image, password) + + class TestServerResize(TestServer): def setUp(self): @@ -1017,7 +1093,7 @@ class TestServerUnshelve(TestServer): self.run_method_with_servers('unshelve', 3) -class TestServerGeneral(testtools.TestCase): +class TestServerGeneral(TestServer): OLD = { 'private': [ { @@ -1067,3 +1143,90 @@ class TestServerGeneral(testtools.TestCase): server._get_ip_address, self.OLD, 'public', [4, 6]) self.assertRaises(exceptions.CommandError, server._get_ip_address, self.OLD, 'private', [6]) + + def test_format_servers_list_power_state(self): + self.assertEqual("NOSTATE", + server._format_servers_list_power_state(0x00)) + self.assertEqual("Running", + server._format_servers_list_power_state(0x01)) + self.assertEqual("", + server._format_servers_list_power_state(0x02)) + self.assertEqual("Paused", + server._format_servers_list_power_state(0x03)) + self.assertEqual("Shutdown", + server._format_servers_list_power_state(0x04)) + self.assertEqual("", + server._format_servers_list_power_state(0x05)) + self.assertEqual("Crashed", + server._format_servers_list_power_state(0x06)) + self.assertEqual("Suspended", + server._format_servers_list_power_state(0x07)) + self.assertEqual("N/A", + server._format_servers_list_power_state(0x08)) + + def test_format_servers_list_networks(self): + # Setup network info to test. + networks = { + u'public': [u'10.20.30.40', u'2001:db8::f'], + u'private': [u'2001:db8::f', u'10.20.30.40'], + } + + # Prepare expected data. + # Since networks is a dict, whose items are in random order, there + # could be two results after formatted. + data_1 = (u'private=2001:db8::f, 10.20.30.40; ' + u'public=10.20.30.40, 2001:db8::f') + data_2 = (u'public=10.20.30.40, 2001:db8::f; ' + u'private=2001:db8::f, 10.20.30.40') + + # Call _format_servers_list_networks(). + networks_format = server._format_servers_list_networks(networks) + + msg = ('Network string is not formatted correctly.\n' + 'reference = %s or %s\n' + 'actual = %s\n' % + (data_1, data_2, networks_format)) + self.assertIn(networks_format, (data_1, data_2), msg) + + @mock.patch('openstackclient.common.utils.find_resource') + def test_prep_server_detail(self, find_resource): + # Setup mock method return value. utils.find_resource() will be called + # twice in _prep_server_detail(): + # - The first time, return image info. + # - The second time, return flavor info. + _image = image_fakes.FakeImage.create_one_image() + _flavor = compute_fakes.FakeFlavor.create_one_flavor() + find_resource.side_effect = [_image, _flavor] + + # compute_client.servers.get() will be called once, return server info. + server_info = { + 'image': {u'id': _image.id}, + 'flavor': {u'id': _flavor.id}, + 'tenant_id': u'tenant-id-xxx', + 'networks': {u'public': [u'10.20.30.40', u'2001:db8::f']}, + 'links': u'http://xxx.yyy.com', + } + _server = compute_fakes.FakeServer.create_one_server(attrs=server_info) + self.servers_mock.get.return_value = _server + + # Prepare result data. + info = { + 'id': _server.id, + 'name': _server.name, + 'addresses': u'public=10.20.30.40, 2001:db8::f', + 'flavor': u'%s (%s)' % (_flavor.name, _flavor.id), + 'image': u'%s (%s)' % (_image.name, _image.id), + 'project_id': u'tenant-id-xxx', + 'properties': '', + } + + # Call _prep_server_detail(). + server_detail = server._prep_server_detail( + self.app.client_manager.compute, + _server + ) + # 'networks' is used to create _server. Remove it. + server_detail.pop('networks') + + # Check the results. + self.assertDictEqual(info, server_detail) diff --git a/openstackclient/tests/fakes.py b/openstackclient/tests/fakes.py index 9f4dcc5..718dff6 100644 --- a/openstackclient/tests/fakes.py +++ b/openstackclient/tests/fakes.py @@ -34,7 +34,15 @@ VERSION = "3" TEST_RESPONSE_DICT = fixture.V2Token(token_id=AUTH_TOKEN, user_name=USERNAME) _s = TEST_RESPONSE_DICT.add_service('identity', name='keystone') -_s.add_endpoint(AUTH_URL + '/v2.0') +_s.add_endpoint(AUTH_URL + ':5000/v2.0') +_s = TEST_RESPONSE_DICT.add_service('network', name='neutron') +_s.add_endpoint(AUTH_URL + ':9696') +_s = TEST_RESPONSE_DICT.add_service('compute', name='nova') +_s.add_endpoint(AUTH_URL + ':8774/v2') +_s = TEST_RESPONSE_DICT.add_service('image', name='glance') +_s.add_endpoint(AUTH_URL + ':9292') +_s = TEST_RESPONSE_DICT.add_service('object', name='swift') +_s.add_endpoint(AUTH_URL + ':8080/v1') TEST_RESPONSE_DICT_V3 = fixture.V3Token(user_name=USERNAME) TEST_RESPONSE_DICT_V3.set_project_scope() @@ -103,6 +111,7 @@ class FakeClientManager(object): self.session = None self.auth_ref = None self.auth_plugin_name = None + self.network_endpoint_enabled = True def get_configuration(self): return { @@ -115,6 +124,9 @@ class FakeClientManager(object): 'identity_api_version': VERSION, } + def is_network_endpoint_enabled(self): + return self.network_endpoint_enabled + class FakeModule(object): def __init__(self, name, version): diff --git a/openstackclient/tests/identity/v2_0/test_catalog.py b/openstackclient/tests/identity/v2_0/test_catalog.py index 7f1835d..ff1d993 100644 --- a/openstackclient/tests/identity/v2_0/test_catalog.py +++ b/openstackclient/tests/identity/v2_0/test_catalog.py @@ -55,6 +55,12 @@ class TestCatalog(utils.TestCommand): class TestCatalogList(TestCatalog): + columns = ( + 'Name', + 'Type', + 'Endpoints', + ) + def setUp(self): super(TestCatalogList, self).setUp() @@ -70,8 +76,7 @@ class TestCatalogList(TestCatalog): columns, data = self.cmd.take_action(parsed_args) self.sc_mock.service_catalog.get_data.assert_called_with() - collist = ('Name', 'Type', 'Endpoints') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = (( 'supernova', 'compute', @@ -113,8 +118,7 @@ class TestCatalogList(TestCatalog): columns, data = self.cmd.take_action(parsed_args) self.sc_mock.service_catalog.get_data.assert_called_with() - collist = ('Name', 'Type', 'Endpoints') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = (( 'supernova', 'compute', diff --git a/openstackclient/tests/identity/v2_0/test_project.py b/openstackclient/tests/identity/v2_0/test_project.py index 16ab195..69b2926 100644 --- a/openstackclient/tests/identity/v2_0/test_project.py +++ b/openstackclient/tests/identity/v2_0/test_project.py @@ -34,6 +34,19 @@ class TestProject(identity_fakes.TestIdentityv2): class TestProjectCreate(TestProject): + columns = ( + 'description', + 'enabled', + 'id', + 'name', + ) + datalist = ( + identity_fakes.project_description, + True, + identity_fakes.project_id, + identity_fakes.project_name, + ) + def setUp(self): super(TestProjectCreate, self).setUp() @@ -69,16 +82,8 @@ class TestProjectCreate(TestProject): identity_fakes.project_name, **kwargs ) - - collist = ('description', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_description, - True, - identity_fakes.project_id, - identity_fakes.project_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_project_create_description(self): arglist = [ @@ -104,15 +109,8 @@ class TestProjectCreate(TestProject): **kwargs ) - collist = ('description', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_description, - True, - identity_fakes.project_id, - identity_fakes.project_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_project_create_enable(self): arglist = [ @@ -139,15 +137,8 @@ class TestProjectCreate(TestProject): **kwargs ) - collist = ('description', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_description, - True, - identity_fakes.project_id, - identity_fakes.project_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_project_create_disable(self): arglist = [ @@ -174,15 +165,8 @@ class TestProjectCreate(TestProject): **kwargs ) - collist = ('description', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_description, - True, - identity_fakes.project_id, - identity_fakes.project_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_project_create_property(self): arglist = [ @@ -211,15 +195,8 @@ class TestProjectCreate(TestProject): **kwargs ) - collist = ('description', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_description, - True, - identity_fakes.project_id, - identity_fakes.project_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_project_create_or_show_exists(self): def _raise_conflict(*args, **kwargs): @@ -260,15 +237,8 @@ class TestProjectCreate(TestProject): **kwargs ) - collist = ('description', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_description, - True, - identity_fakes.project_id, - identity_fakes.project_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_project_create_or_show_not_exists(self): arglist = [ @@ -294,15 +264,8 @@ class TestProjectCreate(TestProject): **kwargs ) - collist = ('description', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_description, - True, - identity_fakes.project_id, - identity_fakes.project_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) class TestProjectDelete(TestProject): @@ -592,12 +555,58 @@ class TestProjectShow(TestProject): identity_fakes.project_id, ) - collist = ('description', 'enabled', 'id', 'name') + collist = ('description', 'enabled', 'id', 'name', 'properties') self.assertEqual(collist, columns) datalist = ( identity_fakes.project_description, True, identity_fakes.project_id, identity_fakes.project_name, + '', ) self.assertEqual(datalist, data) + + +class TestProjectUnset(TestProject): + + def setUp(self): + super(TestProjectUnset, self).setUp() + + project_dict = {'fee': 'fi', 'fo': 'fum'} + project_dict.update(identity_fakes.PROJECT) + self.projects_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(project_dict), + loaded=True, + ) + + # Get the command object to test + self.cmd = project.UnsetProject(self.app, None) + + def test_project_unset_key(self): + arglist = [ + '--property', 'fee', + '--property', 'fo', + identity_fakes.project_name, + ] + verifylist = [ + ('property', ['fee', 'fo']), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.run(parsed_args) + # Set expected values + kwargs = { + 'description': identity_fakes.project_description, + 'enabled': True, + 'fee': None, + 'fo': None, + 'id': identity_fakes.project_id, + 'name': identity_fakes.project_name, + } + + self.projects_mock.update.assert_called_with( + identity_fakes.project_id, + **kwargs + ) diff --git a/openstackclient/tests/identity/v2_0/test_role.py b/openstackclient/tests/identity/v2_0/test_role.py index ec48433..c2bacc5 100644 --- a/openstackclient/tests/identity/v2_0/test_role.py +++ b/openstackclient/tests/identity/v2_0/test_role.py @@ -107,6 +107,15 @@ class TestRoleAdd(TestRole): class TestRoleCreate(TestRole): + columns = ( + 'id', + 'name' + ) + datalist = ( + identity_fakes.role_id, + identity_fakes.role_name, + ) + def setUp(self): super(TestRoleCreate, self).setUp() @@ -136,13 +145,8 @@ class TestRoleCreate(TestRole): identity_fakes.role_name, ) - collist = ('id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.role_id, - identity_fakes.role_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_role_create_or_show_exists(self): def _raise_conflict(*args, **kwargs): @@ -178,13 +182,8 @@ class TestRoleCreate(TestRole): identity_fakes.role_name, ) - collist = ('id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.role_id, - identity_fakes.role_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_role_create_or_show_not_exists(self): arglist = [ @@ -205,13 +204,8 @@ class TestRoleCreate(TestRole): identity_fakes.role_name, ) - collist = ('id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.role_id, - identity_fakes.role_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) class TestRoleDelete(TestRole): @@ -283,6 +277,13 @@ class TestRoleList(TestRole): class TestUserRoleList(TestRole): + columns = ( + 'ID', + 'Name', + 'Project', + 'User' + ) + def setUp(self): super(TestUserRoleList, self).setUp() @@ -395,8 +396,7 @@ class TestUserRoleList(TestRole): identity_fakes.PROJECT_2['id'], ) - collist = ('ID', 'Name', 'Project', 'User') - self.assertEqual(collist, columns) + self.assertEqual(columns, columns) datalist = (( identity_fakes.role_id, identity_fakes.role_name, diff --git a/openstackclient/tests/identity/v2_0/test_service.py b/openstackclient/tests/identity/v2_0/test_service.py index 26a9716..b97786b 100644 --- a/openstackclient/tests/identity/v2_0/test_service.py +++ b/openstackclient/tests/identity/v2_0/test_service.py @@ -32,6 +32,19 @@ class TestService(identity_fakes.TestIdentityv2): class TestServiceCreate(TestService): + columns = ( + 'description', + 'id', + 'name', + 'type', + ) + datalist = ( + identity_fakes.service_description, + identity_fakes.service_id, + identity_fakes.service_name, + identity_fakes.service_type, + ) + def setUp(self): super(TestServiceCreate, self).setUp() @@ -66,15 +79,8 @@ class TestServiceCreate(TestService): None, ) - collist = ('description', 'id', 'name', 'type') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.service_description, - identity_fakes.service_id, - identity_fakes.service_name, - identity_fakes.service_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_service_create_with_type_option(self): arglist = [ @@ -99,15 +105,8 @@ class TestServiceCreate(TestService): None, ) - collist = ('description', 'id', 'name', 'type') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.service_description, - identity_fakes.service_id, - identity_fakes.service_name, - identity_fakes.service_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_service_create_with_name_option(self): arglist = [ @@ -132,15 +131,8 @@ class TestServiceCreate(TestService): None, ) - collist = ('description', 'id', 'name', 'type') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.service_description, - identity_fakes.service_id, - identity_fakes.service_name, - identity_fakes.service_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_service_create_description(self): arglist = [ @@ -166,15 +158,8 @@ class TestServiceCreate(TestService): identity_fakes.service_description, ) - collist = ('description', 'id', 'name', 'type') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.service_description, - identity_fakes.service_id, - identity_fakes.service_name, - identity_fakes.service_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) class TestServiceDelete(TestService): diff --git a/openstackclient/tests/identity/v2_0/test_user.py b/openstackclient/tests/identity/v2_0/test_user.py index bf25681..a25def8 100644 --- a/openstackclient/tests/identity/v2_0/test_user.py +++ b/openstackclient/tests/identity/v2_0/test_user.py @@ -39,6 +39,21 @@ class TestUser(identity_fakes.TestIdentityv2): class TestUserCreate(TestUser): + columns = ( + 'email', + 'enabled', + 'id', + 'name', + 'project_id', + ) + datalist = ( + identity_fakes.user_email, + True, + identity_fakes.user_id, + identity_fakes.user_name, + identity_fakes.project_id, + ) + def setUp(self): super(TestUserCreate, self).setUp() @@ -84,16 +99,8 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('email', 'enabled', 'id', 'name', 'project_id') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.user_email, - True, - identity_fakes.user_id, - identity_fakes.user_name, - identity_fakes.project_id, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_user_create_password(self): arglist = [ @@ -122,17 +129,8 @@ class TestUserCreate(TestUser): None, **kwargs ) - - collist = ('email', 'enabled', 'id', 'name', 'project_id') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.user_email, - True, - identity_fakes.user_id, - identity_fakes.user_name, - identity_fakes.project_id, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_user_create_password_prompt(self): arglist = [ @@ -164,16 +162,8 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('email', 'enabled', 'id', 'name', 'project_id') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.user_email, - True, - identity_fakes.user_id, - identity_fakes.user_name, - identity_fakes.project_id, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_user_create_email(self): arglist = [ @@ -202,16 +192,8 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('email', 'enabled', 'id', 'name', 'project_id') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.user_email, - True, - identity_fakes.user_id, - identity_fakes.user_name, - identity_fakes.project_id, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_user_create_project(self): # Return the new project @@ -255,8 +237,7 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('email', 'enabled', 'id', 'name', 'project_id') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( identity_fakes.user_email, True, @@ -294,16 +275,8 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('email', 'enabled', 'id', 'name', 'project_id') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.user_email, - True, - identity_fakes.user_id, - identity_fakes.user_name, - identity_fakes.project_id, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_user_create_disable(self): arglist = [ @@ -333,16 +306,8 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('email', 'enabled', 'id', 'name', 'project_id') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.user_email, - True, - identity_fakes.user_id, - identity_fakes.user_name, - identity_fakes.project_id, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_user_create_or_show_exists(self): def _raise_conflict(*args, **kwargs): @@ -373,16 +338,8 @@ class TestUserCreate(TestUser): # UserManager.create(name, password, email, tenant_id=, enabled=) self.users_mock.get.assert_called_with(identity_fakes.user_name) - collist = ('email', 'enabled', 'id', 'name', 'project_id') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.user_email, - True, - identity_fakes.user_id, - identity_fakes.user_name, - identity_fakes.project_id, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_user_create_or_show_not_exists(self): arglist = [ @@ -410,17 +367,8 @@ class TestUserCreate(TestUser): None, **kwargs ) - - collist = ('email', 'enabled', 'id', 'name', 'project_id') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.user_email, - True, - identity_fakes.user_id, - identity_fakes.user_name, - identity_fakes.project_id, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) class TestUserDelete(TestUser): @@ -458,6 +406,17 @@ class TestUserDelete(TestUser): class TestUserList(TestUser): + columns = ( + 'ID', + 'Name', + ) + datalist = ( + ( + identity_fakes.user_id, + identity_fakes.user_name, + ), + ) + def setUp(self): super(TestUserList, self).setUp() @@ -495,13 +454,8 @@ class TestUserList(TestUser): self.users_mock.list.assert_called_with(tenant_id=None) - collist = ('ID', 'Name') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.user_id, - identity_fakes.user_name, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_user_list_project(self): arglist = [ @@ -518,13 +472,8 @@ class TestUserList(TestUser): self.users_mock.list.assert_called_with(tenant_id=project_id) - collist = ('ID', 'Name') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.user_id, - identity_fakes.user_name, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_user_list_long(self): arglist = [ diff --git a/openstackclient/tests/identity/v3/test_domain.py b/openstackclient/tests/identity/v3/test_domain.py index cfec10e..969c2df 100644 --- a/openstackclient/tests/identity/v3/test_domain.py +++ b/openstackclient/tests/identity/v3/test_domain.py @@ -29,6 +29,19 @@ class TestDomain(identity_fakes.TestIdentityv3): class TestDomainCreate(TestDomain): + columns = ( + 'description', + 'enabled', + 'id', + 'name', + ) + datalist = ( + identity_fakes.domain_description, + True, + identity_fakes.domain_id, + identity_fakes.domain_name, + ) + def setUp(self): super(TestDomainCreate, self).setUp() @@ -63,15 +76,8 @@ class TestDomainCreate(TestDomain): **kwargs ) - collist = ('description', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.domain_description, - True, - identity_fakes.domain_id, - identity_fakes.domain_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_domain_create_description(self): arglist = [ @@ -97,15 +103,8 @@ class TestDomainCreate(TestDomain): **kwargs ) - collist = ('description', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.domain_description, - True, - identity_fakes.domain_id, - identity_fakes.domain_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_domain_create_enable(self): arglist = [ @@ -131,15 +130,8 @@ class TestDomainCreate(TestDomain): **kwargs ) - collist = ('description', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.domain_description, - True, - identity_fakes.domain_id, - identity_fakes.domain_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_domain_create_disable(self): arglist = [ @@ -165,15 +157,8 @@ class TestDomainCreate(TestDomain): **kwargs ) - collist = ('description', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.domain_description, - True, - identity_fakes.domain_id, - identity_fakes.domain_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) class TestDomainDelete(TestDomain): diff --git a/openstackclient/tests/identity/v3/test_endpoint.py b/openstackclient/tests/identity/v3/test_endpoint.py index ecfa71a..fb88e00 100644 --- a/openstackclient/tests/identity/v3/test_endpoint.py +++ b/openstackclient/tests/identity/v3/test_endpoint.py @@ -37,6 +37,17 @@ class TestEndpoint(identity_fakes.TestIdentityv3): class TestEndpointCreate(TestEndpoint): + columns = ( + 'enabled', + 'id', + 'interface', + 'region', + 'service_id', + 'service_name', + 'service_type', + 'url', + ) + def setUp(self): super(TestEndpointCreate, self).setUp() @@ -86,9 +97,7 @@ class TestEndpointCreate(TestEndpoint): **kwargs ) - collist = ('enabled', 'id', 'interface', 'region', 'service_id', - 'service_name', 'service_type', 'url') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( True, identity_fakes.endpoint_id, @@ -133,9 +142,7 @@ class TestEndpointCreate(TestEndpoint): **kwargs ) - collist = ('enabled', 'id', 'interface', 'region', 'service_id', - 'service_name', 'service_type', 'url') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( True, identity_fakes.endpoint_id, @@ -179,9 +186,7 @@ class TestEndpointCreate(TestEndpoint): **kwargs ) - collist = ('enabled', 'id', 'interface', 'region', 'service_id', - 'service_name', 'service_type', 'url') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( True, identity_fakes.endpoint_id, @@ -225,9 +230,7 @@ class TestEndpointCreate(TestEndpoint): **kwargs ) - collist = ('enabled', 'id', 'interface', 'region', 'service_id', - 'service_name', 'service_type', 'url') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( True, identity_fakes.endpoint_id, @@ -276,6 +279,16 @@ class TestEndpointDelete(TestEndpoint): class TestEndpointList(TestEndpoint): + columns = ( + 'ID', + 'Region', + 'Service Name', + 'Service Type', + 'Enabled', + 'Interface', + 'URL', + ) + def setUp(self): super(TestEndpointList, self).setUp() @@ -306,18 +319,18 @@ class TestEndpointList(TestEndpoint): columns, data = self.cmd.take_action(parsed_args) self.endpoints_mock.list.assert_called_with() - collist = ('ID', 'Region', 'Service Name', 'Service Type', - 'Enabled', 'Interface', 'URL') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.endpoint_id, - identity_fakes.endpoint_region, - self.get_fake_service_name(), - identity_fakes.service_type, - True, - identity_fakes.endpoint_interface, - identity_fakes.endpoint_url, - ),) + self.assertEqual(self.columns, columns) + datalist = ( + ( + identity_fakes.endpoint_id, + identity_fakes.endpoint_region, + self.get_fake_service_name(), + identity_fakes.service_type, + True, + identity_fakes.endpoint_interface, + identity_fakes.endpoint_url, + ), + ) self.assertEqual(datalist, tuple(data)) def test_endpoint_list_service(self): @@ -338,18 +351,18 @@ class TestEndpointList(TestEndpoint): } self.endpoints_mock.list.assert_called_with(**kwargs) - collist = ('ID', 'Region', 'Service Name', 'Service Type', - 'Enabled', 'Interface', 'URL') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.endpoint_id, - identity_fakes.endpoint_region, - self.get_fake_service_name(), - identity_fakes.service_type, - True, - identity_fakes.endpoint_interface, - identity_fakes.endpoint_url, - ),) + self.assertEqual(self.columns, columns) + datalist = ( + ( + identity_fakes.endpoint_id, + identity_fakes.endpoint_region, + self.get_fake_service_name(), + identity_fakes.service_type, + True, + identity_fakes.endpoint_interface, + identity_fakes.endpoint_url, + ), + ) self.assertEqual(datalist, tuple(data)) def test_endpoint_list_interface(self): @@ -370,18 +383,18 @@ class TestEndpointList(TestEndpoint): } self.endpoints_mock.list.assert_called_with(**kwargs) - collist = ('ID', 'Region', 'Service Name', 'Service Type', - 'Enabled', 'Interface', 'URL') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.endpoint_id, - identity_fakes.endpoint_region, - self.get_fake_service_name(), - identity_fakes.service_type, - True, - identity_fakes.endpoint_interface, - identity_fakes.endpoint_url, - ),) + self.assertEqual(self.columns, columns) + datalist = ( + ( + identity_fakes.endpoint_id, + identity_fakes.endpoint_region, + self.get_fake_service_name(), + identity_fakes.service_type, + True, + identity_fakes.endpoint_interface, + identity_fakes.endpoint_url, + ), + ) self.assertEqual(datalist, tuple(data)) def test_endpoint_list_region(self): @@ -402,18 +415,18 @@ class TestEndpointList(TestEndpoint): } self.endpoints_mock.list.assert_called_with(**kwargs) - collist = ('ID', 'Region', 'Service Name', 'Service Type', - 'Enabled', 'Interface', 'URL') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.endpoint_id, - identity_fakes.endpoint_region, - self.get_fake_service_name(), - identity_fakes.service_type, - True, - identity_fakes.endpoint_interface, - identity_fakes.endpoint_url, - ),) + self.assertEqual(self.columns, columns) + datalist = ( + ( + identity_fakes.endpoint_id, + identity_fakes.endpoint_region, + self.get_fake_service_name(), + identity_fakes.service_type, + True, + identity_fakes.endpoint_interface, + identity_fakes.endpoint_url, + ), + ) self.assertEqual(datalist, tuple(data)) @@ -658,8 +671,16 @@ class TestEndpointShow(TestEndpoint): identity_fakes.endpoint_id, ) - collist = ('enabled', 'id', 'interface', 'region', 'service_id', - 'service_name', 'service_type', 'url') + collist = ( + 'enabled', + 'id', + 'interface', + 'region', + 'service_id', + 'service_name', + 'service_type', + 'url', + ) self.assertEqual(collist, columns) datalist = ( True, diff --git a/openstackclient/tests/identity/v3/test_group.py b/openstackclient/tests/identity/v3/test_group.py index 6766a08..59a3681 100644 --- a/openstackclient/tests/identity/v3/test_group.py +++ b/openstackclient/tests/identity/v3/test_group.py @@ -38,6 +38,17 @@ class TestGroup(identity_fakes.TestIdentityv3): class TestGroupList(TestGroup): + columns = ( + 'ID', + 'Name', + ) + datalist = ( + ( + identity_fakes.group_id, + identity_fakes.group_name, + ), + ) + def setUp(self): super(TestGroupList, self).setUp() @@ -87,13 +98,8 @@ class TestGroupList(TestGroup): **kwargs ) - collist = ('ID', 'Name') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.group_id, - identity_fakes.group_name, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_group_list_domain(self): arglist = [ @@ -117,13 +123,8 @@ class TestGroupList(TestGroup): **kwargs ) - collist = ('ID', 'Name') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.group_id, - identity_fakes.group_name, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_group_list_user(self): arglist = [ @@ -147,13 +148,8 @@ class TestGroupList(TestGroup): **kwargs ) - collist = ('ID', 'Name') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.group_id, - identity_fakes.group_name, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_group_list_long(self): arglist = [ @@ -177,17 +173,15 @@ class TestGroupList(TestGroup): **kwargs ) - collist = ( - 'ID', - 'Name', + columns = self.columns + ( 'Domain ID', 'Description', ) - self.assertEqual(collist, columns) datalist = (( identity_fakes.group_id, identity_fakes.group_name, '', '', ), ) + self.assertEqual(columns, columns) self.assertEqual(datalist, tuple(data)) diff --git a/openstackclient/tests/identity/v3/test_identity_provider.py b/openstackclient/tests/identity/v3/test_identity_provider.py index db097d5..50a922b 100644 --- a/openstackclient/tests/identity/v3/test_identity_provider.py +++ b/openstackclient/tests/identity/v3/test_identity_provider.py @@ -33,6 +33,19 @@ class TestIdentityProvider(identity_fakes.TestFederatedIdentity): class TestIdentityProviderCreate(TestIdentityProvider): + columns = ( + 'description', + 'enabled', + 'id', + 'remote_ids', + ) + datalist = ( + identity_fakes.idp_description, + True, + identity_fakes.idp_id, + identity_fakes.formatted_idp_remote_ids, + ) + def setUp(self): super(TestIdentityProviderCreate, self).setUp() @@ -63,15 +76,8 @@ class TestIdentityProviderCreate(TestIdentityProvider): **kwargs ) - collist = ('description', 'enabled', 'id', 'remote_ids') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.idp_description, - True, - identity_fakes.idp_id, - identity_fakes.formatted_idp_remote_ids - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_create_identity_provider_description(self): arglist = [ @@ -97,15 +103,8 @@ class TestIdentityProviderCreate(TestIdentityProvider): **kwargs ) - collist = ('description', 'enabled', 'id', 'remote_ids') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.idp_description, - True, - identity_fakes.idp_id, - identity_fakes.formatted_idp_remote_ids - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_create_identity_provider_remote_id(self): arglist = [ @@ -131,15 +130,8 @@ class TestIdentityProviderCreate(TestIdentityProvider): **kwargs ) - collist = ('description', 'enabled', 'id', 'remote_ids') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.idp_description, - True, - identity_fakes.idp_id, - identity_fakes.formatted_idp_remote_ids - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_create_identity_provider_remote_ids_multiple(self): arglist = [ @@ -166,15 +158,8 @@ class TestIdentityProviderCreate(TestIdentityProvider): **kwargs ) - collist = ('description', 'enabled', 'id', 'remote_ids') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.idp_description, - True, - identity_fakes.idp_id, - identity_fakes.formatted_idp_remote_ids - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_create_identity_provider_remote_ids_file(self): arglist = [ @@ -205,15 +190,8 @@ class TestIdentityProviderCreate(TestIdentityProvider): **kwargs ) - collist = ('description', 'enabled', 'id', 'remote_ids') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.idp_description, - True, - identity_fakes.idp_id, - identity_fakes.formatted_idp_remote_ids - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_create_identity_provider_disabled(self): @@ -247,8 +225,7 @@ class TestIdentityProviderCreate(TestIdentityProvider): **kwargs ) - collist = ('description', 'enabled', 'id', 'remote_ids') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( None, False, @@ -370,6 +347,19 @@ class TestIdentityProviderShow(TestIdentityProvider): class TestIdentityProviderSet(TestIdentityProvider): + columns = ( + 'description', + 'enabled', + 'id', + 'remote_ids', + ) + datalist = ( + identity_fakes.idp_description, + True, + identity_fakes.idp_id, + identity_fakes.idp_remote_ids, + ) + def setUp(self): super(TestIdentityProviderSet, self).setUp() self.cmd = identity_provider.SetIdentityProvider(self.app, None) @@ -401,15 +391,12 @@ class TestIdentityProviderSet(TestIdentityProvider): ('remote_id', None) ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - columns, data = self.cmd.take_action(parsed_args) self.identity_providers_mock.update.assert_called_with( identity_fakes.idp_id, - description=new_description + description=new_description, ) - - collist = ('description', 'enabled', 'id', 'remote_ids') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( identity_fakes.idp_description, False, @@ -456,8 +443,7 @@ class TestIdentityProviderSet(TestIdentityProvider): remote_ids=identity_fakes.idp_remote_ids ) - collist = ('description', 'enabled', 'id', 'remote_ids') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( identity_fakes.idp_description, False, @@ -499,15 +485,8 @@ class TestIdentityProviderSet(TestIdentityProvider): self.identity_providers_mock.update.assert_called_with( identity_fakes.idp_id, enabled=True, remote_ids=identity_fakes.idp_remote_ids) - collist = ('description', 'enabled', 'id', 'remote_ids') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.idp_description, - True, - identity_fakes.idp_id, - identity_fakes.idp_remote_ids - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_identity_provider_replace_remote_ids(self): """Enable Identity Provider. @@ -545,8 +524,7 @@ class TestIdentityProviderSet(TestIdentityProvider): self.identity_providers_mock.update.assert_called_with( identity_fakes.idp_id, enabled=True, remote_ids=[self.new_remote_id]) - collist = ('description', 'enabled', 'id', 'remote_ids') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( identity_fakes.idp_description, True, @@ -595,8 +573,7 @@ class TestIdentityProviderSet(TestIdentityProvider): self.identity_providers_mock.update.assert_called_with( identity_fakes.idp_id, enabled=True, remote_ids=[self.new_remote_id]) - collist = ('description', 'enabled', 'id', 'remote_ids') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( identity_fakes.idp_description, True, @@ -638,5 +615,5 @@ class TestIdentityProviderSet(TestIdentityProvider): # expect take_action() to return (None, None) as # neither --enable nor --disable was specified - self.assertEqual(None, columns) - self.assertEqual(None, data) + self.assertIsNone(columns) + self.assertIsNone(data) diff --git a/openstackclient/tests/identity/v3/test_project.py b/openstackclient/tests/identity/v3/test_project.py index 946bbdc..3654020 100644 --- a/openstackclient/tests/identity/v3/test_project.py +++ b/openstackclient/tests/identity/v3/test_project.py @@ -38,6 +38,21 @@ class TestProject(identity_fakes.TestIdentityv3): class TestProjectCreate(TestProject): + columns = ( + 'description', + 'domain_id', + 'enabled', + 'id', + 'name' + ) + datalist = ( + identity_fakes.project_description, + identity_fakes.domain_id, + True, + identity_fakes.project_id, + identity_fakes.project_name, + ) + def setUp(self): super(TestProjectCreate, self).setUp() @@ -127,16 +142,8 @@ class TestProjectCreate(TestProject): **kwargs ) - collist = ('description', 'domain_id', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_description, - identity_fakes.domain_id, - True, - identity_fakes.project_id, - identity_fakes.project_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_project_create_domain(self): arglist = [ @@ -169,16 +176,8 @@ class TestProjectCreate(TestProject): **kwargs ) - collist = ('description', 'domain_id', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_description, - identity_fakes.domain_id, - True, - identity_fakes.project_id, - identity_fakes.project_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_project_create_domain_no_perms(self): arglist = [ @@ -210,16 +209,8 @@ class TestProjectCreate(TestProject): self.projects_mock.create.assert_called_with( **kwargs ) - collist = ('description', 'domain_id', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_description, - identity_fakes.domain_id, - True, - identity_fakes.project_id, - identity_fakes.project_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_project_create_enable(self): arglist = [ @@ -251,16 +242,8 @@ class TestProjectCreate(TestProject): **kwargs ) - collist = ('description', 'domain_id', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_description, - identity_fakes.domain_id, - True, - identity_fakes.project_id, - identity_fakes.project_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_project_create_disable(self): arglist = [ @@ -292,16 +275,8 @@ class TestProjectCreate(TestProject): **kwargs ) - collist = ('description', 'domain_id', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_description, - identity_fakes.domain_id, - True, - identity_fakes.project_id, - identity_fakes.project_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_project_create_property(self): arglist = [ @@ -334,16 +309,8 @@ class TestProjectCreate(TestProject): **kwargs ) - collist = ('description', 'domain_id', 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_description, - identity_fakes.domain_id, - True, - identity_fakes.project_id, - identity_fakes.project_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_project_create_parent(self): self.projects_mock.get.return_value = fakes.FakeResource( @@ -467,6 +434,17 @@ class TestProjectDelete(TestProject): class TestProjectList(TestProject): + columns = ( + 'ID', + 'Name', + ) + datalist = ( + ( + identity_fakes.project_id, + identity_fakes.project_name, + ), + ) + def setUp(self): super(TestProjectList, self).setUp() @@ -490,13 +468,8 @@ class TestProjectList(TestProject): columns, data = self.cmd.take_action(parsed_args) self.projects_mock.list.assert_called_with() - collist = ('ID', 'Name') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.project_id, - identity_fakes.project_name, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_project_list_long(self): arglist = [ @@ -543,13 +516,8 @@ class TestProjectList(TestProject): self.projects_mock.list.assert_called_with( domain=identity_fakes.domain_id) - collist = ('ID', 'Name') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.project_id, - identity_fakes.project_name, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_project_list_domain_no_perms(self): arglist = [ @@ -567,13 +535,8 @@ class TestProjectList(TestProject): self.projects_mock.list.assert_called_with( domain=identity_fakes.domain_id) - collist = ('ID', 'Name') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.project_id, - identity_fakes.project_name, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) class TestProjectSet(TestProject): @@ -636,7 +599,6 @@ class TestProjectSet(TestProject): # Set expected values kwargs = { 'name': 'qwerty', - 'domain': identity_fakes.domain_id, } # ProjectManager.update(project, name=, domain=, description=, # enabled=, **kwargs) @@ -665,7 +627,6 @@ class TestProjectSet(TestProject): # Set expected values kwargs = { - 'domain': identity_fakes.domain_id, 'description': 'new desc', } self.projects_mock.update.assert_called_with( @@ -692,7 +653,6 @@ class TestProjectSet(TestProject): # Set expected values kwargs = { - 'domain': identity_fakes.domain_id, 'enabled': True, } self.projects_mock.update.assert_called_with( @@ -719,7 +679,6 @@ class TestProjectSet(TestProject): # Set expected values kwargs = { - 'domain': identity_fakes.domain_id, 'enabled': False, } self.projects_mock.update.assert_called_with( @@ -746,7 +705,6 @@ class TestProjectSet(TestProject): # Set expected values kwargs = { - 'domain': identity_fakes.domain_id, 'fee': 'fi', 'fo': 'fum', } diff --git a/openstackclient/tests/identity/v3/test_region.py b/openstackclient/tests/identity/v3/test_region.py index 0ebbbec..9ac9ddf 100644 --- a/openstackclient/tests/identity/v3/test_region.py +++ b/openstackclient/tests/identity/v3/test_region.py @@ -30,6 +30,17 @@ class TestRegion(identity_fakes.TestIdentityv3): class TestRegionCreate(TestRegion): + columns = ( + 'description', + 'parent_region', + 'region', + ) + datalist = ( + identity_fakes.region_description, + identity_fakes.region_parent_region_id, + identity_fakes.region_id, + ) + def setUp(self): super(TestRegionCreate, self).setUp() @@ -66,14 +77,8 @@ class TestRegionCreate(TestRegion): **kwargs ) - collist = ('description', 'parent_region', 'region') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.region_description, - identity_fakes.region_parent_region_id, - identity_fakes.region_id, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_region_create_no_options(self): arglist = [ @@ -97,14 +102,8 @@ class TestRegionCreate(TestRegion): **kwargs ) - collist = ('description', 'parent_region', 'region') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.region_description, - identity_fakes.region_parent_region_id, - identity_fakes.region_id, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_region_create_parent_region_id(self): arglist = [ @@ -129,15 +128,8 @@ class TestRegionCreate(TestRegion): self.regions_mock.create.assert_called_with( **kwargs ) - - collist = ('description', 'parent_region', 'region') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.region_description, - identity_fakes.region_parent_region_id, - identity_fakes.region_id, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) class TestRegionDelete(TestRegion): @@ -169,6 +161,19 @@ class TestRegionDelete(TestRegion): class TestRegionList(TestRegion): + columns = ( + 'Region', + 'Parent Region', + 'Description', + ) + datalist = ( + ( + identity_fakes.region_id, + identity_fakes.region_parent_region_id, + identity_fakes.region_description, + ), + ) + def setUp(self): super(TestRegionList, self).setUp() @@ -192,14 +197,8 @@ class TestRegionList(TestRegion): columns, data = self.cmd.take_action(parsed_args) self.regions_mock.list.assert_called_with() - collist = ('Region', 'Parent Region', 'Description') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.region_id, - identity_fakes.region_parent_region_id, - identity_fakes.region_description, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_region_list_parent_region_id(self): arglist = [ @@ -215,14 +214,8 @@ class TestRegionList(TestRegion): self.regions_mock.list.assert_called_with( parent_region_id=identity_fakes.region_parent_region_id) - collist = ('Region', 'Parent Region', 'Description') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.region_id, - identity_fakes.region_parent_region_id, - identity_fakes.region_description, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) class TestRegionSet(TestRegion): diff --git a/openstackclient/tests/identity/v3/test_role.py b/openstackclient/tests/identity/v3/test_role.py index 8ad4b09..1910c87 100644 --- a/openstackclient/tests/identity/v3/test_role.py +++ b/openstackclient/tests/identity/v3/test_role.py @@ -314,6 +314,17 @@ class TestRoleDelete(TestRole): class TestRoleList(TestRole): + columns = ( + 'ID', + 'Name', + ) + datalist = ( + ( + identity_fakes.role_id, + identity_fakes.role_name, + ), + ) + def setUp(self): super(TestRoleList, self).setUp() @@ -359,13 +370,8 @@ class TestRoleList(TestRole): self.roles_mock.list.assert_called_with() - collist = ('ID', 'Name') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.role_id, - identity_fakes.role_name, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_user_list_inherited(self): arglist = [ @@ -392,13 +398,8 @@ class TestRoleList(TestRole): **kwargs ) - collist = ('ID', 'Name') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.role_id, - identity_fakes.role_name, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_user_list_user(self): arglist = [ @@ -423,13 +424,8 @@ class TestRoleList(TestRole): **kwargs ) - collist = ('ID', 'Name') - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.role_id, - identity_fakes.role_name, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_role_list_domain_user(self): arglist = [ diff --git a/openstackclient/tests/identity/v3/test_role_assignment.py b/openstackclient/tests/identity/v3/test_role_assignment.py index 9817f53..5723a33 100644 --- a/openstackclient/tests/identity/v3/test_role_assignment.py +++ b/openstackclient/tests/identity/v3/test_role_assignment.py @@ -26,6 +26,15 @@ class TestRoleAssignment(identity_fakes.TestIdentityv3): class TestRoleAssignmentList(TestRoleAssignment): + columns = ( + 'Role', + 'User', + 'Group', + 'Project', + 'Domain', + 'Inherited', + ) + def setUp(self): super(TestRoleAssignment, self).setUp() @@ -89,8 +98,7 @@ class TestRoleAssignmentList(TestRoleAssignment): project=None, os_inherit_extension_inherited_to=None) - collist = ('Role', 'User', 'Group', 'Project', 'Domain', 'Inherited') - self.assertEqual(columns, collist) + self.assertEqual(self.columns, columns) datalist = (( identity_fakes.role_id, identity_fakes.user_id, @@ -150,8 +158,7 @@ class TestRoleAssignmentList(TestRoleAssignment): effective=False, os_inherit_extension_inherited_to=None) - collist = ('Role', 'User', 'Group', 'Project', 'Domain', 'Inherited') - self.assertEqual(columns, collist) + self.assertEqual(self.columns, columns) datalist = (( identity_fakes.role_id, identity_fakes.user_id, @@ -211,8 +218,7 @@ class TestRoleAssignmentList(TestRoleAssignment): user=None, os_inherit_extension_inherited_to=None) - collist = ('Role', 'User', 'Group', 'Project', 'Domain', 'Inherited') - self.assertEqual(columns, collist) + self.assertEqual(self.columns, columns) datalist = (( identity_fakes.role_id, '', @@ -272,8 +278,7 @@ class TestRoleAssignmentList(TestRoleAssignment): user=None, os_inherit_extension_inherited_to=None) - collist = ('Role', 'User', 'Group', 'Project', 'Domain', 'Inherited') - self.assertEqual(columns, collist) + self.assertEqual(self.columns, columns) datalist = (( identity_fakes.role_id, identity_fakes.user_id, @@ -333,8 +338,7 @@ class TestRoleAssignmentList(TestRoleAssignment): user=None, os_inherit_extension_inherited_to=None) - collist = ('Role', 'User', 'Group', 'Project', 'Domain', 'Inherited') - self.assertEqual(columns, collist) + self.assertEqual(self.columns, columns) datalist = (( identity_fakes.role_id, identity_fakes.user_id, @@ -392,8 +396,7 @@ class TestRoleAssignmentList(TestRoleAssignment): user=None, os_inherit_extension_inherited_to=None) - collist = ('Role', 'User', 'Group', 'Project', 'Domain', 'Inherited') - self.assertEqual(columns, collist) + self.assertEqual(self.columns, columns) datalist = (( identity_fakes.role_id, identity_fakes.user_id, @@ -453,8 +456,7 @@ class TestRoleAssignmentList(TestRoleAssignment): user=None, os_inherit_extension_inherited_to='projects') - collist = ('Role', 'User', 'Group', 'Project', 'Domain', 'Inherited') - self.assertEqual(columns, collist) + self.assertEqual(self.columns, columns) datalist = (( identity_fakes.role_id, identity_fakes.user_id, diff --git a/openstackclient/tests/identity/v3/test_service.py b/openstackclient/tests/identity/v3/test_service.py index d2b54c7..c609142 100644 --- a/openstackclient/tests/identity/v3/test_service.py +++ b/openstackclient/tests/identity/v3/test_service.py @@ -32,6 +32,21 @@ class TestService(identity_fakes.TestIdentityv3): class TestServiceCreate(TestService): + columns = ( + 'description', + 'enabled', + 'id', + 'name', + 'type', + ) + datalist = ( + identity_fakes.service_description, + True, + identity_fakes.service_id, + identity_fakes.service_name, + identity_fakes.service_type, + ) + def setUp(self): super(TestServiceCreate, self).setUp() @@ -69,16 +84,8 @@ class TestServiceCreate(TestService): enabled=True, ) - collist = ('description', 'enabled', 'id', 'name', 'type') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.service_description, - True, - identity_fakes.service_id, - identity_fakes.service_name, - identity_fakes.service_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_service_create_description(self): arglist = [ @@ -105,16 +112,8 @@ class TestServiceCreate(TestService): enabled=True, ) - collist = ('description', 'enabled', 'id', 'name', 'type') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.service_description, - True, - identity_fakes.service_id, - identity_fakes.service_name, - identity_fakes.service_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_service_create_enable(self): arglist = [ @@ -141,16 +140,8 @@ class TestServiceCreate(TestService): enabled=True, ) - collist = ('description', 'enabled', 'id', 'name', 'type') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.service_description, - True, - identity_fakes.service_id, - identity_fakes.service_name, - identity_fakes.service_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_service_create_disable(self): arglist = [ @@ -177,16 +168,8 @@ class TestServiceCreate(TestService): enabled=False, ) - collist = ('description', 'enabled', 'id', 'name', 'type') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.service_description, - True, - identity_fakes.service_id, - identity_fakes.service_name, - identity_fakes.service_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) class TestServiceDelete(TestService): diff --git a/openstackclient/tests/identity/v3/test_service_provider.py b/openstackclient/tests/identity/v3/test_service_provider.py index e77870d..24fa7c7 100644 --- a/openstackclient/tests/identity/v3/test_service_provider.py +++ b/openstackclient/tests/identity/v3/test_service_provider.py @@ -31,6 +31,21 @@ class TestServiceProvider(service_fakes.TestFederatedIdentity): class TestServiceProviderCreate(TestServiceProvider): + columns = ( + 'auth_url', + 'description', + 'enabled', + 'id', + 'sp_url', + ) + datalist = ( + service_fakes.sp_auth_url, + service_fakes.sp_description, + True, + service_fakes.sp_id, + service_fakes.service_provider_url + ) + def setUp(self): super(TestServiceProviderCreate, self).setUp() @@ -67,16 +82,8 @@ class TestServiceProviderCreate(TestServiceProvider): **kwargs ) - 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 - ) - self.assertEqual(data, datalist) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_create_service_provider_description(self): @@ -109,16 +116,8 @@ class TestServiceProviderCreate(TestServiceProvider): **kwargs ) - collist = ('auth_url', 'description', 'enabled', 'id', 'sp_url') - self.assertEqual(columns, collist) - datalist = ( - service_fakes.sp_auth_url, - service_fakes.sp_description, - True, - service_fakes.sp_id, - service_fakes.service_provider_url - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_create_service_provider_disabled(self): @@ -155,9 +154,7 @@ class TestServiceProviderCreate(TestServiceProvider): id=service_fakes.sp_id, **kwargs ) - - collist = ('auth_url', 'description', 'enabled', 'id', 'sp_url') - self.assertEqual(collist, collist) + self.assertEqual(self.columns, columns) datalist = ( service_fakes.sp_auth_url, None, @@ -282,6 +279,21 @@ class TestServiceProviderShow(TestServiceProvider): class TestServiceProviderSet(TestServiceProvider): + columns = ( + 'auth_url', + 'description', + 'enabled', + 'id', + 'sp_url', + ) + datalist = ( + service_fakes.sp_auth_url, + service_fakes.sp_description, + False, + service_fakes.sp_id, + service_fakes.service_provider_url, + ) + def setUp(self): super(TestServiceProviderSet, self).setUp() self.cmd = service_provider.SetServiceProvider(self.app, None) @@ -321,16 +333,8 @@ class TestServiceProviderSet(TestServiceProvider): sp_url=None ) - collist = ('auth_url', 'description', 'enabled', 'id', 'sp_url') - self.assertEqual(collist, columns) - datalist = ( - service_fakes.sp_auth_url, - service_fakes.sp_description, - False, - service_fakes.sp_id, - service_fakes.service_provider_url - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_service_provider_enable(self): """Enable Service Provider. @@ -361,8 +365,7 @@ class TestServiceProviderSet(TestServiceProvider): self.service_providers_mock.update.assert_called_with( service_fakes.sp_id, enabled=True, description=None, auth_url=None, sp_url=None) - collist = ('auth_url', 'description', 'enabled', 'id', 'sp_url') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( service_fakes.sp_auth_url, service_fakes.sp_description, @@ -370,7 +373,7 @@ class TestServiceProviderSet(TestServiceProvider): service_fakes.sp_id, service_fakes.service_provider_url ) - self.assertEqual(data, datalist) + self.assertEqual(datalist, data) def test_service_provider_no_options(self): def prepare(self): @@ -408,5 +411,5 @@ class TestServiceProviderSet(TestServiceProvider): # expect take_action() to return (None, None) as none of --disabled, # --enabled, --description, --service-provider-url, --auth_url option # was set. - self.assertEqual(columns, None) - self.assertEqual(data, None) + self.assertIsNone(columns) + self.assertIsNone(data) diff --git a/openstackclient/tests/identity/v3/test_user.py b/openstackclient/tests/identity/v3/test_user.py index 76d5f83..1871ed1 100644 --- a/openstackclient/tests/identity/v3/test_user.py +++ b/openstackclient/tests/identity/v3/test_user.py @@ -52,6 +52,23 @@ class TestUser(identity_fakes.TestIdentityv3): class TestUserCreate(TestUser): + columns = ( + 'default_project_id', + 'domain_id', + 'email', + 'enabled', + 'id', + 'name', + ) + datalist = ( + identity_fakes.project_id, + identity_fakes.domain_id, + identity_fakes.user_email, + True, + identity_fakes.user_id, + identity_fakes.user_name, + ) + def setUp(self): super(TestUserCreate, self).setUp() @@ -107,18 +124,8 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('default_project_id', 'domain_id', 'email', - 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_id, - identity_fakes.domain_id, - identity_fakes.user_email, - True, - identity_fakes.user_id, - identity_fakes.user_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_user_create_password(self): arglist = [ @@ -152,19 +159,8 @@ class TestUserCreate(TestUser): self.users_mock.create.assert_called_with( **kwargs ) - - collist = ('default_project_id', 'domain_id', 'email', - 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_id, - identity_fakes.domain_id, - identity_fakes.user_email, - True, - identity_fakes.user_id, - identity_fakes.user_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_user_create_password_prompt(self): arglist = [ @@ -202,18 +198,8 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('default_project_id', 'domain_id', 'email', - 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_id, - identity_fakes.domain_id, - identity_fakes.user_email, - True, - identity_fakes.user_id, - identity_fakes.user_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_user_create_email(self): arglist = [ @@ -247,18 +233,8 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('default_project_id', 'domain_id', 'email', - 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_id, - identity_fakes.domain_id, - identity_fakes.user_email, - True, - identity_fakes.user_id, - identity_fakes.user_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_user_create_project(self): # Return the new project @@ -307,9 +283,7 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('default_project_id', 'domain_id', 'email', - 'enabled', 'id', 'name') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( identity_fakes.PROJECT_2['id'], identity_fakes.domain_id, @@ -369,9 +343,7 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('default_project_id', 'domain_id', 'email', - 'enabled', 'id', 'name') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( identity_fakes.PROJECT_2['id'], identity_fakes.domain_id, @@ -414,18 +386,8 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('default_project_id', 'domain_id', 'email', - 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_id, - identity_fakes.domain_id, - identity_fakes.user_email, - True, - identity_fakes.user_id, - identity_fakes.user_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_user_create_enable(self): arglist = [ @@ -458,18 +420,8 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('default_project_id', 'domain_id', 'email', - 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_id, - identity_fakes.domain_id, - identity_fakes.user_email, - True, - identity_fakes.user_id, - identity_fakes.user_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_user_create_disable(self): arglist = [ @@ -500,19 +452,8 @@ class TestUserCreate(TestUser): self.users_mock.create.assert_called_with( **kwargs ) - - collist = ('default_project_id', 'domain_id', 'email', - 'enabled', 'id', 'name') - self.assertEqual(collist, columns) - datalist = ( - identity_fakes.project_id, - identity_fakes.domain_id, - identity_fakes.user_email, - True, - identity_fakes.user_id, - identity_fakes.user_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) class TestUserDelete(TestUser): @@ -550,6 +491,17 @@ class TestUserDelete(TestUser): class TestUserList(TestUser): + columns = [ + 'ID', + 'Name' + ] + datalist = ( + ( + identity_fakes.user_id, + identity_fakes.user_name, + ), + ) + def setUp(self): super(TestUserList, self).setUp() @@ -614,13 +566,8 @@ class TestUserList(TestUser): **kwargs ) - collist = ['ID', 'Name'] - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.user_id, - identity_fakes.user_name, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_user_list_domain(self): arglist = [ @@ -644,13 +591,8 @@ class TestUserList(TestUser): **kwargs ) - collist = ['ID', 'Name'] - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.user_id, - identity_fakes.user_name, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_user_list_group(self): arglist = [ @@ -674,13 +616,8 @@ class TestUserList(TestUser): **kwargs ) - collist = ['ID', 'Name'] - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.user_id, - identity_fakes.user_name, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_user_list_long(self): arglist = [ @@ -714,15 +651,17 @@ class TestUserList(TestUser): 'Enabled', ] self.assertEqual(collist, columns) - datalist = (( - identity_fakes.user_id, - identity_fakes.user_name, - identity_fakes.project_id, - identity_fakes.domain_id, - '', - identity_fakes.user_email, - True, - ), ) + datalist = ( + ( + identity_fakes.user_id, + identity_fakes.user_name, + identity_fakes.project_id, + identity_fakes.domain_id, + '', + identity_fakes.user_email, + True, + ), + ) self.assertEqual(datalist, tuple(data)) def test_user_list_project(self): @@ -744,13 +683,8 @@ class TestUserList(TestUser): self.role_assignments_mock.list.assert_called_with(**kwargs) self.users_mock.get.assert_called_with(identity_fakes.user_id) - collist = ['ID', 'Name'] - self.assertEqual(collist, columns) - datalist = (( - identity_fakes.user_id, - identity_fakes.user_name, - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) class TestUserSet(TestUser): @@ -1095,6 +1029,25 @@ class TestUserSetPassword(TestUser): current_pass, new_pass ) + def test_user_password_change_no_prompt(self): + current_pass = 'old_pass' + new_pass = 'new_pass' + arglist = [ + '--password', new_pass, + '--original-password', current_pass, + ] + verifylist = [ + ('password', new_pass), + ('original_password', current_pass), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + + self.users_mock.update_password.assert_called_with( + current_pass, new_pass + ) + class TestUserShow(TestUser): diff --git a/openstackclient/tests/image/v1/test_image.py b/openstackclient/tests/image/v1/test_image.py index 4d964bd..1e0b29a 100644 --- a/openstackclient/tests/image/v1/test_image.py +++ b/openstackclient/tests/image/v1/test_image.py @@ -103,6 +103,7 @@ class TestImageCreate(TestImage): '--min-ram', '4', '--protected', '--private', + '--project', 'q', image_fakes.image_name, ] verifylist = [ @@ -114,6 +115,7 @@ class TestImageCreate(TestImage): ('unprotected', False), ('public', False), ('private', True), + ('project', 'q'), ('name', image_fakes.image_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -130,6 +132,7 @@ class TestImageCreate(TestImage): min_ram=4, protected=True, is_public=False, + owner='q', data=mock.ANY, ) @@ -237,6 +240,19 @@ class TestImageDelete(TestImage): class TestImageList(TestImage): + columns = ( + 'ID', + 'Name', + 'Status', + ) + datalist = ( + ( + image_fakes.image_id, + image_fakes.image_name, + '', + ), + ) + def setUp(self): super(TestImageList, self).setUp() @@ -265,15 +281,8 @@ class TestImageList(TestImage): marker=image_fakes.image_id, ) - collist = ('ID', 'Name', 'Status') - - self.assertEqual(collist, columns) - datalist = (( - image_fakes.image_id, - image_fakes.image_name, - '', - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_image_list_public_option(self): arglist = [ @@ -294,15 +303,8 @@ class TestImageList(TestImage): marker=image_fakes.image_id, ) - collist = ('ID', 'Name', 'Status') - - self.assertEqual(collist, columns) - datalist = (( - image_fakes.image_id, - image_fakes.image_name, - '', - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_image_list_private_option(self): arglist = [ @@ -323,15 +325,8 @@ class TestImageList(TestImage): marker=image_fakes.image_id, ) - collist = ('ID', 'Name', 'Status') - - self.assertEqual(collist, columns) - datalist = (( - image_fakes.image_id, - image_fakes.image_name, - '', - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_image_list_long_option(self): arglist = [ @@ -358,7 +353,7 @@ class TestImageList(TestImage): 'Status', 'Visibility', 'Protected', - 'Owner', + 'Project', 'Properties', ) @@ -404,15 +399,8 @@ class TestImageList(TestImage): property_field='properties', ) - collist = ('ID', 'Name', 'Status') - - self.assertEqual(columns, collist) - datalist = (( - image_fakes.image_id, - image_fakes.image_name, - '', - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) @mock.patch('openstackclient.common.utils.sort_items') def test_image_list_sort_option(self, si_mock): @@ -435,15 +423,8 @@ class TestImageList(TestImage): 'name:asc' ) - collist = ('ID', 'Name', 'Status') - - self.assertEqual(collist, columns) - datalist = (( - image_fakes.image_id, - image_fakes.image_name, - '', - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) class TestImageSet(TestImage): @@ -484,22 +465,22 @@ class TestImageSet(TestImage): def test_image_set_options(self): arglist = [ '--name', 'new-name', - '--owner', 'new-owner', '--min-disk', '2', '--min-ram', '4', '--container-format', 'ovf', '--disk-format', 'vmdk', '--size', '35165824', + '--project', 'new-owner', image_fakes.image_name, ] verifylist = [ ('name', 'new-name'), - ('owner', 'new-owner'), ('min_disk', 2), ('min_ram', 4), ('container_format', 'ovf'), ('disk_format', 'vmdk'), ('size', 35165824), + ('project', 'new-owner'), ('image', image_fakes.image_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) diff --git a/openstackclient/tests/image/v2/fakes.py b/openstackclient/tests/image/v2/fakes.py index 11ad455..5441a3e 100644 --- a/openstackclient/tests/image/v2/fakes.py +++ b/openstackclient/tests/image/v2/fakes.py @@ -15,7 +15,10 @@ import copy import mock +import random +import uuid +from openstackclient.common import utils as common_utils from openstackclient.tests import fakes from openstackclient.tests import utils @@ -167,3 +170,133 @@ class TestImagev2(utils.TestCommand): endpoint=fakes.AUTH_URL, token=fakes.AUTH_TOKEN, ) + + +class FakeImage(object): + """Fake one or more images. + + TODO(xiexs): Currently, only image API v2 is supported by this class. + """ + + @staticmethod + def create_one_image(attrs={}): + """Create a fake image. + + :param Dictionary attrs: + A dictionary with all attrbutes of image + :retrun: + A FakeResource object with id, name, owner, protected, + visibility and tags attrs + """ + # Set default attribute + image_info = { + 'id': 'image-id' + uuid.uuid4().hex, + 'name': 'image-name' + uuid.uuid4().hex, + 'owner': 'image-owner' + uuid.uuid4().hex, + 'protected': bool(random.choice([0, 1])), + 'visibility': random.choice(['public', 'private']), + 'tags': [uuid.uuid4().hex for r in range(2)], + } + + # Overwrite default attributes if there are some attributes set + image_info.update(attrs) + + image = fakes.FakeResource( + None, + image_info, + loaded=True) + return image + + @staticmethod + def create_images(attrs={}, count=2): + """Create multiple fake images. + + :param Dictionary attrs: + A dictionary with all attributes of image + :param Integer count: + The number of images to be faked + :return: + A list of FakeResource objects + """ + images = [] + for n in range(0, count): + images.append(FakeImage.create_one_image(attrs)) + + return images + + @staticmethod + def get_images(images=None, count=2): + """Get an iterable MagicMock object with a list of faked images. + + If images list is provided, then initialize the Mock object with the + list. Otherwise create one. + + :param List images: + A list of FakeResource objects faking images + :param Integer count: + The number of images to be faked + :return + An iterable Mock object with side_effect set to a list of faked + images + """ + if images is None: + images = FakeImage.create_images(count) + + return mock.MagicMock(side_effect=images) + + @staticmethod + def get_image_info(image=None): + """Get the image info from a faked image object. + + :param image: + A FakeResource objects faking image + :return + A dictionary which includes the faked image info as follows: + { + 'id': image_id, + 'name': image_name, + 'owner': image_owner, + 'protected': image_protected, + 'visibility': image_visibility, + 'tags': image_tags + } + """ + if image is not None: + return image._info + return {} + + @staticmethod + def get_image_columns(image=None): + """Get the image columns from a faked image object. + + :param image: + A FakeResource objects faking image + :return + A tuple which may include the following keys: + ('id', 'name', 'owner', 'protected', 'visibility', 'tags') + """ + if image is not None: + return tuple(k for k in sorted( + FakeImage.get_image_info(image).keys())) + return tuple([]) + + @staticmethod + def get_image_data(image=None): + """Get the image data from a faked image object. + + :param image: + A FakeResource objects faking image + :return + A tuple which may include the following values: + ('image-123', 'image-foo', 'admin', False, 'public', 'bar, baz') + """ + data_list = [] + if image is not None: + for x in sorted(FakeImage.get_image_info(image).keys()): + if x == 'tags': + # The 'tags' should be format_list + data_list.append( + common_utils.format_list(getattr(image, x))) + else: + data_list.append(getattr(image, x)) + return tuple(data_list) diff --git a/openstackclient/tests/image/v2/test_image.py b/openstackclient/tests/image/v2/test_image.py index be73c4c..d399c9e 100644 --- a/openstackclient/tests/image/v2/test_image.py +++ b/openstackclient/tests/image/v2/test_image.py @@ -31,35 +31,52 @@ class TestImage(image_fakes.TestImagev2): def setUp(self): super(TestImage, self).setUp() - # Get a shortcut to the ServerManager Mock + # Get shortcuts to the Mocks in image client self.images_mock = self.app.client_manager.image.images self.images_mock.reset_mock() self.image_members_mock = self.app.client_manager.image.image_members self.image_members_mock.reset_mock() + + # Get shortcut to the Mocks in identity client self.project_mock = self.app.client_manager.identity.projects self.project_mock.reset_mock() self.domain_mock = self.app.client_manager.identity.domains self.domain_mock.reset_mock() + def setup_images_mock(self, count): + images = image_fakes.FakeImage.create_images(count=count) + + self.images_mock.get = image_fakes.FakeImage.get_images( + images, + 0) + return images + class TestImageCreate(TestImage): def setUp(self): super(TestImageCreate, self).setUp() - self.images_mock.create.return_value = fakes.FakeResource( + self.new_image = image_fakes.FakeImage.create_one_image() + self.images_mock.create.return_value = self.new_image + + self.project_mock.get.return_value = fakes.FakeResource( None, - copy.deepcopy(image_fakes.IMAGE), + copy.deepcopy(identity_fakes.PROJECT), loaded=True, ) - # This is the return value for utils.find_resource() - self.images_mock.get.return_value = copy.deepcopy(image_fakes.IMAGE) - self.images_mock.update.return_value = fakes.FakeResource( + + self.domain_mock.get.return_value = fakes.FakeResource( None, - copy.deepcopy(image_fakes.IMAGE), + copy.deepcopy(identity_fakes.DOMAIN), loaded=True, ) + # This is the return value for utils.find_resource() + self.images_mock.get.return_value = copy.deepcopy( + image_fakes.FakeImage.get_image_info(self.new_image)) + self.images_mock.update.return_value = self.new_image + # Get the command object to test self.cmd = image.CreateImage(self.app, None) @@ -69,12 +86,12 @@ class TestImageCreate(TestImage): } self.images_mock.configure_mock(**mock_exception) arglist = [ - image_fakes.image_name, + self.new_image.name ] verifylist = [ ('container_format', image.DEFAULT_CONTAINER_FORMAT), ('disk_format', image.DEFAULT_DISK_FORMAT), - ('name', image_fakes.image_name), + ('name', self.new_image.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -83,7 +100,7 @@ class TestImageCreate(TestImage): # ImageManager.create(name=, **) self.images_mock.create.assert_called_with( - name=image_fakes.image_name, + name=self.new_image.name, container_format=image.DEFAULT_CONTAINER_FORMAT, disk_format=image.DEFAULT_DISK_FORMAT, ) @@ -95,8 +112,12 @@ class TestImageCreate(TestImage): mock.ANY, mock.ANY, ) - self.assertEqual(image_fakes.IMAGE_columns, columns) - self.assertEqual(image_fakes.IMAGE_SHOW_data, data) + self.assertEqual( + image_fakes.FakeImage.get_image_columns(self.new_image), + columns) + self.assertEqual( + image_fakes.FakeImage.get_image_data(self.new_image), + data) @mock.patch('glanceclient.common.utils.get_data_file', name='Open') def test_image_reserve_options(self, mock_open): @@ -112,22 +133,26 @@ class TestImageCreate(TestImage): '--disk-format', 'fs', '--min-disk', '10', '--min-ram', '4', - '--owner', '123456', - '--protected', - '--private', - image_fakes.image_name, + ('--protected' + if self.new_image.protected else '--unprotected'), + ('--private' + if self.new_image.visibility == 'private' else '--public'), + '--project', self.new_image.owner, + '--project-domain', identity_fakes.domain_id, + self.new_image.name, ] verifylist = [ ('container_format', 'ovf'), ('disk_format', 'fs'), ('min_disk', 10), ('min_ram', 4), - ('owner', '123456'), - ('protected', True), - ('unprotected', False), - ('public', False), - ('private', True), - ('name', image_fakes.image_name), + ('protected', self.new_image.protected), + ('unprotected', not self.new_image.protected), + ('public', self.new_image.visibility == 'public'), + ('private', self.new_image.visibility == 'private'), + ('project', self.new_image.owner), + ('project_domain', identity_fakes.domain_id), + ('name', self.new_image.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -136,14 +161,14 @@ class TestImageCreate(TestImage): # ImageManager.create(name=, **) self.images_mock.create.assert_called_with( - name=image_fakes.image_name, + name=self.new_image.name, container_format='ovf', disk_format='fs', min_disk=10, min_ram=4, - owner='123456', - protected=True, - visibility='private', + owner=identity_fakes.project_id, + protected=self.new_image.protected, + visibility=self.new_image.visibility, ) # Verify update() was not called, if it was show the args @@ -153,14 +178,87 @@ class TestImageCreate(TestImage): mock.ANY, mock.ANY, ) - self.assertEqual(image_fakes.IMAGE_columns, columns) - self.assertEqual(image_fakes.IMAGE_SHOW_data, data) + self.assertEqual( + image_fakes.FakeImage.get_image_columns(self.new_image), + columns) + self.assertEqual( + image_fakes.FakeImage.get_image_data(self.new_image), + data) + + def test_image_create_with_unexist_owner(self): + self.project_mock.get.side_effect = exceptions.NotFound(None) + self.project_mock.find.side_effect = exceptions.NotFound(None) + + arglist = [ + '--container-format', 'ovf', + '--disk-format', 'fs', + '--min-disk', '10', + '--min-ram', '4', + '--owner', 'unexist_owner', + '--protected', + '--private', + image_fakes.image_name, + ] + verifylist = [ + ('container_format', 'ovf'), + ('disk_format', 'fs'), + ('min_disk', 10), + ('min_ram', 4), + ('owner', 'unexist_owner'), + ('protected', True), + ('unprotected', False), + ('public', False), + ('private', True), + ('name', image_fakes.image_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.assertRaises( + exceptions.CommandError, + self.cmd.take_action, + parsed_args, + ) + + def test_image_create_with_unexist_project(self): + self.project_mock.get.side_effect = exceptions.NotFound(None) + self.project_mock.find.side_effect = exceptions.NotFound(None) + + arglist = [ + '--container-format', 'ovf', + '--disk-format', 'fs', + '--min-disk', '10', + '--min-ram', '4', + '--protected', + '--private', + '--project', 'unexist_owner', + image_fakes.image_name, + ] + verifylist = [ + ('container_format', 'ovf'), + ('disk_format', 'fs'), + ('min_disk', 10), + ('min_ram', 4), + ('protected', True), + ('unprotected', False), + ('public', False), + ('private', True), + ('project', 'unexist_owner'), + ('name', image_fakes.image_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.assertRaises( + exceptions.CommandError, + self.cmd.take_action, + parsed_args, + ) @mock.patch('glanceclient.common.utils.get_data_file', name='Open') def test_image_create_file(self, mock_open): mock_file = mock.MagicMock(name='File') mock_open.return_value = mock_file - mock_open.read.return_value = image_fakes.IMAGE_data + mock_open.read.return_value = ( + image_fakes.FakeImage.get_image_data(self.new_image)) mock_exception = { 'find.side_effect': exceptions.CommandError('x'), } @@ -168,23 +266,25 @@ class TestImageCreate(TestImage): arglist = [ '--file', 'filer', - '--unprotected', - '--public', + ('--unprotected' + if not self.new_image.protected else '--protected'), + ('--public' + if self.new_image.visibility == 'public' else '--private'), '--property', 'Alpha=1', '--property', 'Beta=2', - '--tag', 'awesome', - '--tag', 'better', - image_fakes.image_name, + '--tag', self.new_image.tags[0], + '--tag', self.new_image.tags[1], + self.new_image.name, ] verifylist = [ ('file', 'filer'), - ('protected', False), - ('unprotected', True), - ('public', True), - ('private', False), + ('protected', self.new_image.protected), + ('unprotected', not self.new_image.protected), + ('public', self.new_image.visibility == 'public'), + ('private', self.new_image.visibility == 'private'), ('properties', {'Alpha': '1', 'Beta': '2'}), - ('tags', ['awesome', 'better']), - ('name', image_fakes.image_name), + ('tags', self.new_image.tags), + ('name', self.new_image.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -193,14 +293,14 @@ class TestImageCreate(TestImage): # ImageManager.create(name=, **) self.images_mock.create.assert_called_with( - name=image_fakes.image_name, + name=self.new_image.name, container_format=image.DEFAULT_CONTAINER_FORMAT, disk_format=image.DEFAULT_DISK_FORMAT, - protected=False, - visibility='public', + protected=self.new_image.protected, + visibility=self.new_image.visibility, Alpha='1', Beta='2', - tags=['awesome', 'better'], + tags=self.new_image.tags, ) # Verify update() was not called, if it was show the args @@ -210,17 +310,21 @@ class TestImageCreate(TestImage): mock.ANY, mock.ANY, ) - self.assertEqual(image_fakes.IMAGE_columns, columns) - self.assertEqual(image_fakes.IMAGE_SHOW_data, data) + self.assertEqual( + image_fakes.FakeImage.get_image_columns(self.new_image), + columns) + self.assertEqual( + image_fakes.FakeImage.get_image_data(self.new_image), + data) def test_image_create_dead_options(self): arglist = [ '--store', 'somewhere', - image_fakes.image_name, + self.new_image.name, ] verifylist = [ - ('name', image_fakes.image_name), + ('name', self.new_image.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -231,6 +335,17 @@ class TestImageCreate(TestImage): class TestAddProjectToImage(TestImage): + columns = ( + 'image_id', + 'member_id', + 'status', + ) + datalist = ( + image_fakes.image_id, + identity_fakes.project_id, + image_fakes.member_status, + ) + def setUp(self): super(TestAddProjectToImage, self).setUp() @@ -273,14 +388,8 @@ class TestAddProjectToImage(TestImage): image_fakes.image_id, identity_fakes.project_id ) - collist = ('image_id', 'member_id', 'status') - self.assertEqual(collist, columns) - datalist = ( - image_fakes.image_id, - identity_fakes.project_id, - image_fakes.member_status - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_add_project_to_image_with_option(self): arglist = [ @@ -301,14 +410,8 @@ class TestAddProjectToImage(TestImage): image_fakes.image_id, identity_fakes.project_id ) - collist = ('image_id', 'member_id', 'status') - self.assertEqual(collist, columns) - datalist = ( - image_fakes.image_id, - identity_fakes.project_id, - image_fakes.member_status - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) class TestImageDelete(TestImage): @@ -316,23 +419,19 @@ class TestImageDelete(TestImage): def setUp(self): super(TestImageDelete, self).setUp() - # This is the return value for utils.find_resource() - self.images_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(image_fakes.IMAGE), - loaded=True, - ) self.images_mock.delete.return_value = None # Get the command object to test self.cmd = image.DeleteImage(self.app, None) def test_image_delete_no_options(self): + images = self.setup_images_mock(count=1) + arglist = [ - image_fakes.image_id, + images[0].id, ] verifylist = [ - ('images', [image_fakes.image_id]), + ('images', [images[0].id]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -340,12 +439,41 @@ class TestImageDelete(TestImage): self.cmd.take_action(parsed_args) self.images_mock.delete.assert_called_with( - image_fakes.image_id, + images[0].id, ) + def test_image_delete_multi_images(self): + images = self.setup_images_mock(count=3) + + arglist = [i.id for i in images] + verifylist = [ + ('images', arglist), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + + calls = [mock.call(i.id) for i in images] + + self.images_mock.delete.assert_has_calls(calls) + class TestImageList(TestImage): + columns = ( + 'ID', + 'Name', + 'Status', + ) + datalist = ( + ( + image_fakes.image_id, + image_fakes.image_name, + '', + ), + ) + def setUp(self): super(TestImageList, self).setUp() @@ -370,19 +498,10 @@ class TestImageList(TestImage): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) - self.api_mock.image_list.assert_called_with( - marker=image_fakes.image_id, - ) + self.api_mock.image_list.assert_called_with() - collist = ('ID', 'Name', 'Status') - - self.assertEqual(collist, columns) - datalist = (( - image_fakes.image_id, - image_fakes.image_name, - '', - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_image_list_public_option(self): arglist = [ @@ -400,18 +519,10 @@ class TestImageList(TestImage): columns, data = self.cmd.take_action(parsed_args) self.api_mock.image_list.assert_called_with( public=True, - marker=image_fakes.image_id, ) - collist = ('ID', 'Name', 'Status') - - self.assertEqual(collist, columns) - datalist = (( - image_fakes.image_id, - image_fakes.image_name, - '', - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_image_list_private_option(self): arglist = [ @@ -429,18 +540,10 @@ class TestImageList(TestImage): columns, data = self.cmd.take_action(parsed_args) self.api_mock.image_list.assert_called_with( private=True, - marker=image_fakes.image_id, ) - collist = ('ID', 'Name', 'Status') - - self.assertEqual(collist, columns) - datalist = (( - image_fakes.image_id, - image_fakes.image_name, - '', - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_image_list_shared_option(self): arglist = [ @@ -458,18 +561,10 @@ class TestImageList(TestImage): columns, data = self.cmd.take_action(parsed_args) self.api_mock.image_list.assert_called_with( shared=True, - marker=image_fakes.image_id, ) - collist = ('ID', 'Name', 'Status') - - self.assertEqual(columns, collist) - datalist = (( - image_fakes.image_id, - image_fakes.image_name, - '', - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_image_list_long_option(self): arglist = [ @@ -482,9 +577,7 @@ class TestImageList(TestImage): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) - self.api_mock.image_list.assert_called_with( - marker=image_fakes.image_id, - ) + self.api_mock.image_list.assert_called_with() collist = ( 'ID', @@ -495,7 +588,7 @@ class TestImageList(TestImage): 'Status', 'Visibility', 'Protected', - 'Owner', + 'Project', 'Tags', ) @@ -530,9 +623,7 @@ class TestImageList(TestImage): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) - self.api_mock.image_list.assert_called_with( - marker=image_fakes.image_id, - ) + self.api_mock.image_list.assert_called_with() sf_mock.assert_called_with( [image_fakes.IMAGE], attr='a', @@ -540,15 +631,8 @@ class TestImageList(TestImage): property_field='properties', ) - collist = ('ID', 'Name', 'Status') - - self.assertEqual(columns, collist) - datalist = (( - image_fakes.image_id, - image_fakes.image_name, - '', - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) @mock.patch('openstackclient.common.utils.sort_items') def test_image_list_sort_option(self, si_mock): @@ -562,23 +646,52 @@ class TestImageList(TestImage): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) - self.api_mock.image_list.assert_called_with( - marker=image_fakes.image_id, - ) + self.api_mock.image_list.assert_called_with() si_mock.assert_called_with( [image_fakes.IMAGE], 'name:asc' ) - collist = ('ID', 'Name', 'Status') + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) - self.assertEqual(collist, columns) - datalist = (( - image_fakes.image_id, - image_fakes.image_name, - '', - ), ) - self.assertEqual(datalist, tuple(data)) + def test_image_list_limit_option(self): + arglist = [ + '--limit', str(1), + ] + verifylist = [ + ('limit', 1), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + self.api_mock.image_list.assert_called_with( + limit=1, + ) + + self.assertEqual(self.columns, columns) + self.assertEqual(len(self.datalist), len(tuple(data))) + + @mock.patch('openstackclient.common.utils.find_resource') + def test_image_list_marker_option(self, fr_mock): + # tangchen: Since image_fakes.IMAGE is a dict, it cannot offer a .id + # operation. Will fix this by using FakeImage class instead + # of IMAGE dict. + fr_mock.return_value = mock.Mock() + fr_mock.return_value.id = image_fakes.image_id + + arglist = [ + '--marker', image_fakes.image_name, + ] + verifylist = [ + ('marker', image_fakes.image_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + self.api_mock.image_list.assert_called_with( + marker=image_fakes.image_id, + ) class TestRemoveProjectImage(TestImage): @@ -655,6 +768,18 @@ class TestImageSet(TestImage): schemas.SchemaBasedModel, ) + self.project_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.PROJECT), + loaded=True, + ) + + self.domain_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.DOMAIN), + loaded=True, + ) + self.images_mock.get.return_value = self.model(**image_fakes.IMAGE) self.images_mock.update.return_value = self.model(**image_fakes.IMAGE) # Get the command object to test @@ -663,20 +788,22 @@ class TestImageSet(TestImage): def test_image_set_options(self): arglist = [ '--name', 'new-name', - '--owner', 'new-owner', '--min-disk', '2', '--min-ram', '4', '--container-format', 'ovf', '--disk-format', 'vmdk', + '--project', identity_fakes.project_name, + '--project-domain', identity_fakes.domain_id, image_fakes.image_id, ] verifylist = [ ('name', 'new-name'), - ('owner', 'new-owner'), ('min_disk', 2), ('min_ram', 4), ('container_format', 'ovf'), ('disk_format', 'vmdk'), + ('project', identity_fakes.project_name), + ('project_domain', identity_fakes.domain_id), ('image', image_fakes.image_id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -686,7 +813,7 @@ class TestImageSet(TestImage): kwargs = { 'name': 'new-name', - 'owner': 'new-owner', + 'owner': identity_fakes.project_id, 'min_disk': 2, 'min_ram': 4, 'container_format': 'ovf', @@ -696,6 +823,44 @@ class TestImageSet(TestImage): self.images_mock.update.assert_called_with( image_fakes.image_id, **kwargs) + def test_image_set_with_unexist_owner(self): + self.project_mock.get.side_effect = exceptions.NotFound(None) + self.project_mock.find.side_effect = exceptions.NotFound(None) + + arglist = [ + '--owner', 'unexist_owner', + image_fakes.image_id, + ] + verifylist = [ + ('owner', 'unexist_owner'), + ('image', image_fakes.image_id), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.assertRaises( + exceptions.CommandError, + self.cmd.take_action, parsed_args) + + def test_image_set_with_unexist_project(self): + self.project_mock.get.side_effect = exceptions.NotFound(None) + self.project_mock.find.side_effect = exceptions.NotFound(None) + + arglist = [ + '--project', 'unexist_owner', + image_fakes.image_id, + ] + verifylist = [ + ('project', 'unexist_owner'), + ('image', image_fakes.image_id), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.assertRaises( + exceptions.CommandError, + self.cmd.take_action, parsed_args) + def test_image_set_bools1(self): arglist = [ '--protected', @@ -838,6 +1003,64 @@ class TestImageSet(TestImage): **kwargs ) + def test_image_set_activate(self): + arglist = [ + '--tag', 'test-tag', + '--activate', + image_fakes.image_name, + ] + verifylist = [ + ('tags', ['test-tag']), + ('image', image_fakes.image_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + self.cmd.take_action(parsed_args) + + kwargs = { + 'tags': ['test-tag'], + } + + self.images_mock.reactivate.assert_called_with( + image_fakes.image_id, + ) + + # ImageManager.update(image, **kwargs) + self.images_mock.update.assert_called_with( + image_fakes.image_id, + **kwargs + ) + + def test_image_set_deactivate(self): + arglist = [ + '--tag', 'test-tag', + '--deactivate', + image_fakes.image_name, + ] + verifylist = [ + ('tags', ['test-tag']), + ('image', image_fakes.image_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + self.cmd.take_action(parsed_args) + + kwargs = { + 'tags': ['test-tag'], + } + + self.images_mock.deactivate.assert_called_with( + image_fakes.image_id, + ) + + # ImageManager.update(image, **kwargs) + self.images_mock.update.assert_called_with( + image_fakes.image_id, + **kwargs + ) + def test_image_set_tag_merge(self): old_image = copy.copy(image_fakes.IMAGE) old_image['tags'] = ['old1', 'new2'] diff --git a/openstackclient/tests/network/test_common.py b/openstackclient/tests/network/test_common.py index b30fdfc..a3396b9 100644 --- a/openstackclient/tests/network/test_common.py +++ b/openstackclient/tests/network/test_common.py @@ -11,62 +11,93 @@ # under the License. # +import argparse import mock -from openstackclient.common import exceptions from openstackclient.network import common from openstackclient.tests import utils -RESOURCE = 'resource' -RESOURCES = 'resources' -NAME = 'matrix' -ID = 'Fishburne' - -class TestFind(utils.TestCase): +class FakeNetworkAndComputeCommand(common.NetworkAndComputeCommand): + def update_parser_common(self, parser): + parser.add_argument( + 'common', + metavar='<common>', + help='Common argument', + ) + return parser + + def update_parser_network(self, parser): + parser.add_argument( + 'network', + metavar='<network>', + help='Network argument', + ) + return parser + + def update_parser_compute(self, parser): + parser.add_argument( + 'compute', + metavar='<compute>', + help='Compute argument', + ) + return parser + + def take_action_network(self, client, parsed_args): + client.network_action(parsed_args) + return 'take_action_network' + + def take_action_compute(self, client, parsed_args): + client.compute_action(parsed_args) + return 'take_action_compute' + + +class TestNetworkAndComputeCommand(utils.TestCommand): def setUp(self): - super(TestFind, self).setUp() - self.mock_client = mock.Mock() - self.list_resources = mock.Mock() - self.mock_client.list_resources = self.list_resources - self.matrix = {'id': ID} - - def test_name(self): - self.list_resources.return_value = {RESOURCES: [self.matrix]} - - result = common.find(self.mock_client, RESOURCE, RESOURCES, NAME) - - self.assertEqual(ID, result) - self.list_resources.assert_called_with(fields='id', name=NAME) - - def test_id(self): - self.list_resources.side_effect = [{RESOURCES: []}, - {RESOURCES: [self.matrix]}] - - result = common.find(self.mock_client, RESOURCE, RESOURCES, NAME) - - self.assertEqual(ID, result) - self.list_resources.assert_called_with(fields='id', id=NAME) - - def test_nameo(self): - self.list_resources.return_value = {RESOURCES: [self.matrix]} - - result = common.find(self.mock_client, RESOURCE, RESOURCES, NAME, - name_attr='nameo') - - self.assertEqual(ID, result) - self.list_resources.assert_called_with(fields='id', nameo=NAME) - - def test_dups(self): - dup = {'id': 'Larry'} - self.list_resources.return_value = {RESOURCES: [self.matrix, dup]} - - self.assertRaises(exceptions.CommandError, common.find, - self.mock_client, RESOURCE, RESOURCES, NAME) - - def test_nada(self): - self.list_resources.side_effect = [{RESOURCES: []}, - {RESOURCES: []}] - - self.assertRaises(exceptions.CommandError, common.find, - self.mock_client, RESOURCE, RESOURCES, NAME) + super(TestNetworkAndComputeCommand, self).setUp() + + self.namespace = argparse.Namespace() + + # Create network client mocks. + self.app.client_manager.network = mock.Mock() + self.network = self.app.client_manager.network + self.network.network_action = mock.Mock(return_value=None) + + # Create compute client mocks. + self.app.client_manager.compute = mock.Mock() + self.compute = self.app.client_manager.compute + self.compute.compute_action = mock.Mock(return_value=None) + + # Get the command object to test + self.cmd = FakeNetworkAndComputeCommand(self.app, self.namespace) + + def test_take_action_network(self): + arglist = [ + 'common', + 'network' + ] + verifylist = [ + ('common', 'common'), + ('network', 'network') + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + self.network.network_action.assert_called_with(parsed_args) + self.assertEqual('take_action_network', result) + + def test_take_action_compute(self): + arglist = [ + 'common', + 'compute' + ] + verifylist = [ + ('common', 'common'), + ('compute', 'compute') + ] + + self.app.client_manager.network_endpoint_enabled = False + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + self.compute.compute_action.assert_called_with(parsed_args) + self.assertEqual('take_action_compute', result) diff --git a/openstackclient/tests/network/v2/fakes.py b/openstackclient/tests/network/v2/fakes.py index ea191c8..516995e 100644 --- a/openstackclient/tests/network/v2/fakes.py +++ b/openstackclient/tests/network/v2/fakes.py @@ -11,7 +11,13 @@ # under the License. # +import argparse +import copy import mock +import uuid + +from openstackclient.tests import fakes +from openstackclient.tests import utils extension_name = 'Matrix' extension_namespace = 'http://docs.openstack.org/network/' @@ -20,16 +26,530 @@ extension_updated = '2013-07-09T12:00:0-00:00' extension_alias = 'Dystopian' extension_links = '[{"href":''"https://github.com/os/network", "type"}]' -NETEXT = { - 'name': extension_name, - 'namespace': extension_namespace, - 'description': extension_description, - 'updated': extension_updated, - 'alias': extension_alias, - 'links': extension_links, +QUOTA = { + "subnet": 10, + "network": 10, + "floatingip": 50, + "subnetpool": -1, + "security_group_rule": 100, + "security_group": 10, + "router": 10, + "rbac_policy": -1, + "port": 50, } +def create_extension(): + extension = mock.Mock() + extension.name = extension_name + extension.namespace = extension_namespace + extension.description = extension_description + extension.updated = extension_updated + extension.alias = extension_alias + extension.links = extension_links + return extension + + class FakeNetworkV2Client(object): def __init__(self, **kwargs): - self.list_extensions = mock.Mock(return_value={'extensions': [NETEXT]}) + self.extensions = mock.Mock(return_value=[create_extension()]) + + +class TestNetworkV2(utils.TestCommand): + def setUp(self): + super(TestNetworkV2, self).setUp() + + self.namespace = argparse.Namespace() + + self.app.client_manager.session = mock.Mock() + + self.app.client_manager.network = FakeNetworkV2Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) + + +class FakeAvailabilityZone(object): + """Fake one or more network availability zones (AZs).""" + + @staticmethod + def create_one_availability_zone(attrs={}, methods={}): + """Create a fake AZ. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :return: + A FakeResource object with name, state, etc. + """ + # Set default attributes. + availability_zone = { + 'name': uuid.uuid4().hex, + 'state': 'available', + 'resource': 'network', + } + + # Overwrite default attributes. + availability_zone.update(attrs) + + availability_zone = fakes.FakeResource( + info=copy.deepcopy(availability_zone), + methods=methods, + loaded=True) + return availability_zone + + @staticmethod + def create_availability_zones(attrs={}, methods={}, count=2): + """Create multiple fake AZs. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :param int count: + The number of AZs to fake + :return: + A list of FakeResource objects faking the AZs + """ + availability_zones = [] + for i in range(0, count): + availability_zone = \ + FakeAvailabilityZone.create_one_availability_zone( + attrs, methods) + availability_zones.append(availability_zone) + + return availability_zones + + +class FakeNetwork(object): + """Fake one or more networks.""" + + @staticmethod + def create_one_network(attrs={}, methods={}): + """Create a fake network. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :return: + A FakeResource object, with id, name, admin_state_up, + router_external, status, subnets, tenant_id + """ + # Set default attributes. + project_id = 'project-id-' + uuid.uuid4().hex + network_attrs = { + 'id': 'network-id-' + uuid.uuid4().hex, + 'name': 'network-name-' + uuid.uuid4().hex, + 'status': 'ACTIVE', + 'tenant_id': project_id, + 'admin_state_up': True, + 'shared': False, + 'subnets': ['a', 'b'], + 'provider_network_type': 'vlan', + 'router_external': True, + 'availability_zones': [], + 'availability_zone_hints': [], + } + + # Overwrite default attributes. + network_attrs.update(attrs) + + # Set default methods. + network_methods = { + 'keys': ['id', 'name', 'admin_state_up', 'router_external', + 'status', 'subnets', 'tenant_id', 'availability_zones', + 'availability_zone_hints'], + } + + # Overwrite default methods. + network_methods.update(methods) + + network = fakes.FakeResource(info=copy.deepcopy(network_attrs), + methods=copy.deepcopy(network_methods), + loaded=True) + network.project_id = project_id + + return network + + @staticmethod + def create_networks(attrs={}, methods={}, count=2): + """Create multiple fake networks. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :param int count: + The number of networks to fake + :return: + A list of FakeResource objects faking the networks + """ + networks = [] + for i in range(0, count): + networks.append(FakeNetwork.create_one_network(attrs, methods)) + + return networks + + @staticmethod + def get_networks(networks=None, count=2): + """Get an iterable MagicMock object with a list of faked networks. + + If networks list is provided, then initialize the Mock object with the + list. Otherwise create one. + + :param List networks: + A list of FakeResource objects faking networks + :param int count: + The number of networks to fake + :return: + An iterable Mock object with side_effect set to a list of faked + networks + """ + if networks is None: + networks = FakeNetwork.create_networks(count) + return mock.MagicMock(side_effect=networks) + + +class FakePort(object): + """Fake one or more ports.""" + + @staticmethod + def create_one_port(attrs={}, methods={}): + """Create a fake port. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :return: + A FakeResource object, with id, name, etc. + """ + + # Set default attributes. + port_attrs = { + 'admin_state_up': True, + 'allowed_address_pairs': [{}], + 'binding:host_id': 'binding-host-id-' + uuid.uuid4().hex, + 'binding:profile': {}, + 'binding:vif_details': {}, + 'binding:vif_type': 'ovs', + 'binding:vnic_type': 'normal', + 'device_id': 'device-id-' + uuid.uuid4().hex, + 'device_owner': 'compute:nova', + 'dns_assignment': [{}], + 'dns_name': 'dns-name-' + uuid.uuid4().hex, + 'extra_dhcp_opts': [{}], + 'fixed_ips': [{}], + 'id': 'port-id-' + uuid.uuid4().hex, + 'mac_address': 'fa:16:3e:a9:4e:72', + 'name': 'port-name-' + uuid.uuid4().hex, + 'network_id': 'network-id-' + uuid.uuid4().hex, + 'port_security_enabled': True, + 'security_groups': [], + 'status': 'ACTIVE', + 'tenant_id': 'project-id-' + uuid.uuid4().hex, + } + + # Overwrite default attributes. + port_attrs.update(attrs) + + # Set default methods. + port_methods = { + 'keys': ['admin_state_up', 'allowed_address_pairs', + 'binding:host_id', 'binding:profile', + 'binding:vif_details', 'binding:vif_type', + 'binding:vnic_type', 'device_id', 'device_owner', + 'dns_assignment', 'dns_name', 'extra_dhcp_opts', + 'fixed_ips', 'id', 'mac_address', 'name', + 'network_id', 'port_security_enabled', + 'security_groups', 'status', 'tenant_id'], + } + + # Overwrite default methods. + port_methods.update(methods) + + port = fakes.FakeResource(info=copy.deepcopy(port_attrs), + methods=copy.deepcopy(port_methods), + loaded=True) + + # Set attributes with special mappings. + port.project_id = port_attrs['tenant_id'] + port.binding_host_id = port_attrs['binding:host_id'] + port.binding_profile = port_attrs['binding:profile'] + port.binding_vif_details = port_attrs['binding:vif_details'] + port.binding_vif_type = port_attrs['binding:vif_type'] + port.binding_vnic_type = port_attrs['binding:vnic_type'] + + return port + + @staticmethod + def create_ports(attrs={}, methods={}, count=2): + """Create multiple fake ports. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :param int count: + The number of ports to fake + :return: + A list of FakeResource objects faking the ports + """ + ports = [] + for i in range(0, count): + ports.append(FakePort.create_one_port(attrs, methods)) + + return ports + + @staticmethod + def get_ports(ports=None, count=2): + """Get an iterable MagicMock object with a list of faked ports. + + If ports list is provided, then initialize the Mock object with the + list. Otherwise create one. + + :param List ports: + A list of FakeResource objects faking ports + :param int count: + The number of ports to fake + :return: + An iterable Mock object with side_effect set to a list of faked + ports + """ + if ports is None: + ports = FakePort.create_ports(count) + return mock.MagicMock(side_effect=ports) + + +class FakeRouter(object): + """Fake one or more routers.""" + + @staticmethod + def create_one_router(attrs={}, methods={}): + """Create a fake router. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :return: + A FakeResource object, with id, name, admin_state_up, + status, tenant_id + """ + # Set default attributes. + router_attrs = { + 'id': 'router-id-' + uuid.uuid4().hex, + 'name': 'router-name-' + uuid.uuid4().hex, + 'status': 'ACTIVE', + 'admin_state_up': True, + 'distributed': False, + 'ha': False, + 'tenant_id': 'project-id-' + uuid.uuid4().hex, + 'routes': [], + 'external_gateway_info': {}, + 'availability_zone_hints': [], + 'availability_zones': [], + } + + # Overwrite default attributes. + router_attrs.update(attrs) + + # Set default methods. + router_methods = { + 'keys': ['id', 'name', 'admin_state_up', 'distributed', 'ha', + 'tenant_id'], + } + + # Overwrite default methods. + router_methods.update(methods) + + router = fakes.FakeResource(info=copy.deepcopy(router_attrs), + methods=copy.deepcopy(router_methods), + loaded=True) + return router + + @staticmethod + def create_routers(attrs={}, methods={}, count=2): + """Create multiple fake routers. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :param int count: + The number of routers to fake + :return: + A list of FakeResource objects faking the routers + """ + routers = [] + for i in range(0, count): + routers.append(FakeRouter.create_one_router(attrs, methods)) + + return routers + + @staticmethod + def get_routers(routers=None, count=2): + """Get an iterable MagicMock object with a list of faked routers. + + If routers list is provided, then initialize the Mock object with the + list. Otherwise create one. + + :param List routers: + A list of FakeResource objects faking routers + :param int count: + The number of routers to fake + :return: + An iterable Mock object with side_effect set to a list of faked + routers + """ + if routers is None: + routers = FakeRouter.create_routers(count) + return mock.MagicMock(side_effect=routers) + + +class FakeSecurityGroup(object): + """Fake one or more security groups.""" + + @staticmethod + def create_one_security_group(attrs={}, methods={}): + """Create a fake security group. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :return: + A FakeResource object, with id, name, etc. + """ + # Set default attributes. + security_group_attrs = { + 'id': 'security-group-id-' + uuid.uuid4().hex, + 'name': 'security-group-name-' + uuid.uuid4().hex, + 'description': 'security-group-description-' + uuid.uuid4().hex, + 'tenant_id': 'project-id-' + uuid.uuid4().hex, + 'security_group_rules': [], + } + + # Overwrite default attributes. + security_group_attrs.update(attrs) + + # Set default methods. + security_group_methods = {} + + # Overwrite default methods. + security_group_methods.update(methods) + + security_group = fakes.FakeResource( + info=copy.deepcopy(security_group_attrs), + methods=copy.deepcopy(security_group_methods), + loaded=True) + return security_group + + @staticmethod + def create_security_groups(attrs={}, methods={}, count=2): + """Create multiple fake security groups. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :param int count: + The number of security groups to fake + :return: + A list of FakeResource objects faking the security groups + """ + security_groups = [] + for i in range(0, count): + security_groups.append( + FakeRouter.create_one_security_group(attrs, methods)) + + return security_groups + + @staticmethod + def get_security_groups(security_groups=None, count=2): + """Get an iterable MagicMock object with a list of faked security groups. + + If security group list is provided, then initialize the Mock object + with the list. Otherwise create one. + + :param List security groups: + A list of FakeResource objects faking security groups + :param int count: + The number of security groups to fake + :return: + An iterable Mock object with side_effect set to a list of faked + security groups + """ + if security_groups is None: + security_groups = FakeRouter.create_security_groups(count) + return mock.MagicMock(side_effect=security_groups) + + +class FakeSubnet(object): + """Fake one or more subnets.""" + + @staticmethod + def create_one_subnet(attrs={}, methods={}): + """Create a fake subnet. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :return: + A FakeResource object faking the subnet + """ + # Set default attributes. + subnet_attrs = { + 'id': 'subnet-id-' + uuid.uuid4().hex, + 'name': 'subnet-name-' + uuid.uuid4().hex, + 'network_id': 'network-id-' + uuid.uuid4().hex, + 'cidr': '10.10.10.0/24', + 'tenant_id': 'project-id-' + uuid.uuid4().hex, + 'enable_dhcp': True, + 'dns_nameservers': [], + 'allocation_pools': [], + 'host_routes': [], + 'ip_version': '4', + 'gateway_ip': '10.10.10.1', + } + + # Overwrite default attributes. + subnet_attrs.update(attrs) + + # Set default methods. + subnet_methods = { + 'keys': ['id', 'name', 'network_id', 'cidr', 'enable_dhcp', + 'allocation_pools', 'dns_nameservers', 'gateway_ip', + 'host_routes', 'ip_version', 'tenant_id'] + } + + # Overwrite default methods. + subnet_methods.update(methods) + + subnet = fakes.FakeResource(info=copy.deepcopy(subnet_attrs), + methods=copy.deepcopy(subnet_methods), + loaded=True) + + return subnet + + @staticmethod + def create_subnets(attrs={}, methods={}, count=2): + """Create multiple fake subnets. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :param int count: + The number of subnets to fake + :return: + A list of FakeResource objects faking the subnets + """ + subnets = [] + for i in range(0, count): + subnets.append(FakeSubnet.create_one_subnet(attrs, methods)) + + return subnets diff --git a/openstackclient/tests/network/v2/test_network.py b/openstackclient/tests/network/v2/test_network.py index 5506259..f96497a 100644 --- a/openstackclient/tests/network/v2/test_network.py +++ b/openstackclient/tests/network/v2/test_network.py @@ -15,75 +15,120 @@ import copy import mock from openstackclient.common import exceptions +from openstackclient.common import utils from openstackclient.network.v2 import network from openstackclient.tests import fakes from openstackclient.tests.identity.v2_0 import fakes as identity_fakes_v2 from openstackclient.tests.identity.v3 import fakes as identity_fakes_v3 -from openstackclient.tests.network import common - -RESOURCE = 'network' -RESOURCES = 'networks' -FAKE_ID = 'iditty' -FAKE_NAME = 'noo' -FAKE_PROJECT = 'yaa' -RECORD = { - 'id': FAKE_ID, - 'name': FAKE_NAME, - 'admin_state_up': True, - 'router:external': True, - 'status': 'ACTIVE', - 'subnets': ['a', 'b'], - 'tenant_id': FAKE_PROJECT, -} -COLUMNS = ['ID', 'Name', 'Subnets'] -RESPONSE = {RESOURCE: copy.deepcopy(RECORD)} -FILTERED = [ - ( +from openstackclient.tests.network.v2 import fakes as network_fakes +from openstackclient.tests import utils as tests_utils + + +class TestNetwork(network_fakes.TestNetworkV2): + + def setUp(self): + super(TestNetwork, self).setUp() + + # Get a shortcut to the network client + self.network = self.app.client_manager.network + + +class TestCreateNetworkIdentityV3(TestNetwork): + + # The new network created. + _network = network_fakes.FakeNetwork.create_one_network( + attrs={ + 'tenant_id': identity_fakes_v3.project_id, + 'availability_zone_hints': ["nova"], + } + ) + + columns = ( + 'admin_state_up', + 'availability_zone_hints', + 'availability_zones', 'id', 'name', 'project_id', - 'router_type', - 'state', + 'router_external', 'status', 'subnets', - ), - ( - FAKE_ID, - FAKE_NAME, - FAKE_PROJECT, - 'External', - 'UP', - 'ACTIVE', - 'a, b', - ), -] - - -class TestCreateNetwork(common.TestNetworkBase): + ) + + data = ( + network._format_admin_state(_network.admin_state_up), + utils.format_list(_network.availability_zone_hints), + utils.format_list(_network.availability_zones), + _network.id, + _network.name, + _network.project_id, + network._format_router_external(_network.router_external), + _network.status, + utils.format_list(_network.subnets), + ) + + def setUp(self): + super(TestCreateNetworkIdentityV3, self).setUp() + + self.network.create_network = mock.Mock(return_value=self._network) + + # Get the command object to test + self.cmd = network.CreateNetwork(self.app, self.namespace) + + # Set identity client v3. And get a shortcut to Identity client. + identity_client = identity_fakes_v3.FakeIdentityv3Client( + endpoint=fakes.AUTH_URL, + token=fakes.AUTH_TOKEN, + ) + self.app.client_manager.identity = identity_client + self.identity = self.app.client_manager.identity + + # Get a shortcut to the ProjectManager Mock + self.projects_mock = self.identity.projects + self.projects_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes_v3.PROJECT), + loaded=True, + ) + + # Get a shortcut to the DomainManager Mock + self.domains_mock = self.identity.domains + self.domains_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes_v3.DOMAIN), + loaded=True, + ) + def test_create_no_options(self): + arglist = [] + verifylist = [] + + try: + # Missing required args should bail here + self.check_parser(self.cmd, arglist, verifylist) + except tests_utils.ParserException: + pass + + def test_create_default_options(self): arglist = [ - FAKE_NAME, + self._network.name, ] verifylist = [ - ('name', FAKE_NAME), + ('name', self._network.name), ('admin_state', True), ('shared', None), ('project', None), ] - mocker = mock.Mock(return_value=copy.deepcopy(RESPONSE)) - self.app.client_manager.network.create_network = mocker - cmd = network.CreateNetwork(self.app, self.namespace) - - parsed_args = self.check_parser(cmd, arglist, verifylist) - result = list(cmd.take_action(parsed_args)) - - mocker.assert_called_with({ - RESOURCE: { - 'admin_state_up': True, - 'name': FAKE_NAME, - } + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + + self.network.create_network.assert_called_with(**{ + 'admin_state_up': True, + 'name': self._network.name, }) - self.assertEqual(FILTERED, result) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) def test_create_all_options(self): arglist = [ @@ -91,175 +136,233 @@ class TestCreateNetwork(common.TestNetworkBase): "--share", "--project", identity_fakes_v3.project_name, "--project-domain", identity_fakes_v3.domain_name, - FAKE_NAME, + "--availability-zone-hint", "nova", + self._network.name, ] verifylist = [ ('admin_state', False), ('shared', True), ('project', identity_fakes_v3.project_name), ('project_domain', identity_fakes_v3.domain_name), - ('name', FAKE_NAME), + ('availability_zone_hints', ["nova"]), + ('name', self._network.name), ] - mocker = mock.Mock(return_value=copy.deepcopy(RESPONSE)) - self.app.client_manager.network.create_network = mocker - identity_client = identity_fakes_v3.FakeIdentityv3Client( - endpoint=fakes.AUTH_URL, - token=fakes.AUTH_TOKEN, - ) - self.app.client_manager.identity = identity_client - self.projects_mock = self.app.client_manager.identity.projects - self.projects_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes_v3.PROJECT), - loaded=True, - ) - self.domains_mock = self.app.client_manager.identity.domains - self.domains_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes_v3.DOMAIN), - loaded=True, - ) - cmd = network.CreateNetwork(self.app, self.namespace) - - parsed_args = self.check_parser(cmd, arglist, verifylist) - result = list(cmd.take_action(parsed_args)) - - mocker.assert_called_with({ - RESOURCE: { - 'admin_state_up': False, - 'name': FAKE_NAME, - 'shared': True, - 'tenant_id': identity_fakes_v3.project_id, - } + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = (self.cmd.take_action(parsed_args)) + + self.network.create_network.assert_called_with(**{ + 'admin_state_up': False, + 'availability_zone_hints': ["nova"], + 'name': self._network.name, + 'shared': True, + 'tenant_id': identity_fakes_v3.project_id, }) - self.assertEqual(FILTERED, result) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) def test_create_other_options(self): arglist = [ "--enable", "--no-share", - FAKE_NAME, + self._network.name, ] verifylist = [ ('admin_state', True), ('shared', False), - ('name', FAKE_NAME), + ('name', self._network.name), ] - mocker = mock.Mock(return_value=copy.deepcopy(RESPONSE)) - self.app.client_manager.network.create_network = mocker - cmd = network.CreateNetwork(self.app, self.namespace) - - parsed_args = self.check_parser(cmd, arglist, verifylist) - result = list(cmd.take_action(parsed_args)) - - mocker.assert_called_with({ - RESOURCE: { - 'admin_state_up': True, - 'name': FAKE_NAME, - 'shared': False, - } + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + + self.network.create_network.assert_called_with(**{ + 'admin_state_up': True, + 'name': self._network.name, + 'shared': False, }) - self.assertEqual(FILTERED, result) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) - def test_create_with_project_identityv2(self): - arglist = [ - "--project", identity_fakes_v2.project_name, - FAKE_NAME, - ] - verifylist = [ - ('admin_state', True), - ('shared', None), - ('name', FAKE_NAME), - ('project', identity_fakes_v2.project_name), - ] - mocker = mock.Mock(return_value=copy.deepcopy(RESPONSE)) - self.app.client_manager.network.create_network = mocker + +class TestCreateNetworkIdentityV2(TestNetwork): + + # The new network created. + _network = network_fakes.FakeNetwork.create_one_network( + attrs={'tenant_id': identity_fakes_v2.project_id} + ) + + columns = ( + 'admin_state_up', + 'availability_zone_hints', + 'availability_zones', + 'id', + 'name', + 'project_id', + 'router_external', + 'status', + 'subnets', + ) + + data = ( + network._format_admin_state(_network.admin_state_up), + utils.format_list(_network.availability_zone_hints), + utils.format_list(_network.availability_zones), + _network.id, + _network.name, + _network.project_id, + network._format_router_external(_network.router_external), + _network.status, + utils.format_list(_network.subnets), + ) + + def setUp(self): + super(TestCreateNetworkIdentityV2, self).setUp() + + self.network.create_network = mock.Mock(return_value=self._network) + + # Get the command object to test + self.cmd = network.CreateNetwork(self.app, self.namespace) + + # Set identity client v2. And get a shortcut to Identity client. identity_client = identity_fakes_v2.FakeIdentityv2Client( endpoint=fakes.AUTH_URL, token=fakes.AUTH_TOKEN, ) self.app.client_manager.identity = identity_client - self.projects_mock = self.app.client_manager.identity.tenants + self.identity = self.app.client_manager.identity + + # Get a shortcut to the ProjectManager Mock + self.projects_mock = self.identity.tenants self.projects_mock.get.return_value = fakes.FakeResource( None, copy.deepcopy(identity_fakes_v2.PROJECT), loaded=True, ) - cmd = network.CreateNetwork(self.app, self.namespace) - parsed_args = self.check_parser(cmd, arglist, verifylist) - result = list(cmd.take_action(parsed_args)) + # There is no DomainManager Mock in fake identity v2. - mocker.assert_called_with({ - RESOURCE: { - 'admin_state_up': True, - 'name': FAKE_NAME, - 'tenant_id': identity_fakes_v2.project_id, - } + def test_create_with_project_identityv2(self): + arglist = [ + "--project", identity_fakes_v2.project_name, + self._network.name, + ] + verifylist = [ + ('admin_state', True), + ('shared', None), + ('name', self._network.name), + ('project', identity_fakes_v2.project_name), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + + self.network.create_network.assert_called_with(**{ + 'admin_state_up': True, + 'name': self._network.name, + 'tenant_id': identity_fakes_v2.project_id, }) - self.assertEqual(FILTERED, result) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) def test_create_with_domain_identityv2(self): arglist = [ "--project", identity_fakes_v3.project_name, "--project-domain", identity_fakes_v3.domain_name, - FAKE_NAME, + self._network.name, ] verifylist = [ ('admin_state', True), ('shared', None), ('project', identity_fakes_v3.project_name), ('project_domain', identity_fakes_v3.domain_name), - ('name', FAKE_NAME), + ('name', self._network.name), ] - mocker = mock.Mock(return_value=copy.deepcopy(RESPONSE)) - self.app.client_manager.network.create_network = mocker - identity_client = identity_fakes_v2.FakeIdentityv2Client( - endpoint=fakes.AUTH_URL, - token=fakes.AUTH_TOKEN, - ) - self.app.client_manager.identity = identity_client - self.projects_mock = self.app.client_manager.identity.tenants - self.projects_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(identity_fakes_v2.PROJECT), - loaded=True, - ) - cmd = network.CreateNetwork(self.app, self.namespace) - parsed_args = self.check_parser(cmd, arglist, verifylist) + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) self.assertRaises( AttributeError, - cmd.take_action, + self.cmd.take_action, parsed_args, ) -class TestDeleteNetwork(common.TestNetworkBase): +class TestDeleteNetwork(TestNetwork): + + # The network to delete. + _network = network_fakes.FakeNetwork.create_one_network() + + def setUp(self): + super(TestDeleteNetwork, self).setUp() + + self.network.delete_network = mock.Mock(return_value=None) + + self.network.find_network = mock.Mock(return_value=self._network) + + # Get the command object to test + self.cmd = network.DeleteNetwork(self.app, self.namespace) + def test_delete(self): arglist = [ - FAKE_NAME, + self._network.name, ] verifylist = [ - ('networks', [FAKE_NAME]), + ('network', [self._network.name]), ] - lister = mock.Mock(return_value={RESOURCES: [copy.deepcopy(RECORD)]}) - self.app.client_manager.network.list_networks = lister - mocker = mock.Mock(return_value=None) - self.app.client_manager.network.delete_network = mocker - cmd = network.DeleteNetwork(self.app, self.namespace) - - parsed_args = self.check_parser(cmd, arglist, verifylist) - result = cmd.take_action(parsed_args) - - mocker.assert_called_with(FAKE_ID) - self.assertEqual(None, result) - -@mock.patch( - 'openstackclient.api.network_v2.APIv2.network_list' -) -class TestListNetwork(common.TestNetworkBase): + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + + self.network.delete_network.assert_called_with(self._network) + self.assertIsNone(result) + + +class TestListNetwork(TestNetwork): + + # The networks going to be listed up. + _network = network_fakes.FakeNetwork.create_networks(count=3) + + columns = ( + 'ID', + 'Name', + 'Subnets', + ) + columns_long = ( + 'ID', + 'Name', + 'Status', + 'Project', + 'State', + 'Shared', + 'Subnets', + 'Network Type', + 'Router Type', + 'Availability Zones', + ) + + data = [] + for net in _network: + data.append(( + net.id, + net.name, + utils.format_list(net.subnets), + )) + + data_long = [] + for net in _network: + data_long.append(( + net.id, + net.name, + net.status, + net.project_id, + network._format_admin_state(net.admin_state_up), + net.shared, + utils.format_list(net.subnets), + net.provider_network_type, + network._format_router_external(net.router_external), + utils.format_list(net.availability_zones), + )) def setUp(self): super(TestListNetwork, self).setUp() @@ -267,14 +370,9 @@ class TestListNetwork(common.TestNetworkBase): # Get the command object to test self.cmd = network.ListNetwork(self.app, self.namespace) - self.NETWORK_LIST = [ - copy.deepcopy(RECORD), - copy.deepcopy(RECORD), - ] - - def test_network_list_no_options(self, n_mock): - n_mock.return_value = self.NETWORK_LIST + self.network.networks = mock.Mock(return_value=self._network) + def test_network_list_no_options(self): arglist = [] verifylist = [ ('external', False), @@ -285,21 +383,11 @@ class TestListNetwork(common.TestNetworkBase): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) - # Set expected values - n_mock.assert_called_with( - external=False, - ) - - self.assertEqual(tuple(COLUMNS), columns) - datalist = [ - (FAKE_ID, FAKE_NAME, 'a, b'), - (FAKE_ID, FAKE_NAME, 'a, b'), - ] - self.assertEqual(datalist, list(data)) - - def test_list_external(self, n_mock): - n_mock.return_value = self.NETWORK_LIST + self.network.networks.assert_called_with() + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + def test_list_external(self): arglist = [ '--external', ] @@ -312,21 +400,13 @@ class TestListNetwork(common.TestNetworkBase): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) - # Set expected values - n_mock.assert_called_with( - external=True, + self.network.networks.assert_called_with( + **{'router:external': True} ) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) - self.assertEqual(tuple(COLUMNS), columns) - datalist = [ - (FAKE_ID, FAKE_NAME, 'a, b'), - (FAKE_ID, FAKE_NAME, 'a, b'), - ] - self.assertEqual(datalist, list(data)) - - def test_network_list_long(self, n_mock): - n_mock.return_value = self.NETWORK_LIST - + def test_network_list_long(self): arglist = [ '--long', ] @@ -339,145 +419,142 @@ class TestListNetwork(common.TestNetworkBase): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) - # Set expected values - n_mock.assert_called_with( - external=False, - ) + self.network.networks.assert_called_with() + self.assertEqual(self.columns_long, columns) + self.assertEqual(self.data_long, list(data)) - collist = ( - 'ID', - 'Name', - 'Status', - 'Project', - 'State', - 'Shared', - 'Subnets', - 'Network Type', - 'Router Type', - ) - self.assertEqual(columns, collist) - dataitem = ( - FAKE_ID, - FAKE_NAME, - 'ACTIVE', - FAKE_PROJECT, - 'UP', - '', - 'a, b', - '', - 'External', - ) - datalist = [ - dataitem, - dataitem, - ] - self.assertEqual(list(data), datalist) +class TestSetNetwork(TestNetwork): + + # The network to set. + _network = network_fakes.FakeNetwork.create_one_network() + + def setUp(self): + super(TestSetNetwork, self).setUp() + + self.network.update_network = mock.Mock(return_value=None) + + self.network.find_network = mock.Mock(return_value=self._network) + + # Get the command object to test + self.cmd = network.SetNetwork(self.app, self.namespace) -class TestSetNetwork(common.TestNetworkBase): def test_set_this(self): arglist = [ - FAKE_NAME, + self._network.name, '--enable', '--name', 'noob', '--share', ] verifylist = [ - ('identifier', FAKE_NAME), + ('identifier', self._network.name), ('admin_state', True), ('name', 'noob'), ('shared', True), ] - lister = mock.Mock(return_value={RESOURCES: [copy.deepcopy(RECORD)]}) - self.app.client_manager.network.list_networks = lister - mocker = mock.Mock(return_value=None) - self.app.client_manager.network.update_network = mocker - cmd = network.SetNetwork(self.app, self.namespace) - parsed_args = self.check_parser(cmd, arglist, verifylist) - result = cmd.take_action(parsed_args) + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) - exp = {'admin_state_up': True, 'name': 'noob', 'shared': True} - exp_record = {RESOURCE: exp} - mocker.assert_called_with(FAKE_ID, exp_record) - self.assertEqual(None, result) + attrs = { + 'name': 'noob', + 'admin_state_up': True, + 'shared': True, + } + self.network.update_network.assert_called_with(self._network, **attrs) + self.assertIsNone(result) def test_set_that(self): arglist = [ - FAKE_NAME, + self._network.name, '--disable', '--no-share', ] verifylist = [ - ('identifier', FAKE_NAME), + ('identifier', self._network.name), ('admin_state', False), ('shared', False), ] - lister = mock.Mock(return_value={RESOURCES: [copy.deepcopy(RECORD)]}) - self.app.client_manager.network.list_networks = lister - mocker = mock.Mock(return_value=None) - self.app.client_manager.network.update_network = mocker - cmd = network.SetNetwork(self.app, self.namespace) - parsed_args = self.check_parser(cmd, arglist, verifylist) - result = cmd.take_action(parsed_args) + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) - exp = {'admin_state_up': False, 'shared': False} - exp_record = {RESOURCE: exp} - mocker.assert_called_with(FAKE_ID, exp_record) - self.assertEqual(None, result) + attrs = { + 'admin_state_up': False, + 'shared': False, + } + self.network.update_network.assert_called_with(self._network, **attrs) + self.assertIsNone(result) def test_set_nothing(self): - arglist = [FAKE_NAME, ] - verifylist = [('identifier', FAKE_NAME), ] - lister = mock.Mock(return_value={RESOURCES: [copy.deepcopy(RECORD)]}) - self.app.client_manager.network.list_networks = lister - mocker = mock.Mock(return_value=None) - self.app.client_manager.network.update_network = mocker - cmd = network.SetNetwork(self.app, self.namespace) - - parsed_args = self.check_parser(cmd, arglist, verifylist) - self.assertRaises(exceptions.CommandError, cmd.take_action, + arglist = [self._network.name, ] + verifylist = [('identifier', self._network.name), ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.assertRaises(exceptions.CommandError, self.cmd.take_action, parsed_args) -@mock.patch( - 'openstackclient.api.network_v2.APIv2.find_attr' -) -class TestShowNetwork(common.TestNetworkBase): +class TestShowNetwork(TestNetwork): + + # The network to set. + _network = network_fakes.FakeNetwork.create_one_network() + + columns = ( + 'admin_state_up', + 'availability_zone_hints', + 'availability_zones', + 'id', + 'name', + 'project_id', + 'router_external', + 'status', + 'subnets', + ) + + data = ( + network._format_admin_state(_network.admin_state_up), + utils.format_list(_network.availability_zone_hints), + utils.format_list(_network.availability_zones), + _network.id, + _network.name, + _network.project_id, + network._format_router_external(_network.router_external), + _network.status, + utils.format_list(_network.subnets), + ) def setUp(self): super(TestShowNetwork, self).setUp() + self.network.find_network = mock.Mock(return_value=self._network) + # Get the command object to test self.cmd = network.ShowNetwork(self.app, self.namespace) - self.NETWORK_ITEM = copy.deepcopy(RECORD) + def test_show_no_options(self): + arglist = [] + verifylist = [] - def test_show_no_options(self, n_mock): + try: + # Missing required args should bail here + self.check_parser(self.cmd, arglist, verifylist) + except tests_utils.ParserException: + pass + + def test_show_all_options(self): arglist = [ - FAKE_NAME, + self._network.name, ] verifylist = [ - ('identifier', FAKE_NAME), + ('identifier', self._network.name), ] - n_mock.return_value = copy.deepcopy(RECORD) - self.cmd = network.ShowNetwork(self.app, self.namespace) parsed_args = self.check_parser(self.cmd, arglist, verifylist) - result = list(self.cmd.take_action(parsed_args)) - - n_mock.assert_called_with('networks', FAKE_NAME) - self.assertEqual(FILTERED, result) - - def test_show_all_options(self, n_mock): - arglist = [FAKE_NAME] - verifylist = [('identifier', FAKE_NAME)] - n_mock.return_value = copy.deepcopy(RECORD) - self.cmd = network.ShowNetwork(self.app, self.namespace) + columns, data = self.cmd.take_action(parsed_args) - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - result = list(self.cmd.take_action(parsed_args)) + self.network.find_network.assert_called_with(self._network.name, + ignore_missing=False) - n_mock.assert_called_with('networks', FAKE_NAME) - self.assertEqual(FILTERED, result) + self.assertEqual(tuple(self.columns), columns) + self.assertEqual(list(self.data), list(data)) diff --git a/openstackclient/tests/network/v2/test_port.py b/openstackclient/tests/network/v2/test_port.py new file mode 100644 index 0000000..bc246bd --- /dev/null +++ b/openstackclient/tests/network/v2/test_port.py @@ -0,0 +1,140 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import mock + +from openstackclient.common import utils +from openstackclient.network.v2 import port +from openstackclient.tests.network.v2 import fakes as network_fakes +from openstackclient.tests import utils as tests_utils + + +class TestPort(network_fakes.TestNetworkV2): + + def setUp(self): + super(TestPort, self).setUp() + + # Get a shortcut to the network client + self.network = self.app.client_manager.network + + +class TestDeletePort(TestPort): + + # The port to delete. + _port = network_fakes.FakePort.create_one_port() + + def setUp(self): + super(TestDeletePort, self).setUp() + + self.network.delete_port = mock.Mock(return_value=None) + self.network.find_port = mock.Mock(return_value=self._port) + # Get the command object to test + self.cmd = port.DeletePort(self.app, self.namespace) + + def test_delete(self): + arglist = [ + self._port.name, + ] + verifylist = [ + ('port', [self._port.name]), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + self.network.delete_port.assert_called_with(self._port) + self.assertIsNone(result) + + +class TestShowPort(TestPort): + + # The port to show. + _port = network_fakes.FakePort.create_one_port() + + columns = ( + 'admin_state_up', + 'allowed_address_pairs', + 'binding_host_id', + 'binding_profile', + 'binding_vif_details', + 'binding_vif_type', + 'binding_vnic_type', + 'device_id', + 'device_owner', + 'dns_assignment', + 'dns_name', + 'extra_dhcp_opts', + 'fixed_ips', + 'id', + 'mac_address', + 'name', + 'network_id', + 'port_security_enabled', + 'project_id', + 'security_groups', + 'status', + ) + + data = ( + port._format_admin_state(_port.admin_state_up), + utils.format_list_of_dicts(_port.allowed_address_pairs), + _port.binding_host_id, + utils.format_dict(_port.binding_profile), + utils.format_dict(_port.binding_vif_details), + _port.binding_vif_type, + _port.binding_vnic_type, + _port.device_id, + _port.device_owner, + utils.format_list_of_dicts(_port.dns_assignment), + _port.dns_name, + utils.format_list_of_dicts(_port.extra_dhcp_opts), + utils.format_list_of_dicts(_port.fixed_ips), + _port.id, + _port.mac_address, + _port.name, + _port.network_id, + _port.port_security_enabled, + _port.project_id, + utils.format_list(_port.security_groups), + _port.status, + ) + + def setUp(self): + super(TestShowPort, self).setUp() + + self.network.find_port = mock.Mock(return_value=self._port) + + # Get the command object to test + self.cmd = port.ShowPort(self.app, self.namespace) + + def test_show_no_options(self): + arglist = [] + verifylist = [] + + self.assertRaises(tests_utils.ParserException, + self.check_parser, self.cmd, arglist, verifylist) + + def test_show_all_options(self): + arglist = [ + self._port.name, + ] + verifylist = [ + ('port', self._port.name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.network.find_port.assert_called_with(self._port.name, + ignore_missing=False) + self.assertEqual(tuple(self.columns), columns) + self.assertEqual(self.data, data) diff --git a/openstackclient/tests/network/v2/test_router.py b/openstackclient/tests/network/v2/test_router.py new file mode 100644 index 0000000..98e9f17 --- /dev/null +++ b/openstackclient/tests/network/v2/test_router.py @@ -0,0 +1,372 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import mock + +from openstackclient.common import exceptions +from openstackclient.common import utils as osc_utils +from openstackclient.network.v2 import router +from openstackclient.tests.network.v2 import fakes as network_fakes +from openstackclient.tests import utils as tests_utils + + +class TestRouter(network_fakes.TestNetworkV2): + + def setUp(self): + super(TestRouter, self).setUp() + + # Get a shortcut to the network client + self.network = self.app.client_manager.network + + +class TestCreateRouter(TestRouter): + + # The new router created. + new_router = network_fakes.FakeRouter.create_one_router() + + columns = ( + 'admin_state_up', + 'distributed', + 'ha', + 'id', + 'name', + 'project_id', + ) + data = ( + router._format_admin_state(new_router.admin_state_up), + new_router.distributed, + new_router.ha, + new_router.id, + new_router.name, + new_router.tenant_id, + ) + + def setUp(self): + super(TestCreateRouter, self).setUp() + + self.network.create_router = mock.Mock(return_value=self.new_router) + + # Get the command object to test + self.cmd = router.CreateRouter(self.app, self.namespace) + + def test_create_no_options(self): + arglist = [] + verifylist = [] + + try: + self.check_parser(self.cmd, arglist, verifylist) + except tests_utils.ParserException: + pass + + def test_create_default_options(self): + arglist = [ + self.new_router.name, + ] + verifylist = [ + ('name', self.new_router.name), + ('admin_state_up', True), + ('distributed', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = (self.cmd.take_action(parsed_args)) + + self.network.create_router.assert_called_with(**{ + 'admin_state_up': True, + 'name': self.new_router.name, + 'distributed': False, + }) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + def test_create_with_AZ_hints(self): + arglist = [ + self.new_router.name, + '--availability-zone-hint', 'fake-az', + '--availability-zone-hint', 'fake-az2', + ] + verifylist = [ + ('name', self.new_router.name), + ('availability_zone_hints', ['fake-az', 'fake-az2']), + ('admin_state_up', True), + ('distributed', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = (self.cmd.take_action(parsed_args)) + self.network.create_router.assert_called_with(**{ + 'admin_state_up': True, + 'name': self.new_router.name, + 'distributed': False, + 'availability_zone_hints': ['fake-az', 'fake-az2'], + }) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + +class TestDeleteRouter(TestRouter): + + # The router to delete. + _router = network_fakes.FakeRouter.create_one_router() + + def setUp(self): + super(TestDeleteRouter, self).setUp() + + self.network.delete_router = mock.Mock(return_value=None) + + self.network.find_router = mock.Mock(return_value=self._router) + + # Get the command object to test + self.cmd = router.DeleteRouter(self.app, self.namespace) + + def test_delete(self): + arglist = [ + self._router.name, + ] + verifylist = [ + ('router', [self._router.name]), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + self.network.delete_router.assert_called_with(self._router) + self.assertIsNone(result) + + +class TestListRouter(TestRouter): + + # The routers going to be listed up. + routers = network_fakes.FakeRouter.create_routers(count=3) + + columns = ( + 'ID', + 'Name', + 'Status', + 'State', + 'Distributed', + 'HA', + 'Project', + ) + columns_long = columns + ( + 'Routes', + 'External gateway info', + 'Availability zones' + ) + + data = [] + for r in routers: + data.append(( + r.id, + r.name, + r.status, + router._format_admin_state(r.admin_state_up), + r.distributed, + r.ha, + r.tenant_id, + )) + data_long = [] + for i in range(0, len(routers)): + r = routers[i] + data_long.append( + data[i] + ( + r.routes, + router._format_external_gateway_info(r.external_gateway_info), + osc_utils.format_list(r.availability_zones), + ) + ) + + def setUp(self): + super(TestListRouter, self).setUp() + + # Get the command object to test + self.cmd = router.ListRouter(self.app, self.namespace) + + self.network.routers = mock.Mock(return_value=self.routers) + + def test_router_list_no_options(self): + arglist = [] + verifylist = [ + ('long', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + self.network.routers.assert_called_with() + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_router_list_long(self): + arglist = [ + '--long', + ] + verifylist = [ + ('long', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + self.network.routers.assert_called_with() + self.assertEqual(self.columns_long, columns) + self.assertEqual(self.data_long, list(data)) + + +class TestSetRouter(TestRouter): + + # The router to set. + _router = network_fakes.FakeRouter.create_one_router() + + def setUp(self): + super(TestSetRouter, self).setUp() + + self.network.update_router = mock.Mock(return_value=None) + + self.network.find_router = mock.Mock(return_value=self._router) + + # Get the command object to test + self.cmd = router.SetRouter(self.app, self.namespace) + + def test_set_this(self): + arglist = [ + self._router.name, + '--enable', + '--distributed', + '--name', 'noob', + ] + verifylist = [ + ('router', self._router.name), + ('admin_state_up', True), + ('distributed', True), + ('name', 'noob'), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + + attrs = { + 'admin_state_up': True, + 'distributed': True, + 'name': 'noob', + } + self.network.update_router.assert_called_with(self._router, **attrs) + self.assertIsNone(result) + + def test_set_that(self): + arglist = [ + self._router.name, + '--disable', + '--centralized', + ] + verifylist = [ + ('router', self._router.name), + ('admin_state_up', False), + ('distributed', False), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + + attrs = { + 'admin_state_up': False, + 'distributed': False, + } + self.network.update_router.assert_called_with(self._router, **attrs) + self.assertIsNone(result) + + def test_set_distributed_centralized(self): + arglist = [ + self._router.name, + '--distributed', + '--centralized', + ] + verifylist = [ + ('router', self._router.name), + ('distributed', True), + ('distributed', False), + ] + + try: + # Argument parse failing should bail here + self.check_parser(self.cmd, arglist, verifylist) + except tests_utils.ParserException: + pass + + def test_set_nothing(self): + arglist = [self._router.name, ] + verifylist = [('router', self._router.name), ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.assertRaises(exceptions.CommandError, self.cmd.take_action, + parsed_args) + + +class TestShowRouter(TestRouter): + + # The router to set. + _router = network_fakes.FakeRouter.create_one_router() + + columns = ( + 'admin_state_up', + 'distributed', + 'ha', + 'id', + 'name', + 'tenant_id', + ) + + data = ( + router._format_admin_state(_router.admin_state_up), + _router.distributed, + _router.ha, + _router.id, + _router.name, + _router.tenant_id, + ) + + def setUp(self): + super(TestShowRouter, self).setUp() + + self.network.find_router = mock.Mock(return_value=self._router) + + # Get the command object to test + self.cmd = router.ShowRouter(self.app, self.namespace) + + def test_show_no_options(self): + arglist = [] + verifylist = [] + + try: + # Missing required args should bail here + self.check_parser(self.cmd, arglist, verifylist) + except tests_utils.ParserException: + pass + + def test_show_all_options(self): + arglist = [ + self._router.name, + ] + verifylist = [ + ('router', self._router.name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.network.find_router.assert_called_with(self._router.name, + ignore_missing=False) + self.assertEqual(tuple(self.columns), columns) + self.assertEqual(self.data, data) diff --git a/openstackclient/tests/network/v2/test_security_group.py b/openstackclient/tests/network/v2/test_security_group.py new file mode 100644 index 0000000..98388ec --- /dev/null +++ b/openstackclient/tests/network/v2/test_security_group.py @@ -0,0 +1,99 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import mock + +from openstackclient.network.v2 import security_group +from openstackclient.tests.network.v2 import fakes as network_fakes + + +class TestSecurityGroup(network_fakes.TestNetworkV2): + + def setUp(self): + super(TestSecurityGroup, self).setUp() + + # Get a shortcut to the network client + self.network = self.app.client_manager.network + + # Create compute client mocks. + self.app.client_manager.compute = mock.Mock() + self.compute = self.app.client_manager.compute + self.compute.security_groups = mock.Mock() + + +class TestDeleteSecurityGroupNetwork(TestSecurityGroup): + + # The security group to be deleted. + _security_group = \ + network_fakes.FakeSecurityGroup.create_one_security_group() + + def setUp(self): + super(TestDeleteSecurityGroupNetwork, self).setUp() + + self.network.delete_security_group = mock.Mock(return_value=None) + + self.network.find_security_group = mock.Mock( + return_value=self._security_group) + + # Get the command object to test + self.cmd = security_group.DeleteSecurityGroup(self.app, self.namespace) + + def test_security_group_delete(self): + arglist = [ + self._security_group.name, + ] + verifylist = [ + ('group', self._security_group.name), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + + self.network.delete_security_group.assert_called_with( + self._security_group) + self.assertEqual(None, result) + + +class TestDeleteSecurityGroupCompute(TestSecurityGroup): + + # The security group to be deleted. + _security_group = \ + network_fakes.FakeSecurityGroup.create_one_security_group() + + def setUp(self): + super(TestDeleteSecurityGroupCompute, self).setUp() + + self.app.client_manager.network_endpoint_enabled = False + + self.compute.security_groups.delete = mock.Mock(return_value=None) + + self.compute.security_groups.get = mock.Mock( + return_value=self._security_group) + + # Get the command object to test + self.cmd = security_group.DeleteSecurityGroup(self.app, self.namespace) + + def test_security_group_delete(self): + arglist = [ + self._security_group.name, + ] + verifylist = [ + ('group', self._security_group.name), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + + self.compute.security_groups.delete.assert_called_with( + self._security_group.id) + self.assertEqual(None, result) diff --git a/openstackclient/tests/network/v2/test_subnet.py b/openstackclient/tests/network/v2/test_subnet.py new file mode 100644 index 0000000..5fca5ed --- /dev/null +++ b/openstackclient/tests/network/v2/test_subnet.py @@ -0,0 +1,108 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import mock + +from openstackclient.common import utils +from openstackclient.network.v2 import subnet as subnet_v2 +from openstackclient.tests.network.v2 import fakes as network_fakes + + +class TestSubnet(network_fakes.TestNetworkV2): + def setUp(self): + super(TestSubnet, self).setUp() + + # Get a shortcut to the network client + self.network = self.app.client_manager.network + + +class TestListSubnet(TestSubnet): + # The subnets going to be listed up. + _subnet = network_fakes.FakeSubnet.create_subnets(count=3) + + columns = ( + 'ID', + 'Name', + 'Network', + 'Subnet' + ) + columns_long = columns + ( + 'Project', + 'DHCP', + 'Name Servers', + 'Allocation Pools', + 'Host Routes', + 'IP Version', + 'Gateway' + ) + + data = [] + for subnet in _subnet: + data.append(( + subnet.id, + subnet.name, + subnet.network_id, + subnet.cidr, + )) + + data_long = [] + for subnet in _subnet: + data_long.append(( + subnet.id, + subnet.name, + subnet.network_id, + subnet.cidr, + subnet.tenant_id, + subnet.enable_dhcp, + utils.format_list(subnet.dns_nameservers), + subnet_v2._format_allocation_pools(subnet.allocation_pools), + utils.format_list(subnet.host_routes), + subnet.ip_version, + subnet.gateway_ip + )) + + def setUp(self): + super(TestListSubnet, self).setUp() + + # Get the command object to test + self.cmd = subnet_v2.ListSubnet(self.app, self.namespace) + + self.network.subnets = mock.Mock(return_value=self._subnet) + + def test_subnet_list_no_options(self): + arglist = [] + verifylist = [ + ('long', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.network.subnets.assert_called_with() + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_subnet_list_long(self): + arglist = [ + '--long', + ] + verifylist = [ + ('long', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.network.subnets.assert_called_with() + self.assertEqual(self.columns_long, columns) + self.assertEqual(self.data_long, list(data)) diff --git a/openstackclient/tests/object/v1/test_container.py b/openstackclient/tests/object/v1/test_container.py index 2ef2f7b..afcb338 100644 --- a/openstackclient/tests/object/v1/test_container.py +++ b/openstackclient/tests/object/v1/test_container.py @@ -32,6 +32,9 @@ class FakeClient(object): class TestContainer(object_fakes.TestObjectv1): + + columns = ('Name',) + def setUp(self): super(TestContainer, self).setUp() self.app.client_manager.object_store = object_store.APIv1( @@ -73,8 +76,7 @@ class TestContainerList(TestContainer): **kwargs ) - collist = ('Name',) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( (object_fakes.container_name, ), (object_fakes.container_name_3, ), @@ -107,8 +109,7 @@ class TestContainerList(TestContainer): **kwargs ) - collist = ('Name',) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( (object_fakes.container_name, ), (object_fakes.container_name_3, ), @@ -143,8 +144,7 @@ class TestContainerList(TestContainer): **kwargs ) - collist = ('Name',) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( (object_fakes.container_name, ), (object_fakes.container_name_3, ), @@ -176,8 +176,7 @@ class TestContainerList(TestContainer): **kwargs ) - collist = ('Name',) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( (object_fakes.container_name, ), (object_fakes.container_name_3, ), @@ -250,8 +249,7 @@ class TestContainerList(TestContainer): **kwargs ) - collist = ('Name',) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( (object_fakes.container_name, ), (object_fakes.container_name_2, ), diff --git a/openstackclient/tests/object/v1/test_container_all.py b/openstackclient/tests/object/v1/test_container_all.py index 69fc0f3..c2dd02a 100644 --- a/openstackclient/tests/object/v1/test_container_all.py +++ b/openstackclient/tests/object/v1/test_container_all.py @@ -29,6 +29,12 @@ class TestContainerAll(object_fakes.TestObjectv1): class TestContainerCreate(TestContainerAll): + columns = ( + 'account', + 'container', + 'x-trans-id', + ) + def setUp(self): super(TestContainerCreate, self).setUp() @@ -54,8 +60,7 @@ class TestContainerCreate(TestContainerAll): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) - collist = ('account', 'container', 'x-trans-id') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = [( object_fakes.ACCOUNT_ID, 'ernie', @@ -89,8 +94,7 @@ class TestContainerCreate(TestContainerAll): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) - collist = ('account', 'container', 'x-trans-id') - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = [ ( object_fakes.ACCOUNT_ID, @@ -161,6 +165,8 @@ class TestContainerDelete(TestContainerAll): class TestContainerList(TestContainerAll): + columns = ('Name',) + def setUp(self): super(TestContainerList, self).setUp() @@ -187,8 +193,7 @@ class TestContainerList(TestContainerAll): # Lister.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) - collist = ('Name',) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = [ (object_fakes.container_name, ), (object_fakes.container_name_3, ), @@ -219,8 +224,7 @@ class TestContainerList(TestContainerAll): # Lister.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) - collist = ('Name',) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = [ (object_fakes.container_name, ), (object_fakes.container_name_3, ), diff --git a/openstackclient/tests/object/v1/test_object.py b/openstackclient/tests/object/v1/test_object.py index 305fe8f..f0d62f6 100644 --- a/openstackclient/tests/object/v1/test_object.py +++ b/openstackclient/tests/object/v1/test_object.py @@ -40,6 +40,13 @@ class TestObject(object_fakes.TestObjectv1): ) class TestObjectList(TestObject): + columns = ('Name',) + datalist = ( + ( + object_fakes.object_name_2, + ), + ) + def setUp(self): super(TestObjectList, self).setUp() @@ -67,8 +74,7 @@ class TestObjectList(TestObject): container=object_fakes.container_name, ) - collist = ('Name',) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( (object_fakes.object_name_1, ), (object_fakes.object_name_2, ), @@ -102,12 +108,8 @@ class TestObjectList(TestObject): **kwargs ) - collist = ('Name',) - self.assertEqual(collist, columns) - datalist = ( - (object_fakes.object_name_2, ), - ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_object_list_objects_delimiter(self, o_mock): o_mock.return_value = [ @@ -136,12 +138,8 @@ class TestObjectList(TestObject): **kwargs ) - collist = ('Name',) - self.assertEqual(collist, columns) - datalist = ( - (object_fakes.object_name_2, ), - ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_object_list_objects_marker(self, o_mock): o_mock.return_value = [ @@ -170,12 +168,8 @@ class TestObjectList(TestObject): **kwargs ) - collist = ('Name',) - self.assertEqual(collist, columns) - datalist = ( - (object_fakes.object_name_2, ), - ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_object_list_objects_end_marker(self, o_mock): o_mock.return_value = [ @@ -204,12 +198,8 @@ class TestObjectList(TestObject): **kwargs ) - collist = ('Name',) - self.assertEqual(collist, columns) - datalist = ( - (object_fakes.object_name_2, ), - ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_object_list_objects_limit(self, o_mock): o_mock.return_value = [ @@ -238,12 +228,8 @@ class TestObjectList(TestObject): **kwargs ) - collist = ('Name',) - self.assertEqual(collist, columns) - datalist = ( - (object_fakes.object_name_2, ), - ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_object_list_objects_long(self, o_mock): o_mock.return_value = [ @@ -320,8 +306,7 @@ class TestObjectList(TestObject): **kwargs ) - collist = ('Name',) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( (object_fakes.object_name_1, ), (object_fakes.object_name_2, ), diff --git a/openstackclient/tests/object/v1/test_object_all.py b/openstackclient/tests/object/v1/test_object_all.py index 7a76ab7..a90e5b6 100644 --- a/openstackclient/tests/object/v1/test_object_all.py +++ b/openstackclient/tests/object/v1/test_object_all.py @@ -37,6 +37,8 @@ class TestObjectCreate(TestObjectAll): class TestObjectList(TestObjectAll): + columns = ('Name',) + def setUp(self): super(TestObjectList, self).setUp() @@ -69,8 +71,7 @@ class TestObjectList(TestObjectAll): # Lister.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) - collist = ('Name',) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = [ (object_fakes.object_name_1, ), (object_fakes.object_name_2, ), @@ -104,8 +105,7 @@ class TestObjectList(TestObjectAll): # DisplayCommandBase.take_action() returns two tuples columns, data = self.cmd.take_action(parsed_args) - collist = ('Name',) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( (object_fakes.object_name_2, ), ) diff --git a/openstackclient/tests/test_shell.py b/openstackclient/tests/test_shell.py index c548d89..c4546d8 100644 --- a/openstackclient/tests/test_shell.py +++ b/openstackclient/tests/test_shell.py @@ -76,7 +76,7 @@ CLOUD_2 = { 'project_name': 'heart-o-gold', 'username': 'zaphod', }, - 'region_name': 'occ-cloud', + 'region_name': 'occ-cloud,krikkit,occ-env', 'log_file': '/tmp/test_log_file', 'log_level': 'debug', } diff --git a/openstackclient/tests/volume/v1/test_qos_specs.py b/openstackclient/tests/volume/v1/test_qos_specs.py index c2e6c0a..7ecc8ee 100644 --- a/openstackclient/tests/volume/v1/test_qos_specs.py +++ b/openstackclient/tests/volume/v1/test_qos_specs.py @@ -69,6 +69,18 @@ class TestQosAssociate(TestQos): class TestQosCreate(TestQos): + + columns = ( + 'consumer', + 'id', + 'name', + ) + datalist = ( + volume_fakes.qos_consumer, + volume_fakes.qos_id, + volume_fakes.qos_name + ) + def setUp(self): super(TestQosCreate, self).setUp() @@ -97,12 +109,7 @@ class TestQosCreate(TestQos): {'consumer': volume_fakes.qos_default_consumer} ) - collist = ( - 'consumer', - 'id', - 'name' - ) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( volume_fakes.qos_default_consumer, volume_fakes.qos_id, @@ -133,19 +140,8 @@ class TestQosCreate(TestQos): volume_fakes.qos_name, {'consumer': volume_fakes.qos_consumer} ) - - collist = ( - 'consumer', - 'id', - 'name' - ) - self.assertEqual(collist, columns) - datalist = ( - volume_fakes.qos_consumer, - volume_fakes.qos_id, - volume_fakes.qos_name - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_qos_create_with_properties(self): self.qos_mock.create.return_value = fakes.FakeResource( @@ -176,17 +172,11 @@ class TestQosCreate(TestQos): specs ) - collist = ( - 'consumer', - 'id', - 'name', + columns = self.columns + ( 'specs', ) - self.assertEqual(collist, columns) - datalist = ( - volume_fakes.qos_consumer, - volume_fakes.qos_id, - volume_fakes.qos_name, + self.assertEqual(columns, columns) + datalist = self.datalist + ( volume_fakes.qos_specs, ) self.assertEqual(datalist, data) diff --git a/openstackclient/tests/volume/v1/test_volume.py b/openstackclient/tests/volume/v1/test_volume.py index 70ff50d..33255aa 100644 --- a/openstackclient/tests/volume/v1/test_volume.py +++ b/openstackclient/tests/volume/v1/test_volume.py @@ -49,6 +49,29 @@ class TestVolume(volume_fakes.TestVolumev1): class TestVolumeCreate(TestVolume): + columns = ( + 'attach_status', + 'availability_zone', + 'display_description', + 'display_name', + 'id', + 'properties', + 'size', + 'status', + 'type', + ) + datalist = ( + 'detached', + volume_fakes.volume_zone, + volume_fakes.volume_description, + volume_fakes.volume_name, + volume_fakes.volume_id, + volume_fakes.volume_metadata_str, + volume_fakes.volume_size, + volume_fakes.volume_status, + volume_fakes.volume_type, + ) + def setUp(self): super(TestVolumeCreate, self).setUp() @@ -93,31 +116,8 @@ class TestVolumeCreate(TestVolume): None, None, ) - - collist = ( - 'attach_status', - 'availability_zone', - 'display_description', - 'display_name', - 'id', - 'properties', - 'size', - 'status', - 'type', - ) - self.assertEqual(collist, columns) - datalist = ( - 'detached', - volume_fakes.volume_zone, - volume_fakes.volume_description, - volume_fakes.volume_name, - volume_fakes.volume_id, - volume_fakes.volume_metadata_str, - volume_fakes.volume_size, - volume_fakes.volume_status, - volume_fakes.volume_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_volume_create_options(self): arglist = [ @@ -158,30 +158,8 @@ class TestVolumeCreate(TestVolume): None, ) - collist = ( - 'attach_status', - 'availability_zone', - 'display_description', - 'display_name', - 'id', - 'properties', - 'size', - 'status', - 'type', - ) - self.assertEqual(collist, columns) - datalist = ( - 'detached', - volume_fakes.volume_zone, - volume_fakes.volume_description, - volume_fakes.volume_name, - volume_fakes.volume_id, - volume_fakes.volume_metadata_str, - volume_fakes.volume_size, - volume_fakes.volume_status, - volume_fakes.volume_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_volume_create_user_project_id(self): # Return a project @@ -233,30 +211,8 @@ class TestVolumeCreate(TestVolume): None, ) - collist = ( - 'attach_status', - 'availability_zone', - 'display_description', - 'display_name', - 'id', - 'properties', - 'size', - 'status', - 'type', - ) - self.assertEqual(collist, columns) - datalist = ( - 'detached', - volume_fakes.volume_zone, - volume_fakes.volume_description, - volume_fakes.volume_name, - volume_fakes.volume_id, - volume_fakes.volume_metadata_str, - volume_fakes.volume_size, - volume_fakes.volume_status, - volume_fakes.volume_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_volume_create_user_project_name(self): # Return a project @@ -308,30 +264,8 @@ class TestVolumeCreate(TestVolume): None, ) - collist = ( - 'attach_status', - 'availability_zone', - 'display_description', - 'display_name', - 'id', - 'properties', - 'size', - 'status', - 'type', - ) - self.assertEqual(collist, columns) - datalist = ( - 'detached', - volume_fakes.volume_zone, - volume_fakes.volume_description, - volume_fakes.volume_name, - volume_fakes.volume_id, - volume_fakes.volume_metadata_str, - volume_fakes.volume_size, - volume_fakes.volume_status, - volume_fakes.volume_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_volume_create_properties(self): arglist = [ @@ -369,30 +303,8 @@ class TestVolumeCreate(TestVolume): None, ) - collist = ( - 'attach_status', - 'availability_zone', - 'display_description', - 'display_name', - 'id', - 'properties', - 'size', - 'status', - 'type', - ) - self.assertEqual(collist, columns) - datalist = ( - 'detached', - volume_fakes.volume_zone, - volume_fakes.volume_description, - volume_fakes.volume_name, - volume_fakes.volume_id, - volume_fakes.volume_metadata_str, - volume_fakes.volume_size, - volume_fakes.volume_status, - volume_fakes.volume_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_volume_create_image_id(self): self.images_mock.get.return_value = fakes.FakeResource( @@ -435,30 +347,8 @@ class TestVolumeCreate(TestVolume): volume_fakes.image_id, ) - collist = ( - 'attach_status', - 'availability_zone', - 'display_description', - 'display_name', - 'id', - 'properties', - 'size', - 'status', - 'type', - ) - self.assertEqual(collist, columns) - datalist = ( - 'detached', - volume_fakes.volume_zone, - volume_fakes.volume_description, - volume_fakes.volume_name, - volume_fakes.volume_id, - volume_fakes.volume_metadata_str, - volume_fakes.volume_size, - volume_fakes.volume_status, - volume_fakes.volume_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_volume_create_image_name(self): self.images_mock.get.return_value = fakes.FakeResource( @@ -501,34 +391,29 @@ class TestVolumeCreate(TestVolume): volume_fakes.image_id, ) - collist = ( - 'attach_status', - 'availability_zone', - 'display_description', - 'display_name', - 'id', - 'properties', - 'size', - 'status', - 'type', - ) - self.assertEqual(collist, columns) - datalist = ( - 'detached', - volume_fakes.volume_zone, - volume_fakes.volume_description, - volume_fakes.volume_name, - volume_fakes.volume_id, - volume_fakes.volume_metadata_str, - volume_fakes.volume_size, - volume_fakes.volume_status, - volume_fakes.volume_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) class TestVolumeList(TestVolume): + columns = ( + 'ID', + 'Display Name', + 'Status', + 'Size', + 'Attached to', + ) + datalist = ( + ( + volume_fakes.volume_id, + volume_fakes.volume_name, + volume_fakes.volume_status, + volume_fakes.volume_size, + '', + ), + ) + def setUp(self): super(TestVolumeList, self).setUp() @@ -555,23 +440,8 @@ class TestVolumeList(TestVolume): columns, data = self.cmd.take_action(parsed_args) - collist = ( - 'ID', - 'Display Name', - 'Status', - 'Size', - 'Attached to', - ) - self.assertEqual(collist, columns) - - datalist = (( - volume_fakes.volume_id, - volume_fakes.volume_name, - volume_fakes.volume_status, - volume_fakes.volume_size, - '', - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_volume_list_name(self): arglist = [ @@ -586,24 +456,8 @@ class TestVolumeList(TestVolume): parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) - - collist = ( - 'ID', - 'Display Name', - 'Status', - 'Size', - 'Attached to', - ) - self.assertEqual(collist, tuple(columns)) - - datalist = (( - volume_fakes.volume_id, - volume_fakes.volume_name, - volume_fakes.volume_status, - volume_fakes.volume_size, - '', - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, tuple(columns)) + self.assertEqual(self.datalist, tuple(data)) def test_volume_list_status(self): arglist = [ @@ -618,24 +472,8 @@ class TestVolumeList(TestVolume): parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) - - collist = ( - 'ID', - 'Display Name', - 'Status', - 'Size', - 'Attached to', - ) - self.assertEqual(collist, tuple(columns)) - - datalist = (( - volume_fakes.volume_id, - volume_fakes.volume_name, - volume_fakes.volume_status, - volume_fakes.volume_size, - '', - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, tuple(columns)) + self.assertEqual(self.datalist, tuple(data)) def test_volume_list_all_projects(self): arglist = [ @@ -650,24 +488,8 @@ class TestVolumeList(TestVolume): parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) - - collist = ( - 'ID', - 'Display Name', - 'Status', - 'Size', - 'Attached to', - ) - self.assertEqual(collist, columns) - - datalist = (( - volume_fakes.volume_id, - volume_fakes.volume_name, - volume_fakes.volume_status, - volume_fakes.volume_size, - '', - ), ) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, tuple(columns)) + self.assertEqual(self.datalist, tuple(data)) def test_volume_list_long(self): arglist = [ diff --git a/openstackclient/tests/volume/v2/fakes.py b/openstackclient/tests/volume/v2/fakes.py index 60cec33..2fc5c8f 100644 --- a/openstackclient/tests/volume/v2/fakes.py +++ b/openstackclient/tests/volume/v2/fakes.py @@ -202,6 +202,8 @@ class FakeVolumeClient(object): self.restores.resource_class = fakes.FakeResource(None, {}) self.qos_specs = mock.Mock() self.qos_specs.resource_class = fakes.FakeResource(None, {}) + self.availability_zones = mock.Mock() + self.availability_zones.resource_class = fakes.FakeResource(None, {}) self.auth_token = kwargs['token'] self.management_url = kwargs['endpoint'] @@ -254,9 +256,10 @@ class FakeVolume(object): 'key' + uuid.uuid4().hex: 'val' + uuid.uuid4().hex}, 'snapshot_id': random.randint(1, 5), 'availability_zone': 'zone' + uuid.uuid4().hex, - 'attachments': { + 'attachments': [{ 'device': '/dev/' + uuid.uuid4().hex, - 'server_id': uuid.uuid4().hex}, + 'server_id': uuid.uuid4().hex, + }, ], } # Overwrite default attributes if there are some attributes set @@ -304,3 +307,55 @@ class FakeVolume(object): volumes = FakeVolume.create_volumes(count) return mock.MagicMock(side_effect=volumes) + + +class FakeAvailabilityZone(object): + """Fake one or more volume availability zones (AZs).""" + + @staticmethod + def create_one_availability_zone(attrs={}, methods={}): + """Create a fake AZ. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :return: + A FakeResource object with zoneName, zoneState, etc. + """ + # Set default attributes. + availability_zone = { + 'zoneName': uuid.uuid4().hex, + 'zoneState': {'available': True}, + } + + # Overwrite default attributes. + availability_zone.update(attrs) + + availability_zone = fakes.FakeResource( + info=copy.deepcopy(availability_zone), + methods=methods, + loaded=True) + return availability_zone + + @staticmethod + def create_availability_zones(attrs={}, methods={}, count=2): + """Create multiple fake AZs. + + :param Dictionary attrs: + A dictionary with all attributes + :param Dictionary methods: + A dictionary with all methods + :param int count: + The number of AZs to fake + :return: + A list of FakeResource objects faking the AZs + """ + availability_zones = [] + for i in range(0, count): + availability_zone = \ + FakeAvailabilityZone.create_one_availability_zone( + attrs, methods) + availability_zones.append(availability_zone) + + return availability_zones diff --git a/openstackclient/tests/volume/v2/test_backup.py b/openstackclient/tests/volume/v2/test_backup.py index 7af22e8..dc1d787 100644 --- a/openstackclient/tests/volume/v2/test_backup.py +++ b/openstackclient/tests/volume/v2/test_backup.py @@ -166,6 +166,24 @@ class TestBackupRestore(TestBackup): class TestBackupList(TestBackup): + + columns = [ + 'ID', + 'Name', + 'Description', + 'Status', + 'Size', + ] + datalist = ( + ( + volume_fakes.backup_id, + volume_fakes.backup_name, + volume_fakes.backup_description, + volume_fakes.backup_status, + volume_fakes.backup_size + ), + ) + def setUp(self): super(TestBackupList, self).setUp() @@ -193,17 +211,8 @@ class TestBackupList(TestBackup): parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) - collist = ['ID', 'Name', 'Description', 'Status', 'Size'] - self.assertEqual(collist, columns) - - datalist = (( - volume_fakes.backup_id, - volume_fakes.backup_name, - volume_fakes.backup_description, - volume_fakes.backup_status, - volume_fakes.backup_size - ),) - self.assertEqual(datalist, tuple(data)) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, tuple(data)) def test_backup_list_with_options(self): arglist = ["--long"] @@ -212,9 +221,13 @@ class TestBackupList(TestBackup): parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) - collist = ['ID', 'Name', 'Description', 'Status', 'Size', - 'Availability Zone', 'Volume', 'Container'] - self.assertEqual(collist, columns) + columns = self.columns + [ + 'Availability Zone', + 'Volume', + 'Container', + ] + + self.assertEqual(columns, columns) datalist = (( volume_fakes.backup_id, diff --git a/openstackclient/tests/volume/v2/test_qos_specs.py b/openstackclient/tests/volume/v2/test_qos_specs.py index 4222ed0..403634a 100644 --- a/openstackclient/tests/volume/v2/test_qos_specs.py +++ b/openstackclient/tests/volume/v2/test_qos_specs.py @@ -69,6 +69,18 @@ class TestQosAssociate(TestQos): class TestQosCreate(TestQos): + + columns = ( + 'consumer', + 'id', + 'name' + ) + datalist = ( + volume_fakes.qos_consumer, + volume_fakes.qos_id, + volume_fakes.qos_name + ) + def setUp(self): super(TestQosCreate, self).setUp() @@ -97,12 +109,7 @@ class TestQosCreate(TestQos): {'consumer': volume_fakes.qos_default_consumer} ) - collist = ( - 'consumer', - 'id', - 'name' - ) - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = ( volume_fakes.qos_default_consumer, volume_fakes.qos_id, @@ -134,18 +141,8 @@ class TestQosCreate(TestQos): {'consumer': volume_fakes.qos_consumer} ) - collist = ( - 'consumer', - 'id', - 'name' - ) - self.assertEqual(collist, columns) - datalist = ( - volume_fakes.qos_consumer, - volume_fakes.qos_id, - volume_fakes.qos_name - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_qos_create_with_properties(self): self.qos_mock.create.return_value = fakes.FakeResource( @@ -176,17 +173,11 @@ class TestQosCreate(TestQos): specs ) - collist = ( - 'consumer', - 'id', - 'name', + columns = self.columns + ( 'specs', ) - self.assertEqual(collist, columns) - datalist = ( - volume_fakes.qos_consumer, - volume_fakes.qos_id, - volume_fakes.qos_name, + self.assertEqual(columns, columns) + datalist = self.datalist + ( volume_fakes.qos_specs, ) self.assertEqual(datalist, data) diff --git a/openstackclient/tests/volume/v2/test_snapshot.py b/openstackclient/tests/volume/v2/test_snapshot.py index 3b30d4e..1c1dd43 100644 --- a/openstackclient/tests/volume/v2/test_snapshot.py +++ b/openstackclient/tests/volume/v2/test_snapshot.py @@ -202,6 +202,15 @@ class TestSnapshotUnset(TestSnapshot): class TestSnapshotList(TestSnapshot): + + columns = [ + "ID", + "Name", + "Description", + "Status", + "Size" + ] + def setUp(self): super(TestSnapshotList, self).setUp() @@ -231,8 +240,7 @@ class TestSnapshotList(TestSnapshot): parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) - collist = ["ID", "Name", "Description", "Status", "Size"] - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = (( volume_fakes.snapshot_id, volume_fakes.snapshot_name, @@ -249,9 +257,12 @@ class TestSnapshotList(TestSnapshot): columns, data = self.cmd.take_action(parsed_args) - collist = ["ID", "Name", "Description", "Status", "Size", "Created At", - "Volume", "Properties"] - self.assertEqual(collist, columns) + columns = self.columns + [ + "Created At", + "Volume", + "Properties" + ] + self.assertEqual(columns, columns) datalist = (( volume_fakes.snapshot_id, @@ -277,14 +288,7 @@ class TestSnapshotList(TestSnapshot): columns, data = self.cmd.take_action(parsed_args) - collist = [ - "ID", - "Name", - "Description", - "Status", - "Size" - ] - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = (( volume_fakes.snapshot_id, diff --git a/openstackclient/tests/volume/v2/test_type.py b/openstackclient/tests/volume/v2/test_type.py index c63cd1f..9bf6036 100644 --- a/openstackclient/tests/volume/v2/test_type.py +++ b/openstackclient/tests/volume/v2/test_type.py @@ -44,6 +44,17 @@ class TestType(volume_fakes.TestVolume): class TestTypeCreate(TestType): + columns = ( + 'description', + 'id', + 'name', + ) + datalist = ( + volume_fakes.type_description, + volume_fakes.type_id, + volume_fakes.type_name, + ) + def setUp(self): super(TestTypeCreate, self).setUp() @@ -76,18 +87,8 @@ class TestTypeCreate(TestType): is_public=True, ) - collist = ( - 'description', - 'id', - 'name', - ) - self.assertEqual(collist, columns) - datalist = ( - volume_fakes.type_description, - volume_fakes.type_id, - volume_fakes.type_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_type_create_private(self): arglist = [ @@ -110,21 +111,17 @@ class TestTypeCreate(TestType): is_public=False, ) - collist = ( - 'description', - 'id', - 'name', - ) - self.assertEqual(collist, columns) - datalist = ( - volume_fakes.type_description, - volume_fakes.type_id, - volume_fakes.type_name, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) class TestTypeList(TestType): + + columns = [ + "ID", + "Name" + ] + def setUp(self): super(TestTypeList, self).setUp() @@ -146,8 +143,7 @@ class TestTypeList(TestType): parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) - collist = ["ID", "Name"] - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) datalist = (( volume_fakes.type_id, volume_fakes.type_name, @@ -160,8 +156,11 @@ class TestTypeList(TestType): parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) - collist = ["ID", "Name", "Description", "Properties"] - self.assertEqual(collist, columns) + columns = self.columns + [ + "Description", + "Properties" + ] + self.assertEqual(columns, columns) datalist = (( volume_fakes.type_id, volume_fakes.type_name, diff --git a/openstackclient/tests/volume/v2/test_volume.py b/openstackclient/tests/volume/v2/test_volume.py index 70324b6..76c7a27 100644 --- a/openstackclient/tests/volume/v2/test_volume.py +++ b/openstackclient/tests/volume/v2/test_volume.py @@ -14,6 +14,9 @@ import copy +from mock import call + +from openstackclient.common import utils from openstackclient.tests import fakes from openstackclient.tests.identity.v3 import fakes as identity_fakes from openstackclient.tests.volume.v2 import fakes as volume_fakes @@ -36,15 +39,47 @@ class TestVolume(volume_fakes.TestVolume): self.images_mock = self.app.client_manager.image.images self.images_mock.reset_mock() + def setup_volumes_mock(self, count): + volumes = volume_fakes.FakeVolume.create_volumes(count=count) + + self.volumes_mock.get = volume_fakes.FakeVolume.get_volumes( + volumes, + 0) + return volumes + class TestVolumeCreate(TestVolume): + + columns = ( + 'attachments', + 'availability_zone', + 'description', + 'id', + 'name', + 'properties', + 'size', + 'snapshot_id', + 'status', + 'type', + ) + def setUp(self): super(TestVolumeCreate, self).setUp() - self.volumes_mock.create.return_value = fakes.FakeResource( - None, - copy.deepcopy(volume_fakes.VOLUME), - loaded=True, + self.new_volume = volume_fakes.FakeVolume.create_one_volume() + self.volumes_mock.create.return_value = self.new_volume + + self.datalist = ( + self.new_volume.attachments, + self.new_volume.availability_zone, + self.new_volume.description, + self.new_volume.id, + self.new_volume.name, + utils.format_dict(self.new_volume.metadata), + self.new_volume.size, + self.new_volume.snapshot_id, + self.new_volume.status, + self.new_volume.volume_type, ) # Get the command object to test @@ -52,12 +87,12 @@ class TestVolumeCreate(TestVolume): def test_volume_create_min_options(self): arglist = [ - '--size', str(volume_fakes.volume_size), - volume_fakes.volume_name, + '--size', str(self.new_volume.size), + self.new_volume.name, ] verifylist = [ - ('size', volume_fakes.volume_size), - ('name', volume_fakes.volume_name), + ('size', self.new_volume.size), + ('name', self.new_volume.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -65,9 +100,9 @@ class TestVolumeCreate(TestVolume): columns, data = self.cmd.take_action(parsed_args) self.volumes_mock.create.assert_called_with( - size=volume_fakes.volume_size, + size=self.new_volume.size, snapshot_id=None, - name=volume_fakes.volume_name, + name=self.new_volume.name, description=None, volume_type=None, user_id=None, @@ -78,47 +113,23 @@ class TestVolumeCreate(TestVolume): source_volid=None ) - collist = ( - 'attachments', - 'availability_zone', - 'description', - 'id', - 'name', - 'properties', - 'size', - 'snapshot_id', - 'status', - 'type', - ) - self.assertEqual(collist, columns) - datalist = ( - volume_fakes.volume_attachments, - volume_fakes.volume_availability_zone, - volume_fakes.volume_description, - volume_fakes.volume_id, - volume_fakes.volume_name, - volume_fakes.volume_metadata_str, - volume_fakes.volume_size, - volume_fakes.volume_snapshot_id, - volume_fakes.volume_status, - volume_fakes.volume_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_volume_create_options(self): arglist = [ - '--size', str(volume_fakes.volume_size), - '--description', volume_fakes.volume_description, - '--type', volume_fakes.volume_type, - '--availability-zone', volume_fakes.volume_availability_zone, - volume_fakes.volume_name, + '--size', str(self.new_volume.size), + '--description', self.new_volume.description, + '--type', self.new_volume.volume_type, + '--availability-zone', self.new_volume.availability_zone, + self.new_volume.name, ] verifylist = [ - ('size', volume_fakes.volume_size), - ('description', volume_fakes.volume_description), - ('type', volume_fakes.volume_type), - ('availability_zone', volume_fakes.volume_availability_zone), - ('name', volume_fakes.volume_name), + ('size', self.new_volume.size), + ('description', self.new_volume.description), + ('type', self.new_volume.volume_type), + ('availability_zone', self.new_volume.availability_zone), + ('name', self.new_volume.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -126,45 +137,21 @@ class TestVolumeCreate(TestVolume): columns, data = self.cmd.take_action(parsed_args) self.volumes_mock.create.assert_called_with( - size=volume_fakes.volume_size, + size=self.new_volume.size, snapshot_id=None, - name=volume_fakes.volume_name, - description=volume_fakes.volume_description, - volume_type=volume_fakes.volume_type, + name=self.new_volume.name, + description=self.new_volume.description, + volume_type=self.new_volume.volume_type, user_id=None, project_id=None, - availability_zone=volume_fakes.volume_availability_zone, + availability_zone=self.new_volume.availability_zone, metadata=None, imageRef=None, source_volid=None ) - collist = ( - 'attachments', - 'availability_zone', - 'description', - 'id', - 'name', - 'properties', - 'size', - 'snapshot_id', - 'status', - 'type', - ) - self.assertEqual(collist, columns) - datalist = ( - volume_fakes.volume_attachments, - volume_fakes.volume_availability_zone, - volume_fakes.volume_description, - volume_fakes.volume_id, - volume_fakes.volume_name, - volume_fakes.volume_metadata_str, - volume_fakes.volume_size, - volume_fakes.volume_snapshot_id, - volume_fakes.volume_status, - volume_fakes.volume_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_volume_create_user_project_id(self): # Return a project @@ -181,16 +168,16 @@ class TestVolumeCreate(TestVolume): ) arglist = [ - '--size', str(volume_fakes.volume_size), + '--size', str(self.new_volume.size), '--project', identity_fakes.project_id, '--user', identity_fakes.user_id, - volume_fakes.volume_name, + self.new_volume.name, ] verifylist = [ - ('size', volume_fakes.volume_size), + ('size', self.new_volume.size), ('project', identity_fakes.project_id), ('user', identity_fakes.user_id), - ('name', volume_fakes.volume_name), + ('name', self.new_volume.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -198,9 +185,9 @@ class TestVolumeCreate(TestVolume): columns, data = self.cmd.take_action(parsed_args) self.volumes_mock.create.assert_called_with( - size=volume_fakes.volume_size, + size=self.new_volume.size, snapshot_id=None, - name=volume_fakes.volume_name, + name=self.new_volume.name, description=None, volume_type=None, user_id=identity_fakes.user_id, @@ -211,32 +198,8 @@ class TestVolumeCreate(TestVolume): source_volid=None ) - collist = ( - 'attachments', - 'availability_zone', - 'description', - 'id', - 'name', - 'properties', - 'size', - 'snapshot_id', - 'status', - 'type', - ) - self.assertEqual(collist, columns) - datalist = ( - volume_fakes.volume_attachments, - volume_fakes.volume_availability_zone, - volume_fakes.volume_description, - volume_fakes.volume_id, - volume_fakes.volume_name, - volume_fakes.volume_metadata_str, - volume_fakes.volume_size, - volume_fakes.volume_snapshot_id, - volume_fakes.volume_status, - volume_fakes.volume_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_volume_create_user_project_name(self): # Return a project @@ -253,16 +216,16 @@ class TestVolumeCreate(TestVolume): ) arglist = [ - '--size', str(volume_fakes.volume_size), + '--size', str(self.new_volume.size), '--project', identity_fakes.project_name, '--user', identity_fakes.user_name, - volume_fakes.volume_name, + self.new_volume.name, ] verifylist = [ - ('size', volume_fakes.volume_size), + ('size', self.new_volume.size), ('project', identity_fakes.project_name), ('user', identity_fakes.user_name), - ('name', volume_fakes.volume_name), + ('name', self.new_volume.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -270,9 +233,9 @@ class TestVolumeCreate(TestVolume): columns, data = self.cmd.take_action(parsed_args) self.volumes_mock.create.assert_called_with( - size=volume_fakes.volume_size, + size=self.new_volume.size, snapshot_id=None, - name=volume_fakes.volume_name, + name=self.new_volume.name, description=None, volume_type=None, user_id=identity_fakes.user_id, @@ -283,44 +246,20 @@ class TestVolumeCreate(TestVolume): source_volid=None ) - collist = ( - 'attachments', - 'availability_zone', - 'description', - 'id', - 'name', - 'properties', - 'size', - 'snapshot_id', - 'status', - 'type', - ) - self.assertEqual(collist, columns) - datalist = ( - volume_fakes.volume_attachments, - volume_fakes.volume_availability_zone, - volume_fakes.volume_description, - volume_fakes.volume_id, - volume_fakes.volume_name, - volume_fakes.volume_metadata_str, - volume_fakes.volume_size, - volume_fakes.volume_snapshot_id, - volume_fakes.volume_status, - volume_fakes.volume_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_volume_create_properties(self): arglist = [ '--property', 'Alpha=a', '--property', 'Beta=b', - '--size', str(volume_fakes.volume_size), - volume_fakes.volume_name, + '--size', str(self.new_volume.size), + self.new_volume.name, ] verifylist = [ ('property', {'Alpha': 'a', 'Beta': 'b'}), - ('size', volume_fakes.volume_size), - ('name', volume_fakes.volume_name), + ('size', self.new_volume.size), + ('name', self.new_volume.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -328,9 +267,9 @@ class TestVolumeCreate(TestVolume): columns, data = self.cmd.take_action(parsed_args) self.volumes_mock.create.assert_called_with( - size=volume_fakes.volume_size, + size=self.new_volume.size, snapshot_id=None, - name=volume_fakes.volume_name, + name=self.new_volume.name, description=None, volume_type=None, user_id=None, @@ -341,32 +280,8 @@ class TestVolumeCreate(TestVolume): source_volid=None ) - collist = ( - 'attachments', - 'availability_zone', - 'description', - 'id', - 'name', - 'properties', - 'size', - 'snapshot_id', - 'status', - 'type', - ) - self.assertEqual(collist, columns) - datalist = ( - volume_fakes.volume_attachments, - volume_fakes.volume_availability_zone, - volume_fakes.volume_description, - volume_fakes.volume_id, - volume_fakes.volume_name, - volume_fakes.volume_metadata_str, - volume_fakes.volume_size, - volume_fakes.volume_snapshot_id, - volume_fakes.volume_status, - volume_fakes.volume_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_volume_create_image_id(self): self.images_mock.get.return_value = fakes.FakeResource( @@ -377,13 +292,13 @@ class TestVolumeCreate(TestVolume): arglist = [ '--image', volume_fakes.image_id, - '--size', str(volume_fakes.volume_size), - volume_fakes.volume_name, + '--size', str(self.new_volume.size), + self.new_volume.name, ] verifylist = [ ('image', volume_fakes.image_id), - ('size', volume_fakes.volume_size), - ('name', volume_fakes.volume_name), + ('size', self.new_volume.size), + ('name', self.new_volume.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -391,9 +306,9 @@ class TestVolumeCreate(TestVolume): columns, data = self.cmd.take_action(parsed_args) self.volumes_mock.create.assert_called_with( - size=volume_fakes.volume_size, + size=self.new_volume.size, snapshot_id=None, - name=volume_fakes.volume_name, + name=self.new_volume.name, description=None, volume_type=None, user_id=None, @@ -401,35 +316,11 @@ class TestVolumeCreate(TestVolume): availability_zone=None, metadata=None, imageRef=volume_fakes.image_id, - source_volid=None + source_volid=None, ) - collist = ( - 'attachments', - 'availability_zone', - 'description', - 'id', - 'name', - 'properties', - 'size', - 'snapshot_id', - 'status', - 'type', - ) - self.assertEqual(collist, columns) - datalist = ( - volume_fakes.volume_attachments, - volume_fakes.volume_availability_zone, - volume_fakes.volume_description, - volume_fakes.volume_id, - volume_fakes.volume_name, - volume_fakes.volume_metadata_str, - volume_fakes.volume_size, - volume_fakes.volume_snapshot_id, - volume_fakes.volume_status, - volume_fakes.volume_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) def test_volume_create_image_name(self): self.images_mock.get.return_value = fakes.FakeResource( @@ -440,13 +331,13 @@ class TestVolumeCreate(TestVolume): arglist = [ '--image', volume_fakes.image_name, - '--size', str(volume_fakes.volume_size), - volume_fakes.volume_name, + '--size', str(self.new_volume.size), + self.new_volume.name, ] verifylist = [ ('image', volume_fakes.image_name), - ('size', volume_fakes.volume_size), - ('name', volume_fakes.volume_name), + ('size', self.new_volume.size), + ('name', self.new_volume.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -454,9 +345,9 @@ class TestVolumeCreate(TestVolume): columns, data = self.cmd.take_action(parsed_args) self.volumes_mock.create.assert_called_with( - size=volume_fakes.volume_size, + size=self.new_volume.size, snapshot_id=None, - name=volume_fakes.volume_name, + name=self.new_volume.name, description=None, volume_type=None, user_id=None, @@ -467,36 +358,61 @@ class TestVolumeCreate(TestVolume): source_volid=None ) - collist = ( - 'attachments', - 'availability_zone', - 'description', - 'id', - 'name', - 'properties', - 'size', - 'snapshot_id', - 'status', - 'type', - ) - self.assertEqual(collist, columns) - datalist = ( - volume_fakes.volume_attachments, - volume_fakes.volume_availability_zone, - volume_fakes.volume_description, - volume_fakes.volume_id, - volume_fakes.volume_name, - volume_fakes.volume_metadata_str, - volume_fakes.volume_size, - volume_fakes.volume_snapshot_id, - volume_fakes.volume_status, - volume_fakes.volume_type, - ) - self.assertEqual(datalist, data) + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) + + +class TestVolumeDelete(TestVolume): + def setUp(self): + super(TestVolumeDelete, self).setUp() + + self.volumes_mock.delete.return_value = None + + # Get the command object to mock + self.cmd = volume.DeleteVolume(self.app, None) + + def test_volume_delete_one_volume(self): + volumes = self.setup_volumes_mock(count=1) + + arglist = [ + volumes[0].id + ] + verifylist = [ + ("volumes", [volumes[0].id]) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + self.volumes_mock.delete.assert_called_with(volumes[0].id) + + def test_volume_delete_multi_volumes(self): + volumes = self.setup_volumes_mock(count=3) + + arglist = [v.id for v in volumes] + verifylist = [ + ('volumes', arglist), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + + calls = [call(v.id) for v in volumes] + + self.volumes_mock.delete.assert_has_calls(calls) class TestVolumeList(TestVolume): + columns = [ + 'ID', + 'Display Name', + 'Status', + 'Size', + 'Attached to', + ] + def setUp(self): super(TestVolumeList, self).setUp() @@ -539,14 +455,7 @@ class TestVolumeList(TestVolume): columns, data = self.cmd.take_action(parsed_args) - collist = [ - 'ID', - 'Display Name', - 'Status', - 'Size', - 'Attached to', - ] - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) server = volume_fakes.volume_attachment_server['server_id'] device = volume_fakes.volume_attachment_server['device'] @@ -574,19 +483,11 @@ class TestVolumeList(TestVolume): columns, data = self.cmd.take_action(parsed_args) - collist = ( - 'ID', - 'Display Name', - 'Status', - 'Size', - 'Attached to', - ) - self.assertEqual(collist, tuple(columns)) + self.assertEqual(self.columns, columns) server = volume_fakes.volume_attachment_server['server_id'] device = volume_fakes.volume_attachment_server['device'] msg = 'Attached to %s on %s ' % (server, device) - datalist = (( volume_fakes.volume_id, volume_fakes.volume_name, @@ -612,19 +513,11 @@ class TestVolumeList(TestVolume): columns, data = self.cmd.take_action(parsed_args) - collist = ( - 'ID', - 'Display Name', - 'Status', - 'Size', - 'Attached to', - ) - self.assertEqual(collist, tuple(columns)) + self.assertEqual(self.columns, columns) server = volume_fakes.volume_attachment_server['server_id'] device = volume_fakes.volume_attachment_server['device'] msg = 'Attached to %s on %s ' % (server, device) - datalist = (( volume_fakes.volume_id, volume_fakes.volume_name, @@ -648,19 +541,10 @@ class TestVolumeList(TestVolume): columns, data = self.cmd.take_action(parsed_args) - collist = ( - 'ID', - 'Display Name', - 'Status', - 'Size', - 'Attached to', - ) - self.assertEqual(collist, tuple(columns)) - + self.assertEqual(self.columns, columns) server = volume_fakes.volume_attachment_server['server_id'] device = volume_fakes.volume_attachment_server['device'] msg = 'Attached to %s on %s ' % (server, device) - datalist = (( volume_fakes.volume_id, volume_fakes.volume_name, @@ -686,19 +570,11 @@ class TestVolumeList(TestVolume): columns, data = self.cmd.take_action(parsed_args) - collist = ( - 'ID', - 'Display Name', - 'Status', - 'Size', - 'Attached to', - ) - self.assertEqual(collist, tuple(columns)) + self.assertEqual(self.columns, columns) server = volume_fakes.volume_attachment_server['server_id'] device = volume_fakes.volume_attachment_server['device'] msg = 'Attached to %s on %s ' % (server, device) - datalist = (( volume_fakes.volume_id, volume_fakes.volume_name, @@ -722,19 +598,11 @@ class TestVolumeList(TestVolume): columns, data = self.cmd.take_action(parsed_args) - collist = ( - 'ID', - 'Display Name', - 'Status', - 'Size', - 'Attached to', - ) - self.assertEqual(collist, tuple(columns)) + self.assertEqual(self.columns, columns) server = volume_fakes.volume_attachment_server['server_id'] device = volume_fakes.volume_attachment_server['device'] msg = 'Attached to %s on %s ' % (server, device) - datalist = (( volume_fakes.volume_id, volume_fakes.volume_name, @@ -758,14 +626,7 @@ class TestVolumeList(TestVolume): columns, data = self.cmd.take_action(parsed_args) - collist = ( - 'ID', - 'Display Name', - 'Status', - 'Size', - 'Attached to', - ) - self.assertEqual(collist, tuple(columns)) + self.assertEqual(self.columns, columns) server = volume_fakes.volume_attachment_server['server_id'] device = volume_fakes.volume_attachment_server['device'] @@ -793,14 +654,7 @@ class TestVolumeList(TestVolume): columns, data = self.cmd.take_action(parsed_args) - collist = [ - 'ID', - 'Display Name', - 'Status', - 'Size', - 'Attached to', - ] - self.assertEqual(collist, columns) + self.assertEqual(self.columns, columns) server = volume_fakes.volume_attachment_server['server_id'] device = volume_fakes.volume_attachment_server['device'] @@ -882,30 +736,3 @@ class TestVolumeShow(TestVolume): self.assertEqual(volume_fakes.VOLUME_columns, columns) self.assertEqual(volume_fakes.VOLUME_data, data) - - -class TestVolumeDelete(TestVolume): - def setUp(self): - super(TestVolumeDelete, self).setUp() - - self.volumes_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(volume_fakes.VOLUME), - loaded=True) - self.volumes_mock.delete.return_value = None - - # Get the command object to mock - self.cmd = volume.DeleteVolume(self.app, None) - - def test_volume_delete(self): - arglist = [ - volume_fakes.volume_id - ] - verifylist = [ - ("volumes", [volume_fakes.volume_id]) - ] - - parsed_args = self.check_parser(self.cmd, arglist, verifylist) - - self.cmd.take_action(parsed_args) - self.volumes_mock.delete.assert_called_with(volume_fakes.volume_id) diff --git a/openstackclient/volume/v1/backup.py b/openstackclient/volume/v1/backup.py index c668e36..32f39fb 100644 --- a/openstackclient/volume/v1/backup.py +++ b/openstackclient/volume/v1/backup.py @@ -16,21 +16,15 @@ """Volume v1 Backup action implementations""" import copy -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import utils -class CreateBackup(show.ShowOne): +class CreateBackup(command.ShowOne): """Create new backup""" - log = logging.getLogger(__name__ + '.CreateBackup') - def get_parser(self, prog_name): parser = super(CreateBackup, self).get_parser(prog_name) parser.add_argument( @@ -57,7 +51,6 @@ class CreateBackup(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume volume_id = utils.find_resource(volume_client.volumes, @@ -76,8 +69,6 @@ class CreateBackup(show.ShowOne): class DeleteBackup(command.Command): """Delete backup(s)""" - log = logging.getLogger(__name__ + '.DeleteBackup') - def get_parser(self, prog_name): parser = super(DeleteBackup, self).get_parser(prog_name) parser.add_argument( @@ -88,21 +79,17 @@ class DeleteBackup(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume for backup in parsed_args.backups: backup_id = utils.find_resource(volume_client.backups, backup).id volume_client.backups.delete(backup_id) - return -class ListBackup(lister.Lister): +class ListBackup(command.Lister): """List backups""" - log = logging.getLogger(__name__ + '.ListBackup') - def get_parser(self, prog_name): parser = super(ListBackup, self).get_parser(prog_name) parser.add_argument( @@ -113,7 +100,6 @@ class ListBackup(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): def _format_volume_id(volume_id): @@ -158,8 +144,6 @@ class ListBackup(lister.Lister): class RestoreBackup(command.Command): """Restore backup""" - log = logging.getLogger(__name__ + '.RestoreBackup') - def get_parser(self, prog_name): parser = super(RestoreBackup, self).get_parser(prog_name) parser.add_argument( @@ -172,7 +156,6 @@ class RestoreBackup(command.Command): help='Volume to restore to (name or ID)') return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume backup = utils.find_resource(volume_client.backups, @@ -183,11 +166,9 @@ class RestoreBackup(command.Command): destination_volume.id) -class ShowBackup(show.ShowOne): +class ShowBackup(command.ShowOne): """Display backup details""" - log = logging.getLogger(__name__ + '.ShowBackup') - def get_parser(self, prog_name): parser = super(ShowBackup, self).get_parser(prog_name) parser.add_argument( @@ -196,7 +177,6 @@ class ShowBackup(show.ShowOne): help='Backup to display (ID only)') return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume backup = utils.find_resource(volume_client.backups, diff --git a/openstackclient/volume/v1/qos_specs.py b/openstackclient/volume/v1/qos_specs.py index d1c7011..826e5c4 100644 --- a/openstackclient/volume/v1/qos_specs.py +++ b/openstackclient/volume/v1/qos_specs.py @@ -15,13 +15,9 @@ """Volume v1 QoS action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils @@ -29,8 +25,6 @@ from openstackclient.common import utils class AssociateQos(command.Command): """Associate a QoS specification to a volume type""" - log = logging.getLogger(__name__ + '.AssociateQos') - def get_parser(self, prog_name): parser = super(AssociateQos, self).get_parser(prog_name) parser.add_argument( @@ -45,7 +39,6 @@ class AssociateQos(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, @@ -55,14 +48,10 @@ class AssociateQos(command.Command): volume_client.qos_specs.associate(qos_spec.id, volume_type.id) - return - -class CreateQos(show.ShowOne): +class CreateQos(command.ShowOne): """Create new QoS specification""" - log = logging.getLogger(__name__ + '.CreateQos') - def get_parser(self, prog_name): parser = super(CreateQos, self).get_parser(prog_name) parser.add_argument( @@ -88,7 +77,6 @@ class CreateQos(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume specs = {} @@ -105,8 +93,6 @@ class CreateQos(show.ShowOne): class DeleteQos(command.Command): """Delete QoS specification""" - log = logging.getLogger(__name__ + '.DeleteQos') - def get_parser(self, prog_name): parser = super(DeleteQos, self).get_parser(prog_name) parser.add_argument( @@ -117,20 +103,16 @@ class DeleteQos(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume for qos in parsed_args.qos_specs: qos_spec = utils.find_resource(volume_client.qos_specs, qos) volume_client.qos_specs.delete(qos_spec.id) - return class DisassociateQos(command.Command): """Disassociate a QoS specification from a volume type""" - log = logging.getLogger(__name__ + '.DisassociateQos') - def get_parser(self, prog_name): parser = super(DisassociateQos, self).get_parser(prog_name) parser.add_argument( @@ -153,7 +135,6 @@ class DisassociateQos(command.Command): return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, @@ -166,15 +147,10 @@ class DisassociateQos(command.Command): elif parsed_args.all: volume_client.qos_specs.disassociate_all(qos_spec.id) - return - -class ListQos(lister.Lister): +class ListQos(command.Lister): """List QoS specifications""" - log = logging.getLogger(__name__ + '.ListQos') - - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume qos_specs_list = volume_client.qos_specs.list() @@ -200,8 +176,6 @@ class ListQos(lister.Lister): class SetQos(command.Command): """Set QoS specification properties""" - log = logging.getLogger(__name__ + '.SetQos') - def get_parser(self, prog_name): parser = super(SetQos, self).get_parser(prog_name) parser.add_argument( @@ -218,7 +192,6 @@ class SetQos(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, @@ -230,14 +203,10 @@ class SetQos(command.Command): else: self.app.log.error("No changes requested\n") - return - -class ShowQos(show.ShowOne): +class ShowQos(command.ShowOne): """Display QoS specification details""" - log = logging.getLogger(__name__ + '.ShowQos') - def get_parser(self, prog_name): parser = super(ShowQos, self).get_parser(prog_name) parser.add_argument( @@ -247,7 +216,6 @@ class ShowQos(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, @@ -268,8 +236,6 @@ class ShowQos(show.ShowOne): class UnsetQos(command.Command): """Unset QoS specification properties""" - log = logging.getLogger(__name__ + '.SetQos') - def get_parser(self, prog_name): parser = super(UnsetQos, self).get_parser(prog_name) parser.add_argument( @@ -287,7 +253,6 @@ class UnsetQos(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, @@ -298,5 +263,3 @@ class UnsetQos(command.Command): parsed_args.property) else: self.app.log.error("No changes requested\n") - - return diff --git a/openstackclient/volume/v1/snapshot.py b/openstackclient/volume/v1/snapshot.py index 93e17eb..95200e4 100644 --- a/openstackclient/volume/v1/snapshot.py +++ b/openstackclient/volume/v1/snapshot.py @@ -16,22 +16,16 @@ """Volume v1 Snapshot action implementations""" import copy -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils -class CreateSnapshot(show.ShowOne): +class CreateSnapshot(command.ShowOne): """Create new snapshot""" - log = logging.getLogger(__name__ + '.CreateSnapshot') - def get_parser(self, prog_name): parser = super(CreateSnapshot, self).get_parser(prog_name) parser.add_argument( @@ -59,7 +53,6 @@ class CreateSnapshot(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume volume_id = utils.find_resource(volume_client.volumes, @@ -81,8 +74,6 @@ class CreateSnapshot(show.ShowOne): class DeleteSnapshot(command.Command): """Delete snapshot(s)""" - log = logging.getLogger(__name__ + '.DeleteSnapshot') - def get_parser(self, prog_name): parser = super(DeleteSnapshot, self).get_parser(prog_name) parser.add_argument( @@ -93,21 +84,17 @@ class DeleteSnapshot(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume for snapshot in parsed_args.snapshots: snapshot_id = utils.find_resource(volume_client.volume_snapshots, snapshot).id volume_client.volume_snapshots.delete(snapshot_id) - return -class ListSnapshot(lister.Lister): +class ListSnapshot(command.Lister): """List snapshots""" - log = logging.getLogger(__name__ + '.ListSnapshot') - def get_parser(self, prog_name): parser = super(ListSnapshot, self).get_parser(prog_name) parser.add_argument( @@ -124,7 +111,6 @@ class ListSnapshot(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): def _format_volume_id(volume_id): @@ -180,8 +166,6 @@ class ListSnapshot(lister.Lister): class SetSnapshot(command.Command): """Set snapshot properties""" - log = logging.getLogger(__name__ + '.SetSnapshot') - def get_parser(self, prog_name): parser = super(SetSnapshot, self).get_parser(prog_name) parser.add_argument( @@ -205,7 +189,6 @@ class SetSnapshot(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume snapshot = utils.find_resource(volume_client.volume_snapshots, @@ -226,14 +209,11 @@ class SetSnapshot(command.Command): return snapshot.update(**kwargs) - return -class ShowSnapshot(show.ShowOne): +class ShowSnapshot(command.ShowOne): """Display snapshot details""" - log = logging.getLogger(__name__ + '.ShowSnapshot') - def get_parser(self, prog_name): parser = super(ShowSnapshot, self).get_parser(prog_name) parser.add_argument( @@ -242,7 +222,6 @@ class ShowSnapshot(show.ShowOne): help='Snapshot to display (name or ID)') return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume snapshot = utils.find_resource(volume_client.volume_snapshots, @@ -258,8 +237,6 @@ class ShowSnapshot(show.ShowOne): class UnsetSnapshot(command.Command): """Unset snapshot properties""" - log = logging.getLogger(__name__ + '.UnsetSnapshot') - def get_parser(self, prog_name): parser = super(UnsetSnapshot, self).get_parser(prog_name) parser.add_argument( @@ -278,7 +255,6 @@ class UnsetSnapshot(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume snapshot = utils.find_resource( @@ -291,4 +267,3 @@ class UnsetSnapshot(command.Command): ) else: self.app.log.error("No changes requested\n") - return diff --git a/openstackclient/volume/v1/volume.py b/openstackclient/volume/v1/volume.py index 0691d88..90827d2 100644 --- a/openstackclient/volume/v1/volume.py +++ b/openstackclient/volume/v1/volume.py @@ -16,22 +16,16 @@ """Volume v1 Volume action implementations""" import argparse -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils -class CreateVolume(show.ShowOne): +class CreateVolume(command.ShowOne): """Create new volume""" - log = logging.getLogger(__name__ + '.CreateVolume') - def get_parser(self, prog_name): parser = super(CreateVolume, self).get_parser(prog_name) parser.add_argument( @@ -102,7 +96,6 @@ class CreateVolume(show.ShowOne): return parser - @utils.log_method(log) def take_action(self, parsed_args): identity_client = self.app.client_manager.identity @@ -166,8 +159,6 @@ class CreateVolume(show.ShowOne): class DeleteVolume(command.Command): """Delete volume(s)""" - log = logging.getLogger(__name__ + '.DeleteVolume') - def get_parser(self, prog_name): parser = super(DeleteVolume, self).get_parser(prog_name) parser.add_argument( @@ -186,7 +177,6 @@ class DeleteVolume(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume for volume in parsed_args.volumes: @@ -196,14 +186,11 @@ class DeleteVolume(command.Command): volume_client.volumes.force_delete(volume_obj.id) else: volume_client.volumes.delete(volume_obj.id) - return -class ListVolume(lister.Lister): +class ListVolume(command.Lister): """List volumes""" - log = logging.getLogger(__name__ + '.ListVolume') - def get_parser(self, prog_name): parser = super(ListVolume, self).get_parser(prog_name) parser.add_argument( @@ -230,7 +217,6 @@ class ListVolume(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume @@ -317,8 +303,6 @@ class ListVolume(lister.Lister): class SetVolume(command.Command): """Set volume properties""" - log = logging.getLogger(__name__ + '.SetVolume') - def get_parser(self, prog_name): parser = super(SetVolume, self).get_parser(prog_name) parser.add_argument( @@ -351,7 +335,6 @@ class SetVolume(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume volume = utils.find_resource(volume_client.volumes, parsed_args.volume) @@ -382,14 +365,10 @@ class SetVolume(command.Command): if not kwargs and not parsed_args.property and not parsed_args.size: self.app.log.error("No changes requested\n") - return - -class ShowVolume(show.ShowOne): +class ShowVolume(command.ShowOne): """Show volume details""" - log = logging.getLogger(__name__ + '.ShowVolume') - def get_parser(self, prog_name): parser = super(ShowVolume, self).get_parser(prog_name) parser.add_argument( @@ -399,7 +378,6 @@ class ShowVolume(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume volume = utils.find_resource(volume_client.volumes, parsed_args.volume) @@ -421,8 +399,6 @@ class ShowVolume(show.ShowOne): class UnsetVolume(command.Command): """Unset volume properties""" - log = logging.getLogger(__name__ + '.UnsetVolume') - def get_parser(self, prog_name): parser = super(UnsetVolume, self).get_parser(prog_name) parser.add_argument( @@ -441,7 +417,6 @@ class UnsetVolume(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume volume = utils.find_resource( @@ -454,4 +429,3 @@ class UnsetVolume(command.Command): ) else: self.app.log.error("No changes requested\n") - return diff --git a/openstackclient/volume/v1/volume_type.py b/openstackclient/volume/v1/volume_type.py index d7765c7..24d0b23 100644 --- a/openstackclient/volume/v1/volume_type.py +++ b/openstackclient/volume/v1/volume_type.py @@ -15,22 +15,16 @@ """Volume v1 Type action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils -class CreateVolumeType(show.ShowOne): +class CreateVolumeType(command.ShowOne): """Create new volume type""" - log = logging.getLogger(__name__ + '.CreateVolumeType') - def get_parser(self, prog_name): parser = super(CreateVolumeType, self).get_parser(prog_name) parser.add_argument( @@ -47,7 +41,6 @@ class CreateVolumeType(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume volume_type = volume_client.volume_types.create(parsed_args.name) @@ -64,8 +57,6 @@ class CreateVolumeType(show.ShowOne): class DeleteVolumeType(command.Command): """Delete volume type""" - log = logging.getLogger(__name__ + '.DeleteVolumeType') - def get_parser(self, prog_name): parser = super(DeleteVolumeType, self).get_parser(prog_name) parser.add_argument( @@ -75,20 +66,16 @@ class DeleteVolumeType(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume volume_type_id = utils.find_resource( volume_client.volume_types, parsed_args.volume_type).id volume_client.volume_types.delete(volume_type_id) - return -class ListVolumeType(lister.Lister): +class ListVolumeType(command.Lister): """List volume types""" - log = logging.getLogger(__name__ + '.ListVolumeType') - def get_parser(self, prog_name): parser = super(ListVolumeType, self).get_parser(prog_name) parser.add_argument( @@ -98,7 +85,6 @@ class ListVolumeType(lister.Lister): help='List additional fields in output') return parser - @utils.log_method(log) def take_action(self, parsed_args): if parsed_args.long: columns = ('ID', 'Name', 'Extra Specs') @@ -117,8 +103,6 @@ class ListVolumeType(lister.Lister): class SetVolumeType(command.Command): """Set volume type properties""" - log = logging.getLogger(__name__ + '.SetVolumeType') - def get_parser(self, prog_name): parser = super(SetVolumeType, self).get_parser(prog_name) parser.add_argument( @@ -135,7 +119,6 @@ class SetVolumeType(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume volume_type = utils.find_resource( @@ -144,14 +127,10 @@ class SetVolumeType(command.Command): if parsed_args.property: volume_type.set_keys(parsed_args.property) - return - class UnsetVolumeType(command.Command): """Unset volume type properties""" - log = logging.getLogger(__name__ + '.UnsetVolumeType') - def get_parser(self, prog_name): parser = super(UnsetVolumeType, self).get_parser(prog_name) parser.add_argument( @@ -170,7 +149,6 @@ class UnsetVolumeType(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume volume_type = utils.find_resource( @@ -182,14 +160,11 @@ class UnsetVolumeType(command.Command): volume_type.unset_keys(parsed_args.property) else: self.app.log.error("No changes requested\n") - return -class ShowVolumeType(show.ShowOne): +class ShowVolumeType(command.ShowOne): """Display volume type details""" - log = logging.getLogger(__name__ + ".ShowVolumeType") - def get_parser(self, prog_name): parser = super(ShowVolumeType, self).get_parser(prog_name) parser.add_argument( @@ -200,7 +175,6 @@ class ShowVolumeType(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action: (%s)", parsed_args) volume_client = self.app.client_manager.volume volume_type = utils.find_resource( volume_client.volume_types, parsed_args.volume_type) diff --git a/openstackclient/volume/v2/backup.py b/openstackclient/volume/v2/backup.py index 3525e70..64ca97a 100644 --- a/openstackclient/volume/v2/backup.py +++ b/openstackclient/volume/v2/backup.py @@ -15,21 +15,16 @@ """Volume v2 Backup action implementations""" import copy -import logging -from cliff import command -from cliff import lister -from cliff import show import six +from openstackclient.common import command from openstackclient.common import utils -class CreateBackup(show.ShowOne): +class CreateBackup(command.ShowOne): """Create new backup""" - log = logging.getLogger(__name__ + ".CreateBackup") - def get_parser(self, prog_name): parser = super(CreateBackup, self).get_parser(prog_name) parser.add_argument( @@ -56,7 +51,6 @@ class CreateBackup(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action: (%s)", parsed_args) volume_client = self.app.client_manager.volume volume_id = utils.find_resource( volume_client.volumes, parsed_args.volume).id @@ -73,8 +67,6 @@ class CreateBackup(show.ShowOne): class DeleteBackup(command.Command): """Delete backup(s)""" - log = logging.getLogger(__name__ + ".DeleteBackup") - def get_parser(self, prog_name): parser = super(DeleteBackup, self).get_parser(prog_name) parser.add_argument( @@ -86,20 +78,16 @@ class DeleteBackup(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action: (%s)", parsed_args) volume_client = self.app.client_manager.volume for backup in parsed_args.backups: backup_id = utils.find_resource( volume_client.backups, backup).id volume_client.backups.delete(backup_id) - return -class ListBackup(lister.Lister): +class ListBackup(command.Lister): """List backups""" - log = logging.getLogger(__name__ + ".ListBackup") - def get_parser(self, prog_name): parser = super(ListBackup, self).get_parser(prog_name) parser.add_argument( @@ -111,7 +99,6 @@ class ListBackup(lister.Lister): return parser def take_action(self, parsed_args): - self.log.debug("take_action: (%s)", parsed_args) def _format_volume_id(volume_id): """Return a volume name if available @@ -152,11 +139,9 @@ class ListBackup(lister.Lister): ) for s in data)) -class RestoreBackup(show.ShowOne): +class RestoreBackup(command.ShowOne): """Restore backup""" - log = logging.getLogger(__name__ + ".RestoreBackup") - def get_parser(self, prog_name): parser = super(RestoreBackup, self).get_parser(prog_name) parser.add_argument( @@ -172,7 +157,6 @@ class RestoreBackup(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action: (%s)", parsed_args) volume_client = self.app.client_manager.volume backup = utils.find_resource(volume_client.backups, parsed_args.backup) destination_volume = utils.find_resource(volume_client.volumes, @@ -180,11 +164,9 @@ class RestoreBackup(show.ShowOne): return volume_client.restores.restore(backup.id, destination_volume.id) -class ShowBackup(show.ShowOne): +class ShowBackup(command.ShowOne): """Display backup details""" - log = logging.getLogger(__name__ + ".ShowBackup") - def get_parser(self, prog_name): parser = super(ShowBackup, self).get_parser(prog_name) parser.add_argument( @@ -194,7 +176,6 @@ class ShowBackup(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action: (%s)", parsed_args) volume_client = self.app.client_manager.volume backup = utils.find_resource(volume_client.backups, parsed_args.backup) diff --git a/openstackclient/volume/v2/qos_specs.py b/openstackclient/volume/v2/qos_specs.py index b3a34ca..961cc27 100644 --- a/openstackclient/volume/v2/qos_specs.py +++ b/openstackclient/volume/v2/qos_specs.py @@ -15,13 +15,9 @@ """Volume v2 QoS action implementations""" -import logging import six -from cliff import command -from cliff import lister -from cliff import show - +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils @@ -29,8 +25,6 @@ from openstackclient.common import utils class AssociateQos(command.Command): """Associate a QoS specification to a volume type""" - log = logging.getLogger(__name__ + '.AssociateQos') - def get_parser(self, prog_name): parser = super(AssociateQos, self).get_parser(prog_name) parser.add_argument( @@ -45,7 +39,6 @@ class AssociateQos(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, @@ -55,14 +48,10 @@ class AssociateQos(command.Command): volume_client.qos_specs.associate(qos_spec.id, volume_type.id) - return - -class CreateQos(show.ShowOne): +class CreateQos(command.ShowOne): """Create new QoS specification""" - log = logging.getLogger(__name__ + '.CreateQos') - def get_parser(self, prog_name): parser = super(CreateQos, self).get_parser(prog_name) parser.add_argument( @@ -88,7 +77,6 @@ class CreateQos(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume specs = {} @@ -105,8 +93,6 @@ class CreateQos(show.ShowOne): class DeleteQos(command.Command): """Delete QoS specification""" - log = logging.getLogger(__name__ + '.DeleteQos') - def get_parser(self, prog_name): parser = super(DeleteQos, self).get_parser(prog_name) parser.add_argument( @@ -117,20 +103,16 @@ class DeleteQos(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume for qos in parsed_args.qos_specs: qos_spec = utils.find_resource(volume_client.qos_specs, qos) volume_client.qos_specs.delete(qos_spec.id) - return class DisassociateQos(command.Command): """Disassociate a QoS specification from a volume type""" - log = logging.getLogger(__name__ + '.DisassociateQos') - def get_parser(self, prog_name): parser = super(DisassociateQos, self).get_parser(prog_name) parser.add_argument( @@ -153,7 +135,6 @@ class DisassociateQos(command.Command): return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, @@ -166,15 +147,10 @@ class DisassociateQos(command.Command): elif parsed_args.all: volume_client.qos_specs.disassociate_all(qos_spec.id) - return - -class ListQos(lister.Lister): +class ListQos(command.Lister): """List QoS specifications""" - log = logging.getLogger(__name__ + '.ListQos') - - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume qos_specs_list = volume_client.qos_specs.list() @@ -200,8 +176,6 @@ class ListQos(lister.Lister): class SetQos(command.Command): """Set QoS specification properties""" - log = logging.getLogger(__name__ + '.SetQos') - def get_parser(self, prog_name): parser = super(SetQos, self).get_parser(prog_name) parser.add_argument( @@ -218,7 +192,6 @@ class SetQos(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, @@ -230,14 +203,10 @@ class SetQos(command.Command): else: self.app.log.error("No changes requested\n") - return - -class ShowQos(show.ShowOne): +class ShowQos(command.ShowOne): """Display QoS specification details""" - log = logging.getLogger(__name__ + '.ShowQos') - def get_parser(self, prog_name): parser = super(ShowQos, self).get_parser(prog_name) parser.add_argument( @@ -247,7 +216,6 @@ class ShowQos(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, @@ -268,8 +236,6 @@ class ShowQos(show.ShowOne): class UnsetQos(command.Command): """Unset QoS specification properties""" - log = logging.getLogger(__name__ + '.SetQos') - def get_parser(self, prog_name): parser = super(UnsetQos, self).get_parser(prog_name) parser.add_argument( @@ -287,7 +253,6 @@ class UnsetQos(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume qos_spec = utils.find_resource(volume_client.qos_specs, @@ -298,5 +263,3 @@ class UnsetQos(command.Command): parsed_args.property) else: self.app.log.error("No changes requested\n") - - return diff --git a/openstackclient/volume/v2/snapshot.py b/openstackclient/volume/v2/snapshot.py index aa7630a..4d00b72 100644 --- a/openstackclient/volume/v2/snapshot.py +++ b/openstackclient/volume/v2/snapshot.py @@ -15,22 +15,17 @@ """Volume v2 snapshot action implementations""" import copy -import logging -from cliff import command -from cliff import lister -from cliff import show import six +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils -class CreateSnapshot(show.ShowOne): +class CreateSnapshot(command.ShowOne): """Create new snapshot""" - log = logging.getLogger(__name__ + ".CreateSnapshot") - def get_parser(self, prog_name): parser = super(CreateSnapshot, self).get_parser(prog_name) parser.add_argument( @@ -59,7 +54,6 @@ class CreateSnapshot(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action: (%s)", parsed_args) volume_client = self.app.client_manager.volume volume_id = utils.find_resource( volume_client.volumes, parsed_args.volume).id @@ -78,8 +72,6 @@ class CreateSnapshot(show.ShowOne): class DeleteSnapshot(command.Command): """Delete volume snapshot(s)""" - log = logging.getLogger(__name__ + ".DeleteSnapshot") - def get_parser(self, prog_name): parser = super(DeleteSnapshot, self).get_parser(prog_name) parser.add_argument( @@ -91,20 +83,16 @@ class DeleteSnapshot(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action: (%s)", parsed_args) volume_client = self.app.client_manager.volume for snapshot in parsed_args.snapshots: snapshot_id = utils.find_resource( volume_client.volume_snapshots, snapshot).id volume_client.volume_snapshots.delete(snapshot_id) - return -class ListSnapshot(lister.Lister): +class ListSnapshot(command.Lister): """List snapshots""" - log = logging.getLogger(__name__ + ".ListSnapshot") - def get_parser(self, prog_name): parser = super(ListSnapshot, self).get_parser(prog_name) parser.add_argument( @@ -122,7 +110,6 @@ class ListSnapshot(lister.Lister): return parser def take_action(self, parsed_args): - self.log.debug("take_action: (%s)", parsed_args) def _format_volume_id(volume_id): """Return a volume name if available @@ -172,8 +159,6 @@ class ListSnapshot(lister.Lister): class SetSnapshot(command.Command): """Set snapshot properties""" - log = logging.getLogger(__name__ + '.SetSnapshot') - def get_parser(self, prog_name): parser = super(SetSnapshot, self).get_parser(prog_name) parser.add_argument( @@ -197,7 +182,6 @@ class SetSnapshot(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume snapshot = utils.find_resource(volume_client.volume_snapshots, @@ -217,14 +201,11 @@ class SetSnapshot(command.Command): volume_client.volume_snapshots.set_metadata(snapshot.id, parsed_args.property) volume_client.volume_snapshots.update(snapshot.id, **kwargs) - return -class ShowSnapshot(show.ShowOne): +class ShowSnapshot(command.ShowOne): """Display snapshot details""" - log = logging.getLogger(__name__ + ".ShowSnapshot") - def get_parser(self, prog_name): parser = super(ShowSnapshot, self).get_parser(prog_name) parser.add_argument( @@ -235,7 +216,6 @@ class ShowSnapshot(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action: (%s)", parsed_args) volume_client = self.app.client_manager.volume snapshot = utils.find_resource( volume_client.volume_snapshots, parsed_args.snapshot) @@ -248,8 +228,6 @@ class ShowSnapshot(show.ShowOne): class UnsetSnapshot(command.Command): """Unset snapshot properties""" - log = logging.getLogger(__name__ + '.UnsetSnapshot') - def get_parser(self, prog_name): parser = super(UnsetSnapshot, self).get_parser(prog_name) parser.add_argument( @@ -267,7 +245,6 @@ class UnsetSnapshot(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume snapshot = utils.find_resource( @@ -280,4 +257,3 @@ class UnsetSnapshot(command.Command): ) else: self.app.log.error("No changes requested\n") - return diff --git a/openstackclient/volume/v2/volume.py b/openstackclient/volume/v2/volume.py index 925b01d..436ec68 100644 --- a/openstackclient/volume/v2/volume.py +++ b/openstackclient/volume/v2/volume.py @@ -15,23 +15,18 @@ """Volume V2 Volume action implementations""" import copy -import logging -from cliff import command -from cliff import lister -from cliff import show import six +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils from openstackclient.identity import common as identity_common -class CreateVolume(show.ShowOne): +class CreateVolume(command.ShowOne): """Create new volume""" - log = logging.getLogger(__name__ + ".CreateVolume") - def get_parser(self, prog_name): parser = super(CreateVolume, self).get_parser(prog_name) parser.add_argument( @@ -96,8 +91,6 @@ class CreateVolume(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action: (%s)", parsed_args) - identity_client = self.app.client_manager.identity volume_client = self.app.client_manager.volume image_client = self.app.client_manager.image @@ -159,8 +152,6 @@ class CreateVolume(show.ShowOne): class DeleteVolume(command.Command): """Delete volume(s)""" - log = logging.getLogger(__name__ + ".DeleteVolume") - def get_parser(self, prog_name): parser = super(DeleteVolume, self).get_parser(prog_name) parser.add_argument( @@ -180,7 +171,6 @@ class DeleteVolume(command.Command): return parser def take_action(self, parsed_args): - self.log.debug("take_action: (%s)", parsed_args) volume_client = self.app.client_manager.volume for volume in parsed_args.volumes: volume_obj = utils.find_resource( @@ -189,14 +179,11 @@ class DeleteVolume(command.Command): volume_client.volumes.force_delete(volume_obj.id) else: volume_client.volumes.delete(volume_obj.id) - return -class ListVolume(lister.Lister): +class ListVolume(command.Lister): """List volumes""" - log = logging.getLogger(__name__ + '.ListVolume') - def get_parser(self, prog_name): parser = super(ListVolume, self).get_parser(prog_name) parser.add_argument( @@ -235,7 +222,6 @@ class ListVolume(lister.Lister): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume @@ -326,11 +312,9 @@ class ListVolume(lister.Lister): ) for s in data)) -class SetVolume(show.ShowOne): +class SetVolume(command.Command): """Set volume properties""" - log = logging.getLogger(__name__ + '.SetVolume') - def get_parser(self, prog_name): parser = super(SetVolume, self).get_parser(prog_name) parser.add_argument( @@ -363,7 +347,6 @@ class SetVolume(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume volume = utils.find_resource(volume_client.volumes, parsed_args.volume) @@ -394,14 +377,10 @@ class SetVolume(show.ShowOne): if not kwargs and not parsed_args.property and not parsed_args.size: self.app.log.error("No changes requested\n") - return - -class ShowVolume(show.ShowOne): +class ShowVolume(command.ShowOne): """Display volume details""" - log = logging.getLogger(__name__ + '.ShowVolume') - def get_parser(self, prog_name): parser = super(ShowVolume, self).get_parser(prog_name) parser.add_argument( @@ -411,7 +390,6 @@ class ShowVolume(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume volume = utils.find_resource(volume_client.volumes, parsed_args.volume) @@ -424,8 +402,6 @@ class ShowVolume(show.ShowOne): class UnsetVolume(command.Command): """Unset volume properties""" - log = logging.getLogger(__name__ + '.UnsetVolume') - def get_parser(self, prog_name): parser = super(UnsetVolume, self).get_parser(prog_name) parser.add_argument( @@ -444,7 +420,6 @@ class UnsetVolume(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume volume = utils.find_resource( @@ -452,4 +427,3 @@ class UnsetVolume(command.Command): volume_client.volumes.delete_metadata( volume.id, parsed_args.property) - return diff --git a/openstackclient/volume/v2/volume_type.py b/openstackclient/volume/v2/volume_type.py index 583e6ed..d2b3ed6 100644 --- a/openstackclient/volume/v2/volume_type.py +++ b/openstackclient/volume/v2/volume_type.py @@ -14,22 +14,16 @@ """Volume v2 Type action implementations""" -import logging - -from cliff import command -from cliff import lister -from cliff import show import six +from openstackclient.common import command from openstackclient.common import parseractions from openstackclient.common import utils -class CreateVolumeType(show.ShowOne): +class CreateVolumeType(command.ShowOne): """Create new volume type""" - log = logging.getLogger(__name__ + ".CreateVolumeType") - def get_parser(self, prog_name): parser = super(CreateVolumeType, self).get_parser(prog_name) parser.add_argument( @@ -66,7 +60,6 @@ class CreateVolumeType(show.ShowOne): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume @@ -93,8 +86,6 @@ class CreateVolumeType(show.ShowOne): class DeleteVolumeType(command.Command): """Delete volume type""" - log = logging.getLogger(__name__ + ".DeleteVolumeType") - def get_parser(self, prog_name): parser = super(DeleteVolumeType, self).get_parser(prog_name) parser.add_argument( @@ -105,19 +96,15 @@ class DeleteVolumeType(command.Command): return parser def take_action(self, parsed_args): - self.log.info("take_action: (%s)", parsed_args) volume_client = self.app.client_manager.volume volume_type = utils.find_resource( volume_client.volume_types, parsed_args.volume_type) volume_client.volume_types.delete(volume_type.id) - return -class ListVolumeType(lister.Lister): +class ListVolumeType(command.Lister): """List volume types""" - log = logging.getLogger(__name__ + '.ListVolumeType') - def get_parser(self, prog_name): parser = super(ListVolumeType, self).get_parser(prog_name) parser.add_argument( @@ -127,7 +114,6 @@ class ListVolumeType(lister.Lister): help='List additional fields in output') return parser - @utils.log_method(log) def take_action(self, parsed_args): if parsed_args.long: columns = ['ID', 'Name', 'Description', 'Extra Specs'] @@ -146,8 +132,6 @@ class ListVolumeType(lister.Lister): class SetVolumeType(command.Command): """Set volume type properties""" - log = logging.getLogger(__name__ + '.SetVolumeType') - def get_parser(self, prog_name): parser = super(SetVolumeType, self).get_parser(prog_name) parser.add_argument( @@ -174,7 +158,6 @@ class SetVolumeType(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume volume_type = utils.find_resource( @@ -201,14 +184,10 @@ class SetVolumeType(command.Command): if parsed_args.property: volume_type.set_keys(parsed_args.property) - return - -class ShowVolumeType(show.ShowOne): +class ShowVolumeType(command.ShowOne): """Display volume type details""" - log = logging.getLogger(__name__ + ".ShowVolumeType") - def get_parser(self, prog_name): parser = super(ShowVolumeType, self).get_parser(prog_name) parser.add_argument( @@ -219,7 +198,6 @@ class ShowVolumeType(show.ShowOne): return parser def take_action(self, parsed_args): - self.log.debug("take_action: (%s)", parsed_args) volume_client = self.app.client_manager.volume volume_type = utils.find_resource( volume_client.volume_types, parsed_args.volume_type) @@ -231,8 +209,6 @@ class ShowVolumeType(show.ShowOne): class UnsetVolumeType(command.Command): """Unset volume type properties""" - log = logging.getLogger(__name__ + '.UnsetVolumeType') - def get_parser(self, prog_name): parser = super(UnsetVolumeType, self).get_parser(prog_name) parser.add_argument( @@ -250,7 +226,6 @@ class UnsetVolumeType(command.Command): ) return parser - @utils.log_method(log) def take_action(self, parsed_args): volume_client = self.app.client_manager.volume volume_type = utils.find_resource( @@ -258,4 +233,3 @@ class UnsetVolumeType(command.Command): parsed_args.volume_type, ) volume_type.unset_keys(parsed_args.property) - return diff --git a/releasenotes/notes/add-port-delete-command-4789d3881b186cfc.yaml b/releasenotes/notes/add-port-delete-command-4789d3881b186cfc.yaml new file mode 100644 index 0000000..dd1e703 --- /dev/null +++ b/releasenotes/notes/add-port-delete-command-4789d3881b186cfc.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Add support for the ``port delete`` command. + [Bug `1519909 <https://bugs.launchpad.net/python-openstackclient/+bug/1519909>`_] diff --git a/releasenotes/notes/add-port-show-command-de0a599017189a21.yaml b/releasenotes/notes/add-port-show-command-de0a599017189a21.yaml new file mode 100644 index 0000000..cb65266 --- /dev/null +++ b/releasenotes/notes/add-port-show-command-de0a599017189a21.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Add support for the ``port show`` command. + [Bug `1519909 <https://bugs.launchpad.net/python-openstackclient/+bug/1519909>`_] diff --git a/releasenotes/notes/add-subnet-list-command-970f4b397469bdc6.yaml b/releasenotes/notes/add-subnet-list-command-970f4b397469bdc6.yaml new file mode 100644 index 0000000..ec1b7a2 --- /dev/null +++ b/releasenotes/notes/add-subnet-list-command-970f4b397469bdc6.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Add support for the ``subnet list`` command. + [Bug `1523258 <https://bugs.launchpad.net/python-openstackclient/+bug/1523258>`_] diff --git a/releasenotes/notes/bug-1486597-857e20262c038514.yaml b/releasenotes/notes/bug-1486597-857e20262c038514.yaml new file mode 100644 index 0000000..45eebd4 --- /dev/null +++ b/releasenotes/notes/bug-1486597-857e20262c038514.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Add ``project unset`` command for Identity v2 + [Bug `1486597 <https://bugs.launchpad.net/bugs/1486597>`_] diff --git a/releasenotes/notes/bug-1516661-757ef629f899cca3.yaml b/releasenotes/notes/bug-1516661-757ef629f899cca3.yaml new file mode 100644 index 0000000..21c4fb4 --- /dev/null +++ b/releasenotes/notes/bug-1516661-757ef629f899cca3.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Add ``image set --activate|--deactivate`` options (Image v2 only) + [Bug `1516661 <https://bugs.launchpad.net/bugs/1516661>`_] diff --git a/releasenotes/notes/bug-1517134-9efecb257910989c.yaml b/releasenotes/notes/bug-1517134-9efecb257910989c.yaml new file mode 100644 index 0000000..f6b254b --- /dev/null +++ b/releasenotes/notes/bug-1517134-9efecb257910989c.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Add ``--project-domain`` option to ``image create`` and ``image set`` commands + (Image v2 only) + [Bug `1517134 <https://bugs.launchpad.net/bugs/1517134>`_] diff --git a/releasenotes/notes/bug-1519503-978a68a54819dbbc.yaml b/releasenotes/notes/bug-1519503-978a68a54819dbbc.yaml new file mode 100644 index 0000000..89c4023 --- /dev/null +++ b/releasenotes/notes/bug-1519503-978a68a54819dbbc.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Add ``router`` commands ``create``, ``delete``, ``list``, ``set``, ``show`` + [Bug `1519503 <https://bugs.launchpad.net/bugs/1519503>`_] diff --git a/releasenotes/notes/bug-1519512-d20f44aca1f9e9b9.yaml b/releasenotes/notes/bug-1519512-d20f44aca1f9e9b9.yaml new file mode 100644 index 0000000..ae0f1b5 --- /dev/null +++ b/releasenotes/notes/bug-1519512-d20f44aca1f9e9b9.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Make ``security group rule list`` group argument optional to list all + security groups + [Bug `1519512 <https://bugs.launchpad.net/bugs/1519512>`_] diff --git a/releasenotes/notes/bug-1520003-505af921c8afffc9.yaml b/releasenotes/notes/bug-1520003-505af921c8afffc9.yaml new file mode 100644 index 0000000..ca94b95 --- /dev/null +++ b/releasenotes/notes/bug-1520003-505af921c8afffc9.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Add remote security group to `os security group rule list` + [Bug `1520003 <https://bugs.launchpad.net/bugs/1520003>`_] diff --git a/releasenotes/notes/bug-1521492-89b972c6362940a5.yaml b/releasenotes/notes/bug-1521492-89b972c6362940a5.yaml new file mode 100644 index 0000000..6f4766e --- /dev/null +++ b/releasenotes/notes/bug-1521492-89b972c6362940a5.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Change ``server list --flavor`` to now accept flavor ID or name + [Bug `1521492 <https://bugs.launchpad.net/bugs/1521492>`_] diff --git a/releasenotes/notes/bug-1521492-8cde2601591a8c78.yaml b/releasenotes/notes/bug-1521492-8cde2601591a8c78.yaml new file mode 100644 index 0000000..8d86b35 --- /dev/null +++ b/releasenotes/notes/bug-1521492-8cde2601591a8c78.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Change ``server list --image`` to now accept image ID or name + [Bug `1521492 <https://bugs.launchpad.net/bugs/1521492>`_] diff --git a/releasenotes/notes/bug-1522969-63abf273c6e71a07.yaml b/releasenotes/notes/bug-1522969-63abf273c6e71a07.yaml new file mode 100644 index 0000000..98452db --- /dev/null +++ b/releasenotes/notes/bug-1522969-63abf273c6e71a07.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Add ``--src-group`` option to ``security group rule create`` to include a + 'remote' security group rule. + [Bug `1522969 <https://bugs.launchpad.net/bugs/1522969>`_] diff --git a/releasenotes/notes/bug-1524456-9967fac653c91cb2.yaml b/releasenotes/notes/bug-1524456-9967fac653c91cb2.yaml new file mode 100644 index 0000000..37eb950 --- /dev/null +++ b/releasenotes/notes/bug-1524456-9967fac653c91cb2.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + Change the ``project set --domain`` option to use the argument as a lookup + for locating projects in non-default domains. + [Bug `1524456 <https://bugs.launchpad.net/bugs/1524456>`_] diff --git a/releasenotes/notes/bug-1525805-122e6ce0c3cd4945.yaml b/releasenotes/notes/bug-1525805-122e6ce0c3cd4945.yaml new file mode 100644 index 0000000..444b637 --- /dev/null +++ b/releasenotes/notes/bug-1525805-122e6ce0c3cd4945.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Fix case sensitivity when showing object-store properties. + [Bug `1525805 <https://bugs.launchpad.net/bugs/1525805>`_] diff --git a/releasenotes/notes/bug-1527833-42cde11d28b09ac3.yaml b/releasenotes/notes/bug-1527833-42cde11d28b09ac3.yaml new file mode 100644 index 0000000..21f748b --- /dev/null +++ b/releasenotes/notes/bug-1527833-42cde11d28b09ac3.yaml @@ -0,0 +1,7 @@ +--- +other: + - Change the `--owner` option to `--project` in `image create` + and `image set` commands. `--owner` is deprecated and no longer + documented but is still accepted; a warning message will be shown + if it is used. + [Bug `1527833 <https://bugs.launchpad.net/bugs/1527833>`_] diff --git a/releasenotes/notes/bug-1531360-0f5c62d18088e5b5.yaml b/releasenotes/notes/bug-1531360-0f5c62d18088e5b5.yaml new file mode 100644 index 0000000..992f265 --- /dev/null +++ b/releasenotes/notes/bug-1531360-0f5c62d18088e5b5.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + Support non-interactive user password update + [Bug `1531360 <https://bugs.launchpad.net/bugs/1531360>`_] diff --git a/releasenotes/notes/bug-1532945-1a5485b8d0ebddb8.yaml b/releasenotes/notes/bug-1532945-1a5485b8d0ebddb8.yaml new file mode 100644 index 0000000..bee8102 --- /dev/null +++ b/releasenotes/notes/bug-1532945-1a5485b8d0ebddb8.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Add volume support to `os availability zone list` + [Bug `1532945 <https://bugs.launchpad.net/bugs/1532945>`_] + + * New `--compute` option to only list compute availability zones. + * New `--volume` option to only list volume availability zones. diff --git a/releasenotes/notes/bug-1534202-1ba78f0bb744961f.yaml b/releasenotes/notes/bug-1534202-1ba78f0bb744961f.yaml new file mode 100644 index 0000000..36c0a3d --- /dev/null +++ b/releasenotes/notes/bug-1534202-1ba78f0bb744961f.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + Add network support to `os availability zone list` + [Bug `1534202 <https://bugs.launchpad.net/bugs/1534202>`_] + + * New `--network` option to only list network availability zones. diff --git a/releasenotes/notes/bug-1540988-17841cfd5accf7f5.yaml b/releasenotes/notes/bug-1540988-17841cfd5accf7f5.yaml new file mode 100644 index 0000000..eabe420 --- /dev/null +++ b/releasenotes/notes/bug-1540988-17841cfd5accf7f5.yaml @@ -0,0 +1,9 @@ +--- +features: + - | + Add ``--limit`` option to ``image list`` to limit the number of images + in output. + [Bug `1540988 <https://bugs.launchpad.net/bugs/1540988>`_] + - | + Add ``--marker`` option to ``image list`` to handle paginate requests. + [Bug `1540988 <https://bugs.launchpad.net/bugs/1540988>`_] diff --git a/requirements.txt b/requirements.txt index fbe3b8d..cc189ba 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,20 +1,20 @@ # The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -pbr>=1.6 -six>=1.9.0 +pbr>=1.6 # Apache-2.0 +six>=1.9.0 # MIT -Babel>=1.3 +Babel>=1.3 # BSD cliff>=1.15.0 # Apache-2.0 -keystoneauth1>=1.0.0 -os-client-config!=1.6.2,>=1.4.0 -oslo.config>=2.7.0 # Apache-2.0 -oslo.i18n>=1.5.0 # Apache-2.0 -oslo.utils>=2.8.0 # Apache-2.0 -python-glanceclient>=0.18.0 -python-keystoneclient!=1.8.0,>=1.6.0 -python-novaclient!=2.33.0,>=2.29.0 -python-cinderclient>=1.3.1 -python-neutronclient>=2.6.0 -requests>=2.8.1 +keystoneauth1>=2.1.0 # Apache-2.0 +openstacksdk>=0.7.4 # Apache-2.0 +os-client-config>=1.13.1 # Apache-2.0 +oslo.config>=3.4.0 # Apache-2.0 +oslo.i18n>=2.1.0 # Apache-2.0 +oslo.utils>=3.4.0 # Apache-2.0 +python-glanceclient>=1.2.0 # Apache-2.0 +python-keystoneclient!=1.8.0,!=2.1.0,>=1.6.0 # Apache-2.0 +python-novaclient!=2.33.0,>=2.29.0 # Apache-2.0 +python-cinderclient>=1.3.1 # Apache-2.0 +requests!=2.9.0,>=2.8.1 # Apache-2.0 stevedore>=1.5.0 # Apache-2.0 @@ -43,6 +43,7 @@ openstack.cli.base = volume = openstackclient.volume.client openstack.common = + availability_zone_list = openstackclient.common.availability_zone:ListAvailabilityZone configuration_show = openstackclient.common.configuration:ShowConfiguration extension_list = openstackclient.common.extension:ListExtension limits_show = openstackclient.common.limits:ShowLimits @@ -50,8 +51,6 @@ openstack.common = quota_show = openstackclient.common.quota:ShowQuota openstack.compute.v2 = - availability_zone_list = openstackclient.compute.v2.availability_zone:ListAvailabilityZone - compute_agent_create = openstackclient.compute.v2.agent:CreateAgent compute_agent_delete = openstackclient.compute.v2.agent:DeleteAgent compute_agent_list = openstackclient.compute.v2.agent:ListAgent @@ -104,7 +103,6 @@ openstack.compute.v2 = keypair_show = openstackclient.compute.v2.keypair:ShowKeypair security_group_create = openstackclient.compute.v2.security_group:CreateSecurityGroup - security_group_delete = openstackclient.compute.v2.security_group:DeleteSecurityGroup security_group_list = openstackclient.compute.v2.security_group:ListSecurityGroup security_group_set = openstackclient.compute.v2.security_group:SetSecurityGroup security_group_show = openstackclient.compute.v2.security_group:ShowSecurityGroup @@ -163,6 +161,7 @@ openstack.identity.v2 = project_list = openstackclient.identity.v2_0.project:ListProject project_set = openstackclient.identity.v2_0.project:SetProject project_show = openstackclient.identity.v2_0.project:ShowProject + project_unset = openstackclient.identity.v2_0.project:UnsetProject role_add = openstackclient.identity.v2_0.role:AddRole role_create = openstackclient.identity.v2_0.role:CreateRole @@ -332,6 +331,15 @@ openstack.network.v2 = network_list = openstackclient.network.v2.network:ListNetwork network_set = openstackclient.network.v2.network:SetNetwork network_show = openstackclient.network.v2.network:ShowNetwork + port_delete = openstackclient.network.v2.port:DeletePort + port_show = openstackclient.network.v2.port:ShowPort + router_create = openstackclient.network.v2.router:CreateRouter + router_delete = openstackclient.network.v2.router:DeleteRouter + router_list = openstackclient.network.v2.router:ListRouter + router_set = openstackclient.network.v2.router:SetRouter + router_show = openstackclient.network.v2.router:ShowRouter + security_group_delete = openstackclient.network.v2.security_group:DeleteSecurityGroup + subnet_list = openstackclient.network.v2.subnet:ListSubnet openstack.object_store.v1 = object_store_account_set = openstackclient.object.v1.account:SetAccount @@ -440,13 +448,13 @@ universal = 1 [extract_messages] keywords = _ gettext ngettext l_ lazy_gettext mapping_file = babel.cfg -output_file = python-openstackclient/locale/python-openstackclient.pot +output_file = openstackclient/locale/openstackclient.pot [update_catalog] -domain = python-openstackclient -output_dir = python-openstackclient/locale -input_file = python-openstackclient/locale/python-openstackclient.pot +domain = openstackclient +output_dir = openstackclient/locale +input_file = openstackclient/locale/openstackclient.pot [compile_catalog] -directory = python-openstackclient/locale -domain = python-openstackclient +directory = openstackclient/locale +domain = openstackclient diff --git a/test-requirements.txt b/test-requirements.txt index 7322c84..6a73cd9 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -3,28 +3,27 @@ # process, which may cause wedges in the gate later. hacking<0.11,>=0.10.0 -coverage>=3.6 -discover -fixtures>=1.3.1 -mock>=1.2 +coverage>=3.6 # Apache-2.0 +discover # BSD +fixtures>=1.3.1 # Apache-2.0/BSD +mock>=1.2 # BSD oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0 oslotest>=1.10.0 # Apache-2.0 -reno>=0.1.1 # Apache2 -requests-mock>=0.6.0 # Apache-2.0 -sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 -os-testr>=0.4.1 -testrepository>=0.0.18 -testtools>=1.4.0 -WebOb>=1.2.3 -tempest-lib>=0.10.0 +reno>=0.1.1 # Apache2 +requests-mock>=0.7.0 # Apache-2.0 +sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD +os-testr>=0.4.1 # Apache-2.0 +testrepository>=0.0.18 # Apache-2.0/BSD +testtools>=1.4.0 # MIT +WebOb>=1.2.3 # MIT +tempest-lib>=0.13.0 # Apache-2.0 # Install these to generate sphinx autodocs -python-barbicanclient>=3.3.0 -python-congressclient>=1.0.0 -python-designateclient>=1.5.0 -python-heatclient>=0.6.0 -python-ironicclient>=0.8.0 -python-mistralclient>=1.0.0 -python-saharaclient>=0.10.0 -python-tuskarclient>=0.1.17 -python-zaqarclient>=0.3.0 +python-barbicanclient>=3.3.0 # Apache-2.0 +python-congressclient>=1.0.0 # Apache-2.0 +python-designateclient>=1.5.0 # Apache-2.0 +python-heatclient>=0.6.0 # Apache-2.0 +python-ironicclient>=1.1.0 # Apache-2.0 +python-mistralclient>=1.0.0 # Apache-2.0 +python-saharaclient>=0.10.0 # Apache-2.0 +python-zaqarclient>=0.3.0 # Apache-2.0 @@ -27,9 +27,6 @@ commands = python setup.py test --coverage --testr-args='{posargs}' [testenv:debug] commands = oslo_debug_helper -t openstackclient/tests {posargs} -[tox:jenkins] -downloadcache = ~/cache/pip - [testenv:docs] commands = python setup.py build_sphinx |
