diff options
| author | gustavo panizzo <gfa@zumbi.com.ar> | 2015-01-27 13:50:06 +0800 |
|---|---|---|
| committer | git-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com> | 2015-01-27 10:15:11 +0000 |
| commit | 419a599432921be585a80271f1a52ec3a72673f6 (patch) | |
| tree | 33bd36e9e4dbab77de219852711d0cd243f2c7bd | |
| parent | bd19ce0d14dd9315cc6af5e3e66ca9637ed30f7a (diff) | |
| parent | 2bebb2a47dc2a4d22b239749739aa5824109fcf6 (diff) | |
1.0.2-1 (patches applied)applied/1.0.2-1
Imported using git-ubuntu import.
117 files changed, 6559 insertions, 923 deletions
diff --git a/debian/changelog b/debian/changelog index cdad0bd..84e594c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +python-openstackclient (1.0.2-1) experimental; urgency=medium + + * New upstream release. + + -- gustavo panizzo <gfa@zumbi.com.ar> Tue, 27 Jan 2015 13:50:06 +0800 + python-openstackclient (1.0.1-1) experimental; urgency=medium * New upstream release. diff --git a/debian/control b/debian/control index 6357769..ae4960b 100644 --- a/debian/control +++ b/debian/control @@ -16,13 +16,14 @@ Build-Depends-Indep: cliff-tablib (>= 1.0), python-coverage (>= 3.6), python-crypto (>= 2.6.0), python-fixtures (>= 0.3.14), - python-glanceclient (>= 1:0.14.0), + python-glanceclient (>= 1:0.15.0), python-hacking, python-keyring (>= 2.1), python-keystoneclient (>= 1:0.11.1), python-mock (>= 1.0), python-neutronclient(>= 2.3.6), python-novaclient (>= 2:2.18.0), + python-oslo.config (>= 1.6.0), python-oslo.serialization (>=1.0.0), python-oslo.utils (>=1.0.0), python-requests (>= 2.2.0), @@ -44,11 +45,12 @@ Depends: cliff-tablib (>= 1.0), python-cinderclient (>= 1:1.1.0), python-cliff (>= 1.7.0), python-crypto (>= 2.6.0), - python-glanceclient (>= 1:0.14.0), + python-glanceclient (>= 1:0.15.0), python-keyring (>= 1.6.1), python-keystoneclient (>= 1:0.11.1), python-neutronclient(>= 2.3.6), python-novaclient (>= 2:2.18.0), + python-oslo.config (>= 1.6.0), python-requests (>= 2.2.0), python-six (>= 1.7.0), ${misc:Depends}, diff --git a/debian/patches/003-python-oslo-libs-requirements.patch b/debian/patches/003-python-oslo-libs-requirements.patch new file mode 100644 index 0000000..4f2b0e2 --- /dev/null +++ b/debian/patches/003-python-oslo-libs-requirements.patch @@ -0,0 +1,25 @@ +Description: Allow python-oslo.serialization older than 1.2.0 + We have an older version than 1.2.0 on Debian. That's the reason for this change. + Same applies to python-oslo.utils. + . +Author: gustavo panizzo <gfa@zumbi.com.ar> + +--- +Origin: vendor +Forwarded: not-needed +Reviewed-By: gustavo panizzo <gfa@zumbi.com.ar> +Last-Update: <2015-01-27> + +--- a/requirements.txt ++++ b/requirements.txt +@@ -9,8 +9,8 @@ + cliff-tablib>=1.0 + oslo.config>=1.6.0 # Apache-2.0 + oslo.i18n>=1.0.0 # Apache-2.0 +-oslo.utils>=1.2.0 # Apache-2.0 +-oslo.serialization>=1.2.0 # Apache-2.0 ++oslo.utils>=1.0.0 # Apache-2.0 ++oslo.serialization>=1.0.0 # Apache-2.0 + python-glanceclient>=0.15.0 + python-keystoneclient>=0.11.1 + python-novaclient>=2.18.0 diff --git a/debian/patches/series b/debian/patches/series index 97b28cd..6153653 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1 +1,2 @@ +003-python-oslo-libs-requirements.patch update-dependencies.patch diff --git a/debian/patches/update-dependencies.patch b/debian/patches/update-dependencies.patch index fb849c0..6a98dbe 100644 --- a/debian/patches/update-dependencies.patch +++ b/debian/patches/update-dependencies.patch @@ -8,7 +8,7 @@ Last-Update: <2014-12-17> --- a/requirements.txt +++ b/requirements.txt -@@ -16,4 +16,4 @@ +@@ -17,4 +17,4 @@ python-cinderclient>=1.1.0 python-neutronclient>=2.3.6,<3 requests>=2.2.0,!=2.4.0 diff --git a/doc/source/command-objects/access-token.rst b/doc/source/command-objects/access-token.rst new file mode 100644 index 0000000..fd22e76 --- /dev/null +++ b/doc/source/command-objects/access-token.rst @@ -0,0 +1,42 @@ +============ +access token +============ + +Identity v3 + +`Requires: OS-OAUTH1 extension` + +access token create +------------------- + +Create an access token + +.. program:: access token create +.. code:: bash + + os access token create + --consumer-key <consumer-key> + --consumer-secret <consumer-secret> + --request-key <request-key> + --request-secret <request-secret> + --verifier <verifier> + +.. option:: --consumer-key <consumer-key> + + Consumer key (required) + +.. option:: --consumer-secret <consumer-secret> + + Consumer secret (required) + +.. option:: --request-key <request-key> + + Request token to exchange for access token (required) + +.. option:: --request-secret <request-secret> + + Secret associated with <request-key> (required) + +.. option:: --verifier <verifier> + + Verifier associated with <request-key> (required) diff --git a/doc/source/command-objects/aggregate.rst b/doc/source/command-objects/aggregate.rst index 474d811..6a1dd90 100644 --- a/doc/source/command-objects/aggregate.rst +++ b/doc/source/command-objects/aggregate.rst @@ -5,12 +5,14 @@ aggregate Server aggregates provide a mechanism to group servers according to certain criteria. +Compute v2 + aggregate add host ------------------ Add host to aggregate -.. program aggregate add host +.. program:: aggregate add host .. code:: bash os aggregate add host @@ -31,7 +33,7 @@ aggregate create Create a new aggregate -.. program aggregate create +.. program:: aggregate create .. code:: bash os aggregate create @@ -56,7 +58,7 @@ aggregate delete Delete an existing aggregate -.. program aggregate delete +.. program:: aggregate delete .. code:: bash os aggregate delete @@ -71,7 +73,7 @@ aggregate list List all aggregates -.. program aggregate list +.. program:: aggregate list .. code:: bash os aggregate list @@ -86,7 +88,7 @@ aggregate remove host Remove host from aggregate -.. program aggregate remove host +.. program:: aggregate remove host .. code:: bash os aggregate remove host @@ -98,7 +100,7 @@ Remove host from aggregate Aggregate (name or ID) -.. option:: <host> +.. describe:: <host> Host to remove from :ref:`\<aggregate\> <aggregate_remove_host-aggregate>` @@ -107,7 +109,7 @@ aggregate set Set aggregate properties -.. program aggregate set +.. program:: aggregate set .. code:: bash os aggregate set @@ -137,9 +139,9 @@ Set aggregate properties aggregate show -------------- -Show a specific aggregate +Display aggregate details -.. program aggregate show +.. program:: aggregate show .. code:: bash os aggregate show @@ -147,4 +149,4 @@ Show a specific aggregate .. describe:: <aggregate> - Aggregate to show (name or ID) + Aggregate to display (name or ID) diff --git a/doc/source/command-objects/availability_zone.rst b/doc/source/command-objects/availability_zone.rst new file mode 100644 index 0000000..3743523 --- /dev/null +++ b/doc/source/command-objects/availability_zone.rst @@ -0,0 +1,20 @@ +================= +availability zone +================= + +Compute v2 + +availability zone list +---------------------- + +List availability zones and their status + +.. program availability zone list +.. code:: bash + + os availability zone list + [--long] + +.. option:: --long + + List additional fields in output diff --git a/doc/source/command-objects/backup.rst b/doc/source/command-objects/backup.rst new file mode 100644 index 0000000..ec201aa --- /dev/null +++ b/doc/source/command-objects/backup.rst @@ -0,0 +1,104 @@ +====== +backup +====== + +Volume v1 + +backup create +------------- + +Create new backup + +.. program:: backup create +.. code:: bash + + os backup create + [--container <container>] + [--name <name>] + [--description <description>] + <volume> + +.. option:: --container <container> + + Optional backup container name + +.. option:: --name <name> + + Name of the backup + +.. option:: --description <description> + + Description of the backup + +.. _backup_create-backup: +.. describe:: <volume> + + Volume to backup (name or ID) + +backup delete +------------- + +Delete backup(s) + +.. program:: backup delete +.. code:: bash + + os backup delete + <backup> [<backup> ...] + +.. _backup_delete-backup: +.. describe:: <backup> + + Backup(s) to delete (ID only) + +backup list +----------- + +List backups + +.. program:: backup list +.. code:: bash + + os backup list + +.. _backup_list-backup: +.. option:: --long + + List additional fields in output + +backup restore +-------------- + +Restore backup + +.. program:: backup restore +.. code:: bash + + os backup restore + <backup> + <volume> + +.. _backup_restore-backup: +.. describe:: <backup> + + Backup to restore (ID only) + +.. describe:: <volume> + + Volume to restore to (name or ID) + +backup show +----------- + +Display backup details + +.. program:: backup show +.. code:: bash + + os backup show + <backup> + +.. _backup_show-backup: +.. describe:: <backup> + + Backup to display (ID only) diff --git a/doc/source/command-objects/catalog.rst b/doc/source/command-objects/catalog.rst index 99746dd..89db95d 100644 --- a/doc/source/command-objects/catalog.rst +++ b/doc/source/command-objects/catalog.rst @@ -7,6 +7,9 @@ Identity v2 catalog list ------------ +List services in the service catalog + +.. program:: catalog list .. code:: bash os catalog list @@ -14,7 +17,14 @@ catalog list catalog show ------------ +Display service catalog details + +.. program:: catalog show .. code:: bash os catalog show <service> + +.. describe:: <service> + + Service to display (type or name) diff --git a/doc/source/command-objects/console-log.rst b/doc/source/command-objects/console-log.rst index 8e56a07..9eafb61 100644 --- a/doc/source/command-objects/console-log.rst +++ b/doc/source/command-objects/console-log.rst @@ -4,6 +4,8 @@ console log Server console text dump +Compute v2 + console log show ---------------- diff --git a/doc/source/command-objects/console-url.rst b/doc/source/command-objects/console-url.rst index 45a0a52..9cab879 100644 --- a/doc/source/command-objects/console-url.rst +++ b/doc/source/command-objects/console-url.rst @@ -4,6 +4,8 @@ console url Server remote console URL +Compute v2 + console url show ---------------- diff --git a/doc/source/command-objects/consumer.rst b/doc/source/command-objects/consumer.rst new file mode 100644 index 0000000..91294fa --- /dev/null +++ b/doc/source/command-objects/consumer.rst @@ -0,0 +1,83 @@ +======== +consumer +======== + +Identity v3 + +`Requires: OS-OAUTH1 extension` + +consumer create +--------------- + +Create new consumer + +.. program:: consumer create +.. code:: bash + + os consumer create + [--description <description>] + +.. option:: --description <description> + + New consumer description + +consumer delete +--------------- + +Delete consumer + +.. program:: consumer delete +.. code:: bash + + os consumer delete + <consumer> + +.. describe:: <consumer> + + Consumer to delete + +consumer list +------------- + +List consumers + +.. program:: consumer list +.. code:: bash + + os consumer list + +consumer set +------------ + +Set consumer properties + +.. program:: consumer set +.. code:: bash + + os consumer set + [--description <description>] + <consumer> + +.. option:: --description <description> + + New consumer description + +.. describe:: <consumer> + + Consumer to modify + +consumer show +------------- + +Display consumer details + +.. program:: consumer show +.. code:: bash + + os consumer show + <consumer> + +.. _consumer_show-consumer: +.. describe:: <consumer> + + Consumer to display diff --git a/doc/source/command-objects/container.rst b/doc/source/command-objects/container.rst new file mode 100644 index 0000000..3372f4d --- /dev/null +++ b/doc/source/command-objects/container.rst @@ -0,0 +1,105 @@ +========= +container +========= + +Object Store v1 + +container create +---------------- + +Create new container + +.. program:: container create +.. code:: bash + + os container create + <container-name> [<container-name> ...] + +.. describe:: <container-name> + + New container name(s) + +container delete +---------------- + +Delete container + +.. program:: container delete +.. code:: bash + + os container delete + <container> [<container> ...] + +.. describe:: <container> + + Container(s) to delete + +container list +-------------- + +List containers + +.. program:: container list +.. code::bash + + os container list + [--prefix <prefix>] + [--marker <marker>] + [--end-marker <end-marker>] + [--limit <limit>] + [--long] + [--all] + +.. option:: --prefix <prefix> + + Filter list using <prefix> + +.. option:: --marker <marker> + + Anchor for paging + +.. option:: --end-marker <end-marker> + + End anchor for paging + +.. option:: --limit <limit> + + Limit the number of containers returned + +.. option:: --long + + List additional fields in output + +.. option:: --all + + List all containers (default is 10000) + +container save +-------------- + +Save container contents locally + +.. program:: container save +.. code:: bash + + os container save + <container> + +.. describe:: <container> + + Container to save + +container show +-------------- + +Display container details + +.. program:: container show +.. code:: bash + + os container show + [<container>] + +.. describe:: <container> + + Container to display diff --git a/doc/source/command-objects/credentials.rst b/doc/source/command-objects/credentials.rst index ea8fc08..9f4aabe 100644 --- a/doc/source/command-objects/credentials.rst +++ b/doc/source/command-objects/credentials.rst @@ -2,6 +2,8 @@ credentials =========== +Identity v3 + credentials create ------------------ diff --git a/doc/source/command-objects/domain.rst b/doc/source/command-objects/domain.rst new file mode 100644 index 0000000..9447357 --- /dev/null +++ b/doc/source/command-objects/domain.rst @@ -0,0 +1,115 @@ +====== +domain +====== + +Identity v3 + +domain create +------------- + +Create new domain + +.. program:: domain create +.. code:: bash + + os domain create + [--description <description>] + [--enable | --disable] + [--or-show] + <domain-name> + +.. option:: --description <description> + + New domain description + +.. option:: --enable + + Enable domain (default) + +.. option:: --disable + + Disable domain + +.. option:: --or-show + + Return existing domain + + If the domain already exists, return the existing domain data and do not fail. + +.. describe:: <domain-name> + + New domain name + +domain delete +------------- + +Delete domain + +.. program:: domain delete +.. code:: bash + + os domain delete + <domain> + +.. describe:: <domain> + + Domain to delete (name or ID) + +domain list +----------- + +List domains + +.. program:: domain list +.. code:: bash + + os domain list + +domain set +---------- + +Set domain properties + +.. program:: domain set +.. code:: bash + + os domain set + [--name <name>] + [--description <description>] + [--enable | --disable] + <domain> + +.. option:: --name <name> + + New domain name + +.. option:: --description <description> + + New domain description + +.. option:: --enable + + Enable domain + +.. option:: --disable + + Disable domain + +.. describe:: <domain> + + Domain to modify (name or ID) + +domain show +----------- + +Display domain details + +.. program:: domain show +.. code:: bash + + os domain show + <domain> + +.. describe:: <domain> + + Domain to display (name or ID) diff --git a/doc/source/command-objects/ec2-credentials.rst b/doc/source/command-objects/ec2-credentials.rst new file mode 100644 index 0000000..a5b6754 --- /dev/null +++ b/doc/source/command-objects/ec2-credentials.rst @@ -0,0 +1,98 @@ +=============== +ec2 credentials +=============== + +Identity v2 + +ec2 credentials create +---------------------- + +Create EC2 credentials + +.. program:: ec2 credentials create +.. code-block:: bash + + os ec2 credentials create + [--project <project>] + [--user <user>] + +.. option:: --project <project> + + Specify an alternate project (default: current authenticated project) + +.. option:: --user <user> + + Specify an alternate user (default: current authenticated user) + +The :option:`--project` and :option:`--user` options are typically only +useful for admin users, but may be allowed for other users depending on +the policy of the cloud and the roles granted to the user. + +ec2 credentials delete +---------------------- + +Delete EC2 credentials + +.. program:: ec2 credentials delete +.. code-block:: bash + + os ec2 credentials delete + [--user <user>] + <access-key> + +.. option:: --user <user> + + Specify a user + +.. _ec2_credentials_delete-access-key: +.. describe:: access-key + + Credentials access key + +The :option:`--user` option is typically only useful for admin users, but +may be allowed for other users depending on the policy of the cloud and +the roles granted to the user. + +ec2 credentials list +-------------------- + +List EC2 credentials + +.. program:: ec2 credentials list +.. code-block:: bash + + os ec2 credentials list + [--user <user>] + +.. option:: --user <user> + + Filter list by <user> + +The :option:`--user` option is typically only useful for admin users, but +may be allowed for other users depending on the policy of the cloud and +the roles granted to the user. + +ec2 credentials show +-------------------- + +Display EC2 credentials details + +.. program:: ec2 credentials show +.. code-block:: bash + + os ec2 credentials show + [--user <user>] + <access-key> + +.. option:: --user <user> + + Specify a user + +.. _ec2_credentials_show-access-key: +.. describe:: access-key + + Credentials access key + +The :option:`--user` option is typically only useful for admin users, but +may be allowed for other users depending on the policy of the cloud and +the roles granted to the user. diff --git a/doc/source/command-objects/endpoint.rst b/doc/source/command-objects/endpoint.rst index 128ddfa..7846a1b 100644 --- a/doc/source/command-objects/endpoint.rst +++ b/doc/source/command-objects/endpoint.rst @@ -7,39 +7,190 @@ Identity v2, v3 endpoint create --------------- +Create new endpoint + +*Identity version 2 only* + +.. program:: endpoint create +.. code:: bash + + os endpoint create + --publicurl <url> + [--adminurl <url>] + [--internalurl <url>] + [--region <region-id>] + <service> + +.. option:: --publicurl <url> + + New endpoint public URL (required) + +.. option:: --adminurl <url> + + New endpoint admin URL + +.. option:: --internalurl <url> + + New endpoint internal URL + +.. option:: --region <region-id> + + New endpoint region ID + +.. _endpoint_create-endpoint: +.. describe:: <service> + + New endpoint service (name or ID) + +*Identity version 3 only* + .. program:: endpoint create .. code:: bash os endpoint create - --publicurl <public-url> - [--adminurl <admin-url>] - [--internalurl <internal-url>] - [--region <endpoint-region>] + [--region <region-id> + [--enable | --disable] <service> + <interface> + <url> + +.. option:: --region <region-id> + + New endpoint region ID + +.. option:: --enable + + Enable endpoint (default) + +.. option:: --disable + + Disable endpoint + +.. describe:: <service> + + New endpoint service (name or ID) + +.. describe:: <interface> + + New endpoint interface type (admin, public or internal) + +.. describe:: <url> + + New endpoint URL endpoint delete --------------- +Delete endpoint + .. program:: endpoint delete .. code:: bash os endpoint delete <endpoint-id> +.. _endpoint_delete-endpoint: +.. describe:: <endpoint-id> + + Endpoint ID to delete + endpoint list ------------- +List endpoints + .. program:: endpoint list .. code:: bash os endpoint list + [--service <service] + [--interface <interface>] + [--region <region-id>] [--long] +.. option:: --service <service> + + Filter by service + + *Identity version 3 only* + +.. option:: --interface <interface> + + Filter by interface type (admin, public or internal) + + *Identity version 3 only* + +.. option:: --region <region-id> + + Filter by region ID + + *Identity version 3 only* + +.. option:: --long + + List additional fields in output + + *Identity version 2 only* + +endpoint set +------------ + +Set endpoint properties + +*Identity version 3 only* + +.. program:: endpoint set +.. code:: bash + + os endpoint set + [--region <region-id>] + [--interface <interface>] + [--url <url>] + [--service <service>] + [--enable | --disable] + <endpoint-id> + +.. option:: --region <region-id> + + New endpoint region ID + +.. option:: --interface <interface> + + New endpoint interface type (admin, public or internal) + +.. option:: --url <url> + + New endpoint URL + +.. option:: --service <service> + + New endpoint service (name or ID) + +.. option:: --enable + + Enable endpoint + +.. option:: --disable + + Disable endpoint + +.. _endpoint_set-endpoint: +.. describe:: <endpoint-id> + + Endpoint ID to modify + endpoint show ------------- +Display endpoint details + .. program:: endpoint show .. code:: bash os endpoint show - <endpoint_or_service-type> + <endpoint-id> + +.. _endpoint_show-endpoint: +.. describe:: <endpoint-id> + + Endpoint ID to display diff --git a/doc/source/command-objects/federation-protocol.rst b/doc/source/command-objects/federation-protocol.rst new file mode 100644 index 0000000..5b4ea48 --- /dev/null +++ b/doc/source/command-objects/federation-protocol.rst @@ -0,0 +1,112 @@ +=================== +federation protocol +=================== + +Identity v3 + +`Requires: OS-FEDERATION extension` + +federation protocol create +-------------------------- + +Create new federation protocol + +.. program:: federation protocol create +.. code:: bash + + os federation protocol create + --identity-provider <identity-provider> + --mapping <mapping> + <name> + +.. option:: --identity-provider <identity-provider> + + Identity provider that will support the new federation protocol (name or ID) (required) + +.. option:: --mapping <mapping> + + Mapping that is to be used (name or ID) (required) + +.. describe:: <name> + + New federation protocol name (must be unique per identity provider) + +federation protocol delete +-------------------------- + +Delete federation protocol + +.. program:: federation protocol delete +.. code:: bash + + os federation protocol delete + --identity-provider <identity-provider> + <federation-protocol> + +.. option:: --identity-provider <identity-provider> + + Identity provider that supports <federation-protocol> (name or ID) (required) + +.. describe:: <federation-protocol> + + Federation protocol to delete (name or ID) + +federation protocol list +------------------------ + +List federation protocols + +.. program:: federation protocol list +.. code:: bash + + os federation protocol list + --identity-provider <identity-provider> + +.. option:: --identity-provider <identity-provider> + + Identity provider to list (name or ID) (required) + +federation protocol set +----------------------- + +Set federation protocol properties + +.. program:: federation protocol set +.. code:: bash + + os federation protocol set + --identity-provider <identity-provider> + [--mapping <mapping>] + <federation-protocol> + +.. option:: --identity-provider <identity-provider> + + Identity provider that supports <federation-protocol> (name or ID) (required) + +.. option:: --mapping <mapping> + + Mapping that is to be used (name or ID) + +.. describe:: <federation-protocol> + + Federation protocol to modify (name or ID) + +federation protocol show +------------------------ + +Display federation protocol details + +.. program:: federation protocol show +.. code:: bash + + os federation protocol show + --identity-provider <identity-provider> + <federation-protocol> + +.. option:: --identity-provider <identity-provider> + + Identity provider that supports <federation-protocol> (name or ID) (required) + +.. describe:: <federation-protocol> + + Federation protocol to display (name or ID) diff --git a/doc/source/command-objects/flavor.rst b/doc/source/command-objects/flavor.rst new file mode 100644 index 0000000..0083da0 --- /dev/null +++ b/doc/source/command-objects/flavor.rst @@ -0,0 +1,107 @@ +====== +flavor +====== + +Compute v2 + +flavor create +------------- + +Create new flavor + +.. program:: flavor create +.. code:: bash + + os flavor create + [--id <id>] + [--ram <size-mb>] + [--disk <size-gb>] + [--ephemeral-disk <size-gb>] + [--swap <size-mb>] + [--vcpus <num-cpu>] + [--rxtx-factor <factor>] + [--public | --private] + <flavor-name> + +.. option:: --id <id> + + Unique flavor ID; 'auto' creates a UUID (default: auto) + +.. option:: --ram <size-mb> + + Memory size in MB (default 256M) + +.. option:: --disk <size-gb> + + Disk size in GB (default 0G) + +.. option:: --ephemeral-disk <size-gb> + + Ephemeral disk size in GB (default 0G) + +.. option:: --swap <size-gb> + + Swap space size in GB (default 0G) + +.. option:: --vcpus <num-cpu> + + Number of vcpus (default 1) + +.. option:: --rxtx-factor <factor> + + RX/TX factor (default 1) + +.. option:: --public + + Flavor is available to other projects (default) + +.. option:: --private + + Flavor is not available to other projects + +.. _flavor_create-flavor-name: +.. describe:: <flavor-name> + + New flavor name + +flavor delete +------------- + +Delete flavor + +.. program:: flavor delete +.. code:: bash + + os flavor delete + <flavor> + +.. _flavor_delete-flavor: +.. describe:: <flavor> + + Flavor to delete (name or ID) + +flavor list +----------- + +List flavors + +.. program:: flavor list +.. code:: bash + + os flavor list + +flavor show +----------- + +Display flavor details + +.. program:: flavor show +.. code:: bash + + os flavor show + <flavor> + +.. _flavor_show-flavor: +.. describe:: <flavor> + + Flavor to display (name or ID) diff --git a/doc/source/command-objects/group.rst b/doc/source/command-objects/group.rst new file mode 100644 index 0000000..3e7e806 --- /dev/null +++ b/doc/source/command-objects/group.rst @@ -0,0 +1,192 @@ +===== +group +===== + +Identity v3 + +group add user +-------------- + +Add user to group + +.. program:: group add user +.. code:: bash + + os group add user + <group> + <user> + +.. describe:: <group> + + Group to contain <user> (name or ID) + +.. describe:: <user> + + User to add to <group> (name or ID) + +group contains user +------------------- + +Check user membership in group + +.. program:: group contains user +.. code:: bash + + os group contains user + <group> + <user> + +.. describe:: <group> + + Group to check (name or ID) + +.. describe:: <user> + + User to check (name or ID) + +group create +------------ + +Create new group + +.. program:: group create +.. code:: bash + + os group create + [--domain <domain>] + [--description <description>] + [--or-show] + <group-name> + +.. option:: --domain <domain> + + Domain to contain new group (name or ID) + +.. option:: --description <description> + + New group description + +.. option:: --or-show + + Return existing group + + If the group already exists, return the existing group data and do not fail. + +.. describe:: <group-name> + + New group name + +group delete +------------ + +Delete group + +.. program:: group delete +.. code:: bash + + os group delete + [--domain <domain>] + <group> [<group> ...] + +.. option:: --domain <domain> + + Domain containing group(s) (name or ID) + +.. describe:: <group> + + Group(s) to delete (name or ID) + +group list +---------- + +List groups + +.. program:: group list +.. code:: bash + + os group list + [--domain <domain>] + [--user <user>] + [--long] + +.. option:: --domain <domain> + + Filter group list by <domain> (name or ID) + +.. option:: --user <user> + + Filter group list by <user> (name or ID) + +.. option:: --long + + List additional fields in output + +group remove user +----------------- + +Remove user from group + +.. program:: group remove user +.. code:: bash + + os group remove user + <group> + <user> + +.. describe:: <group> + + Group containing <user> (name or ID) + +.. describe:: <user> + + User to remove from <group> (name or ID) + +group set +--------- + +Set group properties + +.. program:: group set +.. code:: bash + + os group set + [--name <name>] + [--domain <domain>] + [--description <description>] + <group> + +.. option:: --name <name> + + New group name + +.. option:: --domain <domain> + + New domain to contain <group> (name or ID) + +.. option:: --description <description> + + New group description + +.. describe:: <group> + + Group to modify (name or ID) + +group show +---------- + +Display group details + +.. program:: group show +.. code:: bash + + os group show + [--domain <domain>] + <group> + +.. option:: --domain <domain> + + Domain containing <group> (name or ID) + +.. describe:: <group> + + Group to display (name or ID) diff --git a/doc/source/command-objects/identity-provider.rst b/doc/source/command-objects/identity-provider.rst new file mode 100644 index 0000000..47e274d --- /dev/null +++ b/doc/source/command-objects/identity-provider.rst @@ -0,0 +1,100 @@ +================= +identity provider +================= + +Identity v3 + +`Requires: OS-FEDERATION extension` + +identity provider create +------------------------ + +Create new identity provider + +.. program:: identity provider create +.. code:: bash + + os identity provider create + [--description <description>] + [--enable | --disable] + <name> + +.. option:: --description + + New identity provider description + +.. option:: --enable + + Enable the identity provider (default) + +.. option:: --disable + + Disable the identity provider + +.. describe:: <name> + + New identity provider name (must be unique) + +identity provider delete +------------------------ + +Delete identity provider + +.. program:: identity provider delete +.. code:: bash + + os identity provider delete + <identity-provider> + +.. describe:: <identity-provider> + + Identity provider to delete + +identity provider list +---------------------- + +List identity providers + +.. program:: identity provider list +.. code:: bash + + os identity provider list + +identity provider set +--------------------- + +Set identity provider properties + +.. program:: identity provider set +.. code:: bash + + os identity provider set + [--enable | --disable] + <identity-provider> + +.. option:: --enable + + Enable the identity provider + +.. option:: --disable + + Disable the identity provider + +.. describe:: <identity-provider> + + Identity provider to modify + +identity provider show +---------------------- + +Display identity provider details + +.. program:: identity provider show +.. code:: bash + + os identity provider show + <identity-provider> + +.. describe:: <identity-provider> + + Identity provider to display diff --git a/doc/source/command-objects/image.rst b/doc/source/command-objects/image.rst new file mode 100644 index 0000000..d9b7726 --- /dev/null +++ b/doc/source/command-objects/image.rst @@ -0,0 +1,245 @@ +====== +image +====== + +Image v1, v2 + +image create +------------ + +*Only supported for Image v1* + +Create/upload an image + +.. program:: image create +.. code:: bash + + os image create + [--id <id>] + [--store <store>] + [--container-format <container-format>] + [--disk-format <disk-format>] + [--owner <project>] + [--size <size>] + [--min-disk <disk-gb>] + [--min-ram <ram-mb>] + [--location <image-url>] + [--copy-from <image-url>] + [--file <file>] + [--volume <volume>] + [--force] + [--checksum <checksum>] + [--protected | --unprotected] + [--public | --private] + [--property <key=value> [...] ] + <image-name> + +.. option:: --id <id> + + Image ID to reserve + +.. option:: --store <store> + + Upload image to this store + +.. option:: --container-format <container-format> + + Image container format (default: bare) + +.. option:: --disk-format <disk-format> + + 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) + +.. option:: --min-disk <disk-gb> + + Minimum disk size needed to boot image, in gigabytes + +.. option:: --min-ram <disk-ram> + + Minimum RAM size needed to boot image, in megabytes + +.. option:: --location <image-url> + + Download image from an existing URL + +.. option:: --copy-from <image-url> + + Copy image from the data store (similar to --location) + +.. option:: --file <file> + + Upload image from local file + +.. option:: --volume <volume> + + Create image from a volume + +.. option:: --force + + Force image creation if volume is in use (only meaningful with --volume) + +.. option:: --checksum <checksum> + + Image hash used for verification + +.. option:: --protected + + Prevent image from being deleted + +.. option:: --unprotected + + Allow image to be deleted (default) + +.. option:: --public + + Image is accessible to the public + +.. option:: --private + + Image is inaccessible to the public (default) + +.. option:: --property <key=value> + + Set a property on this image (repeat for multiple values) + +.. describe:: <image-name> + + New image name + +image delete +------------ + +Delete image(s) + +.. program:: image delete +.. code:: bash + + os image delete + <image> + +.. describe:: <image> + + Image(s) to delete (name or ID) + +image list +---------- + +List available images + +.. program:: image list +.. code:: bash + + os image list + [--page-size <size>] + [--long] + +.. option:: --page-size <size> + + Number of images to request in each paginated request + +.. option:: --long + + List additional fields in output + +image save +---------- + +Save an image locally + +.. program:: image save +.. code:: bash + + os image save + --file <filename> + <image> + +.. option:: --file <filename> + + Downloaded image save filename (default: stdout) + +.. describe:: <image> + + Image to save (name or ID) + +image set +--------- + +*Only supported for Image v1* + +Set image properties + +.. program:: image set +.. code:: bash + + os image set + [--name <name>] + [--owner <project>] + [--min-disk <disk-gb>] + [--min-ram <disk-ram>] + [--protected | --unprotected] + [--public | --private] + [--property <key=value> [...] ] + <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 + +.. option:: --min-ram <disk-ram> + + Minimum RAM size needed to boot image, in megabytes + +.. option:: --protected + + Prevent image from being deleted + +.. option:: --unprotected + + Allow image to be deleted (default) + +.. option:: --public + + Image is accessible to the public + +.. option:: --private + + Image is inaccessible to the public (default) + +.. option:: --property <key=value> + + Set a property on this image (repeat for multiple values) + +.. describe:: <image> + + Image to modify (name or ID) + +image show +---------- + +Display image details + +.. program:: image show +.. code:: bash + + os image show + <image> + +.. describe:: <image> + + Image to display (name or ID) diff --git a/doc/source/command-objects/keypair.rst b/doc/source/command-objects/keypair.rst index 9ba0ee8..04c5721 100644 --- a/doc/source/command-objects/keypair.rst +++ b/doc/source/command-objects/keypair.rst @@ -5,6 +5,8 @@ keypair The badly named keypair is really the public key of an OpenSSH key pair to be used for access to created servers. +Compute v2 + keypair create -------------- @@ -28,7 +30,7 @@ Create new public key keypair delete -------------- -Delete a public key +Delete public key .. program keypair delete .. code:: bash @@ -53,7 +55,7 @@ List public key fingerprints keypair show ------------ -Show public key details +Display public key details .. program keypair show .. code:: bash @@ -68,4 +70,4 @@ Show public key details .. describe:: <key> - Public key to show + Public key to display diff --git a/doc/source/command-objects/limits.rst b/doc/source/command-objects/limits.rst index ac388e0..1eae488 100644 --- a/doc/source/command-objects/limits.rst +++ b/doc/source/command-objects/limits.rst @@ -4,6 +4,8 @@ limits The Compute and Volume APIs have resource usage limits. +Compute v2, Volume v1 + limits show ----------- diff --git a/doc/source/command-objects/mapping.rst b/doc/source/command-objects/mapping.rst new file mode 100644 index 0000000..25af474 --- /dev/null +++ b/doc/source/command-objects/mapping.rst @@ -0,0 +1,91 @@ +======= +mapping +======= + +Identity v3 + +`Requires: OS-FEDERATION extension` + +mapping create +-------------- + +Create new mapping + +.. program:: mapping create +.. code:: bash + + os mapping create + --rules <filename> + <name> + +.. option:: --rules <filename> + + Filename that contains a set of mapping rules (required) + +.. _mapping_create-mapping: +.. describe:: <name> + + New mapping name (must be unique) + +mapping delete +-------------- + +Delete mapping + +.. program:: mapping delete +.. code:: bash + + os mapping delete + <mapping> + +.. _mapping_delete-mapping: +.. describe:: <mapping> + + Mapping to delete + +mapping list +------------ + +List mappings + +.. program:: mapping list +.. code:: bash + + os mapping list + +mapping set +----------- + +Set mapping properties + +.. program:: mapping set +.. code:: bash + + os mapping set + [--rules <filename>] + <mapping> + +.. option:: --rules <filename> + + Filename that contains a new set of mapping rules + +.. _mapping_set-mapping: +.. describe:: <mapping> + + Mapping to modify + +mapping show +------------ + +Display mapping details + +.. program:: mapping show +.. code:: bash + + os mapping show + <mapping> + +.. _mapping_show-mapping: +.. describe:: <mapping> + + Mapping to display diff --git a/doc/source/command-objects/object.rst b/doc/source/command-objects/object.rst new file mode 100644 index 0000000..25cf69e --- /dev/null +++ b/doc/source/command-objects/object.rst @@ -0,0 +1,140 @@ +====== +object +====== + +Object Store v1 + +object create +------------- + +Upload object to container + +.. program:: object create +.. code:: bash + + os object create + <container> + <filename> [<filename> ...] + +.. describe:: <container> + + Container for new object + +.. describe:: <filename> + + Local filename(s) to upload + +object delete +------------- + +Delete object from container + +.. program:: object delete +.. code:: bash + + os object delete + <container> + <object> [<object> ...] + +.. describe:: <container> + + Delete object(s) from <container> + +.. describe:: <object> + + Object(s) to delete + +list object +----------- + +List objects + +.. program object list +.. code:: bash + + os object list + [--prefix <prefix>] + [--delimiter <delimiter>] + [--marker <marker>] + [--end-marker <end-marker>] + [--limit <limit>] + [--long] + [--all] + <container>] + +.. option:: --prefix <prefix> + + Filter list using <prefix> + +.. option:: --delimiter <delimiter> + + Roll up items with <delimiter> + +.. option:: --marker <marker> + + Anchor for paging + +.. option:: --end-marker <end-marker> + + End anchor for paging + +.. option:: --limit <limit> + + Limit number of objects returned + +.. option:: --long + + List additional fields in output + +.. option:: --all + + List all objects in <container> (default is 10000) + +.. describe:: <container> + + Container to list + +object save +----------- + +Save object locally + +.. program:: object save +.. code:: bash + + os object save + [--file <filename>] + [<container>] + [<object>] + +.. option:: --file <filename> + + Destination filename (defaults to object name) + +.. describe:: <container> + + Download <object> from <container> + +.. describe:: <object> + + Object to save + +object show +----------- + +Display object details + +.. program:: object show +.. code:: bash + + os object show + <container> + <object> + +.. describe:: <container> + + Display <object> from <container> + +.. describe:: <object> + + Object to display diff --git a/doc/source/command-objects/policy.rst b/doc/source/command-objects/policy.rst new file mode 100644 index 0000000..195a89f --- /dev/null +++ b/doc/source/command-objects/policy.rst @@ -0,0 +1,95 @@ +====== +policy +====== + +Identity v3 + +policy create +------------- + +Create new policy + +.. program:: policy create +.. code:: bash + + os policy create + [--type <type>] + <filename> + +.. option:: --type <type> + + New MIME type of the policy rules file (defaults to application/json) + +.. describe:: <filename> + + New serialized policy rules file + +policy delete +------------- + +Delete policy + +.. program:: policy delete +.. code:: bash + + os policy delete + <policy> + +.. describe:: <policy> + + Policy to delete + +policy list +----------- + +List policies + +.. program:: policy list +.. code:: bash + + os policy list + [--long] + +.. option:: --long + + List additional fields in output + +policy set +---------- + +Set policy properties + +.. program:: policy set +.. code:: bash + + os policy set + [--type <type>] + [--rules <filename>] + <policy> + +.. option:: --type <type> + + New MIME type of the policy rules file + +.. describe:: --rules <filename> + + New serialized policy rules file + +.. describe:: <policy> + + Policy to modify + +policy show +----------- + +Display policy details + +.. program:: policy show +.. code:: bash + + os policy show + <policy> + +.. describe:: <policy> + + Policy to display diff --git a/doc/source/command-objects/project.rst b/doc/source/command-objects/project.rst index 305e611..b39edb4 100644 --- a/doc/source/command-objects/project.rst +++ b/doc/source/command-objects/project.rst @@ -50,13 +50,13 @@ Create new project project delete -------------- -Delete an existing project +Delete project(s) .. program:: project delete .. code:: bash os project delete - <project> + <project> [<project> ...] .. option:: --domain <domain> @@ -149,6 +149,8 @@ Set project properties project show ------------ +Display project details + .. program:: project show .. code:: bash @@ -165,4 +167,4 @@ project show .. _project_show-project: .. describe:: <project> - Project to show (name or ID) + Project to display (name or ID) diff --git a/doc/source/command-objects/quota.rst b/doc/source/command-objects/quota.rst index ba6712c..053fb47 100644 --- a/doc/source/command-objects/quota.rst +++ b/doc/source/command-objects/quota.rst @@ -4,6 +4,8 @@ quota Resource quotas appear in multiple APIs, OpenStackClient presents them as a single object with multiple properties. +Compute v2, Volume v1 + quota set --------- diff --git a/doc/source/command-objects/region.rst b/doc/source/command-objects/region.rst index 788ed6f..cb4a059 100644 --- a/doc/source/command-objects/region.rst +++ b/doc/source/command-objects/region.rst @@ -9,24 +9,30 @@ region create Create new region +.. program:: region create .. code:: bash os region create [--parent-region <region-id>] - [--description <region-description>] - [--url <region-url>] + [--description <description>] + [--url <url>] <region-id> -:option:`--parent-region` <region-id> - Parent region +.. option:: --parent-region <region-id> + + Parent region ID + +.. option:: --description <description> -:option:`--description` <region-description> New region description -:option:`--url` <region-url> +.. option:: --url <url> + New region URL -:option:`<region-id>` +.. _region_create-region-id: +.. describe:: <region-id> + New region ID region delete @@ -34,61 +40,75 @@ region delete Delete region +.. program:: region delete .. code:: bash os region delete - <region> + <region-id> + +.. _region_delete-region-id: +.. describe:: <region-id> -:option:`<region>` - Region to delete + Region ID to delete region list ----------- List regions +.. program:: region list .. code:: bash os region list [--parent-region <region-id>] -:option:`--parent-region` <region-id> - Filter by a specific parent region +.. option:: --parent-region <region-id> + + Filter by parent region ID region set ---------- Set region properties +.. program:: region set .. code:: bash os region set [--parent-region <region-id>] - [--description <region-description>] - [--url <region-url>] - <region> + [--description <description>] + [--url <url>] + <region-id> + +.. option:: --parent-region <region-id> -:option:`--parent-region` <region-id> - New parent region + New parent region ID + +.. option:: --description <description> -:option:`--description` <region-description> New region description -:option:`--url` <region-url> +.. option:: --url <url> + New region URL -:option:`<region>` - Region ID to modify +.. _region_set-region-id: +.. describe:: <region-id> + + Region to modify region show ----------- -Show region +Display region details +.. program:: region show .. code:: bash os region show - <region> + <region-id> + +.. _region_show-region-id: +.. describe:: <region-id> -:option:`<region>` - Region ID to modify + Region to display diff --git a/doc/source/command-objects/request-token.rst b/doc/source/command-objects/request-token.rst new file mode 100644 index 0000000..84081cb --- /dev/null +++ b/doc/source/command-objects/request-token.rst @@ -0,0 +1,57 @@ +============= +request token +============= + +Identity v3 + +`Requires: OS-OAUTH1 extension` + +request token authorize +----------------------- + +Authorize a request token + +.. program:: request token authorize +.. code:: bash + + os request token authorize + --request-key <consumer-key> + --role <role> + +.. option:: --request-key <request-key> + + Request token to authorize (ID only) (required) + +.. option:: --role <role> + + Roles to authorize (name or ID) (repeat to set multiple values) (required) + +request token create +-------------------- + +Create a request token + +.. program:: request token create +.. code:: bash + + os request token create + --consumer-key <consumer-key> + --consumer-secret <consumer-secret> + --project <project> + [--domain <domain>] + +.. option:: --consumer-key <consumer-key> + + Consumer key (required) + +.. option:: --description <description> + + Consumer secret (required) + +.. option:: --project <project> + + Project that consumer wants to access (name or ID) (required) + +.. option:: --domain <domain> + + Domain owning <project> (name or ID) diff --git a/doc/source/command-objects/role.rst b/doc/source/command-objects/role.rst index 1cc80d7..02766b0 100644 --- a/doc/source/command-objects/role.rst +++ b/doc/source/command-objects/role.rst @@ -59,15 +59,15 @@ Create new role role delete ----------- -Delete an existing role +Delete role(s) .. program:: role delete .. code:: bash os role delete - <role> + <role> [<role> ...] -.. option:: <role> +.. describe:: <role> Role to delete (name or ID) @@ -142,7 +142,7 @@ Remove role from domain/project : user/group .. describe:: <role> - Role to remove from `<project>`:`<user>` (name or ID) + Role to remove (name or ID) role set -------- @@ -169,6 +169,8 @@ Set role properties role show --------- +Display role details + .. program:: role show .. code:: bash @@ -177,4 +179,4 @@ role show .. describe:: <role> - Role to show (name or ID) + Role to display (name or ID) diff --git a/doc/source/command-objects/role_assignment.rst b/doc/source/command-objects/role_assignment.rst new file mode 100644 index 0000000..749d883 --- /dev/null +++ b/doc/source/command-objects/role_assignment.rst @@ -0,0 +1,45 @@ +=============== +role assignment +=============== + +Identity v3 + +role assignment list +-------------------- + +List role assignments + +.. program:: role assignment list +.. code:: bash + + os role assignment list + [--role <role>] + [--user <user>] + [--group <group>] + [--domain <domain>] + [--project <project>] + [--effective] + +.. option:: --role <role> + + Role to filter (name or ID) + +.. option:: --user <user> + + User to filter (name or ID) + +.. option:: --group <group> + + Group to filter (name or ID) + +.. option:: --domain <domain> + + Domain to filter (name or ID) + +.. option:: --project <project> + + Project to filter (name or ID) + +.. option:: --effective + + Returns only effective role assignments (defaults to False) diff --git a/doc/source/command-objects/server-image.rst b/doc/source/command-objects/server-image.rst index 681f6e4..8b48934 100644 --- a/doc/source/command-objects/server-image.rst +++ b/doc/source/command-objects/server-image.rst @@ -5,11 +5,14 @@ server image A server image is a disk image created from a running server instance. The image is created in the Image store. +Compute v2 + server image create ------------------- Create a new disk image from a running server +.. program:: server image create .. code:: bash os server image create @@ -17,11 +20,14 @@ Create a new disk image from a running server [--wait] <server> -:option:`--name` <image-name> +.. option:: --name <image-name> + Name of new image (default is server name) -:option:`--wait` +.. option:: --wait + Wait for image create to complete -:option:`<server>` +.. describe:: <server> + Server (name or ID) diff --git a/doc/source/command-objects/server.rst b/doc/source/command-objects/server.rst index 4f07632..583acae 100644 --- a/doc/source/command-objects/server.rst +++ b/doc/source/command-objects/server.rst @@ -2,22 +2,26 @@ server ====== +Compute v2 server add security group ------------------------- Add security group to server +.. program:: server add security group .. code:: bash os server add security group <server> <group> -:option:`<server>` +.. describe:: <server> + Server (name or ID) -:option:`<group>` +.. describe:: <group> + Security group to add (name or ID) server add volume @@ -25,6 +29,7 @@ server add volume Add volume to server +.. program:: server add volume .. code:: bash os server add volume @@ -32,13 +37,16 @@ Add volume to server <server> <volume> -:option:`--device` <device> +.. option:: --device <device> + Server internal device name for volume -:option:`<server>` +.. describe:: <server> + Server (name or ID) -:option:`<volume>` +.. describe:: <volume> + Volume to add (name or ID) server create @@ -46,6 +54,7 @@ server create Create a new server +.. program:: server create .. code:: bash os server create @@ -66,69 +75,88 @@ Create a new server [--wait] <server-name> -:option:`--image` <image> +.. option:: --image <image> + Create server from this image -:option:`--volume` <volume> +.. option:: --volume <volume> + Create server from this volume -:option:`--flavor` <flavor> +.. option:: --flavor <flavor> + Create server with this flavor -:option:`--security-group` <security-group-name> +.. option:: --security-group <security-group-name> + Security group to assign to this server (repeat for multiple groups) -:option:`--key-name` <key-name> +.. option:: --key-name <key-name> + Keypair to inject into this server (optional extension) -:option:`--property` <key=value> +.. option:: --property <key=value> + Set a property on this server (repeat for multiple values) -:option:`--file` <dest-filename=source-filename> +.. option:: --file <dest-filename=source-filename> + File to inject into image before boot (repeat for multiple files) -:option:`--user-data` <user-data> +.. option:: --user-data <user-data> + User data file to serve from the metadata server -:option:`--availability-zone` <zone-name> +.. option:: --availability-zone <zone-name> + Select an availability zone for the server -:option:`--block-device-mapping` <dev-name=mapping> +.. option:: --block-device-mapping <dev-name=mapping> + Map block devices; map is <id>:<type>:<size(GB)>:<delete_on_terminate> (optional extension) -:option:`--nic` <nic-config-string> +.. option:: --nic <nic-config-string> + Specify NIC configuration (optional extension) -:option:`--hint` <key=value> +.. option:: --hint <key=value> + Hints for the scheduler (optional extension) -:option:`--config-drive` <config-drive-volume>|True +.. option:: --config-drive <config-drive-volume>|True + Use specified volume as the config drive, or 'True' to use an ephemeral drive -:option:`--min` <count> +.. option:: --min <count> + Minimum number of servers to launch (default=1) -:option:`--max` <count> +.. option:: --max <count> + Maximum number of servers to launch (default=1) -:option:`--wait` +.. option:: --wait + Wait for build to complete -:option:`<server-name>` +.. describe:: <server-name> + New server name server delete ------------- -Delete server command +Delete server(s) +.. program:: server delete .. code:: bash os server delete - <server> + <server> [<server> ...] -:option:`<server>` - Server (name or ID) +.. describe:: <server> + + Server to delete (name or ID) server list ----------- @@ -139,8 +167,8 @@ List servers os server list [--reservation-id <reservation-id>] - [--ip <ip-regex>] - [--ip6 <ip6-regex>] + [--ip <ip-address-regex>] + [--ip6 <ip6-address-regex>] [--name <name-regex>] [--instance-name <instance-name-regex>] [--status <status>] @@ -150,37 +178,48 @@ List servers [--all-projects] [--long] -:option:`--reservation-id` <reservation-id> +.. option:: --reservation-id <reservation-id> + Only return instances that match the reservation -:option:`--ip` <ip-address-regex> +.. option:: --ip <ip-address-regex> + Regular expression to match IP addresses -:option:`--ip6` <ip-address-regex> +.. option:: --ip6 <ip-address-regex> + Regular expression to match IPv6 addresses -:option:`--name` <name-regex> +.. option:: --name <name-regex> + Regular expression to match names -:option:`--instance-name` <server-name-regex> +.. option:: --instance-name <server-name-regex> + Regular expression to match instance name (admin only) -:option:`--status` <status> +.. option:: --status <status> + Search by server status -:option:`--flavor` <flavor> +.. option:: --flavor <flavor> + Search by flavor ID -:option:`--image` <image> +.. option:: --image <image> + Search by image ID -:option:`--host` <hostname> +.. option:: --host <hostname> + Search by hostname -:option:`--all-projects` +.. option:: --all-projects + Include all projects (admin only) -:option:`--long` +.. option:: --long + List additional fields in output server lock @@ -188,12 +227,14 @@ server lock Lock server +.. program:: server lock .. code:: bash os server lock <server> -:option:`<server>` +.. describe:: <server> + Server (name or ID) server migrate @@ -201,6 +242,7 @@ server migrate Migrate server to different host +.. program:: server migrate .. code:: bash os server migrate @@ -210,25 +252,32 @@ Migrate server to different host [--wait] <server> -:option:`--wait` - Wait for resize to complete +.. option:: --live <hostname> -:option:`--live` <hostname> Target hostname -:option:`--shared-migration` +.. option:: --shared-migration + Perform a shared live migration (default) -:option:`--block-migration` +.. option:: --block-migration + Perform a block live migration -:option:`--disk-overcommit` +.. option:: --disk-overcommit + Allow disk over-commit on the destination host -:option:`--no-disk-overcommit` +.. option:: --no-disk-overcommit + Do not over-commit disk on the destination host (default) -:option:`<server>` +.. option:: --wait + + Wait for resize to complete + +.. describe:: <server> + Server to migrate (name or ID) server pause @@ -236,12 +285,14 @@ server pause Pause server +.. program:: server pause .. code:: bash os server pause <server> -:option:`<server>` +.. describe:: <server> + Server (name or ID) server reboot @@ -249,6 +300,7 @@ server reboot Perform a hard or soft server reboot +.. program:: server reboot .. code:: bash os server reboot @@ -256,16 +308,20 @@ Perform a hard or soft server reboot [--wait] <server> -:option:`--hard` +.. option:: --hard + Perform a hard reboot -:option:`--soft` +.. option:: --soft + Perform a soft reboot -:option:`--wait` +.. option:: --wait + Wait for reboot to complete -:option:`<server>` +.. describe:: <server> + Server (name or ID) server rebuild @@ -273,6 +329,7 @@ server rebuild Rebuild server +.. program:: server rebuild .. code:: bash os server rebuild @@ -281,16 +338,20 @@ Rebuild server [--wait] <server> -:option:`--image` <image> +.. option:: --image <image> + Recreate server from this image -:option:`--password` <password> +.. option:: --password <password> + Set the password on the rebuilt instance -:option:`--wait` +.. option:: --wait + Wait for rebuild to complete -:option:`<server>` +.. describe:: <server> + Server (name or ID) server remove security group @@ -298,16 +359,19 @@ server remove security group Remove security group from server +.. program:: server remove security group .. code:: bash os server remove security group <server> <group> -:option:`<server>` +.. describe:: <server> + Name or ID of server to use -:option:`<group>` +.. describe:: <group> + Name or ID of security group to remove from server server remove volume @@ -315,16 +379,19 @@ server remove volume Remove volume from server +.. program:: server remove volume .. code:: bash os server remove volume <server> <volume> -:option:`<server>` +.. describe:: <server> + Server (name or ID) -:option:`<volume>` +.. describe:: <volume> + Volume to remove (name or ID) server rescue @@ -332,12 +399,14 @@ server rescue Put server in rescue mode +.. program:: server rescure .. code:: bash os server rescue <server> -:option:`<server>` +.. describe:: <server> + Server (name or ID) server resize @@ -345,6 +414,7 @@ server resize Scale server to a new flavor +.. program:: server resize .. code:: bash os server resize @@ -356,19 +426,24 @@ Scale server to a new flavor --verify | --revert <server> -:option:`--flavor` <flavor> +.. option:: --flavor <flavor> + Resize server to specified flavor -:option:`--verify` +.. option:: --verify + Verify server resize is complete -:option:`--revert` +.. option:: --revert + Restore server state before resize -:option:`--wait` +.. option:: --wait + Wait for resize to complete -:option:`<server>` +.. describe:: <server> + Server (name or ID) A resize operation is implemented by creating a new server and copying @@ -382,12 +457,14 @@ server resume Resume server +.. program:: server resume .. code:: bash os server resume <server> -:option:`<server>` +.. describe:: <server> + Server (name or ID) server set @@ -395,6 +472,7 @@ server set Set server properties +.. program:: server set .. code:: bash os server set @@ -404,17 +482,21 @@ Set server properties --root-password <server> -:option:`--name` <new-name> +.. option:: --name <new-name> + New server name -:option:`--root-password` +.. option:: --root-password + Set new root password (interactive only) -:option:`--property` <key=value> +.. option:: --property <key=value> + Property to add/change for this server (repeat option to set multiple properties) -:option:`<server>` +.. describe:: <server> + Server (name or ID) server show @@ -422,16 +504,19 @@ server show Show server details +.. program:: server show .. code:: bash os server show [--diagnostics] <server> -:option:`--diagnostics` +.. option:: --diagnostics + Display server diagnostics information -:option:`<server>` +.. describe:: <server> + Server (name or ID) server ssh @@ -439,6 +524,7 @@ server ssh Ssh to server +.. program:: server ssh .. code:: bash os server ssh @@ -449,28 +535,36 @@ Ssh to server [--public | --private | --address-type <address-type>] <server> -:option:`--login` <login-name> +.. option:: --login <login-name> + Login name (ssh -l option) -:option:`--port` <port> +.. option:: --port <port> + Destination port (ssh -p option) -:option:`--identity` <keyfile> +.. option:: --identity <keyfile> + Private key file (ssh -i option) -:option:`--option` <config-options> +.. option:: --option <config-options> + Options in ssh_config(5) format (ssh -o option) -:option:`--public` +.. option:: --public + Use public IP address -:option:`--private` +.. option:: --private + Use private IP address -:option:`--address-type` <address-type> +.. option:: --address-type <address-type> + Use other IP address (public, private, etc) -:option:`<server>` +.. describe:: <server> + Server (name or ID) server suspend @@ -478,12 +572,14 @@ server suspend Suspend server +.. program:: server suspend .. code:: bash os server suspend <server> -:option:`<server>` +.. describe:: <server> + Server (name or ID) server unlock @@ -491,12 +587,14 @@ server unlock Unlock server +.. program:: server unlock .. code:: bash os server unlock <server> -:option:`<server>` +.. describe:: <server> + Server (name or ID) server unpause @@ -504,12 +602,14 @@ server unpause Unpause server +.. program:: server unpause .. code:: bash os server unpause <server> -:option:`<server>` +.. describe:: <server> + Server (name or ID) server unrescue @@ -517,12 +617,14 @@ server unrescue Restore server from rescue mode +.. program:: server unrescue .. code:: bash os server unrescue <server> -:option:`<server>` +.. describe:: <server> + Server (name or ID) server unset @@ -530,6 +632,7 @@ server unset Unset server properties +.. program:: server unset .. code:: bash os server unset @@ -537,8 +640,10 @@ Unset server properties [--property <key>] ... <server> -:option:`--property` <key> +.. option:: --property <key> + Property key to remove from server (repeat to set multiple values) -:option:`<server>` +.. describe:: <server> + Server (name or ID) diff --git a/doc/source/command-objects/service.rst b/doc/source/command-objects/service.rst new file mode 100644 index 0000000..352f68a --- /dev/null +++ b/doc/source/command-objects/service.rst @@ -0,0 +1,143 @@ +======= +service +======= + +Identity v2, v3 + +service create +-------------- + +Create new service + +.. program:: service create +.. code-block:: bash + + os service create + [--name <name>] + [--description <description>] + [--enable | --disable] + <type> + +.. option:: --name <name> + + New service name + +.. option:: --description <description> + + New service description + +.. option:: --enable + + Enable service (default) + + *Identity version 3 only* + +.. option:: --disable + + Disable service + + *Identity version 3 only* + +.. _service_create-type: +.. describe:: <type> + + New service type (compute, image, identity, volume, etc) + +service delete +-------------- + +Delete service + +.. program:: service delete +.. code-block:: bash + + os service delete + <service> + +.. _service_delete-type: +.. describe:: <service> + + Service to delete (type, name or ID) + +service list +------------ + +List services + +.. program:: service list +.. code-block:: bash + + os service list + [--long] + +.. option:: --long + + List additional fields in output + +Returns service fields ID, Name and Type. :option:`--long` adds Description +and Enabled (*Identity version 3 only*) to the output. + +service set +----------- + +Set service properties + +* Identity version 3 only* + +.. program:: service set +.. code-block:: bash + + os service set + [--type <type>] + [--name <name>] + [--description <description>] + [--enable | --disable] + <service> + +.. option:: --type <type> + + New service type (compute, image, identity, volume, etc) + +.. option:: --name <name> + + New service name + +.. option:: --description <description> + + New service description + +.. option:: --enable + + Enable service + +.. option:: --disable + + Disable service + +.. _service_set-service: +.. describe:: <service> + + Service to update (type, name or ID) + +service show +------------ + +Display service details + +.. program:: service show +.. code-block:: bash + + os service show + [--catalog] + <service> + +.. option:: --catalog + + Show service catalog information + + *Identity version 2 only* + +.. _service_show-service: +.. describe:: <service> + + Service to display (type, name or ID) diff --git a/doc/source/command-objects/snapshot.rst b/doc/source/command-objects/snapshot.rst new file mode 100644 index 0000000..7bfd1d9 --- /dev/null +++ b/doc/source/command-objects/snapshot.rst @@ -0,0 +1,133 @@ +======== +snapshot +======== + +Volume v1 + +snapshot create +--------------- + +Create new snapshot + +.. program:: snapshot create +.. code:: bash + + os snapshot create + [--name <name>] + [--description <description>] + [--force] + <volume> + +.. option:: --name <name> + + Name of the snapshot + +.. option:: --description <description> + + Description of the snapshot + +.. option:: --force + + Create a snapshot attached to an instance. Default is False + +.. _snapshot_create-snapshot: +.. describe:: <volume> + + Volume to snapshot (name or ID) + +snapshot delete +--------------- + +Delete snapshot(s) + +.. program:: snapshot delete +.. code:: bash + + os snapshot delete + <snapshot> [<snapshot> ...] + +.. _snapshot_delete-snapshot: +.. describe:: <snapshot> + + Snapshot(s) to delete (name or ID) + +snapshot list +------------- + +List snapshots + +.. program:: snapshot list +.. code:: bash + + os snapshot list + +.. option:: --long + + List additional fields in output + +snapshot set +------------ + +Set snapshot properties + +.. program:: snapshot set +.. code:: bash + + os snapshot set + [--name <name>] + [--description <description>] + [--property <key=value> [...] ] + <snapshot> + +.. _snapshot_restore-snapshot: +.. option:: --name <name> + + New snapshot name + +.. option:: --description <description> + + New snapshot description + +.. option:: --property <key=value> + + Property to add or modify for this snapshot (repeat option to set multiple properties) + +.. describe:: <snapshot> + + Snapshot to modify (name or ID) + +snapshot show +------------- + +Display snapshot details + +.. program:: snapshot show +.. code:: bash + + os snapshot show + <snapshot> + +.. _snapshot_show-snapshot: +.. describe:: <snapshot> + + Snapshot to display (name or ID) + +snapshot unset +-------------- + +Unset snapshot properties + +.. program:: snapshot unset +.. code:: bash + + os snapshot unset + [--property <key>] + <snapshot> + +.. option:: --property <key> + + Property to remove from snapshot (repeat option to remove multiple properties) + +.. describe:: <snapshot> + + Snapshot to modify (name or ID) diff --git a/doc/source/command-objects/token.rst b/doc/source/command-objects/token.rst index aec87d2..22260f0 100644 --- a/doc/source/command-objects/token.rst +++ b/doc/source/command-objects/token.rst @@ -7,6 +7,9 @@ Identity v2, v3 token issue ----------- +Issue new token + +.. program:: token issue .. code:: bash os token issue @@ -14,6 +17,16 @@ token issue token revoke ------------ +*Identity version 2 only.* + +Revoke existing token + +.. program:: token revoke .. code:: bash os token revoke + <token> + +.. describe:: <token> + + Token to be deleted diff --git a/doc/source/command-objects/usage.rst b/doc/source/command-objects/usage.rst new file mode 100644 index 0000000..0c86608 --- /dev/null +++ b/doc/source/command-objects/usage.rst @@ -0,0 +1,50 @@ +===== +usage +===== + +Compute v2 + +usage list +---------- + +List resource usage per project + +.. program:: usage list +.. code:: bash + + os usage list + --start <start> + --end <end> + +.. option:: --start <start> + + Usage range start date, ex 2012-01-20 (default: 4 weeks ago) + +.. option:: --end <end> + + Usage range end date, ex 2012-01-20 (default: tomorrow) + +usage show +---------- + +Show resource usage for a single project + +.. program:: usage show +.. code:: bash + + os usage show + --project <project> + --start <start> + --end <end> + +.. option:: --project <project> + + Name or ID of project to show usage for + +.. option:: --start <start> + + Usage range start date, ex 2012-01-20 (default: 4 weeks ago) + +.. option:: --end <end> + + Usage range end date, ex 2012-01-20 (default: tomorrow) diff --git a/doc/source/command-objects/user-role.rst b/doc/source/command-objects/user-role.rst index a25e90f..8283f91 100644 --- a/doc/source/command-objects/user-role.rst +++ b/doc/source/command-objects/user-role.rst @@ -2,6 +2,8 @@ user role ========= +Identity v2 + user role list -------------- diff --git a/doc/source/command-objects/user.rst b/doc/source/command-objects/user.rst index 24a2725..9c81a40 100644 --- a/doc/source/command-objects/user.rst +++ b/doc/source/command-objects/user.rst @@ -72,13 +72,13 @@ Create new user user delete ----------- -Delete user +Delete user(s) .. program:: user delete .. code:: bash os user delete - <user> + <user> [<user> ...] .. option:: --domain <domain> @@ -101,28 +101,26 @@ List users .. code:: bash os user list - [--domain <domain>] [--project <project>] - [--group <group>] + [--domain <domain>] + [--group <group> | --project <project>] [--long] -.. option:: --domain <domain> - - Filter users by `<domain>` (name or ID) - - .. versionadded:: 3 - .. option:: --project <project> Filter users by `<project>` (name or ID) - *Removed in version 3.* +.. option:: --domain <domain> + + Filter users by `<domain>` (name or ID) + + *Identity version 3 only* .. option:: --group <group> Filter users by `<group>` membership (name or ID) - .. versionadded:: 3 + *Identity version 3 only* .. option:: --long @@ -193,6 +191,8 @@ Set user properties user show --------- +Display user details + .. program:: user show .. code:: bash @@ -209,4 +209,4 @@ user show .. _user_show-user: .. describe:: <user> - User to show (name or ID) + User to display (name or ID) diff --git a/doc/source/command-objects/volume-type.rst b/doc/source/command-objects/volume-type.rst new file mode 100644 index 0000000..0898df5 --- /dev/null +++ b/doc/source/command-objects/volume-type.rst @@ -0,0 +1,95 @@ +=========== +volume type +=========== + +Volume v1 + +volume type create +------------------ + +Create new volume type + +.. program:: volume type create +.. code:: bash + + os volume type create + [--property <key=value> [...] ] + <name> + +.. option:: --property <key=value> + + Set a property on this volume type (repeat option to set multiple properties) + +.. describe:: <name> + + New volume type name + +volume type delete +------------------ + +Delete volume type + +.. program:: volume type delete +.. code:: bash + + os volume type delete + <volume-type> + +.. describe:: <volume-type> + + Volume type to delete (name or ID) + +volume type list +---------------- + +List volume types + +.. program:: volume type list +.. code:: bash + + os volume type list + [--long] + +.. option:: --long + + List additional fields in output + +volume type set +--------------- + +Set volume type properties + +.. program:: volume type set +.. code:: bash + + os volume type set + [--property <key=value> [...] ] + <volume-type> + +.. option:: --property <key=value> + + Property to add or modify for this volume type (repeat option to set multiple properties) + +.. describe:: <volume-type> + + Volume type to modify (name or ID) + +volume type unset +----------------- + +Unset volume type properties + +.. program:: volume type unset +.. code:: bash + + os volume type unset + [--property <key>] + <volume-type> + +.. option:: --property <key> + + Property to remove from volume type (repeat option to remove multiple properties) + +.. describe:: <volume-type> + + Volume type to modify (name or ID) diff --git a/doc/source/command-objects/volume.rst b/doc/source/command-objects/volume.rst new file mode 100644 index 0000000..2eec2d7 --- /dev/null +++ b/doc/source/command-objects/volume.rst @@ -0,0 +1,189 @@ +====== +volume +====== + +Volume v1 + +volume create +------------- + +Create new volume + +.. program:: volume create +.. code:: bash + + os volume create + --size <size> + [--snapshot-id <snapshot-id>] + [--description <description>] + [--type <volume-type>] + [--user <user>] + [--project <project>] + [--availability-zone <availability-zone>] + [--image <image>] + [--source <volume>] + [--property <key=value> [...] ] + <name> + +.. option:: --size <size> (required) + + New volume size in GB + +.. option:: --snapshot-id <snapshot-id> + + Use <snapshot-id> as source of new volume + +.. option:: --description <description> + + New volume description + +.. option:: --type <volume-type> + + Use <volume-type> as the new volume type + +.. option:: --user <user> + + Specify an alternate user (name or ID) + +.. option:: --project <project> + + Specify an alternate project (name or ID) + +.. option:: --availability-zone <availability-zone> + + Create new volume in <availability-zone> + +.. option:: --image <image> + + Use <image> as source of new volume (name or ID) + +.. option:: --source <source> + + Volume to clone (name or ID) + +.. option:: --property <key=value> + + Set a property on this volume (repeat option to set multiple properties) + +.. describe:: <name> + + New volume name + +The :option:`--project` and :option:`--user` options are typically only +useful for admin users, but may be allowed for other users depending on +the policy of the cloud and the roles granted to the user. + +volume delete +------------- + +Delete volume(s) + +.. program:: volume delete +.. code:: bash + + os volume delete + [--force] + <volume> [<volume> ...] + +.. option:: --force + + Attempt forced removal of volume(s), regardless of state (defaults to False) + +.. describe:: <volume> + + Volume(s) to delete (name or ID) + +volume list +----------- + +List volumes + +.. program:: volume list +.. code:: bash + + os volume list + [--status <status>] + [--name <name>] + [--all-projects] + [--long] + +.. option:: --status <status> + + Filter results by status + +.. option:: --name <name> + + Filter results by name + +.. option:: --all-projects + + Include all projects (admin only) + +.. option:: --long + + List additional fields in output + +volume set +---------- + +Set volume properties + +.. program:: volume set +.. code:: bash + + os volume set + [--name <name>] + [--description <description>] + [--property <key=value> [...] ] + <volume> + +.. option:: --name <name> + + New volume name + +.. option:: --description <description> + + New volume description + +.. option:: --property <key=value> + + Property to add or modify for this volume (repeat option to set multiple properties) + +.. describe:: <volume> + + Volume to modify (name or ID) + +volume show +----------- + +Show volume details + +.. program:: volume show +.. code:: bash + + os volume show + <volume> + +.. describe:: <volume> + + Volume to display (name or ID) + +volume unset +------------ + +Unset volume properties + +.. program:: volume unset +.. code:: bash + + os volume unset + [--property <key>] + <volume> + +.. option:: --property <key> + + Property to remove from volume (repeat option to remove multiple properties) + +.. describe:: <volume> + + Volume to modify (name or ID) diff --git a/doc/source/commands.rst b/doc/source/commands.rst index 04c451c..6dbaf11 100644 --- a/doc/source/commands.rst +++ b/doc/source/commands.rst @@ -69,48 +69,54 @@ 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. -* ``access token``: Identity - long-lived OAuth-based token +* ``access token``: (**Identity**) long-lived OAuth-based token +* ``availability zone``: (**Compute**) a logical partition of hosts or volume services * ``aggregate``: (**Compute**) a grouping of servers -* ``backup``: Volume - a volume copy +* ``backup``: (**Volume**) a volume copy * ``catalog``: (**Identity**) service catalog * ``console log``: (**Compute**) server console text dump * ``console url``: (**Compute**) server remote console URL -* ``consumer``: Identity - OAuth-based delegatee -* ``container``: Object Store - a grouping of objects +* ``consumer``: (**Identity**) OAuth-based delegatee +* ``container``: (**Object Store**) a grouping of objects * ``credentials``: (**Identity**) specific to identity providers -* ``domain``: Identity - a grouping of projects +* ``domain``: (**Identity**) a grouping of projects +* ``ec2 cedentials``: (**Identity**) AWS EC2-compatible credentials * ``endpoint``: (**Identity**) the base URL used to contact a specific service * ``extension``: (**Compute**, **Identity**, **Volume**) OpenStack server API extensions -* ``flavor``: Compute - pre-defined configurations of servers: ram, root disk, etc -* ``group``: Identity - a grouping of users +* ``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 * ``host``: Compute - the physical computer running a hypervisor * ``hypervisor``: Compute - the virtual machine manager -* ``identity provider``: Identity - a source of users and authentication -* ``image``: Image - a disk image +* ``identity provider``: (**Identity**) a source of users and authentication +* ``image``: (**Image**) a disk image * ``ip fixed``: Compute, Network - an internal IP address assigned to a server * ``ip floating``: Compute, Network - a public IP address that can be mapped to a server * ``keypair``: (**Compute**) an SSH public key * ``limits``: (**Compute**, **Volume**) resource usage limits +* ``mapping``: (**Identity**) a definition to translate identity provider attributes to Identity concepts * ``module``: internal - installed Python modules in the OSC process * ``network``: Network - a virtual network for connecting servers and other resources -* ``object``: Object Store - a single file in the Object Store -* ``policy``: Identity - determines authorization +* ``object``: (**Object Store**) a single file in the Object Store +* ``policy``: (**Identity**) determines authorization * ``project``: (**Identity**) owns a group of resources * ``quota``: (**Compute**, **Volume**) resource usage restrictions -* ``region``: (**Identity**) -* ``request token``: Identity - temporary OAuth-based token -* ``role``: Identity - a policy object used to determine authorization +* ``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 * ``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 * ``server image``: (**Compute**) saved server disk image -* ``service``: Identity - a cloud service -* ``snapshot``: Volume - a point-in-time copy of a volume +* ``service``: (**Identity**) a cloud service +* ``snapshot``: (**Volume**) a point-in-time copy of a volume * ``token``: (**Identity**) a bearer token managed by Identity service +* ``usage``: (**Compute**) display host resources being consumed * ``user``: (**Identity**) individual cloud resources users * ``user role``: (**Identity**) roles assigned to a user -* ``volume``: Volume - block volumes -* ``volume type``: Volume - deployment-specific types of volumes available +* ``volume``: (**Volume**) block volumes +* ``volume type``: (**Volume**) deployment-specific types of volumes available Actions ------- diff --git a/doc/source/humaninterfaceguide.rst b/doc/source/humaninterfaceguide.rst new file mode 100644 index 0000000..9cca5aa --- /dev/null +++ b/doc/source/humaninterfaceguide.rst @@ -0,0 +1,360 @@ +===================== +Human Interface Guide +===================== + +*Note: This page covers the OpenStackClient CLI only but looks familiar +because it was derived from the Horizon HIG.* + +Overview +======== + +What is a HIG? +The Human Interface Guidelines document was created for OpenStack developers +in order to direct the creation of new OpenStackClient command interfaces. + +Personas +======== + +Personas are archetypal users of the system. Keep these types of users in +mind when designing the interface. + +Alice the admin +--------------- + +Alice is an administrator who is responsible for maintaining the OpenStack +cloud installation. She has many years of experience with Linux systems +administration. + +Darren the deployer +------------------- + +Darren is responsible for doing the initial OpenStack deployment on the +host machines. + +Emile the end-user +------------------ + +Emile uses the cloud to do software development inside of the virtual +machines. She uses the command-line tools because she finds it quicker +than using the dashboard. + +Principles +========== + +The principles established in this section define the high-level priorities +to be used when designing and evaluating interactions for the OpenStack +command line interface. Principles are broad in scope and can be considered +the philosophical foundation for the OpenStack experience; while they may +not describe the tactical implementation of design, they should be used +when deciding between multiple courses of design. + +A significant theme for designing for the OpenStack experience concerns +focusing on common uses of the system rather than adding complexity to support +functionality that is rarely used. + +Consistency +----------- + +Consistency between OpenStack experiences will ensure that the command line +interface feels like a single experience instead of a jumble of disparate +products. Fractured experiences only serve to undermine user expectations +about how they should interact with the system, creating an unreliable user +experience. To avoid this, each interaction and visual representation within +the system must be used uniformly and predictably. The architecture and elements +detailed in this document will provide a strong foundation for establishing a +consistent experience. + +Example Review Criteria +~~~~~~~~~~~~~~~~~~~~~~~ + +* Do the command actions adhere to a consistent application of actions? +* Has a new type of command subject or output been introduced? +* Does the design use command elements (options and arguments) as defined? + (See Core Elements.) +* Can any newly proposed command elements (actions or subjects) be accomplished + with existing elements? + +* Does the design adhere to the structural model of the core experience? + (See Core Architecture.) +* Are any data objects displayed or manipulated in a way contradictory to how + they are handled elsewhere in the core experience? + +Simplicity +---------- + +To best support new users and create straight forward interactions, designs +should be as simple as possible. When crafting new commands, designs should +minimize the amount of noise present in output: large amounts of +nonessential data, overabundance of possible actions, etc. Designs should +focus on the intent of the command, requiring only the necessary components +and either removing superfluous elements or making +them accessible through optional arguments. An example of this principle occurs +in OpenStack's use of tables: only the most often used columns are shown by +default. Further data may be accessed through the output control options, +allowing users to specify the types of data that they find useful in their +day-to-day work. + +Example Review Criteria +~~~~~~~~~~~~~~~~~~~~~~~ + +* Can options be used to combine otherwise similar commands? + +* How many of the displayed elements are relevant to the majority of users? +* If multiple actions are required for the user to complete a task, is each + step required or can the process be more efficient? + +User-Centered Design +-------------------- + +Commands should be design based on how a user will interact with the system +and not how the system's backend is organized. While database structures and +APIs may define what is possible, they often do not define good user +experience; consider user goals and the way in which users will want to +interact with their data, then design for these work flows and mold the +interface to the user, not the user to the interface. + +Commands should be discoverable via the interface itself. + +To determine a list of available commands, use the :code:`-h` or +:code:`--help` options: + +.. code-block:: bash + + $ openstack --help + +For help with an individual command, use the :code:`help` command: + +.. code-block:: bash + + $ openstack help server create + +Example Review Criteria +~~~~~~~~~~~~~~~~~~~~~~~ + +* How quickly can a user figure out how to accomplish a given task? +* Has content been grouped and ordered according to usage relationships? +* Do work flows support user goals or add complexity? + +Transparency +------------ + +Make sure users understand the current state of their infrastructure and +interactions. For example, users should be able to access information about +the state of each machine/virtual machine easily, without having to actively +seek out this information. Whenever the user initiates an action, make sure +a confirmation is displayed[1] to show that an input has been received. Upon +completion of a process, make sure the user is informed. Ensure that the user +never questions the state of their environment. + +[1] This goes against the common UNIX philosophy of only reporting error +conditions and output that is specifically requested. + +Example Review Criteria +~~~~~~~~~~~~~~~~~~~~~~~ + +* Does the user receive feedback when initiating a process? +* When a process is completed? +* Does the user have quick access to the state of their infrastructure? + + +Architecture +============ + +Command Structure +----------------- + +OpenStackClient has a consistent and predictable format for all of its commands. + +* The top level command name is :code:`openstack` +* Sub-commands take the form: + +.. code-block:: bash + + openstack [<global-options>] <object-1> <action> [<object-2>] [<command-arguments>] + +Subcommands shall have three distinct parts to its commands (in order that they appear): + +* global options +* command object(s) and action +* command options and arguments + +Output formats: + +* user-friendly tables with headers, etc +* machine-parsable delimited + +Notes: + +* All long options names shall begin with two dashes ('--') and use a single dash + ('-') internally between words (:code:`--like-this`). Underscores ('_') shall not + be used in option names. +* Authentication options conform to the common CLI authentication guidelines in + :doc:`authentication`. + +Global Options +~~~~~~~~~~~~~~ + +Global options are global in the sense that they apply to every command +invocation regardless of action to be performed. They include authentication +credentials and API version selection. Most global options have a corresponding +environment variable that may also be used to set the value. If both are present, +the command-line option takes priority. The environment variable names are derived +from the option name by dropping the leading dashes ('--'), converting each embedded +dash ('-') to an underscore ('_'), and converting to upper case. + +For example, :code:`--os-username` can be set from the environment via +:code:`OS_USERNAME`. + +--help +++++++ + +The standard :code:`--help` global option displays the documentation for invoking +the program and a list of the available commands on standard output. All other +options and commands are ignored when this is present. The traditional short +form help option (:code:`-h`) is also available. + +--version ++++++++++ + +The standard :code:`--version` option displays the name and version on standard +output. All other options and commands are ignored when this is present. + +Command Object(s) and Action +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Commands consist of an object described by one or more words followed by an action. Commands that require two objects have the primary object ahead of the action and the secondary object after the action. Any positional arguments identifying the objects shall appear in the same order as the objects. In badly formed English it is expressed as "(Take) object1 (and perform) action (using) object2 (to it)." + + <object-1> <action> [<object-2>] + +Examples: + +* :code:`group add user <group> <user>` +* :code:`volume type list` # Note that :code:`volume type` is a two-word + single object + +The :code:`help` command is unique as it appears in front of a normal command +and displays the help text for that command rather than execute it. + +Object names are always specified in command in their singular form. This is +contrary to natural language use. + +Command Arguments and Options +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Each command may have its own set of options distinct from the global options. +They follow the same style as the global options and always appear between +the command and any positional arguments the command requires. + +Option Forms +++++++++++++ + +* **boolean**: boolean options shall use a form of :code:`--<true>|--<false>` + (preferred) or :code:`--<option>|--no-<option>`. For example, the + :code:`enabled` state of a project is set with :code:`--enable|--disable`. + +Command Output +-------------- + +The default command output is pretty-printed using the Python +:code:`prettytable` module. + +Machine-parsable output format may be specified with the :code:`--format` +option to :code:`list` and :code:`show` commands. :code:`list` commands +have an option (:code:`--format csv`) for CSV output and :code:`show` commands +have an option (:code:`--format shell`) for the shell variable assignment +syntax of :code:`var="value"`. In both cases, all data fields are quoted with `"` + +Help Commands +------------- + +The help system is considered separately due to its special status +among the commands. Rather than performing tasks against a system, it +provides information about the commands available to perform those +tasks. The format of the :code:`help` command therefore varies from the +form for other commands in that the :code:`help` command appears in front +of the first object in the command. + +The options :code:`--help` and :code:`-h` display the global options and a +list of the supported commands. Note that the commands shown depend on the API +versions that are in effect; i.e. if :code:`--os-identity-api-version=3` is +present Identity API v3 commands are shown. + +Examples +======== + +The following examples depict common command and output formats expected to be produces by the OpenStack client. + +Authentication +-------------- + +Using global options: + +.. code-block:: bash + + $ openstack --os-tenant-name ExampleCo --os-username demo --os-password secrete --os-auth-url http://localhost:5000:/v2.0 server show appweb01 + +------------------------+-----------------------------------------------------+ + | Property | Value | + +------------------------+-----------------------------------------------------+ + | OS-DCF:diskConfig | MANUAL | + | OS-EXT-STS:power_state | 1 | + | flavor | m1.small | + | id | dcbc2185-ba17-4f81-95a9-c3fae9b2b042 | + | image | Ubuntu 12.04 (754c231e-ade2-458c-9f91-c8df107ff7ef) | + | keyname | demo-key | + | name | appweb01 | + | private_address | 10.4.128.13 | + | status | ACTIVE | + | user | demo | + +------------------------+-----------------------------------------------------+ + +Using environment variables: + +.. code-block:: bash + + $ export OS_TENANT_NAME=ExampleCo + $ export OS_USERNAME=demo + $ export OS_PASSWORD=secrete + $ export OS_AUTH_URL=http://localhost:5000:/v2.0 + $ openstack server show appweb01 + +------------------------+-----------------------------------------------------+ + | Property | Value | + +------------------------+-----------------------------------------------------+ + | OS-DCF:diskConfig | MANUAL | + | OS-EXT-STS:power_state | 1 | + | flavor | m1.small | + | id | dcbc2185-ba17-4f81-95a9-c3fae9b2b042 | + | image | Ubuntu 12.04 (754c231e-ade2-458c-9f91-c8df107ff7ef) | + | keyname | demo-key | + | name | appweb01 | + | private_address | 10.4.128.13 | + | status | ACTIVE | + | user | demo | + +------------------------+-----------------------------------------------------+ + +Machine Output Format +--------------------- + +Using the csv output format with a list command: + +.. code-block:: bash + + $ openstack server list --format csv + "ID","Name","Status","Private_Address" + "ead97d84-6988-47fc-9637-3564fc36bc4b","appweb01","ACTIVE","10.4.128.13" + +Using the show command options of shell output format and adding a prefix of +:code:`my_` to avoid collisions with existing environment variables: + +.. code-block:: bash + + $ openstack server show --format shell --prefix my_ appweb01 + my_OS-DCF:diskConfig="MANUAL" + my_OS-EXT-STS:power_state="1" + my_flavor="m1.small" + my_id="dcbc2185-ba17-4f81-95a9-c3fae9b2b042" + my_image="Ubuntu 12.04 (754c231e-ade2-458c-9f91-c8df107ff7ef)" + my_keyname="demo-key" + my_name="appweb01" + my_private_address="10.4.128.13" + my_status="ACTIVE" + my_user="demo" diff --git a/doc/source/index.rst b/doc/source/index.rst index 41c2487..60a43d4 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -11,34 +11,50 @@ Contents: .. toctree:: :maxdepth: 1 - releases command-list commands plugins authentication interactive + humaninterfaceguide + releases man/openstack Getting Started --------------- -* Check out `the wiki`_ -* Try `some commands`_ +* Try :doc:`some commands <command-list>` * Read the source `on OpenStack's Git server`_ +* Install OpenStackClient from `PyPi`_ or a `tarball`_ + + +Project Goals +------------- -.. _the wiki: https://wiki.openstack.org/OpenStackClient -.. _some commands: https://wiki.openstack.org/OpenStackClient/Commands +* Use the OpenStack Python API libraries, extending or replacing them as required +* Use a consistent naming and structure for commands and arguments +* Provide consistent output formats with optional machine parseable formats +* Use a single-binary approach that also contains an embedded shell that can execute + multiple commands on a single authentication (see libvirt's virsh for an example) +* Independence from the OpenStack project names; only API names are referenced (to + the extent possible) Contributing ============ -Code is hosted `on OpenStack's Git server`_. Submit bugs to the -python-openstackclient project on `Launchpad`_. Submit code to -the openstack/python-openstackclient project using `Gerrit`_. +OpenStackClient utilizes all of the usual OpenStack processes and requirements for +contributions. The code is hosted `on OpenStack's Git server`_. `Bug reports`_ +and `blueprints`_ may be submitted to the :code:`python-openstackclient` project +on `Launchpad`_. Code may be submitted to the +:code:`openstack/python-openstackclient` project using `Gerrit`_. -.. _on OpenStack's Git server: https://git.openstack.org/cgit/openstack/python-openstackclient/tree +.. _`on OpenStack's Git server`: https://git.openstack.org/cgit/openstack/python-openstackclient/tree .. _Launchpad: https://launchpad.net/python-openstackclient .. _Gerrit: http://docs.openstack.org/infra/manual/developers.html#development-workflow +.. _Bug reports: https://bugs.launchpad.net/python-openstackclient/+bugs +.. _blueprints: https://blueprints.launchpad.net/python-openstackclient +.. _PyPi: https://pypi.python.org/pypi/python-openstackclient +.. _tarball: http://tarballs.openstack.org/python-openstackclient Indices and Tables ================== diff --git a/doc/source/releases.rst b/doc/source/releases.rst index 0f0f33f..b8647a1 100644 --- a/doc/source/releases.rst +++ b/doc/source/releases.rst @@ -2,6 +2,74 @@ Release Notes ============= +1.0.2 (19 Jan 2015) +=================== + +* The OpenStackClient content from the OpenStack Wiki has been migrated into + the OSC source repo. This includes the :doc:`commands`, :doc:`command-list` + and :doc:`humaninterfaceguide` documents. + +* Set a default domain ID when both ``OS_USER_DOMAIN_ID`` and + ``OS_USER_DOMAIN_NAME`` are not set. This is also done for + ``OS_PROJECT_DOMAIN_ID`` and ``OS_PROJECT_DOMAIN_NAME`. + (*Identity API v3 only*). + Bug 1385338_: Improve domain related defaults when using v3 identity + +* Add new ``usage show`` command to display project resource usage information. + Bug 1400796_: Quick usage report - nova usage + +* Add ``--project`` option to ``user list`` command to filter users by project + (*Identity API v3 only*). + Bug 1397251_: allow `openstack user list` to use other filters + +* Add ``--user`` to ``project list`` command to filter projects by user + (*Identity API v3 only*). + Bug 1394793_: support the keystone api /v3/users/$userid/projects + +* Add ``--project`` and ``--user`` options to ``role list`` to filter roles + by project and/or user. This makes the v2 command very similar to the + v3 command. + (*Identity API v2 only*). + Bug 1409179_: `user role list` command should be worked into `role list` + +* Bug 1390507_: Quota show requires cinder in keystone catalog +* Bug 1400531_: Authentication failure results in useless error message +* Bug 1400597_: delete multiple objects +* Bug 1400795_: No list availability zones option +* Bug 1404073_: type should be required for v2.0 service create +* Bug 1404434_: add missing docs for service command +* Bug 1404931_: volume list does not show attached servers +* Bug 1404997_: Allow description to be set for service create/update +* Bug 1405416_: Compute region selection broken +* Bug 1406654_: Remove deprecated commands from help +* Bug 1406737_: v3 endpoint related commands access service.name without check +* Bug 1408585_: Backup list doesn't show backup's name +* Bug 1410364_: Version discovery fails with default Keystone config +* Bug 1411179_: network client don't use session +* Bug 1411337_: identity v3 service list should have "description" column + +.. _1385338: https://bugs.launchpad.net/bugs/1385338 +.. _1406654: https://bugs.launchpad.net/bugs/1406654 +.. _1411337: https://bugs.launchpad.net/bugs/1411337 +.. _1400531: https://bugs.launchpad.net/bugs/1400531 +.. _1406737: https://bugs.launchpad.net/bugs/1406737 +.. _1409179: https://bugs.launchpad.net/bugs/1409179 +.. _1408585: https://bugs.launchpad.net/bugs/1408585 +.. _1405416: https://bugs.launchpad.net/bugs/1405416 +.. _1404931: https://bugs.launchpad.net/bugs/1404931 +.. _1404434: https://bugs.launchpad.net/bugs/1404434 +.. _1404073: https://bugs.launchpad.net/bugs/1404073 +.. _1400796: https://bugs.launchpad.net/bugs/1400796 +.. _1400795: https://bugs.launchpad.net/bugs/1400795 +.. _1400597: https://bugs.launchpad.net/bugs/1400597 +.. _1397251: https://bugs.launchpad.net/bugs/1397251 +.. _1394793: https://bugs.launchpad.net/bugs/1394793 +.. _1390507: https://bugs.launchpad.net/bugs/1390507 +.. _1410364: https://bugs.launchpad.net/bugs/1410364 +.. _1404997: https://bugs.launchpad.net/bugs/1404997 +.. _1411179: https://bugs.launchpad.net/bugs/1411179 + + 1.0.1 (08 Dec 2014) =================== diff --git a/examples/common.py b/examples/common.py index ad3a5e4..1ccea2a 100755 --- a/examples/common.py +++ b/examples/common.py @@ -102,6 +102,12 @@ def base_parser(parser): default=env('OS_CACERT'), help='CA certificate bundle file (Env: OS_CACERT)', ) + parser.add_argument( + '--os-default-domain', + metavar='<auth-domain>', + default='default', + help='Default domain ID, default=default (Env: OS_DEFAULT_DOMAIN)', + ) verify_group = parser.add_mutually_exclusive_group() verify_group.add_argument( '--verify', diff --git a/openstackclient/api/api.py b/openstackclient/api/api.py index 67386aa..90b4e9c 100644 --- a/openstackclient/api/api.py +++ b/openstackclient/api/api.py @@ -15,8 +15,7 @@ import simplejson as json -from keystoneclient.openstack.common.apiclient \ - import exceptions as ksc_exceptions +from keystoneclient import exceptions as ksc_exceptions from keystoneclient import session as ksc_session from openstackclient.common import exceptions diff --git a/openstackclient/api/auth.py b/openstackclient/api/auth.py index bfb2f83..14bb01d 100644 --- a/openstackclient/api/auth.py +++ b/openstackclient/api/auth.py @@ -16,14 +16,17 @@ import argparse import logging +from six.moves.urllib import parse as urlparse import stevedore from oslo.config import cfg from keystoneclient.auth import base +from keystoneclient.auth.identity.generic import password as ksc_password from openstackclient.common import exceptions as exc from openstackclient.common import utils +from openstackclient.i18n import _ LOG = logging.getLogger(__name__) @@ -72,7 +75,7 @@ def select_auth_plugin(options): auth_plugin_name = 'v2password' else: # let keystoneclient figure it out itself - auth_plugin_name = 'password' + auth_plugin_name = 'osc_password' elif options.os_token: if options.os_identity_api_version == '3': auth_plugin_name = 'v3token' @@ -122,6 +125,25 @@ def build_auth_params(auth_plugin_name, cmd_options): return (auth_plugin_class, auth_params) +def check_valid_auth_options(options, auth_plugin_name): + """Perform basic option checking, provide helpful error messages""" + + msg = '' + if auth_plugin_name.endswith('password'): + if not options.os_username: + msg += _('Set a username with --os-username or OS_USERNAME\n') + if not options.os_auth_url: + msg += _('Set an authentication URL, with --os-auth-url or' + ' OS_AUTH_URL\n') + if (not options.os_project_id and not options.os_domain_id and not + options.os_domain_name and not options.os_project_name): + msg += _('Set a scope, such as a project or domain, with ' + '--os-project-name or OS_PROJECT_NAME') + + if msg: + raise exc.CommandError('Missing parameter(s): \n%s' % msg) + + def build_auth_plugins_option_parser(parser): """Auth plugins options builder @@ -140,7 +162,7 @@ def build_auth_plugins_option_parser(parser): ' (Env: OS_AUTH_TYPE)', choices=available_plugins ) - # make sur we catch old v2.0 env values + # make sure we catch old v2.0 env values envs = { 'OS_PROJECT_NAME': utils.env( 'OS_PROJECT_NAME', @@ -230,3 +252,45 @@ class TokenEndpoint(base.BaseAuthPlugin): ]) return options + + +class OSCGenericPassword(ksc_password.Password): + """Auth plugin hack to work around broken Keystone configurations + + The default Keystone configuration uses http://localhost:xxxx in + admin_endpoint and public_endpoint and are returned in the links.href + attribute by the version routes. Deployments that do not set these + are unusable with newer keystoneclient version discovery. + + """ + + def create_plugin(self, session, version, url, raw_status=None): + """Handle default Keystone endpoint configuration + + Build the actual API endpoint from the scheme, host and port of the + original auth URL and the rest from the returned version URL. + """ + + ver_u = urlparse.urlparse(url) + + # Only hack this if it is the default setting + if ver_u.netloc.startswith('localhost'): + auth_u = urlparse.urlparse(self.auth_url) + # from original auth_url: scheme, netloc + # from api_url: path, query (basically, the rest) + url = urlparse.urlunparse(( + auth_u.scheme, + auth_u.netloc, + ver_u.path, + ver_u.params, + ver_u.query, + ver_u.fragment, + )) + LOG.debug('Version URL updated: %s' % url) + + return super(OSCGenericPassword, self).create_plugin( + session=session, + version=version, + url=url, + raw_status=raw_status, + ) diff --git a/openstackclient/common/clientmanager.py b/openstackclient/common/clientmanager.py index 0396e83..2908c8f 100644 --- a/openstackclient/common/clientmanager.py +++ b/openstackclient/common/clientmanager.py @@ -74,13 +74,16 @@ class ClientManager(object): :param pw_func: Callback function for asking the user for a password. The function takes an optional string for the prompt ('Password: ' on None) and - returns a string containig the password + returns a string containing the password """ # If no auth type is named by the user, select one based on # the supplied options self.auth_plugin_name = auth.select_auth_plugin(auth_options) + # Basic option checking to avoid unhelpful error messages + auth.check_valid_auth_options(auth_options, self.auth_plugin_name) + # Horrible hack alert...must handle prompt for null password if # password auth is requested. if (self.auth_plugin_name.endswith('password') and @@ -98,6 +101,23 @@ class ClientManager(object): self._auth_ref = None self.timing = auth_options.timing + default_domain = auth_options.os_default_domain + # NOTE(stevemar): If PROJECT_DOMAIN_ID or PROJECT_DOMAIN_NAME is + # present, then do not change the behaviour. Otherwise, set the + # PROJECT_DOMAIN_ID to 'OS_DEFAULT_DOMAIN' for better usability. + if (self._api_version.get('identity') == '3' and + not self._auth_params.get('project_domain_id') and + not self._auth_params.get('project_domain_name')): + self._auth_params['project_domain_id'] = default_domain + + # NOTE(stevemar): If USER_DOMAIN_ID or USER_DOMAIN_NAME is present, + # then do not change the behaviour. Otherwise, set the USER_DOMAIN_ID + # to 'OS_DEFAULT_DOMAIN' for better usability. + if (self._api_version.get('identity') == '3' and + not self._auth_params.get('user_domain_id') and + not self._auth_params.get('user_domain_name')): + self._auth_params['user_domain_id'] = default_domain + # For compatibility until all clients can be updated if 'project_name' in self._auth_params: self._project_name = self._auth_params['project_name'] diff --git a/openstackclient/common/quota.py b/openstackclient/common/quota.py index edf4ffd..6d04b5c 100644 --- a/openstackclient/common/quota.py +++ b/openstackclient/common/quota.py @@ -147,6 +147,21 @@ class ShowQuota(show.ShowOne): ) return parser + def get_quota(self, client, parsed_args): + try: + if parsed_args.quota_class: + quota = client.quota_classes.get(parsed_args.project) + elif parsed_args.default: + quota = client.quotas.defaults(parsed_args.project) + else: + quota = client.quotas.get(parsed_args.project) + except Exception as e: + if type(e).__name__ == 'EndpointNotFound': + return {} + else: + raise e + return quota._info + def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) @@ -159,23 +174,12 @@ class ShowQuota(show.ShowOne): # does not exist. If this is determined to be the # intended behaviour of the API we will validate # the argument with Identity ourselves later. - if parsed_args.quota_class: - compute_quota = compute_client.quota_classes.get( - parsed_args.project) - volume_quota = volume_client.quota_classes.get( - parsed_args.project) - elif parsed_args.default: - compute_quota = compute_client.quotas.defaults( - parsed_args.project) - volume_quota = volume_client.quotas.defaults( - parsed_args.project) - else: - compute_quota = compute_client.quotas.get(parsed_args.project) - volume_quota = volume_client.quotas.get(parsed_args.project) + compute_quota_info = self.get_quota(compute_client, parsed_args) + volume_quota_info = self.get_quota(volume_client, parsed_args) info = {} - info.update(compute_quota._info) - info.update(volume_quota._info) + info.update(compute_quota_info) + info.update(volume_quota_info) # Map the internal quota names to the external ones for k, v in itertools.chain( diff --git a/openstackclient/compute/client.py b/openstackclient/compute/client.py index 3725350..166747d 100644 --- a/openstackclient/compute/client.py +++ b/openstackclient/compute/client.py @@ -50,6 +50,7 @@ def make_client(instance): extensions=extensions, http_log_debug=http_log_debug, timings=instance.timing, + region_name=instance._region_name, ) return client diff --git a/openstackclient/compute/v2/aggregate.py b/openstackclient/compute/v2/aggregate.py index bfc2b11..84ed5c7 100644 --- a/openstackclient/compute/v2/aggregate.py +++ b/openstackclient/compute/v2/aggregate.py @@ -290,7 +290,7 @@ class SetAggregate(show.ShowOne): class ShowAggregate(show.ShowOne): - """Show a specific aggregate""" + """Display aggregate details""" log = logging.getLogger(__name__ + '.ShowAggregate') @@ -299,7 +299,7 @@ class ShowAggregate(show.ShowOne): parser.add_argument( 'aggregate', metavar='<aggregate>', - help='Aggregate to show (name or ID)', + help='Aggregate to display (name or ID)', ) return parser diff --git a/openstackclient/compute/v2/availability_zone.py b/openstackclient/compute/v2/availability_zone.py new file mode 100644 index 0000000..648c0ee --- /dev/null +++ b/openstackclient/compute/v2/availability_zone.py @@ -0,0 +1,102 @@ +# 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 + + def take_action(self, parsed_args): + self.log.debug('take_action(%s)', 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/flavor.py b/openstackclient/compute/v2/flavor.py index 6dd00b1..bb89a85 100644 --- a/openstackclient/compute/v2/flavor.py +++ b/openstackclient/compute/v2/flavor.py @@ -34,64 +34,71 @@ class CreateFlavor(show.ShowOne): parser = super(CreateFlavor, self).get_parser(prog_name) parser.add_argument( "name", - metavar="<name>", + metavar="<flavor-name>", help="New flavor name", ) parser.add_argument( "--id", metavar="<id>", default='auto', - help="Unique flavor ID; 'auto' will create a UUID " - "(default: auto)") + help="Unique flavor ID; 'auto' creates a UUID " + "(default: auto)", + ) parser.add_argument( "--ram", type=int, metavar="<size-mb>", default=256, - help="Memory size in MB (default 256M)") + help="Memory size in MB (default 256M)", + ) parser.add_argument( "--disk", type=int, metavar="<size-gb>", default=0, - help="Disk size in GB (default 0G)") + help="Disk size in GB (default 0G)", + ) parser.add_argument( "--ephemeral", type=int, metavar="<size-gb>", + default=0, help="Ephemeral disk size in GB (default 0G)", - default=0) + ) parser.add_argument( "--swap", type=int, metavar="<size-gb>", + default=0, help="Swap space size in GB (default 0G)", - default=0) + ) parser.add_argument( "--vcpus", type=int, metavar="<vcpus>", default=1, - help="Number of vcpus (default 1)") + help="Number of vcpus (default 1)", + ) parser.add_argument( "--rxtx-factor", type=int, metavar="<factor>", + default=1, help="RX/TX factor (default 1)", - default=1) + ) public_group = parser.add_mutually_exclusive_group() public_group.add_argument( "--public", dest="public", action="store_true", default=True, - help="Flavor is accessible to other projects (default)", + help="Flavor is available to other projects (default)", ) public_group.add_argument( "--private", dest="public", action="store_false", - help="Flavor is inaccessible to other projects", + help="Flavor is not available to other projects", ) return parser @@ -118,7 +125,7 @@ class CreateFlavor(show.ShowOne): class DeleteFlavor(command.Command): - """Delete a flavor""" + """Delete flavor""" log = logging.getLogger(__name__ + ".DeleteFlavor") @@ -168,7 +175,7 @@ class ListFlavor(lister.Lister): class ShowFlavor(show.ShowOne): - """Show flavor details""" + """Display flavor details""" log = logging.getLogger(__name__ + ".ShowFlavor") diff --git a/openstackclient/compute/v2/keypair.py b/openstackclient/compute/v2/keypair.py index 6a158d8..edf25f8 100644 --- a/openstackclient/compute/v2/keypair.py +++ b/openstackclient/compute/v2/keypair.py @@ -80,7 +80,7 @@ class CreateKeypair(show.ShowOne): class DeleteKeypair(command.Command): - """Delete a public key""" + """Delete public key""" log = logging.getLogger(__name__ + '.DeleteKeypair') @@ -121,7 +121,7 @@ class ListKeypair(lister.Lister): class ShowKeypair(show.ShowOne): - """Show public key details""" + """Display public key details""" log = logging.getLogger(__name__ + '.ShowKeypair') @@ -130,7 +130,7 @@ class ShowKeypair(show.ShowOne): parser.add_argument( 'name', metavar='<key>', - help='Public key to show', + help='Public key to display', ) parser.add_argument( '--public-key', diff --git a/openstackclient/compute/v2/security_group.py b/openstackclient/compute/v2/security_group.py index cd33085..f7ffb1d 100644 --- a/openstackclient/compute/v2/security_group.py +++ b/openstackclient/compute/v2/security_group.py @@ -23,7 +23,7 @@ from cliff import command from cliff import lister from cliff import show -from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc +from keystoneclient import exceptions as ksc_exc from novaclient.v1_1 import security_group_rules from openstackclient.common import parseractions from openstackclient.common import utils diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index 5ab1d5f..a5d8b0c 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -511,25 +511,27 @@ class CreateServerImage(show.ShowOne): class DeleteServer(command.Command): - """Delete server 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( - 'server', + 'servers', metavar='<server>', - help=_('Server (name or ID)'), + nargs="+", + help=_('Server(s) to delete (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 - server = utils.find_resource( - compute_client.servers, parsed_args.server) - compute_client.servers.delete(server.id) + for server in parsed_args.servers: + server_obj = utils.find_resource( + compute_client.servers, server) + compute_client.servers.delete(server_obj.id) return diff --git a/openstackclient/compute/v2/usage.py b/openstackclient/compute/v2/usage.py index ed98af2..31b90c2 100644 --- a/openstackclient/compute/v2/usage.py +++ b/openstackclient/compute/v2/usage.py @@ -20,12 +20,14 @@ import logging import sys from cliff import lister +from cliff import show +import six from openstackclient.common import utils class ListUsage(lister.Lister): - """List resource usage per project. """ + """List resource usage per project""" log = logging.getLogger(__name__ + ".ListUsage") @@ -36,7 +38,7 @@ class ListUsage(lister.Lister): metavar="<start>", default=None, help="Usage range start date, ex 2012-01-20" - " (default: 4 weeks ago)." + " (default: 4 weeks ago)" ) parser.add_argument( "--end", @@ -60,12 +62,14 @@ class ListUsage(lister.Lister): compute_client = self.app.client_manager.compute columns = ( "tenant_id", + "server_usages", "total_memory_mb_usage", "total_vcpus_usage", "total_local_gb_usage" ) column_headers = ( "Project", + "Servers", "RAM MB-Hours", "CPU Hours", "Disk GB-Hours" @@ -84,7 +88,7 @@ class ListUsage(lister.Lister): else: end = now + datetime.timedelta(days=1) - usage_list = compute_client.usage.list(start, end) + usage_list = compute_client.usage.list(start, end, detailed=True) # Cache the project list project_cache = {} @@ -95,8 +99,8 @@ class ListUsage(lister.Lister): # Just forget it if there's any trouble pass - if len(usage_list) > 0: - sys.stdout.write("Usage from %s to %s:" % ( + if parsed_args.formatter == 'table' and len(usage_list) > 0: + sys.stdout.write("Usage from %s to %s: \n" % ( start.strftime(dateformat), end.strftime(dateformat), )) @@ -106,8 +110,98 @@ class ListUsage(lister.Lister): s, columns, formatters={ 'tenant_id': _format_project, + 'server_usages': lambda x: len(x), 'total_memory_mb_usage': lambda x: float("%.2f" % x), 'total_vcpus_usage': lambda x: float("%.2f" % x), 'total_local_gb_usage': lambda x: float("%.2f" % x), }, ) for s in usage_list)) + + +class ShowUsage(show.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( + "--project", + metavar="<project>", + default=None, + help="Name or ID of project to show usage for" + ) + parser.add_argument( + "--start", + metavar="<start>", + default=None, + help="Usage range start date, ex 2012-01-20" + " (default: 4 weeks ago)" + ) + parser.add_argument( + "--end", + metavar="<end>", + default=None, + help="Usage range end date, ex 2012-01-20 (default: tomorrow)" + ) + 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" + now = datetime.datetime.utcnow() + + if parsed_args.start: + start = datetime.datetime.strptime(parsed_args.start, dateformat) + else: + start = now - datetime.timedelta(weeks=4) + + if parsed_args.end: + end = datetime.datetime.strptime(parsed_args.end, dateformat) + else: + end = now + datetime.timedelta(days=1) + + if parsed_args.project: + project = utils.find_resource( + identity_client.projects, + parsed_args.project, + ).id + else: + # Get the project from the current auth + project = self.app.client_manager.auth_ref.project_id + + usage = compute_client.usage.get(project, start, end) + + if parsed_args.formatter == 'table': + sys.stdout.write("Usage from %s to %s on project %s: \n" % ( + start.strftime(dateformat), + end.strftime(dateformat), + project + )) + + info = {} + info['Servers'] = len(usage.server_usages) + info['RAM MB-Hours'] = float("%.2f" % usage.total_memory_mb_usage) + info['CPU Hours'] = float("%.2f" % usage.total_vcpus_usage) + info['Disk GB-Hours'] = float("%.2f" % usage.total_local_gb_usage) + return zip(*sorted(six.iteritems(info))) + + +# This is out of order due to the subclass, will eventually be removed + +class ListProjectUsage(ListUsage): + """List resource usage per project""" + + deprecated = True + + log = logging.getLogger('DEPRECATED:') + + def take_action(self, parsed_args): + self.log.warning( + "%s is deprecated, use 'usage list'", + getattr(self, 'cmd_name', 'this command'), + ) + return super(ListProjectUsage, self).take_action(parsed_args) diff --git a/openstackclient/identity/v2_0/catalog.py b/openstackclient/identity/v2_0/catalog.py index 1a96fdf..f604837 100644 --- a/openstackclient/identity/v2_0/catalog.py +++ b/openstackclient/identity/v2_0/catalog.py @@ -59,7 +59,7 @@ class ListCatalog(lister.Lister): class ShowCatalog(show.ShowOne): - """Show service catalog details""" + """Display service catalog details""" log = logging.getLogger(__name__ + '.ShowCatalog') @@ -68,7 +68,7 @@ class ShowCatalog(show.ShowOne): parser.add_argument( 'service', metavar='<service>', - help=_('Service to display (type, name or ID)'), + help=_('Service to display (type or name)'), ) return parser @@ -83,17 +83,17 @@ class ShowCatalog(show.ShowOne): data = None for service in sc.get_data(): - if ( - 'name' in service and - service['name'] != parsed_args.service and - 'type' in service and - service['type'] != parsed_args.service - ): - continue - - data = service - data['endpoints'] = _format_endpoints(data['endpoints']) - if 'endpoints_links' in data: - data.pop('endpoints_links') + if (service.get('name') == parsed_args.service or + service.get('type') == parsed_args.service): + data = service + data['endpoints'] = _format_endpoints(data['endpoints']) + if 'endpoints_links' in data: + data.pop('endpoints_links') + break + + if not data: + self.app.log.error('service %s not found\n' % + parsed_args.service) + return ([], []) return zip(*sorted(six.iteritems(data))) diff --git a/openstackclient/identity/v2_0/ec2creds.py b/openstackclient/identity/v2_0/ec2creds.py index a20ffd4..90553eb 100644 --- a/openstackclient/identity/v2_0/ec2creds.py +++ b/openstackclient/identity/v2_0/ec2creds.py @@ -37,12 +37,14 @@ class CreateEC2Creds(show.ShowOne): parser.add_argument( '--project', metavar='<project>', - help=_('Specify a project [admin only]'), + help=_('Specify an alternate project' + ' (default: current authenticated project)'), ) parser.add_argument( '--user', metavar='<user>', - help=_('Specify a user [admin only]'), + help=_('Specify an alternate user' + ' (default: current authenticated user)'), ) return parser @@ -95,7 +97,7 @@ class DeleteEC2Creds(command.Command): parser.add_argument( '--user', metavar='<user>', - help=_('Specify a user [admin only]'), + help=_('Specify a user'), ) return parser @@ -125,7 +127,7 @@ class ListEC2Creds(lister.Lister): parser.add_argument( '--user', metavar='<user>', - help=_('Specify a user [admin only]'), + help=_('Specify a user'), ) return parser @@ -154,7 +156,7 @@ class ListEC2Creds(lister.Lister): class ShowEC2Creds(show.ShowOne): - """Show EC2 credentials""" + """Display EC2 credentials details""" log = logging.getLogger(__name__ + '.ShowEC2Creds') @@ -168,7 +170,7 @@ class ShowEC2Creds(show.ShowOne): parser.add_argument( '--user', metavar='<user>', - help=_('Specify a user [admin only]'), + help=_('Specify a user'), ) return parser diff --git a/openstackclient/identity/v2_0/endpoint.py b/openstackclient/identity/v2_0/endpoint.py index c5189b6..370a931 100644 --- a/openstackclient/identity/v2_0/endpoint.py +++ b/openstackclient/identity/v2_0/endpoint.py @@ -28,7 +28,7 @@ from openstackclient.identity import common class CreateEndpoint(show.ShowOne): - """Create endpoint""" + """Create new endpoint""" log = logging.getLogger(__name__ + '.CreateEndpoint') @@ -36,25 +36,30 @@ class CreateEndpoint(show.ShowOne): parser = super(CreateEndpoint, self).get_parser(prog_name) parser.add_argument( 'service', - metavar='<endpoint-service>', - help=_('New endpoint service')) - parser.add_argument( - '--region', - metavar='<region>', - help=_('New endpoint region')) + metavar='<service>', + help=_('New endpoint service (name or ID)'), + ) parser.add_argument( '--publicurl', - metavar='<public-url>', + metavar='<url>', required=True, - help=_('New endpoint public URL')) + help=_('New endpoint public URL (required)'), + ) parser.add_argument( '--adminurl', - metavar='<admin-url>', - help=_('New endpoint admin URL')) + metavar='<url>', + help=_('New endpoint admin URL'), + ) parser.add_argument( '--internalurl', - metavar='<internal-url>', - help=_('New endpoint internal URL')) + metavar='<url>', + help=_('New endpoint internal URL'), + ) + parser.add_argument( + '--region', + metavar='<region-id>', + help=_('New endpoint region ID'), + ) return parser def take_action(self, parsed_args): @@ -76,7 +81,7 @@ class CreateEndpoint(show.ShowOne): class DeleteEndpoint(command.Command): - """Delete endpoint command""" + """Delete endpoint""" log = logging.getLogger(__name__ + '.DeleteEndpoint') @@ -85,7 +90,7 @@ class DeleteEndpoint(command.Command): parser.add_argument( 'endpoint', metavar='<endpoint-id>', - help=_('ID of endpoint to delete')) + help=_('Endpoint ID to delete')) return parser def take_action(self, parsed_args): @@ -96,7 +101,7 @@ class DeleteEndpoint(command.Command): class ListEndpoint(lister.Lister): - """List endpoint command""" + """List endpoints""" log = logging.getLogger(__name__ + '.ListEndpoint') @@ -106,7 +111,8 @@ class ListEndpoint(lister.Lister): '--long', action='store_true', default=False, - help=_('List additional fields in output')) + help=_('List additional fields in output'), + ) return parser def take_action(self, parsed_args): @@ -131,7 +137,7 @@ class ListEndpoint(lister.Lister): class ShowEndpoint(show.ShowOne): - """Show endpoint command""" + """Display endpoint details""" log = logging.getLogger(__name__ + '.ShowEndpoint') @@ -139,8 +145,9 @@ class ShowEndpoint(show.ShowOne): parser = super(ShowEndpoint, self).get_parser(prog_name) parser.add_argument( 'endpoint_or_service', - metavar='<endpoint_or_service>', - help=_('Endpoint ID or name, type or ID of service to display')) + metavar='<endpoint-id>', + help=_('Endpoint ID to display'), + ) return parser def take_action(self, parsed_args): diff --git a/openstackclient/identity/v2_0/project.py b/openstackclient/identity/v2_0/project.py index b2f9942..d01807a 100644 --- a/openstackclient/identity/v2_0/project.py +++ b/openstackclient/identity/v2_0/project.py @@ -21,7 +21,7 @@ import six from cliff import command from cliff import lister from cliff import show -from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc +from keystoneclient import exceptions as ksc_exc from openstackclient.common import parseractions from openstackclient.common import utils @@ -104,16 +104,17 @@ class CreateProject(show.ShowOne): class DeleteProject(command.Command): - """Delete an existing project""" + """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( - 'project', + 'projects', metavar='<project>', - help=_('Project to delete (name or ID)'), + nargs="+", + help=_('Project(s) to delete (name or ID)'), ) return parser @@ -121,12 +122,12 @@ class DeleteProject(command.Command): self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity - project = utils.find_resource( - identity_client.tenants, - parsed_args.project, - ) - - identity_client.tenants.delete(project.id) + for project in parsed_args.projects: + project_obj = utils.find_resource( + identity_client.tenants, + project, + ) + identity_client.tenants.delete(project_obj.id) return @@ -240,7 +241,7 @@ class SetProject(command.Command): class ShowProject(show.ShowOne): - """Show project details""" + """Display project details""" log = logging.getLogger(__name__ + '.ShowProject') @@ -249,7 +250,7 @@ class ShowProject(show.ShowOne): parser.add_argument( 'project', metavar='<project>', - help=_('Project to show (name or ID)')) + help=_('Project to display (name or ID)')) return parser def take_action(self, parsed_args): diff --git a/openstackclient/identity/v2_0/role.py b/openstackclient/identity/v2_0/role.py index cec9509..3167f50 100644 --- a/openstackclient/identity/v2_0/role.py +++ b/openstackclient/identity/v2_0/role.py @@ -21,7 +21,7 @@ import six from cliff import command from cliff import lister from cliff import show -from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc +from keystoneclient import exceptions as ksc_exc from openstackclient.common import exceptions from openstackclient.common import utils @@ -114,16 +114,17 @@ class CreateRole(show.ShowOne): class DeleteRole(command.Command): - """Delete an existing role""" + """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( - 'role', + 'roles', metavar='<role>', - help=_('Role to delete (name or ID)'), + nargs="+", + help=_('Role(s) to delete (name or ID)'), ) return parser @@ -131,12 +132,12 @@ class DeleteRole(command.Command): self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity - role = utils.find_resource( - identity_client.roles, - parsed_args.role, - ) - - identity_client.roles.delete(role.id) + for role in parsed_args.roles: + role_obj = utils.find_resource( + identity_client.roles, + role, + ) + identity_client.roles.delete(role_obj.id) return @@ -145,10 +146,75 @@ class ListRole(lister.Lister): log = logging.getLogger(__name__ + '.ListRole') + def get_parser(self, prog_name): + parser = super(ListRole, self).get_parser(prog_name) + parser.add_argument( + '--project', + metavar='<project>', + help='Filter roles by <project> (name or ID)', + ) + parser.add_argument( + '--user', + metavar='<user>', + help='Filter roles by <user> (name or ID)', + ) + return parser + def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) - columns = ('ID', 'Name') - data = self.app.client_manager.identity.roles.list() + identity_client = self.app.client_manager.identity + auth_ref = self.app.client_manager.auth_ref + + # No user or project specified, list all roles in the system + if not parsed_args.user and not parsed_args.project: + columns = ('ID', 'Name') + data = identity_client.roles.list() + elif parsed_args.user and parsed_args.project: + user = utils.find_resource( + identity_client.users, + parsed_args.user, + ) + project = utils.find_resource( + identity_client.projects, + parsed_args.project, + ) + data = identity_client.roles.roles_for_user(user.id, project.id) + + elif parsed_args.user: + user = utils.find_resource( + identity_client.users, + parsed_args.user, + ) + if self.app.client_manager.auth_ref: + project = utils.find_resource( + identity_client.projects, + auth_ref.project_id + ) + else: + msg = _("Project must be specified") + raise exceptions.CommandError(msg) + data = identity_client.roles.roles_for_user(user.id, project.id) + elif parsed_args.project: + project = utils.find_resource( + identity_client.projects, + parsed_args.project, + ) + if self.app.client_manager.auth_ref: + user = utils.find_resource( + identity_client.users, + auth_ref.user_id + ) + else: + msg = _("User must be specified") + raise exceptions.CommandError(msg) + data = identity_client.roles.roles_for_user(user.id, project.id) + + if parsed_args.user or parsed_args.project: + columns = ('ID', 'Name', 'Project', 'User') + for user_role in data: + user_role.user = user.name + user_role.project = project.name + return (columns, (utils.get_item_properties( s, columns, @@ -225,7 +291,7 @@ class ListUserRole(lister.Lister): class RemoveRole(command.Command): - """Remove role from project:user""" + """Remove role from project : user""" log = logging.getLogger(__name__ + '.RemoveRole') @@ -234,7 +300,7 @@ class RemoveRole(command.Command): parser.add_argument( 'role', metavar='<role>', - help=_('Role to remove from <project>:<user> (name or ID)'), + help=_('Role to remove (name or ID)'), ) parser.add_argument( '--project', @@ -266,7 +332,7 @@ class RemoveRole(command.Command): class ShowRole(show.ShowOne): - """Show single role""" + """Display role details""" log = logging.getLogger(__name__ + '.ShowRole') @@ -275,7 +341,7 @@ class ShowRole(show.ShowOne): parser.add_argument( 'role', metavar='<role>', - help=_('Role to show (name or ID)'), + help=_('Role to display (name or ID)'), ) return parser diff --git a/openstackclient/identity/v2_0/service.py b/openstackclient/identity/v2_0/service.py index e8848dd..f863023 100644 --- a/openstackclient/identity/v2_0/service.py +++ b/openstackclient/identity/v2_0/service.py @@ -15,6 +15,7 @@ """Service action implementations""" +import argparse import logging import six @@ -36,19 +37,24 @@ class CreateService(show.ShowOne): def get_parser(self, prog_name): parser = super(CreateService, self).get_parser(prog_name) parser.add_argument( - 'name', - metavar='<service-name>', - help=_('New service name'), + 'type_or_name', + metavar='<type>', + help=_('New service type (compute, image, identity, volume, etc)'), ) - parser.add_argument( + type_or_name_group = parser.add_mutually_exclusive_group() + type_or_name_group.add_argument( '--type', - metavar='<service-type>', - required=True, - help=_('New service type (compute, image, identity, volume, etc)'), + metavar='<type>', + help=argparse.SUPPRESS, + ) + type_or_name_group.add_argument( + '--name', + metavar='<name>', + help=_('New service name'), ) parser.add_argument( '--description', - metavar='<service-description>', + metavar='<description>', help=_('New service description'), ) return parser @@ -57,9 +63,28 @@ class CreateService(show.ShowOne): self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity + type_or_name = parsed_args.type_or_name + name = parsed_args.name + type = parsed_args.type + + # If only a single positional is present, it's a <type>. + # This is not currently legal so it is considered a new case. + if not type and not name: + type = type_or_name + # If --type option is present then positional is handled as <name>; + # display deprecation message. + elif type: + name = type_or_name + self.log.warning(_('The argument --type is deprecated, use service' + ' create --name <service-name> type instead.')) + # If --name option is present the positional is handled as <type>. + # Making --type optional is new, but back-compatible + elif name: + type = type_or_name + service = identity_client.services.create( - parsed_args.name, - parsed_args.type, + name, + type, parsed_args.description) info = {} @@ -100,7 +125,8 @@ class ListService(lister.Lister): '--long', action='store_true', default=False, - help=_('List additional fields in output')) + help=_('List additional fields in output'), + ) return parser def take_action(self, parsed_args): @@ -109,17 +135,16 @@ class ListService(lister.Lister): if parsed_args.long: columns = ('ID', 'Name', 'Type', 'Description') else: - columns = ('ID', 'Name') + columns = ('ID', 'Name', 'Type') data = self.app.client_manager.identity.services.list() - return (columns, - (utils.get_item_properties( - s, columns, - formatters={}, - ) for s in data)) + return ( + columns, + (utils.get_item_properties(s, columns) for s in data), + ) class ShowService(show.ShowOne): - """Show service details""" + """Display service details""" log = logging.getLogger(__name__ + '.ShowService') diff --git a/openstackclient/identity/v2_0/user.py b/openstackclient/identity/v2_0/user.py index 955e19e..500aeec 100644 --- a/openstackclient/identity/v2_0/user.py +++ b/openstackclient/identity/v2_0/user.py @@ -21,7 +21,7 @@ import six from cliff import command from cliff import lister from cliff import show -from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc +from keystoneclient import exceptions as ksc_exc from openstackclient.common import utils from openstackclient.i18n import _ # noqa @@ -128,16 +128,17 @@ class CreateUser(show.ShowOne): class DeleteUser(command.Command): - """Delete user""" + """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( - 'user', + 'users', metavar='<user>', - help=_('User to delete (name or ID)'), + nargs="+", + help=_('User(s) to delete (name or ID)'), ) return parser @@ -145,12 +146,12 @@ class DeleteUser(command.Command): self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity - user = utils.find_resource( - identity_client.users, - parsed_args.user, - ) - - identity_client.users.delete(user.id) + for user in parsed_args.users: + user_obj = utils.find_resource( + identity_client.users, + user, + ) + identity_client.users.delete(user_obj.id) return @@ -348,7 +349,7 @@ class SetUser(command.Command): class ShowUser(show.ShowOne): - """Show user details""" + """Display user details""" log = logging.getLogger(__name__ + '.ShowUser') diff --git a/openstackclient/identity/v3/consumer.py b/openstackclient/identity/v3/consumer.py index b7e57d8..ffbd510 100644 --- a/openstackclient/identity/v3/consumer.py +++ b/openstackclient/identity/v3/consumer.py @@ -27,7 +27,7 @@ from openstackclient.common import utils class CreateConsumer(show.ShowOne): - """Create consumer command""" + """Create new consumer""" log = logging.getLogger(__name__ + '.CreateConsumer') @@ -35,7 +35,7 @@ class CreateConsumer(show.ShowOne): parser = super(CreateConsumer, self).get_parser(prog_name) parser.add_argument( '--description', - metavar='<consumer-description>', + metavar='<description>', help='New consumer description', ) return parser @@ -51,7 +51,7 @@ class CreateConsumer(show.ShowOne): class DeleteConsumer(command.Command): - """Delete consumer command""" + """Delete consumer""" log = logging.getLogger(__name__ + '.DeleteConsumer') @@ -60,7 +60,7 @@ class DeleteConsumer(command.Command): parser.add_argument( 'consumer', metavar='<consumer>', - help='ID of consumer to delete', + help='Consumer to delete', ) return parser @@ -74,7 +74,7 @@ class DeleteConsumer(command.Command): class ListConsumer(lister.Lister): - """List consumer command""" + """List consumers""" log = logging.getLogger(__name__ + '.ListConsumer') @@ -90,7 +90,7 @@ class ListConsumer(lister.Lister): class SetConsumer(command.Command): - """Set consumer command""" + """Set consumer properties""" log = logging.getLogger(__name__ + '.SetConsumer') @@ -99,11 +99,11 @@ class SetConsumer(command.Command): parser.add_argument( 'consumer', metavar='<consumer>', - help='ID of consumer to change', + help='Consumer to modify', ) parser.add_argument( '--description', - metavar='<new-consumer-description>', + metavar='<description>', help='New consumer description', ) return parser @@ -118,7 +118,7 @@ class SetConsumer(command.Command): kwargs['description'] = parsed_args.description if not len(kwargs): - sys.stdout.write("Consumer not updated, no arguments present") + sys.stdout.write('Consumer not updated, no arguments present') return consumer = identity_client.oauth1.consumers.update( @@ -127,7 +127,7 @@ class SetConsumer(command.Command): class ShowConsumer(show.ShowOne): - """Show consumer command""" + """Display consumer details""" log = logging.getLogger(__name__ + '.ShowConsumer') @@ -136,7 +136,7 @@ class ShowConsumer(show.ShowOne): parser.add_argument( 'consumer', metavar='<consumer>', - help='ID of consumer to display', + help='Consumer to display', ) return parser diff --git a/openstackclient/identity/v3/domain.py b/openstackclient/identity/v3/domain.py index 1233fea..38f99a9 100644 --- a/openstackclient/identity/v3/domain.py +++ b/openstackclient/identity/v3/domain.py @@ -22,14 +22,14 @@ import sys from cliff import command from cliff import lister from cliff import show -from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc +from keystoneclient import exceptions as ksc_exc from openstackclient.common import utils from openstackclient.i18n import _ # noqa class CreateDomain(show.ShowOne): - """Create domain command""" + """Create new domain""" log = logging.getLogger(__name__ + '.CreateDomain') @@ -42,21 +42,20 @@ class CreateDomain(show.ShowOne): ) parser.add_argument( '--description', - metavar='<domain-description>', + metavar='<description>', help='New domain description', ) enable_group = parser.add_mutually_exclusive_group() enable_group.add_argument( '--enable', - dest='enabled', action='store_true', - default=True, - help='Enable domain') + help='Enable domain (default)', + ) enable_group.add_argument( '--disable', - dest='enabled', - action='store_false', - help='Disable domain') + action='store_true', + help='Disable domain', + ) parser.add_argument( '--or-show', action='store_true', @@ -68,11 +67,15 @@ class CreateDomain(show.ShowOne): self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity + enabled = True + if parsed_args.disable: + enabled = False + try: domain = identity_client.domains.create( name=parsed_args.name, description=parsed_args.description, - enabled=parsed_args.enabled, + enabled=enabled, ) except ksc_exc.Conflict as e: if parsed_args.or_show: @@ -87,7 +90,7 @@ class CreateDomain(show.ShowOne): class DeleteDomain(command.Command): - """Delete domain command""" + """Delete domain""" log = logging.getLogger(__name__ + '.DeleteDomain') @@ -96,7 +99,7 @@ class DeleteDomain(command.Command): parser.add_argument( 'domain', metavar='<domain>', - help='Name or ID of domain to delete', + help='Domain to delete (name or ID)', ) return parser @@ -110,7 +113,7 @@ class DeleteDomain(command.Command): class ListDomain(lister.Lister): - """List domain command""" + """List domains""" log = logging.getLogger(__name__ + '.ListDomain') @@ -126,7 +129,7 @@ class ListDomain(lister.Lister): class SetDomain(command.Command): - """Set domain command""" + """Set domain properties""" log = logging.getLogger(__name__ + '.SetDomain') @@ -135,28 +138,26 @@ class SetDomain(command.Command): parser.add_argument( 'domain', metavar='<domain>', - help='Name or ID of domain to change', + help='Domain to modify (name or ID)', ) parser.add_argument( '--name', - metavar='<new-domain-name>', + metavar='<name>', help='New domain name', ) parser.add_argument( '--description', - metavar='<domain-description>', + metavar='<description>', help='New domain description', ) enable_group = parser.add_mutually_exclusive_group() enable_group.add_argument( '--enable', - dest='enabled', action='store_true', - help='Enable domain (default)', + help='Enable domain', ) enable_group.add_argument( '--disable', - dest='disabled', action='store_true', help='Disable domain', ) @@ -172,9 +173,10 @@ class SetDomain(command.Command): kwargs['name'] = parsed_args.name if parsed_args.description: kwargs['description'] = parsed_args.description - if parsed_args.enabled: + + if parsed_args.enable: kwargs['enabled'] = True - if parsed_args.disabled: + if parsed_args.disable: kwargs['enabled'] = False if not kwargs: @@ -185,7 +187,7 @@ class SetDomain(command.Command): class ShowDomain(show.ShowOne): - """Show domain command""" + """Display domain details""" log = logging.getLogger(__name__ + '.ShowDomain') @@ -194,7 +196,7 @@ class ShowDomain(show.ShowOne): parser.add_argument( 'domain', metavar='<domain>', - help='Name or ID of domain to display', + help='Domain to display (name or ID)', ) return parser diff --git a/openstackclient/identity/v3/endpoint.py b/openstackclient/identity/v3/endpoint.py index 0c077c5..52db5ac 100644 --- a/openstackclient/identity/v3/endpoint.py +++ b/openstackclient/identity/v3/endpoint.py @@ -27,8 +27,15 @@ from openstackclient.common import utils from openstackclient.identity import common +def get_service_name(service): + if hasattr(service, 'name'): + return service.name + else: + return '' + + class CreateEndpoint(show.ShowOne): - """Create endpoint command""" + """Create new endpoint""" log = logging.getLogger(__name__ + '.CreateEndpoint') @@ -37,27 +44,31 @@ class CreateEndpoint(show.ShowOne): parser.add_argument( 'service', metavar='<service>', - help='Name or ID of new endpoint service') + help='New endpoint service (name or ID)', + ) parser.add_argument( 'interface', metavar='<interface>', choices=['admin', 'public', 'internal'], - help='New endpoint interface, must be admin, public or internal') + help='New endpoint interface type (admin, public or internal)', + ) parser.add_argument( 'url', metavar='<url>', - help='New endpoint URL') + help='New endpoint URL', + ) parser.add_argument( '--region', - metavar='<region>', - help='New endpoint region') + metavar='<region-id>', + help='New endpoint region ID', + ) enable_group = parser.add_mutually_exclusive_group() enable_group.add_argument( '--enable', dest='enabled', action='store_true', default=True, - help='Enable endpoint', + help='Enable endpoint (default)', ) enable_group.add_argument( '--disable', @@ -83,13 +94,13 @@ class CreateEndpoint(show.ShowOne): info = {} endpoint._info.pop('links') info.update(endpoint._info) - info['service_name'] = service.name + info['service_name'] = get_service_name(service) info['service_type'] = service.type return zip(*sorted(six.iteritems(info))) class DeleteEndpoint(command.Command): - """Delete endpoint command""" + """Delete endpoint""" log = logging.getLogger(__name__ + '.DeleteEndpoint') @@ -97,8 +108,9 @@ class DeleteEndpoint(command.Command): parser = super(DeleteEndpoint, self).get_parser(prog_name) parser.add_argument( 'endpoint', - metavar='<endpoint>', - help='ID of endpoint to delete') + metavar='<endpoint-id>', + help='Endpoint ID to delete', + ) return parser def take_action(self, parsed_args): @@ -111,7 +123,7 @@ class DeleteEndpoint(command.Command): class ListEndpoint(lister.Lister): - """List endpoint command""" + """List endpoints""" log = logging.getLogger(__name__ + '.ListEndpoint') @@ -120,17 +132,19 @@ class ListEndpoint(lister.Lister): parser.add_argument( '--service', metavar='<service>', - help='Filter by a specific service') + help='Filter by service', + ) parser.add_argument( '--interface', metavar='<interface>', choices=['admin', 'public', 'internal'], - help='Filter by a specific interface, must be admin, public or' - ' internal') + help='Filter by interface type (admin, public or internal)', + ) parser.add_argument( '--region', - metavar='<region>', - help='Filter by a specific region') + metavar='<region-id>', + help='Filter by region ID', + ) return parser def take_action(self, parsed_args): @@ -150,7 +164,7 @@ class ListEndpoint(lister.Lister): for ep in data: service = common.find_service(identity_client, ep.service_id) - ep.service_name = service.name + ep.service_name = get_service_name(service) ep.service_type = service.type return (columns, (utils.get_item_properties( @@ -160,7 +174,7 @@ class ListEndpoint(lister.Lister): class SetEndpoint(command.Command): - """Set endpoint command""" + """Set endpoint properties""" log = logging.getLogger(__name__ + '.SetEndpoint') @@ -168,25 +182,30 @@ class SetEndpoint(command.Command): parser = super(SetEndpoint, self).get_parser(prog_name) parser.add_argument( 'endpoint', - metavar='<endpoint>', - help='ID of endpoint to update') + metavar='<endpoint-id>', + help='Endpoint ID to modify', + ) + parser.add_argument( + '--region', + metavar='<region-id>', + help='New endpoint region ID', + ) parser.add_argument( '--interface', metavar='<interface>', choices=['admin', 'public', 'internal'], - help='New endpoint interface, must be admin|public|internal') + help='New endpoint interface type (admin, public or internal)', + ) parser.add_argument( '--url', metavar='<url>', - help='New endpoint URL') + help='New endpoint URL', + ) parser.add_argument( '--service', metavar='<service>', - help='Name or ID of new endpoint service') - parser.add_argument( - '--region', - metavar='<region>', - help='New endpoint region') + help='New endpoint service (name or ID)', + ) enable_group = parser.add_mutually_exclusive_group() enable_group.add_argument( '--enable', @@ -238,7 +257,7 @@ class SetEndpoint(command.Command): class ShowEndpoint(show.ShowOne): - """Show endpoint command""" + """Display endpoint details""" log = logging.getLogger(__name__ + '.ShowEndpoint') @@ -246,8 +265,9 @@ class ShowEndpoint(show.ShowOne): parser = super(ShowEndpoint, self).get_parser(prog_name) parser.add_argument( 'endpoint', - metavar='<endpoint>', - help='ID of endpoint to display') + metavar='<endpoint-id>', + help='Endpoint ID to display', + ) return parser def take_action(self, parsed_args): @@ -261,6 +281,6 @@ class ShowEndpoint(show.ShowOne): info = {} endpoint._info.pop('links') info.update(endpoint._info) - info['service_name'] = service.name + info['service_name'] = get_service_name(service) info['service_type'] = service.type return zip(*sorted(six.iteritems(info))) diff --git a/openstackclient/identity/v3/federation_protocol.py b/openstackclient/identity/v3/federation_protocol.py index 693ec94..57e8255 100644 --- a/openstackclient/identity/v3/federation_protocol.py +++ b/openstackclient/identity/v3/federation_protocol.py @@ -25,7 +25,7 @@ from openstackclient.common import utils class CreateProtocol(show.ShowOne): - """Create new Federation Protocol tied to an Identity Provider""" + """Create new federation protocol""" log = logging.getLogger(__name__ + 'CreateProtocol') @@ -34,16 +34,19 @@ class CreateProtocol(show.ShowOne): parser.add_argument( 'federation_protocol', metavar='<name>', - help='Protocol (must be unique per Identity Provider') + help='New federation protocol name (must be unique per identity ' + ' provider)') parser.add_argument( '--identity-provider', metavar='<identity-provider>', - help=('Identity Provider you want to add the Protocol to ' - '(must already exist)'), required=True) + required=True, + help='Identity provider that will support the new federation ' + ' protocol (name or ID) (required)') parser.add_argument( '--mapping', - metavar='<mapping>', required=True, - help='Mapping you want to be used (must already exist)') + metavar='<mapping>', + required=True, + help='Mapping that is to be used (name or ID) (required)') return parser @@ -66,7 +69,7 @@ class CreateProtocol(show.ShowOne): class DeleteProtocol(command.Command): - """Delete Federation Protocol tied to a Identity Provider""" + """Delete federation protocol""" log = logging.getLogger(__name__ + '.DeleteProtocol') @@ -74,12 +77,14 @@ class DeleteProtocol(command.Command): parser = super(DeleteProtocol, self).get_parser(prog_name) parser.add_argument( 'federation_protocol', - metavar='<name>', - help='Protocol (must be unique per Identity Provider') + metavar='<federation-protocol>', + help='Federation protocol to delete (name or ID)') parser.add_argument( '--identity-provider', - metavar='<identity-provider>', required=True, - help='Identity Provider the Protocol is tied to') + metavar='<identity-provider>', + required=True, + help='Identity provider that supports <federation-protocol> ' + '(name or ID) (required)') return parser @@ -92,7 +97,7 @@ class DeleteProtocol(command.Command): class ListProtocols(lister.Lister): - """List Protocols tied to an Identity Provider""" + """List federation protocols""" log = logging.getLogger(__name__ + '.ListProtocols') @@ -100,8 +105,9 @@ class ListProtocols(lister.Lister): parser = super(ListProtocols, self).get_parser(prog_name) parser.add_argument( '--identity-provider', - metavar='<identity-provider>', required=True, - help='Identity Provider the Protocol is tied to') + metavar='<identity-provider>', + required=True, + help='Identity provider to list (name or ID) (required)') return parser @@ -118,7 +124,7 @@ class ListProtocols(lister.Lister): class SetProtocol(command.Command): - """Set Protocol tied to an Identity Provider""" + """Set federation protocol properties""" log = logging.getLogger(__name__ + '.SetProtocol') @@ -127,21 +133,26 @@ class SetProtocol(command.Command): parser.add_argument( 'federation_protocol', metavar='<name>', - help='Protocol (must be unique per Identity Provider') + help='Federation protocol to modify (name or ID)') parser.add_argument( '--identity-provider', - metavar='<identity-provider>', required=True, - help=('Identity Provider you want to add the Protocol to ' - '(must already exist)')) + metavar='<identity-provider>', + required=True, + help='Identity provider that supports <federation-protocol> ' + '(name or ID) (required)') parser.add_argument( '--mapping', - metavar='<mapping>', required=True, - help='Mapping you want to be used (must already exist)') + metavar='<mapping>', + help='Mapping that is to be used (name or ID)') return parser def take_action(self, parsed_args): identity_client = self.app.client_manager.identity + if not parsed_args.mapping: + self.app.log.error("No changes requested") + return + protocol = identity_client.federation.protocols.update( parsed_args.identity_provider, parsed_args.federation_protocol, parsed_args.mapping) @@ -156,7 +167,7 @@ class SetProtocol(command.Command): class ShowProtocol(show.ShowOne): - """Show Protocol tied to an Identity Provider""" + """Display federation protocol details""" log = logging.getLogger(__name__ + '.ShowProtocol') @@ -164,13 +175,14 @@ class ShowProtocol(show.ShowOne): parser = super(ShowProtocol, self).get_parser(prog_name) parser.add_argument( 'federation_protocol', - metavar='<name>', - help='Protocol (must be unique per Identity Provider') + metavar='<federation-protocol>', + help='Federation protocol to display (name or ID)') parser.add_argument( '--identity-provider', - metavar='<identity-provider>', required=True, - help=('Identity Provider you want to add the Protocol to ' - '(must already exist)')) + metavar='<identity-provider>', + required=True, + help=('Identity provider that supports <federation-protocol> ' + '(name or ID) (required)')) return parser def take_action(self, parsed_args): diff --git a/openstackclient/identity/v3/group.py b/openstackclient/identity/v3/group.py index 5d3cf64..94e101f 100644 --- a/openstackclient/identity/v3/group.py +++ b/openstackclient/identity/v3/group.py @@ -22,7 +22,7 @@ import sys from cliff import command from cliff import lister from cliff import show -from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc +from keystoneclient import exceptions as ksc_exc from openstackclient.common import utils from openstackclient.i18n import _ # noqa @@ -39,12 +39,12 @@ class AddUserToGroup(command.Command): parser.add_argument( 'group', metavar='<group>', - help='Group name or ID that user will be added to', + help='Group to contain <user> (name or ID)', ) parser.add_argument( 'user', metavar='<user>', - help='User name or ID to add to group', + help='User to add to <group> (name or ID)', ) return parser @@ -68,7 +68,7 @@ class AddUserToGroup(command.Command): class CheckUserInGroup(command.Command): - """Checks that user is in a specific group""" + """Check user membership in group""" log = logging.getLogger(__name__ + '.CheckUserInGroup') @@ -77,12 +77,12 @@ class CheckUserInGroup(command.Command): parser.add_argument( 'group', metavar='<group>', - help='Group name or ID that user will be added to', + help='Group to check (name or ID)', ) parser.add_argument( 'user', metavar='<user>', - help='User name or ID to add to group', + help='User to check (name or ID)', ) return parser @@ -106,7 +106,7 @@ class CheckUserInGroup(command.Command): class CreateGroup(show.ShowOne): - """Create group command""" + """Create new group""" log = logging.getLogger(__name__ + '.CreateGroup') @@ -115,15 +115,18 @@ class CreateGroup(show.ShowOne): parser.add_argument( 'name', metavar='<group-name>', - help='New group name') - parser.add_argument( - '--description', - metavar='<group-description>', - help='New group description') + help='New group name', + ) parser.add_argument( '--domain', - metavar='<group-domain>', - help='References the domain ID or name which owns the group') + metavar='<domain>', + help='Domain to contain new group (name or ID)', + ) + parser.add_argument( + '--description', + metavar='<description>', + help='New group description', + ) parser.add_argument( '--or-show', action='store_true', @@ -159,20 +162,21 @@ class CreateGroup(show.ShowOne): class DeleteGroup(command.Command): - """Delete group 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( - 'group', + 'groups', metavar='<group>', - help='Name or ID of group to delete') + nargs="+", + help='Group(s) to delete (name or ID)') parser.add_argument( '--domain', metavar='<domain>', - help='Domain where group resides (name or ID)', + help='Domain containing group(s) (name or ID)', ) return parser @@ -180,16 +184,18 @@ class DeleteGroup(command.Command): self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity + domain = None if parsed_args.domain: domain = common.find_domain(identity_client, parsed_args.domain) - group = utils.find_resource(identity_client.groups, - parsed_args.group, - domain_id=domain.id) - else: - group = utils.find_resource(identity_client.groups, - parsed_args.group) - - identity_client.groups.delete(group.id) + for group in parsed_args.groups: + if domain is not None: + group_obj = utils.find_resource(identity_client.groups, + group, + domain_id=domain.id) + else: + group_obj = utils.find_resource(identity_client.groups, + group) + identity_client.groups.delete(group_obj.id) return @@ -208,7 +214,7 @@ class ListGroup(lister.Lister): parser.add_argument( '--user', metavar='<user>', - help='List group memberships for <user> (name or ID)', + help='Filter group list by <user> (name or ID)', ) parser.add_argument( '--long', @@ -256,7 +262,7 @@ class ListGroup(lister.Lister): class RemoveUserFromGroup(command.Command): - """Remove user to group""" + """Remove user from group""" log = logging.getLogger(__name__ + '.RemoveUserFromGroup') @@ -265,12 +271,12 @@ class RemoveUserFromGroup(command.Command): parser.add_argument( 'group', metavar='<group>', - help='Group name or ID that user will be removed from', + help='Group containing <user> (name or ID)', ) parser.add_argument( 'user', metavar='<user>', - help='User name or ID to remove from group', + help='User to remove from <group> (name or ID)', ) return parser @@ -294,7 +300,7 @@ class RemoveUserFromGroup(command.Command): class SetGroup(command.Command): - """Set group command""" + """Set group properties""" log = logging.getLogger(__name__ + '.SetGroup') @@ -303,18 +309,18 @@ class SetGroup(command.Command): parser.add_argument( 'group', metavar='<group>', - help='Name or ID of group to change') + help='Group to modify (name or ID)') parser.add_argument( '--name', - metavar='<new-group-name>', + metavar='<name>', help='New group name') parser.add_argument( '--domain', - metavar='<group-domain>', - help='New domain name or ID that will now own the group') + metavar='<domain>', + help='New domain to contain <group> (name or ID)') parser.add_argument( '--description', - metavar='<group-description>', + metavar='<description>', help='New group description') return parser @@ -338,7 +344,7 @@ class SetGroup(command.Command): class ShowGroup(show.ShowOne): - """Show group command""" + """Display group details""" log = logging.getLogger(__name__ + '.ShowGroup') @@ -347,12 +353,12 @@ class ShowGroup(show.ShowOne): parser.add_argument( 'group', metavar='<group>', - help='Name or ID of group to display', + help='Group to display (name or ID)', ) parser.add_argument( '--domain', metavar='<domain>', - help='Domain where group resides (name or ID)', + help='Domain containing <group> (name or ID)', ) return parser diff --git a/openstackclient/identity/v3/identity_provider.py b/openstackclient/identity/v3/identity_provider.py index 8a1b22d..691446d 100644 --- a/openstackclient/identity/v3/identity_provider.py +++ b/openstackclient/identity/v3/identity_provider.py @@ -15,7 +15,6 @@ import logging import six -import sys from cliff import command from cliff import lister @@ -33,22 +32,21 @@ class CreateIdentityProvider(show.ShowOne): parser = super(CreateIdentityProvider, self).get_parser(prog_name) parser.add_argument( 'identity_provider_id', - metavar='<identity-provider-id>', - help='New identity provider ID (must be unique)' + metavar='<name>', + help='New identity provider name (must be unique)' ) parser.add_argument( '--description', metavar='<description>', help='New identity provider description', ) - enable_identity_provider = parser.add_mutually_exclusive_group() enable_identity_provider.add_argument( '--enable', dest='enabled', action='store_true', default=True, - help='Enable identity provider', + help='Enable identity provider (default)', ) enable_identity_provider.add_argument( '--disable', @@ -71,7 +69,7 @@ class CreateIdentityProvider(show.ShowOne): class DeleteIdentityProvider(command.Command): - """Delete an identity provider""" + """Delete identity provider""" log = logging.getLogger(__name__ + '.DeleteIdentityProvider') @@ -79,8 +77,8 @@ class DeleteIdentityProvider(command.Command): parser = super(DeleteIdentityProvider, self).get_parser(prog_name) parser.add_argument( 'identity_provider', - metavar='<identity-provider-id>', - help='Identity provider ID to delete', + metavar='<identity-provider>', + help='Identity provider to delete', ) return parser @@ -118,10 +116,9 @@ class SetIdentityProvider(command.Command): parser = super(SetIdentityProvider, self).get_parser(prog_name) parser.add_argument( 'identity_provider', - metavar='<identity-provider-id>', - help='Identity provider ID to change', + metavar='<identity-provider>', + help='Identity provider to modify', ) - enable_identity_provider = parser.add_mutually_exclusive_group() enable_identity_provider.add_argument( '--enable', @@ -144,19 +141,17 @@ class SetIdentityProvider(command.Command): elif parsed_args.disable is True: enabled = False else: - sys.stdout.write("Identity Provider not updated, " - "no arguments present") + self.log.error("No changes requested") return (None, None) identity_provider = federation_client.identity_providers.update( parsed_args.identity_provider, enabled=enabled) - info = {} - info.update(identity_provider._info) - return zip(*sorted(six.iteritems(info))) + identity_provider._info.pop('links', None) + return zip(*sorted(six.iteritems(identity_provider._info))) class ShowIdentityProvider(show.ShowOne): - """Show identity provider details""" + """Display identity provider details""" log = logging.getLogger(__name__ + '.ShowIdentityProvider') @@ -164,8 +159,8 @@ class ShowIdentityProvider(show.ShowOne): parser = super(ShowIdentityProvider, self).get_parser(prog_name) parser.add_argument( 'identity_provider', - metavar='<identity-provider-id>', - help='Identity provider ID to show', + metavar='<identity-provider>', + help='Identity provider to display', ) return parser diff --git a/openstackclient/identity/v3/mapping.py b/openstackclient/identity/v3/mapping.py index c530a40..c79331e 100644 --- a/openstackclient/identity/v3/mapping.py +++ b/openstackclient/identity/v3/mapping.py @@ -80,7 +80,7 @@ class _RulesReader(object): class CreateMapping(show.ShowOne, _RulesReader): - """Create new federation mapping""" + """Create new mapping""" log = logging.getLogger(__name__ + '.CreateMapping') @@ -89,12 +89,12 @@ class CreateMapping(show.ShowOne, _RulesReader): parser.add_argument( 'mapping', metavar='<name>', - help='New mapping (must be unique)', + help='New mapping name (must be unique)', ) parser.add_argument( '--rules', - metavar='<rules>', required=True, - help='Filename with rules', + metavar='<filename>', required=True, + help='Filename that contains a set of mapping rules (required)', ) return parser @@ -112,7 +112,7 @@ class CreateMapping(show.ShowOne, _RulesReader): class DeleteMapping(command.Command): - """Delete federation mapping""" + """Delete mapping""" log = logging.getLogger(__name__ + '.DeleteMapping') @@ -120,7 +120,7 @@ class DeleteMapping(command.Command): parser = super(DeleteMapping, self).get_parser(prog_name) parser.add_argument( 'mapping', - metavar='<name>', + metavar='<mapping>', help='Mapping to delete', ) return parser @@ -134,7 +134,7 @@ class DeleteMapping(command.Command): class ListMapping(lister.Lister): - """List federation mappings""" + """List mappings""" log = logging.getLogger(__name__ + '.ListMapping') def take_action(self, parsed_args): @@ -149,8 +149,8 @@ class ListMapping(lister.Lister): return (columns, items) -class SetMapping(show.ShowOne, _RulesReader): - """Update federation mapping""" +class SetMapping(command.Command, _RulesReader): + """Set mapping properties""" log = logging.getLogger(__name__ + '.SetMapping') @@ -159,12 +159,12 @@ class SetMapping(show.ShowOne, _RulesReader): parser.add_argument( 'mapping', metavar='<name>', - help='Mapping to update.', + help='Mapping to modify', ) parser.add_argument( '--rules', - metavar='<rules>', required=True, - help='Filename with rules', + metavar='<filename>', + help='Filename that contains a new set of mapping rules', ) return parser @@ -172,19 +172,22 @@ class SetMapping(show.ShowOne, _RulesReader): self.log.debug('take_action(%s)' % parsed_args) identity_client = self.app.client_manager.identity + if not parsed_args.rules: + self.app.log.error("No changes requested") + return + rules = self._read_rules(parsed_args.rules) mapping = identity_client.federation.mappings.update( mapping=parsed_args.mapping, rules=rules) - info = {} - info.update(mapping._info) - return zip(*sorted(six.iteritems(info))) + mapping._info.pop('links', None) + return zip(*sorted(six.iteritems(mapping._info))) class ShowMapping(show.ShowOne): - """Show federation mapping details""" + """Display mapping details""" log = logging.getLogger(__name__ + '.ShowMapping') @@ -192,8 +195,8 @@ class ShowMapping(show.ShowOne): parser = super(ShowMapping, self).get_parser(prog_name) parser.add_argument( 'mapping', - metavar='<name>', - help='Mapping to show', + metavar='<mapping>', + help='Mapping to display', ) return parser diff --git a/openstackclient/identity/v3/policy.py b/openstackclient/identity/v3/policy.py index 802880b..8293542 100644 --- a/openstackclient/identity/v3/policy.py +++ b/openstackclient/identity/v3/policy.py @@ -27,7 +27,7 @@ from openstackclient.common import utils class CreatePolicy(show.ShowOne): - """Create policy command""" + """Create new policy""" log = logging.getLogger(__name__ + '.CreatePolicy') @@ -35,20 +35,21 @@ class CreatePolicy(show.ShowOne): parser = super(CreatePolicy, self).get_parser(prog_name) parser.add_argument( '--type', - metavar='<policy-type>', + metavar='<type>', default="application/json", - help='New MIME type of the policy blob - i.e.: application/json', + help='New MIME type of the policy rules file ' + '(defaults to application/json)', ) parser.add_argument( - 'blob_file', - metavar='<blob-file>', - help='New policy rule set itself, as a serialized blob, in a file', + 'rules', + metavar='<filename>', + help='New serialized policy rules file', ) return parser def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) - blob = utils.read_blob_file_contents(parsed_args.blob_file) + blob = utils.read_blob_file_contents(parsed_args.rules) identity_client = self.app.client_manager.identity policy = identity_client.policies.create( @@ -56,11 +57,12 @@ class CreatePolicy(show.ShowOne): ) policy._info.pop('links') + policy._info.update({'rules': policy._info.pop('blob')}) return zip(*sorted(six.iteritems(policy._info))) class DeletePolicy(command.Command): - """Delete policy command""" + """Delete policy""" log = logging.getLogger(__name__ + '.DeletePolicy') @@ -68,8 +70,8 @@ class DeletePolicy(command.Command): parser = super(DeletePolicy, self).get_parser(prog_name) parser.add_argument( 'policy', - metavar='<policy-id>', - help='ID of policy to delete', + metavar='<policy>', + help='Policy to delete', ) return parser @@ -81,28 +83,30 @@ class DeletePolicy(command.Command): class ListPolicy(lister.Lister): - """List policy command""" + """List policies""" log = logging.getLogger(__name__ + '.ListPolicy') def get_parser(self, prog_name): parser = super(ListPolicy, self).get_parser(prog_name) parser.add_argument( - '--include-blob', + '--long', action='store_true', default=False, - help='Additional fields are listed in output', + help='List additional fields in output', ) return parser def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) - if parsed_args.include_blob: + if parsed_args.long: columns = ('ID', 'Type', 'Blob') + column_headers = ('ID', 'Type', 'Rules') else: columns = ('ID', 'Type') + column_headers = columns data = self.app.client_manager.identity.policies.list() - return (columns, + return (column_headers, (utils.get_item_properties( s, columns, formatters={}, @@ -110,7 +114,7 @@ class ListPolicy(lister.Lister): class SetPolicy(command.Command): - """Set policy command""" + """Set policy properties""" log = logging.getLogger(__name__ + '.SetPolicy') @@ -118,18 +122,18 @@ class SetPolicy(command.Command): parser = super(SetPolicy, self).get_parser(prog_name) parser.add_argument( 'policy', - metavar='<policy-id>', - help='ID of policy to change', + metavar='<policy>', + help='Policy to modify', ) parser.add_argument( '--type', - metavar='<policy-type>', - help='New MIME Type of the policy blob - i.e.: application/json', + metavar='<type>', + help='New MIME type of the policy rules file', ) parser.add_argument( - '--blob-file', - metavar='<blob_file>', - help='New policy rule set itself, as a serialized blob, in a file', + '--rules', + metavar='<filename>', + help='New serialized policy rules file', ) return parser @@ -138,8 +142,8 @@ class SetPolicy(command.Command): identity_client = self.app.client_manager.identity blob = None - if parsed_args.blob_file: - blob = utils.read_blob_file_contents(parsed_args.blob_file) + if parsed_args.rules: + blob = utils.read_blob_file_contents(parsed_args.rules) kwargs = {} if blob: @@ -148,14 +152,14 @@ class SetPolicy(command.Command): kwargs['type'] = parsed_args.type if not kwargs: - sys.stdout.write("Policy not updated, no arguments present \n") + sys.stdout.write('Policy not updated, no arguments present \n') return identity_client.policies.update(parsed_args.policy, **kwargs) return class ShowPolicy(show.ShowOne): - """Show policy command""" + """Display policy details""" log = logging.getLogger(__name__ + '.ShowPolicy') @@ -163,8 +167,8 @@ class ShowPolicy(show.ShowOne): parser = super(ShowPolicy, self).get_parser(prog_name) parser.add_argument( 'policy', - metavar='<policy-id>', - help='ID of policy to display', + metavar='<policy>', + help='Policy to display', ) return parser @@ -175,4 +179,5 @@ class ShowPolicy(show.ShowOne): parsed_args.policy) policy._info.pop('links') + policy._info.update({'rules': policy._info.pop('blob')}) return zip(*sorted(six.iteritems(policy._info))) diff --git a/openstackclient/identity/v3/project.py b/openstackclient/identity/v3/project.py index 2c2d408..9a54e5c 100644 --- a/openstackclient/identity/v3/project.py +++ b/openstackclient/identity/v3/project.py @@ -21,7 +21,7 @@ import six from cliff import command from cliff import lister from cliff import show -from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc +from keystoneclient import exceptions as ksc_exc from openstackclient.common import parseractions from openstackclient.common import utils @@ -117,16 +117,17 @@ class CreateProject(show.ShowOne): class DeleteProject(command.Command): - """Delete an existing project""" + """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( - 'project', + 'projects', metavar='<project>', - help='Project to delete (name or ID)', + nargs="+", + help='Project(s) to delete (name or ID)', ) parser.add_argument( '--domain', @@ -139,16 +140,18 @@ class DeleteProject(command.Command): self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity + domain = None if parsed_args.domain: domain = common.find_domain(identity_client, parsed_args.domain) - project = utils.find_resource(identity_client.projects, - parsed_args.project, - domain_id=domain.id) - else: - project = utils.find_resource(identity_client.projects, - parsed_args.project) - - identity_client.projects.delete(project.id) + for project in parsed_args.projects: + if domain is not None: + project_obj = utils.find_resource(identity_client.projects, + project, + domain_id=domain.id) + else: + project_obj = utils.find_resource(identity_client.projects, + project) + identity_client.projects.delete(project_obj.id) return @@ -295,7 +298,7 @@ class SetProject(command.Command): class ShowProject(show.ShowOne): - """Show project command""" + """Display project details""" log = logging.getLogger(__name__ + '.ShowProject') @@ -304,7 +307,7 @@ class ShowProject(show.ShowOne): parser.add_argument( 'project', metavar='<project>', - help='Name or ID of project to display', + help='Project to display (name or ID)', ) parser.add_argument( '--domain', diff --git a/openstackclient/identity/v3/region.py b/openstackclient/identity/v3/region.py index cce3417..5cb51fc 100644 --- a/openstackclient/identity/v3/region.py +++ b/openstackclient/identity/v3/region.py @@ -35,22 +35,22 @@ class CreateRegion(show.ShowOne): # seems like poor UX, we will only support user-defined IDs. parser.add_argument( 'region', - metavar='<region>', - help=_('New region'), + metavar='<region-id>', + help=_('New region ID'), ) parser.add_argument( '--parent-region', - metavar='<parent-region>', - help=_('The parent region of new region'), + metavar='<region-id>', + help=_('Parent region ID'), ) parser.add_argument( '--description', - metavar='<region-description>', + metavar='<description>', help=_('New region description'), ) parser.add_argument( '--url', - metavar='<region-url>', + metavar='<url>', help=_('New region url'), ) @@ -82,8 +82,8 @@ class DeleteRegion(command.Command): parser = super(DeleteRegion, self).get_parser(prog_name) parser.add_argument( 'region', - metavar='<region>', - help=_('Region to delete'), + metavar='<region-id>', + help=_('Region ID to delete'), ) return parser @@ -104,8 +104,8 @@ class ListRegion(lister.Lister): parser = super(ListRegion, self).get_parser(prog_name) parser.add_argument( '--parent-region', - metavar='<parent-region>', - help=_('Filter by parent region'), + metavar='<region-id>', + help=_('Filter by parent region ID'), ) return parser @@ -137,22 +137,22 @@ class SetRegion(command.Command): parser = super(SetRegion, self).get_parser(prog_name) parser.add_argument( 'region', - metavar='<region>', - help=_('Region to change'), + metavar='<region-id>', + help=_('Region to modify'), ) parser.add_argument( '--parent-region', - metavar='<parent-region>', - help=_('New parent region of the region'), + metavar='<region-id>', + help=_('New parent region ID'), ) parser.add_argument( '--description', - metavar='<region-description>', + metavar='<description>', help=_('New region description'), ) parser.add_argument( '--url', - metavar='<region-url>', + metavar='<url>', help=_('New region url'), ) return parser @@ -179,7 +179,7 @@ class SetRegion(command.Command): class ShowRegion(show.ShowOne): - """Show region""" + """Display region details""" log = logging.getLogger(__name__ + '.ShowRegion') @@ -187,7 +187,7 @@ class ShowRegion(show.ShowOne): parser = super(ShowRegion, self).get_parser(prog_name) parser.add_argument( 'region', - metavar='<region>', + metavar='<region-id>', help=_('Region to display'), ) return parser diff --git a/openstackclient/identity/v3/role.py b/openstackclient/identity/v3/role.py index 017ffd7..0376070 100644 --- a/openstackclient/identity/v3/role.py +++ b/openstackclient/identity/v3/role.py @@ -22,7 +22,7 @@ import sys from cliff import command from cliff import lister from cliff import show -from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc +from keystoneclient import exceptions as ksc_exc from openstackclient.common import utils from openstackclient.i18n import _ # noqa @@ -177,16 +177,17 @@ class CreateRole(show.ShowOne): class DeleteRole(command.Command): - """Delete an existing role""" + """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( - 'role', + 'roles', metavar='<role>', - help='Role to delete (name or ID)', + nargs="+", + help='Role(s) to delete (name or ID)', ) return parser @@ -194,12 +195,12 @@ class DeleteRole(command.Command): self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity - role = utils.find_resource( - identity_client.roles, - parsed_args.role, - ) - - identity_client.roles.delete(role.id) + for role in parsed_args.roles: + role_obj = utils.find_resource( + identity_client.roles, + role, + ) + identity_client.roles.delete(role_obj.id) return @@ -466,7 +467,7 @@ class SetRole(command.Command): class ShowRole(show.ShowOne): - """Show single role""" + """Display role details""" log = logging.getLogger(__name__ + '.ShowRole') @@ -475,7 +476,7 @@ class ShowRole(show.ShowOne): parser.add_argument( 'role', metavar='<role>', - help='Role to show (name or ID)', + help='Role to display (name or ID)', ) return parser diff --git a/openstackclient/identity/v3/role_assignment.py b/openstackclient/identity/v3/role_assignment.py index 5cc97e8..f053b60 100644 --- a/openstackclient/identity/v3/role_assignment.py +++ b/openstackclient/identity/v3/role_assignment.py @@ -21,7 +21,7 @@ from openstackclient.common import utils class ListRoleAssignment(lister.Lister): - """Lists role assignments according to the given filters""" + """List role assignments""" log = logging.getLogger(__name__ + '.ListRoleAssignment') @@ -36,29 +36,29 @@ class ListRoleAssignment(lister.Lister): parser.add_argument( '--role', metavar='<role>', - help='Name or ID of role to filter', + help='Role to filter (name or ID)', ) user_or_group = parser.add_mutually_exclusive_group() user_or_group.add_argument( '--user', metavar='<user>', - help='Name or ID of user to filter', + help='User to filter (name or ID)', ) user_or_group.add_argument( '--group', metavar='<group>', - help='Name or ID of group to filter', + help='Group to filter (name or ID)', ) domain_or_project = parser.add_mutually_exclusive_group() domain_or_project.add_argument( '--domain', metavar='<domain>', - help='Name or ID of domain to filter', + help='Domain to filter (name or ID)', ) domain_or_project.add_argument( '--project', metavar='<project>', - help='Name or ID of project to filter', + help='Project to filter (name or ID)', ) return parser diff --git a/openstackclient/identity/v3/service.py b/openstackclient/identity/v3/service.py index 4f62226..d63a953 100644 --- a/openstackclient/identity/v3/service.py +++ b/openstackclient/identity/v3/service.py @@ -35,24 +35,29 @@ class CreateService(show.ShowOne): parser = super(CreateService, self).get_parser(prog_name) parser.add_argument( 'type', - metavar='<service-type>', + metavar='<type>', help='New service type (compute, image, identity, volume, etc)', ) parser.add_argument( '--name', - metavar='<service-name>', + metavar='<name>', help='New service name', ) + parser.add_argument( + '--description', + metavar='<description>', + help='New service description', + ) enable_group = parser.add_mutually_exclusive_group() enable_group.add_argument( '--enable', action='store_true', - help='Enable project', + help='Enable service (default)', ) enable_group.add_argument( '--disable', action='store_true', - help='Disable project', + help='Disable service', ) return parser @@ -67,6 +72,7 @@ class CreateService(show.ShowOne): service = identity_client.services.create( name=parsed_args.name, type=parsed_args.type, + description=parsed_args.description, enabled=enabled, ) @@ -84,7 +90,7 @@ class DeleteService(command.Command): parser.add_argument( 'service', metavar='<service>', - help='Service to delete (name or ID)', + help='Service to delete (type or ID)', ) return parser @@ -103,16 +109,28 @@ class ListService(lister.Lister): log = logging.getLogger(__name__ + '.ListService') + def get_parser(self, prog_name): + parser = super(ListService, 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): self.log.debug('take_action(%s)', parsed_args) - columns = ('ID', 'Name', 'Type', 'Enabled') + if parsed_args.long: + columns = ('ID', 'Name', 'Type', 'Description', 'Enabled') + else: + columns = ('ID', 'Name', 'Type') data = self.app.client_manager.identity.services.list() - return (columns, - (utils.get_item_properties( - s, columns, - formatters={}, - ) for s in data)) + return ( + columns, + (utils.get_item_properties(s, columns) for s in data), + ) class SetService(command.Command): @@ -125,11 +143,11 @@ class SetService(command.Command): parser.add_argument( 'service', metavar='<service>', - help='Service to update (name or ID)', + help='Service to update (type, name or ID)', ) parser.add_argument( '--type', - metavar='<service-type>', + metavar='<type>', help='New service type (compute, image, identity, volume, etc)', ) parser.add_argument( @@ -137,16 +155,21 @@ class SetService(command.Command): metavar='<service-name>', help='New service name', ) + parser.add_argument( + '--description', + metavar='<description>', + help='New service description', + ) enable_group = parser.add_mutually_exclusive_group() enable_group.add_argument( '--enable', action='store_true', - help='Enable project', + help='Enable service', ) enable_group.add_argument( '--disable', action='store_true', - help='Disable project', + help='Disable service', ) return parser @@ -156,6 +179,7 @@ class SetService(command.Command): if (not parsed_args.name and not parsed_args.type + and not parsed_args.description and not parsed_args.enable and not parsed_args.disable): return @@ -167,6 +191,8 @@ class SetService(command.Command): kwargs['type'] = parsed_args.type if parsed_args.name: kwargs['name'] = parsed_args.name + if parsed_args.description: + kwargs['description'] = parsed_args.description if parsed_args.enable: kwargs['enabled'] = True if parsed_args.disable: @@ -180,7 +206,7 @@ class SetService(command.Command): class ShowService(show.ShowOne): - """Show service details""" + """Display service details""" log = logging.getLogger(__name__ + '.ShowService') diff --git a/openstackclient/identity/v3/token.py b/openstackclient/identity/v3/token.py index 5b09b69..7000b62 100644 --- a/openstackclient/identity/v3/token.py +++ b/openstackclient/identity/v3/token.py @@ -20,9 +20,12 @@ import six from cliff import show +from openstackclient.common import utils +from openstackclient.identity import common + class AuthorizeRequestToken(show.ShowOne): - """Authorize request token""" + """Authorize a request token""" log = logging.getLogger(__name__ + '.AuthorizeRequestToken') @@ -31,13 +34,16 @@ class AuthorizeRequestToken(show.ShowOne): parser.add_argument( '--request-key', metavar='<request-key>', - help='Request token key', + help='Request token to authorize (ID only) (required)', required=True ) parser.add_argument( - '--role-ids', - metavar='<role-ids>', - help='Requested role IDs', + '--role', + metavar='<role>', + action='append', + default=[], + help='Roles to authorize (name or ID) ' + '(repeat to set multiple values) (required)', required=True ) return parser @@ -46,20 +52,24 @@ class AuthorizeRequestToken(show.ShowOne): self.log.debug('take_action(%s)' % parsed_args) identity_client = self.app.client_manager.identity + # NOTE(stevemar): We want a list of role ids roles = [] - for r_id in parsed_args.role_ids.split(): - roles.append(r_id) + for role in parsed_args.role: + role_id = utils.find_resource( + identity_client.roles, + role, + ).id + roles.append(role_id) verifier_pin = identity_client.oauth1.request_tokens.authorize( parsed_args.request_key, roles) - info = {} - info.update(verifier_pin._info) - return zip(*sorted(six.iteritems(info))) + + return zip(*sorted(six.iteritems(verifier_pin._info))) class CreateAccessToken(show.ShowOne): - """Create access token""" + """Create an access token""" log = logging.getLogger(__name__ + '.CreateAccessToken') @@ -68,31 +78,31 @@ class CreateAccessToken(show.ShowOne): parser.add_argument( '--consumer-key', metavar='<consumer-key>', - help='Consumer key', + help='Consumer key (required)', required=True ) parser.add_argument( '--consumer-secret', metavar='<consumer-secret>', - help='Consumer secret', + help='Consumer secret (required)', required=True ) parser.add_argument( '--request-key', metavar='<request-key>', - help='Request token key', + help='Request token to exchange for access token (required)', required=True ) parser.add_argument( '--request-secret', metavar='<request-secret>', - help='Request token secret', + help='Secret associated with <request-key> (required)', required=True ) parser.add_argument( '--verifier', metavar='<verifier>', - help='Verifier Pin', + help='Verifier associated with <request-key> (required)', required=True ) return parser @@ -104,13 +114,11 @@ class CreateAccessToken(show.ShowOne): parsed_args.consumer_key, parsed_args.consumer_secret, parsed_args.request_key, parsed_args.request_secret, parsed_args.verifier) - info = {} - info.update(access_token._info) - return zip(*sorted(six.iteritems(info))) + return zip(*sorted(six.iteritems(access_token._info))) class CreateRequestToken(show.ShowOne): - """Create request token""" + """Create a request token""" log = logging.getLogger(__name__ + '.CreateRequestToken') @@ -119,33 +127,50 @@ class CreateRequestToken(show.ShowOne): parser.add_argument( '--consumer-key', metavar='<consumer-key>', - help='Consumer key', + help='Consumer key (required)', required=True ) parser.add_argument( '--consumer-secret', metavar='<consumer-secret>', - help='Consumer secret', + help='Consumer secret (required)', required=True ) parser.add_argument( - '--project-id', - metavar='<project-id>', - help='Requested project ID', + '--project', + metavar='<project>', + help='Project that consumer wants to access (name or ID)' + ' (required)', required=True ) + parser.add_argument( + '--domain', + metavar='<domain>', + help='Domain owning <project> (name or ID)', + ) return parser def take_action(self, parsed_args): self.log.debug('take_action(%s)' % parsed_args) - token_client = self.app.client_manager.identity.oauth1.request_tokens + + identity_client = self.app.client_manager.identity + + if parsed_args.domain: + domain = common.find_domain(identity_client, parsed_args.domain) + project = utils.find_resource(identity_client.projects, + parsed_args.project, + domain_id=domain.id) + else: + project = utils.find_resource(identity_client.projects, + parsed_args.project) + + token_client = identity_client.oauth1.request_tokens + request_token = token_client.create( parsed_args.consumer_key, parsed_args.consumer_secret, - parsed_args.project_id) - info = {} - info.update(request_token._info) - return zip(*sorted(six.iteritems(info))) + project.id) + return zip(*sorted(six.iteritems(request_token._info))) class IssueToken(show.ShowOne): diff --git a/openstackclient/identity/v3/user.py b/openstackclient/identity/v3/user.py index 665dd4b..7b847ee 100644 --- a/openstackclient/identity/v3/user.py +++ b/openstackclient/identity/v3/user.py @@ -15,13 +15,14 @@ """Identity v3 User action implementations""" +import copy import logging import six from cliff import command from cliff import lister from cliff import show -from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc +from keystoneclient import exceptions as ksc_exc from openstackclient.common import utils from openstackclient.i18n import _ # noqa @@ -137,16 +138,17 @@ class CreateUser(show.ShowOne): class DeleteUser(command.Command): - """Delete user""" + """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( - 'user', + 'users', metavar='<user>', - help='User to delete (name or ID)', + nargs="+", + help='User(s) to delete (name or ID)', ) parser.add_argument( '--domain', @@ -159,16 +161,18 @@ class DeleteUser(command.Command): self.log.debug('take_action(%s)', parsed_args) identity_client = self.app.client_manager.identity + domain = None if parsed_args.domain: domain = common.find_domain(identity_client, parsed_args.domain) - user = utils.find_resource(identity_client.users, - parsed_args.user, - domain_id=domain.id) - else: - user = utils.find_resource(identity_client.users, - parsed_args.user) - - identity_client.users.delete(user.id) + for user in parsed_args.users: + if domain is not None: + user_obj = utils.find_resource(identity_client.users, + user, + domain_id=domain.id) + else: + user_obj = utils.find_resource(identity_client.users, + user) + identity_client.users.delete(user_obj.id) return @@ -184,11 +188,17 @@ class ListUser(lister.Lister): metavar='<domain>', help='Filter users by <domain> (name or ID)', ) - parser.add_argument( + project_or_group = parser.add_mutually_exclusive_group() + project_or_group.add_argument( '--group', metavar='<group>', help='Filter users by <group> membership (name or ID)', ) + project_or_group.add_argument( + '--project', + metavar='<project>', + help='Filter users by <project> (name or ID)', + ) parser.add_argument( '--long', action='store_true', @@ -215,19 +225,56 @@ class ListUser(lister.Lister): else: group = None - # List users + if parsed_args.project: + if domain is not None: + project = utils.find_resource( + identity_client.projects, + parsed_args.project, + domain_id=domain + ).id + else: + project = utils.find_resource( + identity_client.projects, + parsed_args.project, + ).id + + assignments = identity_client.role_assignments.list( + project=project) + + # NOTE(stevemar): If a user has more than one role on a project + # then they will have two entries in the returned data. Since we + # are looking for any role, let's just track unique user IDs. + user_ids = set() + for assignment in assignments: + if hasattr(assignment, 'user'): + user_ids.add(assignment.user['id']) + + # NOTE(stevemar): Call find_resource once we have unique IDs, so + # it's fewer trips to the Identity API, then collect the data. + data = [] + for user_id in user_ids: + user = utils.find_resource(identity_client.users, user_id) + data.append(user) + + else: + data = identity_client.users.list( + domain=domain, + group=group, + ) + + # Column handling if parsed_args.long: - columns = ('ID', 'Name', 'Project Id', 'Domain Id', - 'Description', 'Email', 'Enabled') + columns = ['ID', 'Name', 'Default Project Id', 'Domain Id', + 'Description', 'Email', 'Enabled'] + column_headers = copy.deepcopy(columns) + column_headers[2] = 'Project' + column_headers[3] = 'Domain' else: - columns = ('ID', 'Name') - data = identity_client.users.list( - domain=domain, - group=group, - ) + columns = ['ID', 'Name'] + column_headers = columns return ( - columns, + column_headers, (utils.get_item_properties( s, columns, formatters={}, @@ -375,7 +422,7 @@ class SetPasswordUser(command.Command): class ShowUser(show.ShowOne): - """Show user details""" + """Display user details""" log = logging.getLogger(__name__ + '.ShowUser') diff --git a/openstackclient/image/v1/image.py b/openstackclient/image/v1/image.py index 32dd388..d7ece25 100644 --- a/openstackclient/image/v1/image.py +++ b/openstackclient/image/v1/image.py @@ -49,7 +49,7 @@ class CreateImage(show.ShowOne): parser = super(CreateImage, self).get_parser(prog_name) parser.add_argument( "name", - metavar="<name>", + metavar="<image-name>", help="New image name", ) parser.add_argument( @@ -159,7 +159,7 @@ class CreateImage(show.ShowOne): dest="properties", metavar="<key=value>", action=parseractions.KeyValueAction, - help="Set an image property " + help="Set a property on this image " "(repeat option to set multiple properties)", ) return parser @@ -262,16 +262,17 @@ class CreateImage(show.ShowOne): class DeleteImage(command.Command): - """Delete an image""" + """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( - "image", + "images", metavar="<image>", - help="Name or ID of image to delete", + nargs="+", + help="Image(s) to delete (name or ID)", ) return parser @@ -279,11 +280,12 @@ class DeleteImage(command.Command): self.log.debug("take_action(%s)", parsed_args) image_client = self.app.client_manager.image - image = utils.find_resource( - image_client.images, - parsed_args.image, - ) - image_client.images.delete(image.id) + for image in parsed_args.images: + image_obj = utils.find_resource( + image_client.images, + image, + ) + image_client.images.delete(image_obj.id) class ListImage(lister.Lister): @@ -335,12 +337,12 @@ class SaveImage(command.Command): parser.add_argument( "--file", metavar="<filename>", - help="Downloaded image save filename [default: stdout]", + help="Downloaded image save filename (default: stdout)", ) parser.add_argument( "image", metavar="<image>", - help="Name or ID of image to save", + help="Image to save (name or ID)", ) return parser @@ -358,7 +360,7 @@ class SaveImage(command.Command): class SetImage(show.ShowOne): - """Change image properties""" + """Set image properties""" log = logging.getLogger(__name__ + ".SetImage") @@ -367,7 +369,7 @@ class SetImage(show.ShowOne): parser.add_argument( "image", metavar="<image>", - help="Image name or ID to change", + help="Image to modify (name or ID)", ) parser.add_argument( "--name", @@ -377,7 +379,7 @@ class SetImage(show.ShowOne): parser.add_argument( "--owner", metavar="<project>", - help="New image owner project name or ID", + help="New image owner project (name or ID)", ) parser.add_argument( "--min-disk", @@ -418,7 +420,7 @@ class SetImage(show.ShowOne): dest="properties", metavar="<key=value>", action=parseractions.KeyValueAction, - help="Set an image property " + help="Set a property on this image " "(repeat option to set multiple properties)", ) return parser @@ -472,7 +474,7 @@ class SetImage(show.ShowOne): class ShowImage(show.ShowOne): - """Show image details""" + """Display image details""" log = logging.getLogger(__name__ + ".ShowImage") @@ -481,7 +483,7 @@ class ShowImage(show.ShowOne): parser.add_argument( "image", metavar="<image>", - help="Name or ID of image to display", + help="Image to display (name or ID)", ) return parser diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py index c12ff11..d5ee692 100644 --- a/openstackclient/image/v2/image.py +++ b/openstackclient/image/v2/image.py @@ -27,16 +27,17 @@ from openstackclient.common import utils class DeleteImage(command.Command): - """Delete an image""" + """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( - "image", + "images", metavar="<image>", - help="Name or ID of image to delete", + nargs="+", + help="Image(s) to delete (name or ID)", ) return parser @@ -44,11 +45,12 @@ class DeleteImage(command.Command): self.log.debug("take_action(%s)", parsed_args) image_client = self.app.client_manager.image - image = utils.find_resource( - image_client.images, - parsed_args.image, - ) - image_client.images.delete(image.id) + for image in parsed_args.images: + image_obj = utils.find_resource( + image_client.images, + image, + ) + image_client.images.delete(image_obj.id) class ListImage(lister.Lister): @@ -100,12 +102,12 @@ class SaveImage(command.Command): parser.add_argument( "--file", metavar="<filename>", - help="Downloaded image save filename [default: stdout]", + help="Downloaded image save filename (default: stdout)", ) parser.add_argument( "image", metavar="<image>", - help="Name or ID of image to save", + help="Image to save (name or ID)", ) return parser @@ -123,7 +125,7 @@ class SaveImage(command.Command): class ShowImage(show.ShowOne): - """Show image details""" + """Display image details""" log = logging.getLogger(__name__ + ".ShowImage") @@ -132,7 +134,7 @@ class ShowImage(show.ShowOne): parser.add_argument( "image", metavar="<image>", - help="Name or ID of image to display", + help="Image to display (name or ID)", ) return parser diff --git a/openstackclient/network/client.py b/openstackclient/network/client.py index bb3e1b2..858a507 100644 --- a/openstackclient/network/client.py +++ b/openstackclient/network/client.py @@ -34,21 +34,9 @@ def make_client(instance): API_VERSIONS) LOG.debug('Instantiating network client: %s', network_client) - endpoint = instance.get_endpoint_for_service_type( - API_NAME, - region_name=instance._region_name, - ) - return network_client( - username=instance._username, - tenant_name=instance._project_name, - password=instance._password, + session=instance.session, region_name=instance._region_name, - auth_url=instance._auth_url, - endpoint_url=endpoint, - token=instance.auth.get_token(instance.session), - insecure=instance._insecure, - ca_cert=instance._cacert, ) diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py index f34666b..0d68f82 100644 --- a/openstackclient/network/v2/network.py +++ b/openstackclient/network/v2/network.py @@ -86,26 +86,27 @@ class CreateNetwork(show.ShowOne): class DeleteNetwork(command.Command): - """Delete a network""" + """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( - 'identifier', + 'networks', metavar="<network>", - help=("Name or identifier of network to delete") + nargs="+", + 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 - _id = common.find(client, 'network', 'networks', - parsed_args.identifier) delete_method = getattr(client, "delete_network") - delete_method(_id) + for network in parsed_args.networks: + _id = common.find(client, 'network', 'networks', network) + delete_method(_id) return diff --git a/openstackclient/object/v1/container.py b/openstackclient/object/v1/container.py index ead3df4..bc4fdec 100644 --- a/openstackclient/object/v1/container.py +++ b/openstackclient/object/v1/container.py @@ -27,7 +27,7 @@ from openstackclient.common import utils class CreateContainer(lister.Lister): - """Create a container""" + """Create new container""" log = logging.getLogger(__name__ + '.CreateContainer') @@ -35,9 +35,9 @@ class CreateContainer(lister.Lister): parser = super(CreateContainer, self).get_parser(prog_name) parser.add_argument( 'containers', - metavar='<container>', + metavar='<container-name>', nargs="+", - help='Container name(s) to create', + help='New container name(s)', ) return parser @@ -60,7 +60,7 @@ class CreateContainer(lister.Lister): class DeleteContainer(command.Command): - """Delete a container""" + """Delete container""" log = logging.getLogger(__name__ + '.DeleteContainer') @@ -70,7 +70,7 @@ class DeleteContainer(command.Command): 'containers', metavar='<container>', nargs="+", - help='Container name(s) to delete', + help='Container(s) to delete', ) return parser @@ -157,7 +157,7 @@ class ListContainer(lister.Lister): class SaveContainer(command.Command): - """Save the contents of a container locally""" + """Save container contents locally""" log = logging.getLogger(__name__ + ".SaveContainer") @@ -166,7 +166,7 @@ class SaveContainer(command.Command): parser.add_argument( 'container', metavar='<container>', - help='Container name to save', + help='Container to save', ) return parser @@ -179,7 +179,7 @@ class SaveContainer(command.Command): class ShowContainer(show.ShowOne): - """Show container information""" + """Display container details""" log = logging.getLogger(__name__ + '.ShowContainer') @@ -188,7 +188,7 @@ class ShowContainer(show.ShowOne): parser.add_argument( 'container', metavar='<container>', - help='Container name to display', + help='Container to display', ) return parser diff --git a/openstackclient/object/v1/object.py b/openstackclient/object/v1/object.py index cbe9da2..752d784 100644 --- a/openstackclient/object/v1/object.py +++ b/openstackclient/object/v1/object.py @@ -27,7 +27,7 @@ from openstackclient.common import utils class CreateObject(lister.Lister): - """Upload an object to a container""" + """Upload object to container""" log = logging.getLogger(__name__ + '.CreateObject') @@ -36,13 +36,13 @@ class CreateObject(lister.Lister): parser.add_argument( 'container', metavar='<container>', - help='Container to store new object', + help='Container for new object', ) parser.add_argument( 'objects', - metavar='<object-name>', + metavar='<filename>', nargs="+", - help='Local path of object(s) to upload', + help='Local filename(s) to upload', ) return parser @@ -66,7 +66,7 @@ class CreateObject(lister.Lister): class DeleteObject(command.Command): - """Delete an object within a container""" + """Delete object from container""" log = logging.getLogger(__name__ + '.DeleteObject') @@ -75,11 +75,11 @@ class DeleteObject(command.Command): parser.add_argument( 'container', metavar='<container>', - help='Container that stores the object to delete', + help='Delete object(s) from <container>', ) parser.add_argument( 'objects', - metavar='<object-name>', + metavar='<object>', nargs="+", help='Object(s) to delete', ) @@ -104,8 +104,8 @@ class ListObject(lister.Lister): parser = super(ListObject, self).get_parser(prog_name) parser.add_argument( "container", - metavar="<container-name>", - help="List contents of container-name", + metavar="<container>", + help="Container to list", ) parser.add_argument( "--prefix", @@ -188,7 +188,7 @@ class ListObject(lister.Lister): class SaveObject(command.Command): - """Save an object locally""" + """Save object locally""" log = logging.getLogger(__name__ + ".SaveObject") @@ -197,17 +197,17 @@ class SaveObject(command.Command): parser.add_argument( "--file", metavar="<filename>", - help="Downloaded object filename [defaults to object name]", + help="Destination filename (defaults to object name)", ) parser.add_argument( 'container', metavar='<container>', - help='Container name that has the object', + help='Download <object> from <container>', ) parser.add_argument( "object", metavar="<object>", - help="Name of the object to save", + help="Object to save", ) return parser @@ -222,7 +222,7 @@ class SaveObject(command.Command): class ShowObject(show.ShowOne): - """Show object information""" + """Display object details""" log = logging.getLogger(__name__ + '.ShowObject') @@ -231,12 +231,12 @@ class ShowObject(show.ShowOne): parser.add_argument( 'container', metavar='<container>', - help='Container name for object to display', + help='Display <object> from <container>', ) parser.add_argument( 'object', metavar='<object>', - help='Object name to display', + help='Object to display', ) return parser diff --git a/openstackclient/shell.py b/openstackclient/shell.py index ac5556a..246f51b 100644 --- a/openstackclient/shell.py +++ b/openstackclient/shell.py @@ -303,7 +303,8 @@ class OpenStackShell(app.App): def prepare_to_run_command(self, cmd): """Set up auth and API versions""" self.log.info( - 'command: %s.%s', + 'command: %s -> %s.%s', + getattr(cmd, 'cmd_name', '<none>'), cmd.__class__.__module__, cmd.__class__.__name__, ) diff --git a/openstackclient/tests/common/test_clientmanager.py b/openstackclient/tests/common/test_clientmanager.py index 8c27e56..3b2b976 100644 --- a/openstackclient/tests/common/test_clientmanager.py +++ b/openstackclient/tests/common/test_clientmanager.py @@ -49,6 +49,7 @@ class FakeOptions(object): self.timing = None self.os_region_name = None self.os_url = None + self.os_default_domain = 'default' self.__dict__.update(kwargs) @@ -126,7 +127,8 @@ class TestClientManager(utils.TestCase): client_manager = clientmanager.ClientManager( auth_options=FakeOptions(os_auth_url=fakes.AUTH_URL, os_username=fakes.USERNAME, - os_password=fakes.PASSWORD), + os_password=fakes.PASSWORD, + os_project_name=fakes.PROJECT_NAME), api_version=API_VERSION, verify=False, ) @@ -183,6 +185,7 @@ class TestClientManager(utils.TestCase): auth_options=FakeOptions(os_auth_url=fakes.AUTH_URL, os_username=fakes.USERNAME, os_password=fakes.PASSWORD, + os_project_name=fakes.PROJECT_NAME, os_auth_type='v2password'), api_version=API_VERSION, verify='cafile', @@ -218,7 +221,8 @@ class TestClientManager(utils.TestCase): # test password auth params = dict(os_auth_url=fakes.AUTH_URL, os_username=fakes.USERNAME, - os_password=fakes.PASSWORD) + os_password=fakes.PASSWORD, + os_project_name=fakes.PROJECT_NAME) self._select_auth_plugin(params, '2.0', 'v2password') self._select_auth_plugin(params, '3', 'v3password') self._select_auth_plugin(params, 'XXX', 'password') diff --git a/openstackclient/tests/compute/v2/test_server.py b/openstackclient/tests/compute/v2/test_server.py index 19c1344..d51beef 100644 --- a/openstackclient/tests/compute/v2/test_server.py +++ b/openstackclient/tests/compute/v2/test_server.py @@ -232,7 +232,7 @@ class TestServerDelete(TestServer): compute_fakes.server_id, ] verifylist = [ - ('server', compute_fakes.server_id), + ('servers', [compute_fakes.server_id]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) diff --git a/openstackclient/tests/fakes.py b/openstackclient/tests/fakes.py index 93d4294..d37555e 100644 --- a/openstackclient/tests/fakes.py +++ b/openstackclient/tests/fakes.py @@ -25,6 +25,7 @@ AUTH_TOKEN = "foobar" AUTH_URL = "http://0.0.0.0" USERNAME = "itchy" PASSWORD = "scratchy" +PROJECT_NAME = "poochie" TEST_RESPONSE_DICT = fixture.V2Token(token_id=AUTH_TOKEN, user_name=USERNAME) @@ -37,7 +38,7 @@ TEST_RESPONSE_DICT_V3.set_project_scope() TEST_VERSIONS = fixture.DiscoveryList(href=AUTH_URL) -class FakeStdout: +class FakeStdout(object): def __init__(self): self.content = [] diff --git a/openstackclient/tests/identity/v2_0/test_project.py b/openstackclient/tests/identity/v2_0/test_project.py index 833b5d8..0c5ef77 100644 --- a/openstackclient/tests/identity/v2_0/test_project.py +++ b/openstackclient/tests/identity/v2_0/test_project.py @@ -15,7 +15,7 @@ import copy -from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc +from keystoneclient import exceptions as ksc_exc from openstackclient.identity.v2_0 import project from openstackclient.tests import fakes @@ -326,7 +326,7 @@ class TestProjectDelete(TestProject): identity_fakes.project_id, ] verifylist = [ - ('project', identity_fakes.project_id), + ('projects', [identity_fakes.project_id]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) diff --git a/openstackclient/tests/identity/v2_0/test_role.py b/openstackclient/tests/identity/v2_0/test_role.py index 6746774..2e3a286 100644 --- a/openstackclient/tests/identity/v2_0/test_role.py +++ b/openstackclient/tests/identity/v2_0/test_role.py @@ -16,7 +16,7 @@ import copy import mock -from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc +from keystoneclient import exceptions as ksc_exc from openstackclient.common import exceptions from openstackclient.identity.v2_0 import role @@ -234,7 +234,7 @@ class TestRoleDelete(TestRole): identity_fakes.role_name, ] verifylist = [ - ('role', identity_fakes.role_name), + ('roles', [identity_fakes.role_name]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) diff --git a/openstackclient/tests/identity/v2_0/test_service.py b/openstackclient/tests/identity/v2_0/test_service.py index 6c93574..7360658 100644 --- a/openstackclient/tests/identity/v2_0/test_service.py +++ b/openstackclient/tests/identity/v2_0/test_service.py @@ -44,14 +44,80 @@ class TestServiceCreate(TestService): # Get the command object to test self.cmd = service.CreateService(self.app, None) - def test_service_create_name_type(self): + def test_service_create_with_type_positional(self): + arglist = [ + identity_fakes.service_type, + ] + verifylist = [ + ('type_or_name', identity_fakes.service_type), + ('type', None), + ('description', None), + ('name', None), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # ServiceManager.create(name, service_type, description) + self.services_mock.create.assert_called_with( + None, + identity_fakes.service_type, + None, + ) + + collist = ('description', 'id', 'name', 'type') + self.assertEqual(columns, collist) + datalist = ( + identity_fakes.service_description, + identity_fakes.service_id, + identity_fakes.service_name, + identity_fakes.service_type, + ) + self.assertEqual(data, datalist) + + def test_service_create_with_type_option(self): arglist = [ '--type', identity_fakes.service_type, identity_fakes.service_name, ] verifylist = [ + ('type_or_name', identity_fakes.service_name), ('type', identity_fakes.service_type), ('description', None), + ('name', None), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # ServiceManager.create(name, service_type, description) + self.services_mock.create.assert_called_with( + identity_fakes.service_name, + identity_fakes.service_type, + None, + ) + + collist = ('description', 'id', 'name', 'type') + self.assertEqual(columns, collist) + datalist = ( + identity_fakes.service_description, + identity_fakes.service_id, + identity_fakes.service_name, + identity_fakes.service_type, + ) + self.assertEqual(data, datalist) + + def test_service_create_with_name_option(self): + arglist = [ + '--name', identity_fakes.service_name, + identity_fakes.service_type, + ] + verifylist = [ + ('type_or_name', identity_fakes.service_type), + ('type', None), + ('description', None), ('name', identity_fakes.service_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -78,12 +144,13 @@ class TestServiceCreate(TestService): def test_service_create_description(self): arglist = [ - '--type', identity_fakes.service_type, + '--name', identity_fakes.service_name, '--description', identity_fakes.service_description, - identity_fakes.service_name, + identity_fakes.service_type, ] verifylist = [ - ('type', identity_fakes.service_type), + ('type_or_name', identity_fakes.service_type), + ('type', None), ('description', identity_fakes.service_description), ('name', identity_fakes.service_name), ] @@ -168,11 +235,12 @@ class TestServiceList(TestService): self.services_mock.list.assert_called_with() - collist = ('ID', 'Name') + collist = ('ID', 'Name', 'Type') self.assertEqual(columns, collist) datalist = (( identity_fakes.service_id, identity_fakes.service_name, + identity_fakes.service_type, ), ) self.assertEqual(tuple(data), datalist) diff --git a/openstackclient/tests/identity/v2_0/test_user.py b/openstackclient/tests/identity/v2_0/test_user.py index a025dd7..ccdf240 100644 --- a/openstackclient/tests/identity/v2_0/test_user.py +++ b/openstackclient/tests/identity/v2_0/test_user.py @@ -16,7 +16,7 @@ import copy import mock -from keystoneclient.openstack.common.apiclient import exceptions as ksc_exc +from keystoneclient import exceptions as ksc_exc from openstackclient.identity.v2_0 import user from openstackclient.tests import fakes from openstackclient.tests.identity.v2_0 import fakes as identity_fakes @@ -443,7 +443,7 @@ class TestUserDelete(TestUser): identity_fakes.user_id, ] verifylist = [ - ('user', identity_fakes.user_id), + ('users', [identity_fakes.user_id]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) diff --git a/openstackclient/tests/identity/v3/fakes.py b/openstackclient/tests/identity/v3/fakes.py index 7acaa7f..68e6751 100644 --- a/openstackclient/tests/identity/v3/fakes.py +++ b/openstackclient/tests/identity/v3/fakes.py @@ -147,11 +147,21 @@ ROLE = { service_id = 's-123' service_name = 'Texaco' service_type = 'gas' +service_description = 'oil brand' SERVICE = { 'id': service_id, 'name': service_name, 'type': service_type, + 'description': service_description, + 'enabled': True, + 'links': base_url + 'services/' + service_id, +} + +SERVICE_WITHOUT_NAME = { + 'id': service_id, + 'type': service_type, + 'description': service_description, 'enabled': True, 'links': base_url + 'services/' + service_id, } @@ -179,7 +189,7 @@ user_email = 'paul@applecorps.com' USER = { 'id': user_id, 'name': user_name, - 'project_id': project_id, + 'default_project_id': project_id, 'email': user_email, 'enabled': True, 'domain_id': domain_id, diff --git a/openstackclient/tests/identity/v3/test_domain.py b/openstackclient/tests/identity/v3/test_domain.py index 8dad5bc..cfec10e 100644 --- a/openstackclient/tests/identity/v3/test_domain.py +++ b/openstackclient/tests/identity/v3/test_domain.py @@ -46,7 +46,6 @@ class TestDomainCreate(TestDomain): identity_fakes.domain_name, ] verifylist = [ - ('enabled', True), ('name', identity_fakes.domain_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -81,7 +80,6 @@ class TestDomainCreate(TestDomain): ] verifylist = [ ('description', 'new desc'), - ('enabled', True), ('name', identity_fakes.domain_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -115,7 +113,7 @@ class TestDomainCreate(TestDomain): identity_fakes.domain_name, ] verifylist = [ - ('enabled', True), + ('enable', True), ('name', identity_fakes.domain_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -149,7 +147,7 @@ class TestDomainCreate(TestDomain): identity_fakes.domain_name, ] verifylist = [ - ('enabled', False), + ('disable', True), ('name', identity_fakes.domain_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -333,7 +331,7 @@ class TestDomainSet(TestDomain): identity_fakes.domain_id, ] verifylist = [ - ('enabled', True), + ('enable', True), ('domain', identity_fakes.domain_id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -356,7 +354,7 @@ class TestDomainSet(TestDomain): identity_fakes.domain_id, ] verifylist = [ - ('disabled', True), + ('disable', True), ('domain', identity_fakes.domain_id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) diff --git a/openstackclient/tests/identity/v3/test_endpoint.py b/openstackclient/tests/identity/v3/test_endpoint.py index ea05326..ecfa71a 100644 --- a/openstackclient/tests/identity/v3/test_endpoint.py +++ b/openstackclient/tests/identity/v3/test_endpoint.py @@ -31,6 +31,9 @@ class TestEndpoint(identity_fakes.TestIdentityv3): self.services_mock = self.app.client_manager.identity.services self.services_mock.reset_mock() + def get_fake_service_name(self): + return identity_fakes.service_name + class TestEndpointCreate(TestEndpoint): @@ -92,7 +95,7 @@ class TestEndpointCreate(TestEndpoint): identity_fakes.endpoint_interface, identity_fakes.endpoint_region, identity_fakes.service_id, - identity_fakes.service_name, + self.get_fake_service_name(), identity_fakes.service_type, identity_fakes.endpoint_url, ) @@ -139,7 +142,7 @@ class TestEndpointCreate(TestEndpoint): identity_fakes.endpoint_interface, identity_fakes.endpoint_region, identity_fakes.service_id, - identity_fakes.service_name, + self.get_fake_service_name(), identity_fakes.service_type, identity_fakes.endpoint_url, ) @@ -185,7 +188,7 @@ class TestEndpointCreate(TestEndpoint): identity_fakes.endpoint_interface, identity_fakes.endpoint_region, identity_fakes.service_id, - identity_fakes.service_name, + self.get_fake_service_name(), identity_fakes.service_type, identity_fakes.endpoint_url, ) @@ -231,7 +234,7 @@ class TestEndpointCreate(TestEndpoint): identity_fakes.endpoint_interface, identity_fakes.endpoint_region, identity_fakes.service_id, - identity_fakes.service_name, + self.get_fake_service_name(), identity_fakes.service_type, identity_fakes.endpoint_url, ) @@ -309,7 +312,7 @@ class TestEndpointList(TestEndpoint): datalist = (( identity_fakes.endpoint_id, identity_fakes.endpoint_region, - identity_fakes.service_name, + self.get_fake_service_name(), identity_fakes.service_type, True, identity_fakes.endpoint_interface, @@ -319,10 +322,10 @@ class TestEndpointList(TestEndpoint): def test_endpoint_list_service(self): arglist = [ - '--service', identity_fakes.service_name, + '--service', identity_fakes.service_id, ] verifylist = [ - ('service', identity_fakes.service_name), + ('service', identity_fakes.service_id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -341,7 +344,7 @@ class TestEndpointList(TestEndpoint): datalist = (( identity_fakes.endpoint_id, identity_fakes.endpoint_region, - identity_fakes.service_name, + self.get_fake_service_name(), identity_fakes.service_type, True, identity_fakes.endpoint_interface, @@ -373,7 +376,7 @@ class TestEndpointList(TestEndpoint): datalist = (( identity_fakes.endpoint_id, identity_fakes.endpoint_region, - identity_fakes.service_name, + self.get_fake_service_name(), identity_fakes.service_type, True, identity_fakes.endpoint_interface, @@ -405,7 +408,7 @@ class TestEndpointList(TestEndpoint): datalist = (( identity_fakes.endpoint_id, identity_fakes.endpoint_region, - identity_fakes.service_name, + self.get_fake_service_name(), identity_fakes.service_type, True, identity_fakes.endpoint_interface, @@ -664,8 +667,85 @@ class TestEndpointShow(TestEndpoint): identity_fakes.endpoint_interface, identity_fakes.endpoint_region, identity_fakes.service_id, - identity_fakes.service_name, + self.get_fake_service_name(), identity_fakes.service_type, identity_fakes.endpoint_url, ) self.assertEqual(datalist, data) + + +class TestEndpointCreateServiceWithoutName(TestEndpointCreate): + + def setUp(self): + super(TestEndpointCreate, self).setUp() + + self.endpoints_mock.create.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.ENDPOINT), + loaded=True, + ) + + # This is the return value for common.find_resource(service) + self.services_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.SERVICE_WITHOUT_NAME), + loaded=True, + ) + + # Get the command object to test + self.cmd = endpoint.CreateEndpoint(self.app, None) + + def get_fake_service_name(self): + return '' + + +class TestEndpointListServiceWithoutName(TestEndpointList): + + def setUp(self): + super(TestEndpointList, self).setUp() + + self.endpoints_mock.list.return_value = [ + fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.ENDPOINT), + loaded=True, + ), + ] + + # This is the return value for common.find_resource(service) + self.services_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.SERVICE_WITHOUT_NAME), + loaded=True, + ) + + # Get the command object to test + self.cmd = endpoint.ListEndpoint(self.app, None) + + def get_fake_service_name(self): + return '' + + +class TestEndpointShowServiceWithoutName(TestEndpointShow): + + def setUp(self): + super(TestEndpointShow, self).setUp() + + self.endpoints_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.ENDPOINT), + loaded=True, + ) + + # This is the return value for common.find_resource(service) + self.services_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.SERVICE_WITHOUT_NAME), + loaded=True, + ) + + # Get the command object to test + self.cmd = endpoint.ShowEndpoint(self.app, None) + + def get_fake_service_name(self): + return '' diff --git a/openstackclient/tests/identity/v3/test_oauth.py b/openstackclient/tests/identity/v3/test_oauth.py index 15ba04e..435042d 100644 --- a/openstackclient/tests/identity/v3/test_oauth.py +++ b/openstackclient/tests/identity/v3/test_oauth.py @@ -26,6 +26,10 @@ class TestOAuth1(identity_fakes.TestOAuth1): self.access_tokens_mock.reset_mock() self.request_tokens_mock = identity_client.oauth1.request_tokens self.request_tokens_mock.reset_mock() + self.projects_mock = identity_client.projects + self.projects_mock.reset_mock() + self.roles_mock = identity_client.roles + self.roles_mock.reset_mock() class TestRequestTokenCreate(TestOAuth1): @@ -39,18 +43,24 @@ class TestRequestTokenCreate(TestOAuth1): loaded=True, ) + self.projects_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.PROJECT), + loaded=True, + ) + self.cmd = token.CreateRequestToken(self.app, None) def test_create_request_tokens(self): arglist = [ '--consumer-key', identity_fakes.consumer_id, '--consumer-secret', identity_fakes.consumer_secret, - '--project-id', identity_fakes.project_id, + '--project', identity_fakes.project_id, ] verifylist = [ ('consumer_key', identity_fakes.consumer_id), ('consumer_secret', identity_fakes.consumer_secret), - ('project_id', identity_fakes.project_id), + ('project', identity_fakes.project_id), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) @@ -77,6 +87,12 @@ class TestRequestTokenAuthorize(TestOAuth1): def setUp(self): super(TestRequestTokenAuthorize, self).setUp() + self.roles_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.ROLE), + loaded=True, + ) + copied_verifier = copy.deepcopy(identity_fakes.OAUTH_VERIFIER) resource = fakes.FakeResource(None, copied_verifier, loaded=True) self.request_tokens_mock.authorize.return_value = resource @@ -85,11 +101,11 @@ class TestRequestTokenAuthorize(TestOAuth1): def test_authorize_request_tokens(self): arglist = [ '--request-key', identity_fakes.request_token_id, - '--role-ids', identity_fakes.role_id, + '--role', identity_fakes.role_name, ] verifylist = [ ('request_key', identity_fakes.request_token_id), - ('role_ids', identity_fakes.role_id), + ('role', [identity_fakes.role_name]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) columns, data = self.cmd.take_action(parsed_args) diff --git a/openstackclient/tests/identity/v3/test_project.py b/openstackclient/tests/identity/v3/test_project.py index 1060a27..d16f973 100644 --- a/openstackclient/tests/identity/v3/test_project.py +++ b/openstackclient/tests/identity/v3/test_project.py @@ -353,7 +353,7 @@ class TestProjectDelete(TestProject): identity_fakes.project_id, ] verifylist = [ - ('project', identity_fakes.project_id), + ('projects', [identity_fakes.project_id]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) diff --git a/openstackclient/tests/identity/v3/test_role.py b/openstackclient/tests/identity/v3/test_role.py index 3d2a402..1a9e6aa 100644 --- a/openstackclient/tests/identity/v3/test_role.py +++ b/openstackclient/tests/identity/v3/test_role.py @@ -271,7 +271,7 @@ class TestRoleDelete(TestRole): identity_fakes.role_name, ] verifylist = [ - ('role', identity_fakes.role_name), + ('roles', [identity_fakes.role_name]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) diff --git a/openstackclient/tests/identity/v3/test_service.py b/openstackclient/tests/identity/v3/test_service.py index 57db77b..7766a29 100644 --- a/openstackclient/tests/identity/v3/test_service.py +++ b/openstackclient/tests/identity/v3/test_service.py @@ -51,6 +51,7 @@ class TestServiceCreate(TestService): ] verifylist = [ ('name', identity_fakes.service_name), + ('description', None), ('enable', False), ('disable', False), ('type', identity_fakes.service_type), @@ -64,12 +65,50 @@ class TestServiceCreate(TestService): self.services_mock.create.assert_called_with( name=identity_fakes.service_name, type=identity_fakes.service_type, + description=None, enabled=True, ) - collist = ('enabled', 'id', 'name', 'type') + collist = ('description', 'enabled', 'id', 'name', 'type') self.assertEqual(columns, collist) datalist = ( + identity_fakes.service_description, + True, + identity_fakes.service_id, + identity_fakes.service_name, + identity_fakes.service_type, + ) + self.assertEqual(data, datalist) + + def test_service_create_description(self): + arglist = [ + '--description', identity_fakes.service_description, + identity_fakes.service_type, + ] + verifylist = [ + ('name', None), + ('description', identity_fakes.service_description), + ('enable', False), + ('disable', False), + ('type', identity_fakes.service_type), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + # ServiceManager.create(name=, type=, enabled=, **kwargs) + self.services_mock.create.assert_called_with( + name=None, + type=identity_fakes.service_type, + description=identity_fakes.service_description, + enabled=True, + ) + + collist = ('description', 'enabled', 'id', 'name', 'type') + self.assertEqual(columns, collist) + datalist = ( + identity_fakes.service_description, True, identity_fakes.service_id, identity_fakes.service_name, @@ -84,6 +123,7 @@ class TestServiceCreate(TestService): ] verifylist = [ ('name', None), + ('description', None), ('enable', True), ('disable', False), ('type', identity_fakes.service_type), @@ -97,12 +137,14 @@ class TestServiceCreate(TestService): self.services_mock.create.assert_called_with( name=None, type=identity_fakes.service_type, + description=None, enabled=True, ) - collist = ('enabled', 'id', 'name', 'type') + collist = ('description', 'enabled', 'id', 'name', 'type') self.assertEqual(columns, collist) datalist = ( + identity_fakes.service_description, True, identity_fakes.service_id, identity_fakes.service_name, @@ -117,6 +159,7 @@ class TestServiceCreate(TestService): ] verifylist = [ ('name', None), + ('description', None), ('enable', False), ('disable', True), ('type', identity_fakes.service_type), @@ -130,12 +173,14 @@ class TestServiceCreate(TestService): self.services_mock.create.assert_called_with( name=None, type=identity_fakes.service_type, + description=None, enabled=False, ) - collist = ('enabled', 'id', 'name', 'type') + collist = ('description', 'enabled', 'id', 'name', 'type') self.assertEqual(columns, collist) datalist = ( + identity_fakes.service_description, True, identity_fakes.service_id, identity_fakes.service_name, @@ -202,12 +247,36 @@ class TestServiceList(TestService): self.services_mock.list.assert_called_with() - collist = ('ID', 'Name', 'Type', 'Enabled') + collist = ('ID', 'Name', 'Type') self.assertEqual(columns, collist) datalist = (( identity_fakes.service_id, identity_fakes.service_name, identity_fakes.service_type, + ), ) + self.assertEqual(tuple(data), datalist) + + def test_service_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.services_mock.list.assert_called_with() + + collist = ('ID', 'Name', 'Type', 'Description', 'Enabled') + self.assertEqual(columns, collist) + datalist = (( + identity_fakes.service_id, + identity_fakes.service_name, + identity_fakes.service_type, + identity_fakes.service_description, True, ), ) self.assertEqual(tuple(data), datalist) @@ -239,6 +308,7 @@ class TestServiceSet(TestService): verifylist = [ ('type', None), ('name', None), + ('description', None), ('enable', False), ('disable', False), ('service', identity_fakes.service_name), @@ -256,6 +326,7 @@ class TestServiceSet(TestService): verifylist = [ ('type', identity_fakes.service_type), ('name', None), + ('description', None), ('enable', False), ('disable', False), ('service', identity_fakes.service_name), @@ -283,6 +354,7 @@ class TestServiceSet(TestService): verifylist = [ ('type', None), ('name', identity_fakes.service_name), + ('description', None), ('enable', False), ('disable', False), ('service', identity_fakes.service_name), @@ -302,6 +374,34 @@ class TestServiceSet(TestService): **kwargs ) + def test_service_set_description(self): + arglist = [ + '--description', identity_fakes.service_description, + identity_fakes.service_name, + ] + verifylist = [ + ('type', None), + ('name', None), + ('description', identity_fakes.service_description), + ('enable', False), + ('disable', False), + ('service', identity_fakes.service_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.run(parsed_args) + self.assertEqual(result, 0) + + # Set expected values + kwargs = { + 'description': identity_fakes.service_description, + } + # ServiceManager.update(service, name=, type=, enabled=, **kwargs) + self.services_mock.update.assert_called_with( + identity_fakes.service_id, + **kwargs + ) + def test_service_set_enable(self): arglist = [ '--enable', @@ -310,6 +410,7 @@ class TestServiceSet(TestService): verifylist = [ ('type', None), ('name', None), + ('description', None), ('enable', True), ('disable', False), ('service', identity_fakes.service_name), @@ -337,6 +438,7 @@ class TestServiceSet(TestService): verifylist = [ ('type', None), ('name', None), + ('description', None), ('enable', False), ('disable', True), ('service', identity_fakes.service_name), @@ -388,9 +490,10 @@ class TestServiceShow(TestService): identity_fakes.service_name, ) - collist = ('enabled', 'id', 'name', 'type') + collist = ('description', 'enabled', 'id', 'name', 'type') self.assertEqual(columns, collist) datalist = ( + identity_fakes.service_description, True, identity_fakes.service_id, identity_fakes.service_name, diff --git a/openstackclient/tests/identity/v3/test_user.py b/openstackclient/tests/identity/v3/test_user.py index bb59ebe..35dd98e 100644 --- a/openstackclient/tests/identity/v3/test_user.py +++ b/openstackclient/tests/identity/v3/test_user.py @@ -44,6 +44,11 @@ class TestUser(identity_fakes.TestIdentityv3): self.users_mock = self.app.client_manager.identity.users self.users_mock.reset_mock() + # Shortcut for RoleAssignmentManager Mock + self.role_assignments_mock = self.app.client_manager.identity.\ + role_assignments + self.role_assignments_mock.reset_mock() + class TestUserCreate(TestUser): @@ -102,15 +107,16 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('domain_id', 'email', 'enabled', 'id', 'name', 'project_id') + collist = ('default_project_id', 'domain_id', 'email', + 'enabled', 'id', 'name') self.assertEqual(columns, collist) datalist = ( + identity_fakes.project_id, identity_fakes.domain_id, identity_fakes.user_email, True, identity_fakes.user_id, identity_fakes.user_name, - identity_fakes.project_id, ) self.assertEqual(data, datalist) @@ -147,15 +153,16 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('domain_id', 'email', 'enabled', 'id', 'name', 'project_id') + collist = ('default_project_id', 'domain_id', 'email', + 'enabled', 'id', 'name') self.assertEqual(columns, collist) datalist = ( + identity_fakes.project_id, identity_fakes.domain_id, identity_fakes.user_email, True, identity_fakes.user_id, identity_fakes.user_name, - identity_fakes.project_id, ) self.assertEqual(data, datalist) @@ -195,15 +202,16 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('domain_id', 'email', 'enabled', 'id', 'name', 'project_id') + collist = ('default_project_id', 'domain_id', 'email', + 'enabled', 'id', 'name') self.assertEqual(columns, collist) datalist = ( + identity_fakes.project_id, identity_fakes.domain_id, identity_fakes.user_email, True, identity_fakes.user_id, identity_fakes.user_name, - identity_fakes.project_id, ) self.assertEqual(data, datalist) @@ -239,15 +247,16 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('domain_id', 'email', 'enabled', 'id', 'name', 'project_id') + collist = ('default_project_id', 'domain_id', 'email', + 'enabled', 'id', 'name') self.assertEqual(columns, collist) datalist = ( + identity_fakes.project_id, identity_fakes.domain_id, identity_fakes.user_email, True, identity_fakes.user_id, identity_fakes.user_name, - identity_fakes.project_id, ) self.assertEqual(data, datalist) @@ -260,7 +269,7 @@ class TestUserCreate(TestUser): ) # Set up to return an updated user USER_2 = copy.deepcopy(identity_fakes.USER) - USER_2['project_id'] = identity_fakes.PROJECT_2['id'] + USER_2['default_project_id'] = identity_fakes.PROJECT_2['id'] self.users_mock.create.return_value = fakes.FakeResource( None, USER_2, @@ -298,15 +307,16 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('domain_id', 'email', 'enabled', 'id', 'name', 'project_id') + collist = ('default_project_id', 'domain_id', 'email', + 'enabled', 'id', 'name') self.assertEqual(columns, collist) datalist = ( + identity_fakes.PROJECT_2['id'], identity_fakes.domain_id, identity_fakes.user_email, True, identity_fakes.user_id, identity_fakes.user_name, - identity_fakes.PROJECT_2['id'], ) self.assertEqual(data, datalist) @@ -342,15 +352,16 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('domain_id', 'email', 'enabled', 'id', 'name', 'project_id') + collist = ('default_project_id', 'domain_id', 'email', + 'enabled', 'id', 'name') self.assertEqual(columns, collist) datalist = ( + identity_fakes.project_id, identity_fakes.domain_id, identity_fakes.user_email, True, identity_fakes.user_id, identity_fakes.user_name, - identity_fakes.project_id, ) self.assertEqual(data, datalist) @@ -385,15 +396,16 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('domain_id', 'email', 'enabled', 'id', 'name', 'project_id') + collist = ('default_project_id', 'domain_id', 'email', + 'enabled', 'id', 'name') self.assertEqual(columns, collist) datalist = ( + identity_fakes.project_id, identity_fakes.domain_id, identity_fakes.user_email, True, identity_fakes.user_id, identity_fakes.user_name, - identity_fakes.project_id, ) self.assertEqual(data, datalist) @@ -427,15 +439,16 @@ class TestUserCreate(TestUser): **kwargs ) - collist = ('domain_id', 'email', 'enabled', 'id', 'name', 'project_id') + collist = ('default_project_id', 'domain_id', 'email', + 'enabled', 'id', 'name') self.assertEqual(columns, collist) datalist = ( + identity_fakes.project_id, identity_fakes.domain_id, identity_fakes.user_email, True, identity_fakes.user_id, identity_fakes.user_name, - identity_fakes.project_id, ) self.assertEqual(data, datalist) @@ -461,7 +474,7 @@ class TestUserDelete(TestUser): identity_fakes.user_id, ] verifylist = [ - ('user', identity_fakes.user_id), + ('users', [identity_fakes.user_id]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -503,6 +516,21 @@ class TestUserList(TestUser): loaded=True, ) + self.projects_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.PROJECT), + loaded=True, + ) + + self.role_assignments_mock.list.return_value = [ + fakes.FakeResource( + None, + copy.deepcopy( + identity_fakes.ASSIGNMENT_WITH_PROJECT_ID_AND_USER_ID), + loaded=True, + ) + ] + # Get the command object to test self.cmd = user.ListUser(self.app, None) @@ -524,7 +552,7 @@ class TestUserList(TestUser): **kwargs ) - collist = ('ID', 'Name') + collist = ['ID', 'Name'] self.assertEqual(columns, collist) datalist = (( identity_fakes.user_id, @@ -554,7 +582,7 @@ class TestUserList(TestUser): **kwargs ) - collist = ('ID', 'Name') + collist = ['ID', 'Name'] self.assertEqual(columns, collist) datalist = (( identity_fakes.user_id, @@ -584,7 +612,7 @@ class TestUserList(TestUser): **kwargs ) - collist = ('ID', 'Name') + collist = ['ID', 'Name'] self.assertEqual(columns, collist) datalist = (( identity_fakes.user_id, @@ -614,15 +642,15 @@ class TestUserList(TestUser): **kwargs ) - collist = ( + collist = [ 'ID', 'Name', - 'Project Id', - 'Domain Id', + 'Project', + 'Domain', 'Description', 'Email', 'Enabled', - ) + ] self.assertEqual(columns, collist) datalist = (( identity_fakes.user_id, @@ -635,6 +663,33 @@ class TestUserList(TestUser): ), ) self.assertEqual(datalist, tuple(data)) + def test_user_list_project(self): + arglist = [ + '--project', identity_fakes.project_name, + ] + verifylist = [ + ('project', identity_fakes.project_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # DisplayCommandBase.take_action() returns two tuples + columns, data = self.cmd.take_action(parsed_args) + + kwargs = { + 'project': identity_fakes.project_id, + } + + 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(columns, collist) + datalist = (( + identity_fakes.user_id, + identity_fakes.user_name, + ), ) + self.assertEqual(datalist, tuple(data)) + class TestUserSet(TestUser): @@ -1020,14 +1075,15 @@ class TestUserShow(TestUser): self.users_mock.get.assert_called_with(identity_fakes.user_id) - collist = ('domain_id', 'email', 'enabled', 'id', 'name', 'project_id') + collist = ('default_project_id', 'domain_id', 'email', + 'enabled', 'id', 'name') self.assertEqual(columns, collist) datalist = ( + identity_fakes.project_id, identity_fakes.domain_id, identity_fakes.user_email, True, identity_fakes.user_id, identity_fakes.user_name, - identity_fakes.project_id, ) self.assertEqual(data, datalist) diff --git a/openstackclient/tests/image/v1/test_image.py b/openstackclient/tests/image/v1/test_image.py index a056693..4d21ac4 100644 --- a/openstackclient/tests/image/v1/test_image.py +++ b/openstackclient/tests/image/v1/test_image.py @@ -288,7 +288,7 @@ class TestImageDelete(TestImage): image_fakes.image_id, ] verifylist = [ - ('image', image_fakes.image_id), + ('images', [image_fakes.image_id]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) diff --git a/openstackclient/tests/image/v2/test_image.py b/openstackclient/tests/image/v2/test_image.py index 3e9eeeb..bc61a89 100644 --- a/openstackclient/tests/image/v2/test_image.py +++ b/openstackclient/tests/image/v2/test_image.py @@ -51,7 +51,7 @@ class TestImageDelete(TestImage): image_fakes.image_id, ] verifylist = [ - ('image', image_fakes.image_id), + ('images', [image_fakes.image_id]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) diff --git a/openstackclient/tests/network/v2/test_network.py b/openstackclient/tests/network/v2/test_network.py index 468db5e..b893229 100644 --- a/openstackclient/tests/network/v2/test_network.py +++ b/openstackclient/tests/network/v2/test_network.py @@ -120,7 +120,7 @@ class TestDeleteNetwork(common.TestNetworkBase): FAKE_NAME, ] verifylist = [ - ('identifier', FAKE_NAME), + ('networks', [FAKE_NAME]), ] lister = mock.Mock(return_value={RESOURCES: [RECORD]}) self.app.client_manager.network.list_networks = lister diff --git a/openstackclient/volume/v1/backup.py b/openstackclient/volume/v1/backup.py index 992fa7b..71c8ed3 100644 --- a/openstackclient/volume/v1/backup.py +++ b/openstackclient/volume/v1/backup.py @@ -15,6 +15,7 @@ """Volume v1 Backup action implementations""" +import copy import logging import six @@ -26,7 +27,7 @@ from openstackclient.common import utils class CreateBackup(show.ShowOne): - """Create backup command""" + """Create new backup""" log = logging.getLogger(__name__ + '.CreateBackup') @@ -35,13 +36,13 @@ class CreateBackup(show.ShowOne): parser.add_argument( 'volume', metavar='<volume>', - help='The name or ID of the volume to backup', + help='Volume to backup (name or ID)', ) parser.add_argument( '--container', metavar='<container>', required=False, - help='Optional backup container name.', + help='Optional backup container name', ) parser.add_argument( '--name', @@ -73,52 +74,89 @@ class CreateBackup(show.ShowOne): class DeleteBackup(command.Command): - """Delete backup 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( - 'backup', + 'backups', metavar='<backup>', - help='Name or ID of backup to delete', + nargs="+", + help='Backup(s) to delete (ID only)', ) return parser def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume - backup_id = utils.find_resource(volume_client.backups, - parsed_args.backup).id - volume_client.backups.delete(backup_id) + 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): - """List backup command""" + """List backups""" log = logging.getLogger(__name__ + '.ListBackup') + def get_parser(self, prog_name): + parser = super(ListBackup, 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): self.log.debug('take_action(%s)', parsed_args) - columns = ( - 'ID', - 'Display Name', - 'Display Description', - 'Status', - 'Size' - ) + + def _format_volume_id(volume_id): + """Return a volume name if available + + :param volume_id: a volume ID + :rtype: either the volume ID or name + """ + + volume = volume_id + if volume_id in volume_cache.keys(): + volume = volume_cache[volume_id].display_name + return volume + + if parsed_args.long: + columns = ['ID', 'Name', 'Description', 'Status', 'Size', + 'Availability Zone', 'Volume ID', 'Container'] + column_headers = copy.deepcopy(columns) + column_headers[6] = 'Volume' + else: + columns = ['ID', 'Name', 'Description', 'Status', 'Size'] + column_headers = columns + + # Cache the volume list + volume_cache = {} + try: + for s in self.app.client_manager.volume.volumes.list(): + volume_cache[s.id] = s + except Exception: + # Just forget it if there's any trouble + pass + data = self.app.client_manager.volume.backups.list() - return (columns, + + return (column_headers, (utils.get_item_properties( s, columns, - formatters={}, + formatters={'Volume ID': _format_volume_id}, ) for s in data)) class RestoreBackup(command.Command): - """Restore backup command""" + """Restore backup""" log = logging.getLogger(__name__ + '.RestoreBackup') @@ -127,11 +165,11 @@ class RestoreBackup(command.Command): parser.add_argument( 'backup', metavar='<backup>', - help='ID of backup to restore') + help='Backup to restore (ID only)') parser.add_argument( 'volume', - metavar='<dest-volume>', - help='ID of volume to restore to') + metavar='<volume>', + help='Volume to restore to (name or ID)') return parser def take_action(self, parsed_args): @@ -146,7 +184,7 @@ class RestoreBackup(command.Command): class ShowBackup(show.ShowOne): - """Show backup command""" + """Display backup details""" log = logging.getLogger(__name__ + '.ShowBackup') @@ -155,7 +193,7 @@ class ShowBackup(show.ShowOne): parser.add_argument( 'backup', metavar='<backup>', - help='Name or ID of backup to display') + help='Backup to display (ID only)') return parser def take_action(self, parsed_args): diff --git a/openstackclient/volume/v1/snapshot.py b/openstackclient/volume/v1/snapshot.py index 9cc3c4c..5ec2b3c 100644 --- a/openstackclient/volume/v1/snapshot.py +++ b/openstackclient/volume/v1/snapshot.py @@ -15,19 +15,20 @@ """Volume v1 Snapshot action implementations""" +import copy import logging import six -import sys from cliff import command from cliff import lister from cliff import show +from openstackclient.common import parseractions from openstackclient.common import utils class CreateSnapshot(show.ShowOne): - """Create snapshot command""" + """Create new snapshot""" log = logging.getLogger(__name__ + '.CreateSnapshot') @@ -36,7 +37,7 @@ class CreateSnapshot(show.ShowOne): parser.add_argument( 'volume', metavar='<volume>', - help='The name or ID of the volume to snapshot', + help='Volume to snapshot (name or ID)', ) parser.add_argument( '--name', @@ -70,56 +71,103 @@ class CreateSnapshot(show.ShowOne): parsed_args.description ) + snapshot._info.update( + {'properties': utils.format_dict(snapshot._info.pop('metadata'))} + ) + return zip(*sorted(six.iteritems(snapshot._info))) class DeleteSnapshot(command.Command): - """Delete snapshot 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( - 'snapshot', + 'snapshots', metavar='<snapshot>', - help='Name or ID of snapshot to delete', + nargs="+", + help='Snapshot(s) to delete (name or ID)', ) return parser def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume - snapshot_id = utils.find_resource(volume_client.volume_snapshots, - parsed_args.snapshot).id - volume_client.volume_snapshots.delete(snapshot_id) + 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): - """List snapshot command""" + """List snapshots""" log = logging.getLogger(__name__ + '.ListSnapshot') + def get_parser(self, prog_name): + parser = super(ListSnapshot, 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): self.log.debug('take_action(%s)', parsed_args) - columns = ( - 'ID', - 'Display Name', - 'Display Description', - 'Status', - 'Size' - ) + + def _format_volume_id(volume_id): + """Return a volume name if available + + :param volume_id: a volume ID + :rtype: either the volume ID or name + """ + + volume = volume_id + if volume_id in volume_cache.keys(): + volume = volume_cache[volume_id].display_name + return volume + + if parsed_args.long: + columns = ['ID', 'Display Name', 'Display Description', 'Status', + 'Size', 'Created At', 'Volume ID', 'Metadata'] + column_headers = copy.deepcopy(columns) + column_headers[6] = 'Volume' + column_headers[7] = 'Properties' + else: + columns = ['ID', 'Display Name', 'Display Description', 'Status', + 'Size'] + column_headers = copy.deepcopy(columns) + + # Always update Name and Description + column_headers[1] = 'Name' + column_headers[2] = 'Description' + + # Cache the volume list + volume_cache = {} + try: + for s in self.app.client_manager.volume.volumes.list(): + volume_cache[s.id] = s + except Exception: + # Just forget it if there's any trouble + pass + data = self.app.client_manager.volume.volume_snapshots.list() - return (columns, + return (column_headers, (utils.get_item_properties( s, columns, - formatters={}, + formatters={'Metadata': utils.format_dict, + 'Volume ID': _format_volume_id}, ) for s in data)) class SetSnapshot(command.Command): - """Set snapshot command""" + """Set snapshot properties""" log = logging.getLogger(__name__ + '.SetSnapshot') @@ -128,15 +176,22 @@ class SetSnapshot(command.Command): parser.add_argument( 'snapshot', metavar='<snapshot>', - help='Name or ID of snapshot to change') + help='Snapshot to modify (name or ID)') parser.add_argument( '--name', - metavar='<new-snapshot-name>', + metavar='<name>', help='New snapshot name') parser.add_argument( '--description', - metavar='<new-snapshot-description>', + metavar='<description>', help='New snapshot description') + parser.add_argument( + '--property', + metavar='<key=value>', + action=parseractions.KeyValueAction, + help='Property to add/change for this snapshot ' + '(repeat option to set multiple properties)', + ) return parser def take_action(self, parsed_args): @@ -144,21 +199,27 @@ class SetSnapshot(command.Command): volume_client = self.app.client_manager.volume snapshot = utils.find_resource(volume_client.volume_snapshots, parsed_args.snapshot) + + if parsed_args.property: + volume_client.volume_snapshots.set_metadata(snapshot.id, + parsed_args.property) + kwargs = {} if parsed_args.name: kwargs['display_name'] = parsed_args.name if parsed_args.description: kwargs['display_description'] = parsed_args.description - if not kwargs: - sys.stdout.write("Snapshot not updated, no arguments present") + if not kwargs and not parsed_args.property: + self.app.log.error("No changes requested\n") return + snapshot.update(**kwargs) return class ShowSnapshot(show.ShowOne): - """Show snapshot command""" + """Display snapshot details""" log = logging.getLogger(__name__ + '.ShowSnapshot') @@ -167,7 +228,7 @@ class ShowSnapshot(show.ShowOne): parser.add_argument( 'snapshot', metavar='<snapshot>', - help='Name or ID of snapshot to display') + help='Snapshot to display (name or ID)') return parser def take_action(self, parsed_args): @@ -176,4 +237,46 @@ class ShowSnapshot(show.ShowOne): snapshot = utils.find_resource(volume_client.volume_snapshots, parsed_args.snapshot) + snapshot._info.update( + {'properties': utils.format_dict(snapshot._info.pop('metadata'))} + ) + return zip(*sorted(six.iteritems(snapshot._info))) + + +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( + 'snapshot', + metavar='<snapshot>', + help='Snapshot to modify (name or ID)', + ) + parser.add_argument( + '--property', + metavar='<key>', + action='append', + default=[], + help='Property to remove from snapshot ' + '(repeat to remove multiple values)', + ) + 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) + + if parsed_args.property: + volume_client.volume_snapshots.delete_metadata( + snapshot.id, + parsed_args.property, + ) + else: + self.app.log.error("No changes requested\n") + return diff --git a/openstackclient/volume/v1/type.py b/openstackclient/volume/v1/type.py index 71bfc9e..46d1828 100644 --- a/openstackclient/volume/v1/type.py +++ b/openstackclient/volume/v1/type.py @@ -71,7 +71,7 @@ class DeleteVolumeType(command.Command): parser.add_argument( 'volume_type', metavar='<volume-type>', - help='Name or ID of volume type to delete', + help='Volume type to delete (name or ID)', ) return parser @@ -115,7 +115,7 @@ class ListVolumeType(lister.Lister): class SetVolumeType(command.Command): - """Set volume type property""" + """Set volume type properties""" log = logging.getLogger(__name__ + '.SetVolumeType') @@ -124,13 +124,13 @@ class SetVolumeType(command.Command): parser.add_argument( 'volume_type', metavar='<volume-type>', - help='Volume type name or ID to update', + help='Volume type to modify (name or ID)', ) parser.add_argument( '--property', metavar='<key=value>', action=parseractions.KeyValueAction, - help='Property to add/change for this volume type ' + help='Property to add or modify for this volume type ' '(repeat option to set multiple properties)', ) return parser @@ -148,7 +148,7 @@ class SetVolumeType(command.Command): class UnsetVolumeType(command.Command): - """Unset volume type property""" + """Unset volume type properties""" log = logging.getLogger(__name__ + '.UnsetVolumeType') @@ -157,14 +157,14 @@ class UnsetVolumeType(command.Command): parser.add_argument( 'volume_type', metavar='<volume-type>', - help='Type ID or name to remove', + help='Volume type to modify (name or ID)', ) parser.add_argument( '--property', metavar='<key>', action='append', default=[], - help='Property key to remove from volume ' + help='Property to remove from volume type ' '(repeat option to remove multiple properties)', ) return parser diff --git a/openstackclient/volume/v1/volume.py b/openstackclient/volume/v1/volume.py index 84c216d..e59331f 100644 --- a/openstackclient/volume/v1/volume.py +++ b/openstackclient/volume/v1/volume.py @@ -36,14 +36,14 @@ class CreateVolume(show.ShowOne): parser.add_argument( 'name', metavar='<name>', - help='Name of the new volume', + help='New volume name', ) parser.add_argument( '--size', metavar='<size>', required=True, type=int, - help='New volume size', + help='New volume size in GB', ) parser.add_argument( '--snapshot-id', @@ -53,22 +53,22 @@ class CreateVolume(show.ShowOne): parser.add_argument( '--description', metavar='<description>', - help='Description of the volume', + help='New volume description', ) parser.add_argument( '--type', metavar='<volume-type>', - help='Type of volume', + help='Use <volume-type> as the new volume type', ) parser.add_argument( '--user', metavar='<user>', - help='Specify a different user (admin only)', + help='Specify an alternate user (name or ID)', ) parser.add_argument( '--project', metavar='<project>', - help='Specify a different project (admin only)', + help='Specify an alternate project (name or ID)', ) parser.add_argument( '--availability-zone', @@ -76,22 +76,22 @@ class CreateVolume(show.ShowOne): help='Create new volume in <availability-zone>', ) parser.add_argument( - '--property', - metavar='<key=value>', - action=parseractions.KeyValueAction, - help='Property to store for this volume ' - '(repeat option to set multiple properties)', - ) - parser.add_argument( '--image', metavar='<image>', - help='Use <image> as source of new volume', + help='Use <image> as source of new volume (name or ID)', ) parser.add_argument( '--source', metavar='<volume>', help='Volume to clone (name or ID)', ) + parser.add_argument( + '--property', + metavar='<key=value>', + action=parseractions.KeyValueAction, + help='Set a property on this volume ' + '(repeat option to set multiple properties)', + ) return parser @@ -155,35 +155,38 @@ class CreateVolume(show.ShowOne): class DeleteVolume(command.Command): - """Delete a volume""" + """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( - 'volume', + 'volumes', metavar='<volume>', - help='Volume to delete (name or ID)', + nargs="+", + help='Volume(s) to delete (name or ID)', ) parser.add_argument( '--force', dest='force', action='store_true', default=False, - help='Attempt forced removal of a volume, regardless of state', + help='Attempt forced removal of volume(s), regardless of state ' + '(defaults to False)', ) return parser def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) volume_client = self.app.client_manager.volume - volume = utils.find_resource( - volume_client.volumes, parsed_args.volume) - if parsed_args.force: - volume_client.volumes.force_delete(volume.id) - else: - volume_client.volumes.delete(volume.id) + for volume in parsed_args.volumes: + volume_obj = utils.find_resource( + volume_client.volumes, volume) + if parsed_args.force: + volume_client.volumes.force_delete(volume_obj.id) + else: + volume_client.volumes.delete(volume_obj.id) return @@ -214,13 +217,32 @@ class ListVolume(lister.Lister): '--long', action='store_true', default=False, - help='Display properties', + help='List additional fields in output', ) return parser def take_action(self, parsed_args): self.log.debug('take_action(%s)', parsed_args) + volume_client = self.app.client_manager.volume + compute_client = self.app.client_manager.compute + + def _format_attach(attachments): + """Return a formatted string of a volume's attached instances + + :param volume: a volume.attachments field + :rtype: a string of formatted instances + """ + + msg = '' + for attachment in attachments: + server = attachment['server_id'] + if server in server_cache.keys(): + server = server_cache[server].name + device = attachment['device'] + msg += 'Attached to %s on %s ' % (server, device) + return msg + if parsed_args.long: columns = ( 'ID', @@ -229,7 +251,7 @@ class ListVolume(lister.Lister): 'Size', 'Volume Type', 'Bootable', - 'Attached to', + 'Attachments', 'Metadata', ) column_headers = ( @@ -239,7 +261,7 @@ class ListVolume(lister.Lister): 'Size', 'Type', 'Bootable', - 'Attached', + 'Attached to', 'Properties', ) else: @@ -248,28 +270,38 @@ class ListVolume(lister.Lister): 'Display Name', 'Status', 'Size', - 'Attached to', + 'Attachments', ) column_headers = ( 'ID', 'Display Name', 'Status', 'Size', - 'Attached', + 'Attached to', ) + + # Cache the server list + server_cache = {} + try: + for s in compute_client.servers.list(): + server_cache[s.id] = s + except Exception: + # Just forget it if there's any trouble + pass + search_opts = { 'all_tenants': parsed_args.all_projects, 'display_name': parsed_args.name, 'status': parsed_args.status, } - volume_client = self.app.client_manager.volume data = volume_client.volumes.list(search_opts=search_opts) return (column_headers, (utils.get_item_properties( s, columns, - formatters={'Metadata': utils.format_dict}, + formatters={'Metadata': utils.format_dict, + 'Attachments': _format_attach}, ) for s in data)) @@ -287,19 +319,19 @@ class SetVolume(command.Command): ) parser.add_argument( '--name', - metavar='<new-name>', + metavar='<name>', help='New volume name', ) parser.add_argument( '--description', - metavar='<new-description>', + metavar='<description>', help='New volume description', ) parser.add_argument( '--property', metavar='<key=value>', action=parseractions.KeyValueAction, - help='Property to add/change for this volume ' + help='Property to add or modify for this volume ' '(repeat option to set multiple properties)', ) return parser @@ -369,15 +401,15 @@ class UnsetVolume(command.Command): parser.add_argument( 'volume', metavar='<volume>', - help='Volume to change (name or ID)', + help='Volume to modify (name or ID)', ) parser.add_argument( '--property', metavar='<key>', action='append', default=[], - help='Property key to remove from volume ' - '(repeat to set multiple values)', + help='Property to remove from volume ' + '(repeat option to remove multiple properties)', ) return parser diff --git a/python-openstackclient/locale/de/LC_MESSAGES/python-openstackclient.po b/python-openstackclient/locale/de/LC_MESSAGES/python-openstackclient.po new file mode 100644 index 0000000..28d8031 --- /dev/null +++ b/python-openstackclient/locale/de/LC_MESSAGES/python-openstackclient.po @@ -0,0 +1,765 @@ +# German translations for python-openstackclient. +# Copyright (C) 2015 ORGANIZATION +# This file is distributed under the same license as the +# python-openstackclient project. +# +# Translators: +# Ettore Atalan <atalanttore@googlemail.com>, 2014-2015 +msgid "" +msgstr "" +"Project-Id-Version: python-openstackclient\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2015-01-19 06:14+0000\n" +"PO-Revision-Date: 2015-01-16 21:14+0000\n" +"Last-Translator: openstackjenkins <jenkins@openstack.org>\n" +"Language-Team: German (http://www.transifex.com/projects/p/python-" +"openstackclient/language/de/)\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 1.3\n" + +#: openstackclient/api/auth.py:132 +msgid "Set a username with --os-username or OS_USERNAME\n" +msgstr "" + +#: openstackclient/api/auth.py:134 +msgid "Set an authentication URL, with --os-auth-url or OS_AUTH_URL\n" +msgstr "" + +#: openstackclient/api/auth.py:138 +msgid "" +"Set a scope, such as a project or domain, with --os-project-name or " +"OS_PROJECT_NAME" +msgstr "" + +#: openstackclient/compute/v2/availability_zone.py:72 +#: openstackclient/compute/v2/server.py:601 +#: openstackclient/identity/v2_0/endpoint.py:114 +#: openstackclient/identity/v2_0/project.py:145 +#: openstackclient/identity/v2_0/service.py:128 +#: openstackclient/identity/v2_0/user.py:174 +msgid "List additional fields in output" +msgstr "Zusätzliche Fehler in der Ausgabe auflisten" + +#: openstackclient/compute/v2/server.py:112 +#: openstackclient/compute/v2/server.py:149 +#: openstackclient/compute/v2/server.py:460 +#: openstackclient/compute/v2/server.py:671 +#: openstackclient/compute/v2/server.py:705 +#: openstackclient/compute/v2/server.py:788 +#: openstackclient/compute/v2/server.py:812 +#: openstackclient/compute/v2/server.py:867 +#: openstackclient/compute/v2/server.py:959 +#: openstackclient/compute/v2/server.py:999 +#: openstackclient/compute/v2/server.py:1025 +#: openstackclient/compute/v2/server.py:1090 +#: openstackclient/compute/v2/server.py:1114 +#: openstackclient/compute/v2/server.py:1173 +#: openstackclient/compute/v2/server.py:1210 +#: openstackclient/compute/v2/server.py:1368 +#: openstackclient/compute/v2/server.py:1392 +#: openstackclient/compute/v2/server.py:1416 +#: openstackclient/compute/v2/server.py:1440 +#: openstackclient/compute/v2/server.py:1464 +msgid "Server (name or ID)" +msgstr "Server (Name oder Kennung)" + +#: openstackclient/compute/v2/server.py:117 +msgid "Security group to add (name or ID)" +msgstr "Zu hinzufügende Sicherheitsgruppe (Name oder Kennung)" + +#: openstackclient/compute/v2/server.py:154 +msgid "Volume to add (name or ID)" +msgstr "Zu hinzufügender Datenträger (Name oder Kennung)" + +#: openstackclient/compute/v2/server.py:159 +msgid "Server internal device name for volume" +msgstr "Serverinterner Gerätename für Datenträger" + +#: openstackclient/compute/v2/server.py:195 +#: openstackclient/compute/v2/server.py:1119 +msgid "New server name" +msgstr "Neuer Servername" + +#: openstackclient/compute/v2/server.py:203 +msgid "Create server from this image" +msgstr "Server aus diesem Abbild erstellen" + +#: openstackclient/compute/v2/server.py:208 +msgid "Create server from this volume" +msgstr "Server aus diesem Datenträger erstellen" + +#: openstackclient/compute/v2/server.py:214 +msgid "Create server with this flavor" +msgstr "Server mit dieser Variante erstellen" + +#: openstackclient/compute/v2/server.py:221 +msgid "Security group to assign to this server (repeat for multiple groups)" +msgstr "" +"Zu diesem Server zuweisende Sicherheitsgruppe (für mehrere Gruppen " +"wiederholen)" + +#: openstackclient/compute/v2/server.py:227 +msgid "Keypair to inject into this server (optional extension)" +msgstr "In diesem Server einzufügendes Schlüsselpaar (optionale Erweiterung)" + +#: openstackclient/compute/v2/server.py:233 +msgid "Set a property on this server (repeat for multiple values)" +msgstr "" +"Legen Sie eine Eigenschaft auf diesem Server fest (für mehrere Werte " +"wiederholen)" + +#: openstackclient/compute/v2/server.py:241 +msgid "File to inject into image before boot (repeat for multiple files)" +msgstr "" +"Vor dem Start auf diesem Abbild einzufügende Datei (für mehrere Dateien " +"wiederholen)" + +#: openstackclient/compute/v2/server.py:247 +msgid "User data file to serve from the metadata server" +msgstr "Vom Metadatenserver anzubietende Benutzerdatendatei" + +#: openstackclient/compute/v2/server.py:252 +msgid "Select an availability zone for the server" +msgstr "Wählen Sie eine Verfügbarkeitszone für den Server aus" + +#: openstackclient/compute/v2/server.py:259 +msgid "" +"Map block devices; map is <id>:<type>:<size(GB)>:<delete_on_terminate> " +"(optional extension)" +msgstr "" +"Blockorientierte Geräte abbilden; Abbildung ist " +"<Kennung>:<Typ>:<Größe(GB)>:<beim_Beenden_löschen> (optionale " +"Erweiterung)" + +#: openstackclient/compute/v2/server.py:268 +msgid "Specify NIC configuration (optional extension)" +msgstr "Geben Sie eine NIC-Konfiguration an (optionale Erweiterung)" + +#: openstackclient/compute/v2/server.py:275 +msgid "Hints for the scheduler (optional extension)" +msgstr "Hinweise für den Planer (optionale Erweiterung)" + +#: openstackclient/compute/v2/server.py:281 +msgid "" +"Use specified volume as the config drive, or 'True' to use an ephemeral " +"drive" +msgstr "" +"Benutzerdefinierter Datenträger als Konfigurationslaufwerk oder 'True', " +"um ein flüchtiges Laufwerk zu verwenden" + +#: openstackclient/compute/v2/server.py:289 +msgid "Minimum number of servers to launch (default=1)" +msgstr "Minimale Anzahl der zu startenden Server (Standard=1)" + +#: openstackclient/compute/v2/server.py:296 +msgid "Maximum number of servers to launch (default=1)" +msgstr "Maximale Anzahl der zu startenden Server (Standard=1)" + +#: openstackclient/compute/v2/server.py:301 +msgid "Wait for build to complete" +msgstr "Warten Sie, bis die Herstellung abgeschlossen ist" + +#: openstackclient/compute/v2/server.py:341 +msgid "min instances should be <= max instances" +msgstr "min. Instanzen sollten <= max. Instanzen sein" + +#: openstackclient/compute/v2/server.py:344 +msgid "min instances should be > 0" +msgstr "min. Instanzen sollten > 0 sein" + +#: openstackclient/compute/v2/server.py:347 +msgid "max instances should be > 0" +msgstr "max. Instanzen sollten > 0 sein" + +#: openstackclient/compute/v2/server.py:441 +#, python-format +msgid "Error creating server: %s" +msgstr "Fehler beim Erstellen des Servers: %s" + +#: openstackclient/compute/v2/server.py:443 +msgid "" +"\n" +"Error creating server" +msgstr "" +"\n" +"Fehler beim Erstellen des Servers" + +#: openstackclient/compute/v2/server.py:465 +msgid "Name of new image (default is server name)" +msgstr "Name des neuen Abbilds (Servername ist Standard)" + +#: openstackclient/compute/v2/server.py:470 +msgid "Wait for image create to complete" +msgstr "Warten Sie, bis die Abbilderstellung abgeschlossen ist" + +#: openstackclient/compute/v2/server.py:500 +#, python-format +msgid "Error creating server snapshot: %s" +msgstr "Fehler beim Erstellen der Server-Schattenkopie: %s" + +#: openstackclient/compute/v2/server.py:502 +msgid "" +"\n" +"Error creating server snapshot" +msgstr "" +"\n" +"Fehler beim Erstellen der Server-Schattenkopie" + +#: openstackclient/compute/v2/server.py:524 +msgid "Server(s) to delete (name or ID)" +msgstr "Zu löschende(r) Server (Name oder Kennung)" + +#: openstackclient/compute/v2/server.py:548 +msgid "Only return instances that match the reservation" +msgstr "Nur Instanzen zurückgeben, die der Einschränkung entsprechen" + +#: openstackclient/compute/v2/server.py:553 +msgid "Regular expression to match IP addresses" +msgstr "Regulärer Ausdruck zum Abgleichen mit IP-Adressen" + +#: openstackclient/compute/v2/server.py:558 +msgid "Regular expression to match IPv6 addresses" +msgstr "Regulärer Ausdruck zum Abgleichen mit IPv6-Adressen" + +#: openstackclient/compute/v2/server.py:563 +msgid "Regular expression to match names" +msgstr "Regulärer Ausdruck zum Abgleichen mit Namen" + +#: openstackclient/compute/v2/server.py:568 +msgid "Regular expression to match instance name (admin only)" +msgstr "Regulärer Ausdruck zum Abgleichen des Instanznamens (nur Administrator) " + +#: openstackclient/compute/v2/server.py:574 +msgid "Search by server status" +msgstr "Nach Serverstatus suchen" + +#: openstackclient/compute/v2/server.py:579 +msgid "Search by flavor" +msgstr "Nach Variante suchen" + +#: openstackclient/compute/v2/server.py:584 +msgid "Search by image" +msgstr "Nach Bild suchen" + +#: openstackclient/compute/v2/server.py:589 +msgid "Search by hostname" +msgstr "Nach Hostname suchen" + +#: openstackclient/compute/v2/server.py:595 +msgid "Include all projects (admin only)" +msgstr "Alle Projekte miteinbeziehen (nur Administrator)" + +#: openstackclient/compute/v2/server.py:710 +msgid "Target hostname" +msgstr "Zielhostname" + +#: openstackclient/compute/v2/server.py:718 +msgid "Perform a shared live migration (default)" +msgstr "Gemeinsame Live-Migration ausführen (Standard)" + +#: openstackclient/compute/v2/server.py:724 +msgid "Perform a block live migration" +msgstr "Blockorientierte Live-Migration ausführen" + +#: openstackclient/compute/v2/server.py:731 +msgid "Allow disk over-commit on the destination host" +msgstr "Festplattenüberladung auf dem Zielhost erlauben" + +#: openstackclient/compute/v2/server.py:738 +msgid "Do not over-commit disk on the destination host (default)" +msgstr "Festplatte auf dem Zielhost nicht überladen (Standard)" + +#: openstackclient/compute/v2/server.py:744 +#: openstackclient/compute/v2/server.py:1045 +msgid "Wait for resize to complete" +msgstr "Warten Sie, bis die Größenänderung abgeschlossen ist" + +#: openstackclient/compute/v2/server.py:772 +#: openstackclient/compute/v2/server.py:1070 +msgid "Complete\n" +msgstr "Fertig\n" + +#: openstackclient/compute/v2/server.py:774 +msgid "" +"\n" +"Error migrating server" +msgstr "" +"\n" +"Fehler beim Migrieren des Servers" + +#: openstackclient/compute/v2/server.py:821 +msgid "Perform a hard reboot" +msgstr "Harten Neustart ausführen" + +#: openstackclient/compute/v2/server.py:829 +msgid "Perform a soft reboot" +msgstr "Weichen Neustart ausführen" + +#: openstackclient/compute/v2/server.py:834 +msgid "Wait for reboot to complete" +msgstr "Warten Sie, bis der Neustart abgeschlossen ist" + +#: openstackclient/compute/v2/server.py:851 +msgid "" +"\n" +"Reboot complete\n" +msgstr "" +"\n" +"Neustart abgeschlossen\n" + +#: openstackclient/compute/v2/server.py:853 +msgid "" +"\n" +"Error rebooting server\n" +msgstr "" +"\n" +"Fehler beim Neustarten des Servers\n" + +#: openstackclient/compute/v2/server.py:873 +msgid "Recreate server from this image" +msgstr "Server aus diesem Abbild neu erstellen" + +#: openstackclient/compute/v2/server.py:883 +msgid "Wait for rebuild to complete" +msgstr "Warten Sie, bis die Wiederherstellung abgeschlossen ist" + +#: openstackclient/compute/v2/server.py:904 +msgid "" +"\n" +"Complete\n" +msgstr "" +"\n" +"Fertig\n" + +#: openstackclient/compute/v2/server.py:906 +msgid "" +"\n" +"Error rebuilding server" +msgstr "" +"\n" +"Fehler bei der Wiederherstellung des Servers" + +#: openstackclient/compute/v2/server.py:923 +msgid "Name or ID of server to use" +msgstr "Name oder Kennung des zu verwendenden Servers" + +#: openstackclient/compute/v2/server.py:928 +msgid "Name or ID of security group to remove from server" +msgstr "Name oder Kennung der vom Server zu entfernenden Sicherheitsgruppe" + +#: openstackclient/compute/v2/server.py:964 +msgid "Volume to remove (name or ID)" +msgstr "Zu entfernender Datenträger (Name oder Kennung)" + +#: openstackclient/compute/v2/server.py:1030 +msgid "Resize server to specified flavor" +msgstr "Servergröße auf angegebene Variante ändern" + +#: openstackclient/compute/v2/server.py:1035 +msgid "Verify server resize is complete" +msgstr "Überprüfen, ob die Größenänderung abgeschlossen ist" + +#: openstackclient/compute/v2/server.py:1040 +msgid "Restore server state before resize" +msgstr "Serverstatus vor der Größenänderung wiederherstellen" + +#: openstackclient/compute/v2/server.py:1072 +msgid "" +"\n" +"Error resizing server" +msgstr "" +"\n" +"Fehler bei der Größenänderung des Servers" + +#: openstackclient/compute/v2/server.py:1124 +msgid "Set new root password (interactive only)" +msgstr "Neues root-Passwort festlegen (Nur interaktiv)" + +#: openstackclient/compute/v2/server.py:1130 +msgid "" +"Property to add/change for this server (repeat option to set multiple " +"properties)" +msgstr "" +"Zu hinzufügende/ändernde Eigenschaft für diesen Server (wiederholen Sie " +"die Option, um mehrere Eigenschaften festzulegen)" + +#: openstackclient/compute/v2/server.py:1154 +msgid "New password: " +msgstr "Neues Passwort:" + +#: openstackclient/compute/v2/server.py:1155 +msgid "Retype new password: " +msgstr "Neues Passwort erneut eingeben:" + +#: openstackclient/compute/v2/server.py:1159 +msgid "Passwords do not match, password unchanged" +msgstr "Passwörter stimmen nicht überein, Passwort unverändert" + +#: openstackclient/compute/v2/server.py:1179 +msgid "Display server diagnostics information" +msgstr "Serverdiagnoseinformationen anzeigen" + +#: openstackclient/compute/v2/server.py:1192 +msgid "Error retrieving diagnostics data" +msgstr "Fehler beim Abrufen der Diagnosedaten" + +#: openstackclient/compute/v2/server.py:1215 +msgid "Login name (ssh -l option)" +msgstr "Anmeldename (ssh -l Option)" + +#: openstackclient/compute/v2/server.py:1226 +msgid "Destination port (ssh -p option)" +msgstr "Zielport (ssh -p Option)" + +#: openstackclient/compute/v2/server.py:1238 +msgid "Private key file (ssh -i option)" +msgstr "Private Schlüsseldatei (ssh -i Option)" + +#: openstackclient/compute/v2/server.py:1249 +msgid "Options in ssh_config(5) format (ssh -o option)" +msgstr "Optionen im ssh_config(5)-Format (ssh -o Option)" + +#: openstackclient/compute/v2/server.py:1263 +msgid "Use only IPv4 addresses" +msgstr "Nur IPv4-Adressen verwenden" + +#: openstackclient/compute/v2/server.py:1270 +msgid "Use only IPv6 addresses" +msgstr "Nur IPv6-Adressen verwenden" + +#: openstackclient/compute/v2/server.py:1279 +msgid "Use public IP address" +msgstr "Öffentliche IP-Adresse verwenden" + +#: openstackclient/compute/v2/server.py:1287 +msgid "Use private IP address" +msgstr "Private IP-Adresse verwenden" + +#: openstackclient/compute/v2/server.py:1294 +msgid "Use other IP address (public, private, etc)" +msgstr "Andere IP-Adresse verwenden (öffentlich, privat, usw.)" + +#: openstackclient/compute/v2/server.py:1471 +msgid "Property key to remove from server (repeat to unset multiple values)" +msgstr "" +"Vom Server zu entfernender Eigenschaftsschlüssel (zum Aufheben von " +"mehreren Werten wiederholen)" + +#: openstackclient/identity/v2_0/catalog.py:71 +msgid "Service to display (type or name)" +msgstr "" + +#: openstackclient/identity/v2_0/ec2creds.py:40 +msgid "Specify an alternate project (default: current authenticated project)" +msgstr "" +"Geben Sie ein alternatives Projekt an (Standard: aktuell " +"authentifiziertes Projekt)" + +#: openstackclient/identity/v2_0/ec2creds.py:46 +msgid "Specify an alternate user (default: current authenticated user)" +msgstr "" +"Geben Sie einen alternativen Benutzer an (Standard: aktuell " +"authentifizierter Benutzer)" + +#: openstackclient/identity/v2_0/ec2creds.py:95 +#: openstackclient/identity/v2_0/ec2creds.py:168 +msgid "Credentials access key" +msgstr "Anmeldedaten-Zugriffsschlüssel" + +#: openstackclient/identity/v2_0/ec2creds.py:100 +#: openstackclient/identity/v2_0/ec2creds.py:130 +#: openstackclient/identity/v2_0/ec2creds.py:173 +msgid "Specify a user" +msgstr "Geben Sie einen Benutzer an" + +#: openstackclient/identity/v2_0/endpoint.py:40 +msgid "New endpoint service (name or ID)" +msgstr "Neuer Endpunktdienst (Name oder Kennung)" + +#: openstackclient/identity/v2_0/endpoint.py:46 +msgid "New endpoint public URL (required)" +msgstr "Öffentliche URL des neuen Endpunktes (erforderlich)" + +#: openstackclient/identity/v2_0/endpoint.py:51 +msgid "New endpoint admin URL" +msgstr "Administrator-URL des neuen Endpunktes" + +#: openstackclient/identity/v2_0/endpoint.py:56 +msgid "New endpoint internal URL" +msgstr "Interne URL des neuen Endpunktes" + +#: openstackclient/identity/v2_0/endpoint.py:61 +msgid "New endpoint region ID" +msgstr "Neue Endpunkt-Regionskennung" + +#: openstackclient/identity/v2_0/endpoint.py:93 +msgid "Endpoint ID to delete" +msgstr "Zu löschende Endpunktkennung" + +#: openstackclient/identity/v2_0/endpoint.py:149 +msgid "Endpoint ID to display" +msgstr "Anzuzeigende Endpunktkennung" + +#: openstackclient/identity/v2_0/project.py:41 +msgid "New project name" +msgstr "Name des neuen Projekts" + +#: openstackclient/identity/v2_0/project.py:46 +msgid "Project description" +msgstr "Projektbeschreibung" + +#: openstackclient/identity/v2_0/project.py:52 +msgid "Enable project (default)" +msgstr "Projekt aktivieren (Standardeinstellung)" + +#: openstackclient/identity/v2_0/project.py:57 +#: openstackclient/identity/v2_0/project.py:194 +msgid "Disable project" +msgstr "Projekt deaktivieren" + +#: openstackclient/identity/v2_0/project.py:63 +msgid "Add a property to <name> (repeat option to set multiple properties)" +msgstr "" +"Fügen Sie eine Eigenschaft zu <Name> hinzu (wiederholen Sie die Option, " +"um mehrere Eigenschaften festzulegen)" + +#: openstackclient/identity/v2_0/project.py:69 +#: openstackclient/identity/v3/project.py:75 +msgid "Return existing project" +msgstr "Vorhandenes Projekt zurückgeben" + +#: openstackclient/identity/v2_0/project.py:117 +msgid "Project(s) to delete (name or ID)" +msgstr "Zu löschende(s) Projekt(e) (Name oder Kennung)" + +#: openstackclient/identity/v2_0/project.py:173 +msgid "Project to modify (name or ID)" +msgstr "Zu änderndes Projekt (Name oder Kennung)" + +#: openstackclient/identity/v2_0/project.py:178 +msgid "Set project name" +msgstr "Projektname festlegen" + +#: openstackclient/identity/v2_0/project.py:183 +msgid "Set project description" +msgstr "Projektbeschreibung festlegen" + +#: openstackclient/identity/v2_0/project.py:189 +msgid "Enable project" +msgstr "Projekt aktivieren" + +#: openstackclient/identity/v2_0/project.py:200 +msgid "Set a project property (repeat option to set multiple properties)" +msgstr "" +"Legen Sie eine Projekteigenschaft fest (wiederholen Sie die Option, um " +"mehrere Eigenschaften festzulegen)" + +#: openstackclient/identity/v2_0/project.py:253 +msgid "Project to display (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/role.py:41 +msgid "Role to add to <project>:<user> (name or ID)" +msgstr "Zu <project>:<user> hinzuzufügende Rolle (Name oder Kennung)" + +#: openstackclient/identity/v2_0/role.py:47 +#: openstackclient/identity/v2_0/role.py:309 +msgid "Include <project> (name or ID)" +msgstr "<project> miteinbeziehen (Name oder Kennung)" + +#: openstackclient/identity/v2_0/role.py:53 +#: openstackclient/identity/v2_0/role.py:315 +msgid "Include <user> (name or ID)" +msgstr "<user> miteinbeziehen (Name oder Kennung)" + +#: openstackclient/identity/v2_0/role.py:87 +msgid "New role name" +msgstr "Name der neuen Rolle" + +#: openstackclient/identity/v2_0/role.py:92 +#: openstackclient/identity/v3/role.py:157 +msgid "Return existing role" +msgstr "Vorhandene Rolle zurückgeben" + +#: openstackclient/identity/v2_0/role.py:127 +msgid "Role(s) to delete (name or ID)" +msgstr "Zu löschende Rolle(n) (Name oder Kennung)" + +#: openstackclient/identity/v2_0/role.py:194 +#: openstackclient/identity/v2_0/role.py:257 +msgid "Project must be specified" +msgstr "Projekt muss angegeben werden" + +#: openstackclient/identity/v2_0/role.py:208 +#: openstackclient/identity/v2_0/role.py:263 +msgid "User must be specified" +msgstr "Benutzer muss angegeben werden" + +#: openstackclient/identity/v2_0/role.py:236 +msgid "User to list (name or ID)" +msgstr "Aufzulistender Benutzer (Name oder Kennung)" + +#: openstackclient/identity/v2_0/role.py:241 +msgid "Filter users by <project> (name or ID)" +msgstr "Benutzer nach <project> filtern (Name oder Kennung)" + +#: openstackclient/identity/v2_0/role.py:303 +msgid "Role to remove (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/role.py:344 +msgid "Role to display (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/service.py:42 +msgid "New service type (compute, image, identity, volume, etc)" +msgstr "Neuer Diensttyp (Berechnen, Abbild, Identität, Datenträger, usw.)" + +#: openstackclient/identity/v2_0/service.py:53 +msgid "New service name" +msgstr "Name des neuen Dienstes" + +#: openstackclient/identity/v2_0/service.py:58 +msgid "New service description" +msgstr "Beschreibung des neuen Dienstes" + +#: openstackclient/identity/v2_0/service.py:78 +msgid "" +"The argument --type is deprecated, use service create --name <service-" +"name> type instead." +msgstr "" +"Das Argument --type ist veraltet, verwenden Sie stattdessen service " +"create --name <Dienstname> type." + +#: openstackclient/identity/v2_0/service.py:105 +msgid "Service to delete (name or ID)" +msgstr "Zu löschender Dienst (Name oder Kennung)" + +#: openstackclient/identity/v2_0/service.py:156 +msgid "Service to display (type, name or ID)" +msgstr "Anzuzeigender Dienst (Typ, Name oder Kennung)" + +#: openstackclient/identity/v2_0/service.py:162 +msgid "Show service catalog information" +msgstr "Dienstkataloginformation anzeigen" + +#: openstackclient/identity/v2_0/service.py:180 +#, python-format +msgid "No service catalog with a type, name or ID of '%s' exists." +msgstr "Kein Dienstkatalog mit Typ, Namen oder Kennung von '%s' ist vorhanden." + +#: openstackclient/identity/v2_0/token.py:54 +msgid "Token to be deleted" +msgstr "Zu löschender Token" + +#: openstackclient/identity/v2_0/user.py:40 +msgid "New user name" +msgstr "Neuer Benutzername" + +#: openstackclient/identity/v2_0/user.py:45 +msgid "Default project (name or ID)" +msgstr "Standardprojekt (Name oder Kennung)" + +#: openstackclient/identity/v2_0/user.py:50 +#: openstackclient/identity/v2_0/user.py:273 +msgid "Set user password" +msgstr "Benutzerpasswort festlegen" + +#: openstackclient/identity/v2_0/user.py:56 +#: openstackclient/identity/v2_0/user.py:279 +msgid "Prompt interactively for password" +msgstr "Interaktiv nach dem Passwort abfragen" + +#: openstackclient/identity/v2_0/user.py:61 +#: openstackclient/identity/v2_0/user.py:284 +msgid "Set user email address" +msgstr "E-Mail-Adresse des Benutzers festlegen" + +#: openstackclient/identity/v2_0/user.py:67 +#: openstackclient/identity/v2_0/user.py:290 +msgid "Enable user (default)" +msgstr "Benutzer aktivieren (Standardeinstellung)" + +#: openstackclient/identity/v2_0/user.py:72 +#: openstackclient/identity/v2_0/user.py:295 +msgid "Disable user" +msgstr "Benutzer deaktivieren" + +#: openstackclient/identity/v2_0/user.py:77 +#: openstackclient/identity/v3/user.py:89 +msgid "Return existing user" +msgstr "Vorhandenen Benutzer zurückgeben" + +#: openstackclient/identity/v2_0/user.py:141 +msgid "User(s) to delete (name or ID)" +msgstr "Zu löschende(r) Benutzer (Name oder Kennung)" + +#: openstackclient/identity/v2_0/user.py:168 +msgid "Filter users by project (name or ID)" +msgstr "Benutzer nach Projekt filtern (Name oder Kennung)" + +#: openstackclient/identity/v2_0/user.py:258 +msgid "User to change (name or ID)" +msgstr "Zu ändernder Benutzer (Name oder Kennung)" + +#: openstackclient/identity/v2_0/user.py:263 +msgid "Set user name" +msgstr "Benutzername festlegen" + +#: openstackclient/identity/v2_0/user.py:268 +msgid "Set default project (name or ID)" +msgstr "Standardprojekt festlegen (Name oder Kennung)" + +#: openstackclient/identity/v2_0/user.py:361 +msgid "User to display (name or ID)" +msgstr "Anzuzeigender Benutzer (Name oder Kennung)" + +#: openstackclient/identity/v3/domain.py:62 +msgid "Return existing domain" +msgstr "Vorhandene Domäne zurückgeben" + +#: openstackclient/identity/v3/group.py:133 +msgid "Return existing group" +msgstr "Vorhandene Gruppe zurückgeben" + +#: openstackclient/identity/v3/region.py:39 +msgid "New region ID" +msgstr "Neue Regionskennung" + +#: openstackclient/identity/v3/region.py:44 +msgid "Parent region ID" +msgstr "Übergeordnete Regionskennung" + +#: openstackclient/identity/v3/region.py:49 +#: openstackclient/identity/v3/region.py:151 +msgid "New region description" +msgstr "Beschreibung des neuen Bereichs" + +#: openstackclient/identity/v3/region.py:54 +#: openstackclient/identity/v3/region.py:156 +msgid "New region url" +msgstr "URL des neuen Bereichs" + +#: openstackclient/identity/v3/region.py:86 +msgid "Region ID to delete" +msgstr "Zu löschende Regionskennung" + +#: openstackclient/identity/v3/region.py:108 +msgid "Filter by parent region ID" +msgstr "Nach übergeordneter Regionskennung filtern" + +#: openstackclient/identity/v3/region.py:141 +msgid "Region to modify" +msgstr "" + +#: openstackclient/identity/v3/region.py:146 +msgid "New parent region ID" +msgstr "Neue übergeordnete Regionskennung" + +#: openstackclient/identity/v3/region.py:191 +msgid "Region to display" +msgstr "" + diff --git a/python-openstackclient/locale/python-openstackclient.pot b/python-openstackclient/locale/python-openstackclient.pot index 5dcdac8..b2f659c 100644 --- a/python-openstackclient/locale/python-openstackclient.pot +++ b/python-openstackclient/locale/python-openstackclient.pot @@ -1,15 +1,15 @@ # Translations template for python-openstackclient. -# Copyright (C) 2014 ORGANIZATION +# Copyright (C) 2015 ORGANIZATION # This file is distributed under the same license as the # python-openstackclient project. -# FIRST AUTHOR <EMAIL@ADDRESS>, 2014. +# FIRST AUTHOR <EMAIL@ADDRESS>, 2015. # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: python-openstackclient 0.4.2.dev43.gaf67658\n" +"Project-Id-Version: python-openstackclient 1.0.1.post122\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2014-10-09 13:11-0400\n" +"POT-Creation-Date: 2015-01-19 06:14+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" @@ -18,61 +18,705 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 1.3\n" +#: openstackclient/api/auth.py:132 +msgid "Set a username with --os-username or OS_USERNAME\n" +msgstr "" + +#: openstackclient/api/auth.py:134 +msgid "Set an authentication URL, with --os-auth-url or OS_AUTH_URL\n" +msgstr "" + +#: openstackclient/api/auth.py:138 +msgid "" +"Set a scope, such as a project or domain, with --os-project-name or " +"OS_PROJECT_NAME" +msgstr "" + +#: openstackclient/compute/v2/availability_zone.py:72 +#: openstackclient/compute/v2/server.py:601 +#: openstackclient/identity/v2_0/endpoint.py:114 +#: openstackclient/identity/v2_0/project.py:145 +#: openstackclient/identity/v2_0/service.py:128 +#: openstackclient/identity/v2_0/user.py:174 +msgid "List additional fields in output" +msgstr "" + +#: openstackclient/compute/v2/server.py:112 +#: openstackclient/compute/v2/server.py:149 +#: openstackclient/compute/v2/server.py:460 +#: openstackclient/compute/v2/server.py:671 +#: openstackclient/compute/v2/server.py:705 +#: openstackclient/compute/v2/server.py:788 +#: openstackclient/compute/v2/server.py:812 +#: openstackclient/compute/v2/server.py:867 +#: openstackclient/compute/v2/server.py:959 +#: openstackclient/compute/v2/server.py:999 +#: openstackclient/compute/v2/server.py:1025 +#: openstackclient/compute/v2/server.py:1090 +#: openstackclient/compute/v2/server.py:1114 +#: openstackclient/compute/v2/server.py:1173 +#: openstackclient/compute/v2/server.py:1210 +#: openstackclient/compute/v2/server.py:1368 +#: openstackclient/compute/v2/server.py:1392 +#: openstackclient/compute/v2/server.py:1416 +#: openstackclient/compute/v2/server.py:1440 +#: openstackclient/compute/v2/server.py:1464 +msgid "Server (name or ID)" +msgstr "" + +#: openstackclient/compute/v2/server.py:117 +msgid "Security group to add (name or ID)" +msgstr "" + +#: openstackclient/compute/v2/server.py:154 +msgid "Volume to add (name or ID)" +msgstr "" + +#: openstackclient/compute/v2/server.py:159 +msgid "Server internal device name for volume" +msgstr "" + +#: openstackclient/compute/v2/server.py:195 +#: openstackclient/compute/v2/server.py:1119 +msgid "New server name" +msgstr "" + +#: openstackclient/compute/v2/server.py:203 +msgid "Create server from this image" +msgstr "" + +#: openstackclient/compute/v2/server.py:208 +msgid "Create server from this volume" +msgstr "" + +#: openstackclient/compute/v2/server.py:214 +msgid "Create server with this flavor" +msgstr "" + +#: openstackclient/compute/v2/server.py:221 +msgid "Security group to assign to this server (repeat for multiple groups)" +msgstr "" + +#: openstackclient/compute/v2/server.py:227 +msgid "Keypair to inject into this server (optional extension)" +msgstr "" + +#: openstackclient/compute/v2/server.py:233 +msgid "Set a property on this server (repeat for multiple values)" +msgstr "" + +#: openstackclient/compute/v2/server.py:241 +msgid "File to inject into image before boot (repeat for multiple files)" +msgstr "" + +#: openstackclient/compute/v2/server.py:247 +msgid "User data file to serve from the metadata server" +msgstr "" + +#: openstackclient/compute/v2/server.py:252 +msgid "Select an availability zone for the server" +msgstr "" + +#: openstackclient/compute/v2/server.py:259 +msgid "" +"Map block devices; map is <id>:<type>:<size(GB)>:<delete_on_terminate> " +"(optional extension)" +msgstr "" + +#: openstackclient/compute/v2/server.py:268 +msgid "Specify NIC configuration (optional extension)" +msgstr "" + +#: openstackclient/compute/v2/server.py:275 +msgid "Hints for the scheduler (optional extension)" +msgstr "" + +#: openstackclient/compute/v2/server.py:281 +msgid "" +"Use specified volume as the config drive, or 'True' to use an ephemeral " +"drive" +msgstr "" + +#: openstackclient/compute/v2/server.py:289 +msgid "Minimum number of servers to launch (default=1)" +msgstr "" + +#: openstackclient/compute/v2/server.py:296 +msgid "Maximum number of servers to launch (default=1)" +msgstr "" + +#: openstackclient/compute/v2/server.py:301 +msgid "Wait for build to complete" +msgstr "" + +#: openstackclient/compute/v2/server.py:341 +msgid "min instances should be <= max instances" +msgstr "" + +#: openstackclient/compute/v2/server.py:344 +msgid "min instances should be > 0" +msgstr "" + +#: openstackclient/compute/v2/server.py:347 +msgid "max instances should be > 0" +msgstr "" + +#: openstackclient/compute/v2/server.py:441 +#, python-format +msgid "Error creating server: %s" +msgstr "" + +#: openstackclient/compute/v2/server.py:443 +msgid "" +"\n" +"Error creating server" +msgstr "" + +#: openstackclient/compute/v2/server.py:465 +msgid "Name of new image (default is server name)" +msgstr "" + +#: openstackclient/compute/v2/server.py:470 +msgid "Wait for image create to complete" +msgstr "" + +#: openstackclient/compute/v2/server.py:500 +#, python-format +msgid "Error creating server snapshot: %s" +msgstr "" + +#: openstackclient/compute/v2/server.py:502 +msgid "" +"\n" +"Error creating server snapshot" +msgstr "" + +#: openstackclient/compute/v2/server.py:524 +msgid "Server(s) to delete (name or ID)" +msgstr "" + +#: openstackclient/compute/v2/server.py:548 +msgid "Only return instances that match the reservation" +msgstr "" + +#: openstackclient/compute/v2/server.py:553 +msgid "Regular expression to match IP addresses" +msgstr "" + +#: openstackclient/compute/v2/server.py:558 +msgid "Regular expression to match IPv6 addresses" +msgstr "" + +#: openstackclient/compute/v2/server.py:563 +msgid "Regular expression to match names" +msgstr "" + +#: openstackclient/compute/v2/server.py:568 +msgid "Regular expression to match instance name (admin only)" +msgstr "" + +#: openstackclient/compute/v2/server.py:574 +msgid "Search by server status" +msgstr "" + +#: openstackclient/compute/v2/server.py:579 +msgid "Search by flavor" +msgstr "" + +#: openstackclient/compute/v2/server.py:584 +msgid "Search by image" +msgstr "" + +#: openstackclient/compute/v2/server.py:589 +msgid "Search by hostname" +msgstr "" + +#: openstackclient/compute/v2/server.py:595 +msgid "Include all projects (admin only)" +msgstr "" + +#: openstackclient/compute/v2/server.py:710 +msgid "Target hostname" +msgstr "" + +#: openstackclient/compute/v2/server.py:718 +msgid "Perform a shared live migration (default)" +msgstr "" + +#: openstackclient/compute/v2/server.py:724 +msgid "Perform a block live migration" +msgstr "" + +#: openstackclient/compute/v2/server.py:731 +msgid "Allow disk over-commit on the destination host" +msgstr "" + +#: openstackclient/compute/v2/server.py:738 +msgid "Do not over-commit disk on the destination host (default)" +msgstr "" + +#: openstackclient/compute/v2/server.py:744 +#: openstackclient/compute/v2/server.py:1045 +msgid "Wait for resize to complete" +msgstr "" + +#: openstackclient/compute/v2/server.py:772 +#: openstackclient/compute/v2/server.py:1070 +msgid "Complete\n" +msgstr "" + +#: openstackclient/compute/v2/server.py:774 +msgid "" +"\n" +"Error migrating server" +msgstr "" + +#: openstackclient/compute/v2/server.py:821 +msgid "Perform a hard reboot" +msgstr "" + +#: openstackclient/compute/v2/server.py:829 +msgid "Perform a soft reboot" +msgstr "" + +#: openstackclient/compute/v2/server.py:834 +msgid "Wait for reboot to complete" +msgstr "" + +#: openstackclient/compute/v2/server.py:851 +msgid "" +"\n" +"Reboot complete\n" +msgstr "" + +#: openstackclient/compute/v2/server.py:853 +msgid "" +"\n" +"Error rebooting server\n" +msgstr "" + +#: openstackclient/compute/v2/server.py:873 +msgid "Recreate server from this image" +msgstr "" + +#: openstackclient/compute/v2/server.py:883 +msgid "Wait for rebuild to complete" +msgstr "" + +#: openstackclient/compute/v2/server.py:904 +msgid "" +"\n" +"Complete\n" +msgstr "" + +#: openstackclient/compute/v2/server.py:906 +msgid "" +"\n" +"Error rebuilding server" +msgstr "" + +#: openstackclient/compute/v2/server.py:923 +msgid "Name or ID of server to use" +msgstr "" + +#: openstackclient/compute/v2/server.py:928 +msgid "Name or ID of security group to remove from server" +msgstr "" + +#: openstackclient/compute/v2/server.py:964 +msgid "Volume to remove (name or ID)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1030 +msgid "Resize server to specified flavor" +msgstr "" + +#: openstackclient/compute/v2/server.py:1035 +msgid "Verify server resize is complete" +msgstr "" + +#: openstackclient/compute/v2/server.py:1040 +msgid "Restore server state before resize" +msgstr "" + +#: openstackclient/compute/v2/server.py:1072 +msgid "" +"\n" +"Error resizing server" +msgstr "" + +#: openstackclient/compute/v2/server.py:1124 +msgid "Set new root password (interactive only)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1130 +msgid "" +"Property to add/change for this server (repeat option to set multiple " +"properties)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1154 +msgid "New password: " +msgstr "" + +#: openstackclient/compute/v2/server.py:1155 +msgid "Retype new password: " +msgstr "" + +#: openstackclient/compute/v2/server.py:1159 +msgid "Passwords do not match, password unchanged" +msgstr "" + +#: openstackclient/compute/v2/server.py:1179 +msgid "Display server diagnostics information" +msgstr "" + +#: openstackclient/compute/v2/server.py:1192 +msgid "Error retrieving diagnostics data" +msgstr "" + +#: openstackclient/compute/v2/server.py:1215 +msgid "Login name (ssh -l option)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1226 +msgid "Destination port (ssh -p option)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1238 +msgid "Private key file (ssh -i option)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1249 +msgid "Options in ssh_config(5) format (ssh -o option)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1263 +msgid "Use only IPv4 addresses" +msgstr "" + +#: openstackclient/compute/v2/server.py:1270 +msgid "Use only IPv6 addresses" +msgstr "" + +#: openstackclient/compute/v2/server.py:1279 +msgid "Use public IP address" +msgstr "" + +#: openstackclient/compute/v2/server.py:1287 +msgid "Use private IP address" +msgstr "" + +#: openstackclient/compute/v2/server.py:1294 +msgid "Use other IP address (public, private, etc)" +msgstr "" + +#: openstackclient/compute/v2/server.py:1471 +msgid "Property key to remove from server (repeat to unset multiple values)" +msgstr "" + +#: openstackclient/identity/v2_0/catalog.py:71 +msgid "Service to display (type or name)" +msgstr "" + +#: openstackclient/identity/v2_0/ec2creds.py:40 +msgid "Specify an alternate project (default: current authenticated project)" +msgstr "" + +#: openstackclient/identity/v2_0/ec2creds.py:46 +msgid "Specify an alternate user (default: current authenticated user)" +msgstr "" + +#: openstackclient/identity/v2_0/ec2creds.py:95 +#: openstackclient/identity/v2_0/ec2creds.py:168 +msgid "Credentials access key" +msgstr "" + +#: openstackclient/identity/v2_0/ec2creds.py:100 +#: openstackclient/identity/v2_0/ec2creds.py:130 +#: openstackclient/identity/v2_0/ec2creds.py:173 +msgid "Specify a user" +msgstr "" + +#: openstackclient/identity/v2_0/endpoint.py:40 +msgid "New endpoint service (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/endpoint.py:46 +msgid "New endpoint public URL (required)" +msgstr "" + +#: openstackclient/identity/v2_0/endpoint.py:51 +msgid "New endpoint admin URL" +msgstr "" + +#: openstackclient/identity/v2_0/endpoint.py:56 +msgid "New endpoint internal URL" +msgstr "" + +#: openstackclient/identity/v2_0/endpoint.py:61 +msgid "New endpoint region ID" +msgstr "" + +#: openstackclient/identity/v2_0/endpoint.py:93 +msgid "Endpoint ID to delete" +msgstr "" + +#: openstackclient/identity/v2_0/endpoint.py:149 +msgid "Endpoint ID to display" +msgstr "" + +#: openstackclient/identity/v2_0/project.py:41 +msgid "New project name" +msgstr "" + +#: openstackclient/identity/v2_0/project.py:46 +msgid "Project description" +msgstr "" + +#: openstackclient/identity/v2_0/project.py:52 +msgid "Enable project (default)" +msgstr "" + +#: openstackclient/identity/v2_0/project.py:57 +#: openstackclient/identity/v2_0/project.py:194 +msgid "Disable project" +msgstr "" + +#: openstackclient/identity/v2_0/project.py:63 +msgid "Add a property to <name> (repeat option to set multiple properties)" +msgstr "" + +#: openstackclient/identity/v2_0/project.py:69 +#: openstackclient/identity/v3/project.py:75 +msgid "Return existing project" +msgstr "" + +#: openstackclient/identity/v2_0/project.py:117 +msgid "Project(s) to delete (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/project.py:173 +msgid "Project to modify (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/project.py:178 +msgid "Set project name" +msgstr "" + +#: openstackclient/identity/v2_0/project.py:183 +msgid "Set project description" +msgstr "" + +#: openstackclient/identity/v2_0/project.py:189 +msgid "Enable project" +msgstr "" + +#: openstackclient/identity/v2_0/project.py:200 +msgid "Set a project property (repeat option to set multiple properties)" +msgstr "" + +#: openstackclient/identity/v2_0/project.py:253 +msgid "Project to display (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/role.py:41 +msgid "Role to add to <project>:<user> (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/role.py:47 +#: openstackclient/identity/v2_0/role.py:309 +msgid "Include <project> (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/role.py:53 +#: openstackclient/identity/v2_0/role.py:315 +msgid "Include <user> (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/role.py:87 +msgid "New role name" +msgstr "" + +#: openstackclient/identity/v2_0/role.py:92 +#: openstackclient/identity/v3/role.py:157 +msgid "Return existing role" +msgstr "" + +#: openstackclient/identity/v2_0/role.py:127 +msgid "Role(s) to delete (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/role.py:194 +#: openstackclient/identity/v2_0/role.py:257 +msgid "Project must be specified" +msgstr "" + +#: openstackclient/identity/v2_0/role.py:208 +#: openstackclient/identity/v2_0/role.py:263 +msgid "User must be specified" +msgstr "" + +#: openstackclient/identity/v2_0/role.py:236 +msgid "User to list (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/role.py:241 +msgid "Filter users by <project> (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/role.py:303 +msgid "Role to remove (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/role.py:344 +msgid "Role to display (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/service.py:42 +msgid "New service type (compute, image, identity, volume, etc)" +msgstr "" + +#: openstackclient/identity/v2_0/service.py:53 +msgid "New service name" +msgstr "" + +#: openstackclient/identity/v2_0/service.py:58 +msgid "New service description" +msgstr "" + +#: openstackclient/identity/v2_0/service.py:78 +msgid "" +"The argument --type is deprecated, use service create --name <service-" +"name> type instead." +msgstr "" + +#: openstackclient/identity/v2_0/service.py:105 +msgid "Service to delete (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/service.py:156 +msgid "Service to display (type, name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/service.py:162 +msgid "Show service catalog information" +msgstr "" + +#: openstackclient/identity/v2_0/service.py:180 +#, python-format +msgid "No service catalog with a type, name or ID of '%s' exists." +msgstr "" + +#: openstackclient/identity/v2_0/token.py:54 +msgid "Token to be deleted" +msgstr "" + #: openstackclient/identity/v2_0/user.py:40 -#: openstackclient/identity/v2_0/user.py:246 msgid "New user name" msgstr "" #: openstackclient/identity/v2_0/user.py:45 -#: openstackclient/identity/v2_0/user.py:251 -msgid "New user password" +msgid "Default project (name or ID)" msgstr "" -#: openstackclient/identity/v2_0/user.py:51 -#: openstackclient/identity/v2_0/user.py:257 -msgid "Prompt interactively for password" +#: openstackclient/identity/v2_0/user.py:50 +#: openstackclient/identity/v2_0/user.py:273 +msgid "Set user password" msgstr "" #: openstackclient/identity/v2_0/user.py:56 -#: openstackclient/identity/v2_0/user.py:262 -msgid "New user email address" +#: openstackclient/identity/v2_0/user.py:279 +msgid "Prompt interactively for password" msgstr "" #: openstackclient/identity/v2_0/user.py:61 -msgid "Set default project (name or ID)" +#: openstackclient/identity/v2_0/user.py:284 +msgid "Set user email address" msgstr "" #: openstackclient/identity/v2_0/user.py:67 -#: openstackclient/identity/v2_0/user.py:273 +#: openstackclient/identity/v2_0/user.py:290 msgid "Enable user (default)" msgstr "" #: openstackclient/identity/v2_0/user.py:72 -#: openstackclient/identity/v2_0/user.py:278 +#: openstackclient/identity/v2_0/user.py:295 msgid "Disable user" msgstr "" -#: openstackclient/identity/v2_0/user.py:124 -msgid "User to delete (name or ID)" +#: openstackclient/identity/v2_0/user.py:77 +#: openstackclient/identity/v3/user.py:89 +msgid "Return existing user" msgstr "" -#: openstackclient/identity/v2_0/user.py:151 -msgid "Filter users by project (name or ID)" +#: openstackclient/identity/v2_0/user.py:141 +msgid "User(s) to delete (name or ID)" msgstr "" -#: openstackclient/identity/v2_0/user.py:157 -msgid "List additional fields in output" +#: openstackclient/identity/v2_0/user.py:168 +msgid "Filter users by project (name or ID)" msgstr "" -#: openstackclient/identity/v2_0/user.py:241 +#: openstackclient/identity/v2_0/user.py:258 msgid "User to change (name or ID)" msgstr "" -#: openstackclient/identity/v2_0/user.py:267 -msgid "New default project (name or ID)" +#: openstackclient/identity/v2_0/user.py:263 +msgid "Set user name" msgstr "" -#: openstackclient/identity/v2_0/user.py:344 +#: openstackclient/identity/v2_0/user.py:268 +msgid "Set default project (name or ID)" +msgstr "" + +#: openstackclient/identity/v2_0/user.py:361 msgid "User to display (name or ID)" msgstr "" +#: openstackclient/identity/v3/domain.py:62 +msgid "Return existing domain" +msgstr "" + +#: openstackclient/identity/v3/group.py:133 +msgid "Return existing group" +msgstr "" + +#: openstackclient/identity/v3/region.py:39 +msgid "New region ID" +msgstr "" + +#: openstackclient/identity/v3/region.py:44 +msgid "Parent region ID" +msgstr "" + +#: openstackclient/identity/v3/region.py:49 +#: openstackclient/identity/v3/region.py:151 +msgid "New region description" +msgstr "" + +#: openstackclient/identity/v3/region.py:54 +#: openstackclient/identity/v3/region.py:156 +msgid "New region url" +msgstr "" + +#: openstackclient/identity/v3/region.py:86 +msgid "Region ID to delete" +msgstr "" + +#: openstackclient/identity/v3/region.py:108 +msgid "Filter by parent region ID" +msgstr "" + +#: openstackclient/identity/v3/region.py:141 +msgid "Region to modify" +msgstr "" + +#: openstackclient/identity/v3/region.py:146 +msgid "New parent region ID" +msgstr "" + +#: openstackclient/identity/v3/region.py:191 +msgid "Region to display" +msgstr "" + diff --git a/requirements.txt b/requirements.txt index 287935a..fb73445 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,10 +7,11 @@ six>=1.7.0 Babel>=1.3 cliff>=1.7.0 # Apache-2.0 cliff-tablib>=1.0 +oslo.config>=1.6.0 # Apache-2.0 oslo.i18n>=1.0.0 # Apache-2.0 oslo.utils>=1.0.0 # Apache-2.0 oslo.serialization>=1.0.0 # Apache-2.0 -python-glanceclient>=0.14.0 +python-glanceclient>=0.15.0 python-keystoneclient>=0.11.1 python-novaclient>=2.18.0 python-cinderclient>=1.1.0 @@ -29,6 +29,7 @@ console_scripts = keystoneclient.auth.plugin = token_endpoint = openstackclient.api.auth:TokenEndpoint + osc_password = openstackclient.api.auth:OSCGenericPassword openstack.cli = command_list = openstackclient.common.module:ListCommand @@ -49,6 +50,8 @@ 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 @@ -95,7 +98,7 @@ openstack.compute.v2 = keypair_list = openstackclient.compute.v2.keypair:ListKeypair keypair_show = openstackclient.compute.v2.keypair:ShowKeypair - project_usage_list = openstackclient.compute.v2.usage:ListUsage + project_usage_list = openstackclient.compute.v2.usage:ListProjectUsage security_group_create = openstackclient.compute.v2.security_group:CreateSecurityGroup security_group_delete = openstackclient.compute.v2.security_group:DeleteSecurityGroup @@ -131,6 +134,9 @@ openstack.compute.v2 = server_unrescue = openstackclient.compute.v2.server:UnrescueServer server_unset = openstackclient.compute.v2.server:UnsetServer + usage_list = openstackclient.compute.v2.usage:ListUsage + usage_show = openstackclient.compute.v2.usage:ShowUsage + openstack.identity.v2 = catalog_list = openstackclient.identity.v2_0.catalog:ListCatalog catalog_show = openstackclient.identity.v2_0.catalog:ShowCatalog @@ -321,6 +327,7 @@ openstack.volume.v1 = snapshot_list = openstackclient.volume.v1.snapshot:ListSnapshot snapshot_set = openstackclient.volume.v1.snapshot:SetSnapshot snapshot_show = openstackclient.volume.v1.snapshot:ShowSnapshot + snapshot_unset = openstackclient.volume.v1.snapshot:UnsetSnapshot volume_create = openstackclient.volume.v1.volume:CreateVolume volume_delete = openstackclient.volume.v1.volume:DeleteVolume diff --git a/test-requirements.txt b/test-requirements.txt index ac3e715..e897e60 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,7 +1,7 @@ # 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. -hacking>=0.9.1,<0.10 +hacking>=0.10.0,<0.11 coverage>=3.6 discover |
