summaryrefslogtreecommitdiff
diff options
authorUbuntu Git Importer <usd-importer-do-not-mail@canonical.com>2020-07-02 17:11:19 +0000
committerUbuntu Git Importer <usd-importer-do-not-mail@canonical.com>2020-07-02 17:11:19 +0000
commit9c972f002555f486463f0411646980a59ca8b68a (patch)
tree765ba21333f33d92545a4f1a023bfcf6f9dde430
parent04b346535fea2f2b946425a89b21463d3583b0ab (diff)
New upstream version 2.6.0upstream/ubuntu/2.6.0.xz
-rw-r--r--doc/source/command-beta.rst12
-rw-r--r--doc/source/command-objects/address-scope.rst6
-rw-r--r--doc/source/command-objects/compute-agent.rst6
-rw-r--r--doc/source/command-objects/compute-service.rst5
-rw-r--r--doc/source/command-objects/endpoint.rst6
-rw-r--r--doc/source/command-objects/flavor.rst22
-rw-r--r--doc/source/command-objects/image.rst27
-rw-r--r--doc/source/command-objects/ip-availability.rst (renamed from doc/source/specs/ip-availability.rst)7
-rw-r--r--doc/source/command-objects/keypair.rst4
-rw-r--r--doc/source/command-objects/network-segment.rst54
-rw-r--r--doc/source/command-objects/server-backup.rst44
-rw-r--r--doc/source/command-objects/server-group.rst2
-rw-r--r--doc/source/command-objects/server.rst5
-rw-r--r--doc/source/command-objects/volume-transfer-request.rst21
-rw-r--r--doc/source/command-objects/volume-type.rst2
-rw-r--r--doc/source/commands.rst4
-rw-r--r--doc/source/index.rst2
-rw-r--r--doc/source/man/openstack.rst23
-rw-r--r--functional/tests/compute/v2/test_server.py8
-rw-r--r--functional/tests/image/v2/test_image.py9
-rw-r--r--functional/tests/network/v2/test_ip_availability.py53
-rw-r--r--functional/tests/network/v2/test_network_segment.py60
-rw-r--r--openstackclient/common/command.py10
-rw-r--r--openstackclient/common/quota.py2
-rw-r--r--openstackclient/compute/client.py18
-rw-r--r--openstackclient/compute/v2/agent.py22
-rw-r--r--openstackclient/compute/v2/flavor.py104
-rw-r--r--openstackclient/compute/v2/keypair.py4
-rw-r--r--openstackclient/compute/v2/server.py37
-rw-r--r--openstackclient/compute/v2/server_backup.py134
-rw-r--r--openstackclient/compute/v2/server_group.py12
-rw-r--r--openstackclient/compute/v2/service.py38
-rw-r--r--openstackclient/identity/v2_0/catalog.py2
-rw-r--r--openstackclient/identity/v2_0/endpoint.py8
-rw-r--r--openstackclient/identity/v2_0/project.py9
-rw-r--r--openstackclient/identity/v2_0/role.py6
-rw-r--r--openstackclient/identity/v2_0/user.py5
-rw-r--r--openstackclient/identity/v3/catalog.py2
-rw-r--r--openstackclient/identity/v3/consumer.py13
-rw-r--r--openstackclient/identity/v3/credential.py25
-rw-r--r--openstackclient/identity/v3/domain.py26
-rw-r--r--openstackclient/identity/v3/ec2creds.py12
-rw-r--r--openstackclient/identity/v3/endpoint.py42
-rw-r--r--openstackclient/identity/v3/federation_protocol.py46
-rw-r--r--openstackclient/identity/v3/group.py90
-rw-r--r--openstackclient/identity/v3/identity_provider.py39
-rw-r--r--openstackclient/identity/v3/mapping.py21
-rw-r--r--openstackclient/identity/v3/policy.py21
-rw-r--r--openstackclient/identity/v3/project.py52
-rw-r--r--openstackclient/identity/v3/role.py51
-rw-r--r--openstackclient/identity/v3/role_assignment.py15
-rw-r--r--openstackclient/identity/v3/service.py34
-rw-r--r--openstackclient/identity/v3/service_provider.py38
-rw-r--r--openstackclient/identity/v3/token.py35
-rw-r--r--openstackclient/identity/v3/trust.py27
-rw-r--r--openstackclient/identity/v3/unscoped_saml.py9
-rw-r--r--openstackclient/identity/v3/user.py65
-rw-r--r--openstackclient/image/v2/image.py89
-rw-r--r--openstackclient/locale/de/LC_MESSAGES/openstackclient.po117
-rw-r--r--openstackclient/locale/openstackclient.pot1410
-rw-r--r--openstackclient/locale/zh_TW/LC_MESSAGES/openstackclient.po63
-rw-r--r--openstackclient/network/client.py7
-rw-r--r--openstackclient/network/common.py17
-rw-r--r--openstackclient/network/v2/address_scope.py24
-rw-r--r--openstackclient/network/v2/ip_availability.py109
-rw-r--r--openstackclient/network/v2/network_segment.py115
-rw-r--r--openstackclient/network/v2/port.py17
-rw-r--r--openstackclient/releasenotes/notes/bug-1543222-6f8579344ff5c958.yaml6
-rw-r--r--openstackclient/shell.py2
-rw-r--r--openstackclient/tests/common/test_command.py15
-rw-r--r--openstackclient/tests/compute/v2/fakes.py55
-rw-r--r--openstackclient/tests/compute/v2/test_agent.py254
-rw-r--r--openstackclient/tests/compute/v2/test_flavor.py185
-rw-r--r--openstackclient/tests/compute/v2/test_server.py148
-rw-r--r--openstackclient/tests/compute/v2/test_server_backup.py270
-rw-r--r--openstackclient/tests/compute/v2/test_service.py57
-rw-r--r--openstackclient/tests/fakes.py8
-rw-r--r--openstackclient/tests/image/v2/fakes.py2
-rw-r--r--openstackclient/tests/image/v2/test_image.py93
-rw-r--r--openstackclient/tests/network/v2/fakes.py115
-rw-r--r--openstackclient/tests/network/v2/test_address_scope.py70
-rw-r--r--openstackclient/tests/network/v2/test_ip_availability.py180
-rw-r--r--openstackclient/tests/network/v2/test_network_segment.py199
-rw-r--r--openstackclient/tests/network/v2/test_port.py74
-rw-r--r--openstackclient/tests/utils.py1
-rw-r--r--openstackclient/tests/volume/v1/fakes.py55
-rw-r--r--openstackclient/tests/volume/v1/test_transfer_request.py114
-rw-r--r--openstackclient/tests/volume/v1/test_volume.py3
-rw-r--r--openstackclient/tests/volume/v2/fakes.py130
-rw-r--r--openstackclient/tests/volume/v2/test_qos_specs.py336
-rw-r--r--openstackclient/tests/volume/v2/test_transfer_request.py114
-rw-r--r--openstackclient/tests/volume/v2/test_type.py6
-rw-r--r--openstackclient/tests/volume/v2/test_volume.py48
-rw-r--r--openstackclient/volume/v1/qos_specs.py4
-rw-r--r--openstackclient/volume/v1/snapshot.py6
-rw-r--r--openstackclient/volume/v1/volume.py5
-rw-r--r--openstackclient/volume/v1/volume_transfer_request.py51
-rw-r--r--openstackclient/volume/v1/volume_type.py2
-rw-r--r--openstackclient/volume/v2/qos_specs.py8
-rw-r--r--openstackclient/volume/v2/snapshot.py9
-rw-r--r--openstackclient/volume/v2/volume.py4
-rw-r--r--openstackclient/volume/v2/volume_transfer_request.py51
-rw-r--r--openstackclient/volume/v2/volume_type.py27
-rw-r--r--releasenotes/notes/add-server-backup-e63feaebb6140f83.yaml3
-rw-r--r--releasenotes/notes/address-scope-delete-multi-31c3af73feb31265.yaml5
-rw-r--r--releasenotes/notes/bp-routed-networks-3eea4978c93aa126.yaml6
-rw-r--r--releasenotes/notes/bug-1554886-8e5249a655e7e7b6.yaml5
-rw-r--r--releasenotes/notes/bug-1575461-4d7d90e792132064.yaml10
-rw-r--r--releasenotes/notes/bug-1582968-4d44912a033b242c.yaml4
-rw-r--r--releasenotes/notes/bug-1588384-eb6976fcfb90cb4c.yaml7
-rw-r--r--releasenotes/notes/compute-agent-deff48988e81b30e.yaml5
-rw-r--r--releasenotes/notes/ip-availability-ca1cf440f6c70afc.yaml5
-rw-r--r--releasenotes/notes/server-set-state-214b12ec2161de4d.yaml6
-rw-r--r--releasenotes/notes/service-set-option-61772a8940ad0778.yaml6
-rw-r--r--releasenotes/source/conf.py20
-rw-r--r--releasenotes/source/index.rst1
-rw-r--r--releasenotes/source/mitaka.rst6
-rw-r--r--releasenotes/source/pre_20_releases.rst (renamed from doc/source/releases.rst)25
-rw-r--r--requirements.txt6
-rw-r--r--setup.cfg13
-rw-r--r--test-requirements.txt6
121 files changed, 3914 insertions, 2356 deletions
diff --git a/doc/source/command-beta.rst b/doc/source/command-beta.rst
index 53a4420..f0a4f85 100644
--- a/doc/source/command-beta.rst
+++ b/doc/source/command-beta.rst
@@ -33,7 +33,7 @@ example list
List examples
.. caution:: This is a beta command and subject to change.
- Use global option ``--enable-beta-commands`` to
+ Use global option ``--os-beta-command`` to
enable this command.
.. program:: example list
@@ -52,7 +52,7 @@ The command help must label the command as a beta.
"""Display example details
(Caution: This is a beta command and subject to change.
- Use global option --enable-beta-commands to enable
+ Use global option --os-beta-command to enable
this command)
"""
@@ -60,13 +60,9 @@ Implementation
--------------
The command must raise a ``CommandError`` exception if beta commands
-are not enabled via ``--enable-beta-commands`` global option.
+are not enabled via ``--os-beta-command`` global option.
.. code-block:: python
def take_action(self, parsed_args):
- if not self.app.options.enable_beta_commands:
- msg = _('Caution: This is a beta command and subject to '
- 'change. Use global option --enable-beta-commands '
- 'to enable this command.')
- raise exceptions.CommandError(msg)
+ self.validate_os_beta_command_enabled()
diff --git a/doc/source/command-objects/address-scope.rst b/doc/source/command-objects/address-scope.rst
index a2ab566..7481ed5 100644
--- a/doc/source/command-objects/address-scope.rst
+++ b/doc/source/command-objects/address-scope.rst
@@ -50,18 +50,18 @@ Create new address scope
address scope delete
--------------------
-Delete an address scope
+Delete address scope(s)
.. program:: address scope delete
.. code:: bash
os address scope delete
- <address-scope>
+ <address-scope> [<address-scope> ...]
.. _address_scope_delete-address-scope:
.. describe:: <address-scope>
- Address scope to delete (name or ID)
+ Address scope(s) to delete (name or ID)
address scope list
------------------
diff --git a/doc/source/command-objects/compute-agent.rst b/doc/source/command-objects/compute-agent.rst
index 395ee4f..b00a981 100644
--- a/doc/source/command-objects/compute-agent.rst
+++ b/doc/source/command-objects/compute-agent.rst
@@ -44,17 +44,17 @@ Create compute agent
compute agent delete
--------------------
-Delete compute agent command
+Delete compute agent(s)
.. program:: compute agent delete
.. code:: bash
- os compute agent delete <id>
+ os compute agent delete <id> [<id> ...]
.. _compute_agent-delete:
.. describe:: <id>
- ID of agent to delete
+ ID of agent(s) to delete
compute agent list
------------------
diff --git a/doc/source/command-objects/compute-service.rst b/doc/source/command-objects/compute-service.rst
index bda64c8..71225bc 100644
--- a/doc/source/command-objects/compute-service.rst
+++ b/doc/source/command-objects/compute-service.rst
@@ -63,7 +63,7 @@ Set service command
.. _compute-service-set:
.. option:: --enable
- Enable service (default)
+ Enable service
.. option:: --disable
@@ -71,8 +71,7 @@ Set service command
.. option:: --disable-reason <reason>
- Reason for disabling the service (in quotes). Note that when the service
- is enabled, this option is ignored.
+ Reason for disabling the service (in quotes). Should be used with --disable option.
.. describe:: <host>
diff --git a/doc/source/command-objects/endpoint.rst b/doc/source/command-objects/endpoint.rst
index 074f20a..9872a58 100644
--- a/doc/source/command-objects/endpoint.rst
+++ b/doc/source/command-objects/endpoint.rst
@@ -188,9 +188,9 @@ Display endpoint details
.. code:: bash
os endpoint show
- <endpoint-id>
+ <endpoint>
.. _endpoint_show-endpoint:
-.. describe:: <endpoint-id>
+.. describe:: <endpoint>
- Endpoint ID to display
+ Endpoint to display (endpoint ID, service ID, service name, service type)
diff --git a/doc/source/command-objects/flavor.rst b/doc/source/command-objects/flavor.rst
index 322943d..a30bede 100644
--- a/doc/source/command-objects/flavor.rst
+++ b/doc/source/command-objects/flavor.rst
@@ -128,12 +128,23 @@ Set flavor properties
os flavor set
[--property <key=value> [...] ]
+ [--project <project>]
+ [--project-domain <project-domain>]
<flavor>
.. option:: --property <key=value>
Property to add or modify for this flavor (repeat option to set multiple properties)
+.. option:: --project <project>
+
+ Set flavor access to project (name or ID) (admin only)
+
+.. option:: --project-domain <project-domain>
+
+ Domain the project belongs to (name or ID).
+ This can be used in case collisions between project names exist.
+
.. describe:: <flavor>
Flavor to modify (name or ID)
@@ -164,12 +175,23 @@ Unset flavor properties
os flavor unset
[--property <key> [...] ]
+ [--project <project>]
+ [--project-domain <project-domain>]
<flavor>
.. option:: --property <key>
Property to remove from flavor (repeat option to remove multiple properties)
+.. option:: --project <project>
+
+ Remove flavor access from project (name or ID) (admin only)
+
+.. option:: --project-domain <project-domain>
+
+ Domain the project belongs to (name or ID).
+ This can be used in case collisions between project names exist.
+
.. describe:: <flavor>
Flavor to modify (name or ID)
diff --git a/doc/source/command-objects/image.rst b/doc/source/command-objects/image.rst
index 942c03d..d6451af 100644
--- a/doc/source/command-objects/image.rst
+++ b/doc/source/command-objects/image.rst
@@ -499,3 +499,30 @@ Display image details
.. describe:: <image>
Image to display (name or ID)
+
+image unset
+-----------
+
+*Only supported for Image v2*
+
+Unset image tags or properties
+
+.. program:: image unset
+.. code:: bash
+
+ os image set
+ [--tag <tag>]
+ [--property <property>]
+ <image>
+
+.. option:: --tag <tag>
+
+ Unset a tag on this image (repeat option to unset multiple tags)
+
+.. option:: --property <property>
+
+ Unset a property on this image (repeat option to unset multiple properties)
+
+.. describe:: <image>
+
+ Image to modify (name or ID)
diff --git a/doc/source/specs/ip-availability.rst b/doc/source/command-objects/ip-availability.rst
index cf0c71f..55b7842 100644
--- a/doc/source/specs/ip-availability.rst
+++ b/doc/source/command-objects/ip-availability.rst
@@ -24,12 +24,12 @@ number of allocated IP addresses from that pool.
.. option:: --ip-version {4,6}
- List IP availability for specific version
+ List IP availability of given IP version networks
(Default is 4)
.. option:: --project <project>
- List IP availability for specific project
+ List IP availability of given project
(name or ID)
ip availability show
@@ -57,5 +57,4 @@ subnet within the network as well.
.. _ip_availability_show-network
.. describe:: <network>
- Show network IP availability for specific
- network (name or ID)
+ Show IP availability for a specific network (name or ID)
diff --git a/doc/source/command-objects/keypair.rst b/doc/source/command-objects/keypair.rst
index e49acac..6638b8c 100644
--- a/doc/source/command-objects/keypair.rst
+++ b/doc/source/command-objects/keypair.rst
@@ -40,7 +40,7 @@ Delete public key
.. describe:: <key>
- Public key to delete
+ Public key to delete (name only)
keypair list
------------
@@ -66,7 +66,7 @@ Display public key details
.. option:: --public-key
- Show only bare public key
+ Show only bare public key (name only)
.. describe:: <key>
diff --git a/doc/source/command-objects/network-segment.rst b/doc/source/command-objects/network-segment.rst
new file mode 100644
index 0000000..56a11e1
--- /dev/null
+++ b/doc/source/command-objects/network-segment.rst
@@ -0,0 +1,54 @@
+===============
+network segment
+===============
+
+A **network segment** is an isolated Layer 2 segment within a network.
+A network may contain multiple network segments. Depending on the
+network configuration, Layer 2 connectivity between network segments
+within a network may not be guaranteed.
+
+Network v2
+
+network segment list
+--------------------
+
+List network segments
+
+.. caution:: This is a beta command and subject to change.
+ Use global option ``--os-beta-command`` to
+ enable this command.
+
+.. program:: network segment list
+.. code:: bash
+
+ os network segment list
+ [--long]
+ [--network <network>]
+
+.. option:: --long
+
+ List additional fields in output
+
+.. option:: --network <network>
+
+ List network segments that belong to this network (name or ID)
+
+network segment show
+--------------------
+
+Display network segment details
+
+.. caution:: This is a beta command and subject to change.
+ Use global option ``--os-beta-command`` to
+ enable this command.
+
+.. program:: network segment show
+.. code:: bash
+
+ os network segment show
+ <network-segment>
+
+.. _network_segment_show-segment:
+.. describe:: <network-segment>
+
+ Network segment to display (ID only)
diff --git a/doc/source/command-objects/server-backup.rst b/doc/source/command-objects/server-backup.rst
new file mode 100644
index 0000000..23e17d5
--- /dev/null
+++ b/doc/source/command-objects/server-backup.rst
@@ -0,0 +1,44 @@
+=============
+server backup
+=============
+
+A server backup is a disk image created in the Image store from a running server
+instance. The backup command manages the number of archival copies to retain.
+
+Compute v2
+
+server backup create
+--------------------
+
+Create a server backup image
+
+.. program:: server create
+.. code:: bash
+
+ os server backup create
+ [--name <image-name>]
+ [--type <backup-type>]
+ [--rotate <count>]
+ [--wait]
+ <server>
+
+.. option:: --name <image-name>
+
+ Name of the backup image (default: server name)
+
+.. option:: --type <backup-type>
+
+ Used to populate the ``backup_type`` property of the backup
+ image (default: empty)
+
+.. option:: --rotate <count>
+
+ Number of backup images to keep (default: 1)
+
+.. option:: --wait
+
+ Wait for operation to complete
+
+.. describe:: <server>
+
+ Server to back up (name or ID)
diff --git a/doc/source/command-objects/server-group.rst b/doc/source/command-objects/server-group.rst
index 55d789c..414f49b 100644
--- a/doc/source/command-objects/server-group.rst
+++ b/doc/source/command-objects/server-group.rst
@@ -31,7 +31,7 @@ Create a new server group
server group delete
-------------------
-Delete an existing server group
+Delete existing server group(s)
.. program:: server group delete
.. code-block:: bash
diff --git a/doc/source/command-objects/server.rst b/doc/source/command-objects/server.rst
index bf97298..f11355b 100644
--- a/doc/source/command-objects/server.rst
+++ b/doc/source/command-objects/server.rst
@@ -559,6 +559,7 @@ Set server properties
--property <key=value>
[--property <key=value>] ...
--root-password
+ --state <state>
<server>
.. option:: --name <new-name>
@@ -574,6 +575,10 @@ Set server properties
Property to add/change for this server
(repeat option to set multiple properties)
+.. option:: --state <state>
+
+ New server state (valid value: active, error)
+
.. describe:: <server>
Server (name or ID)
diff --git a/doc/source/command-objects/volume-transfer-request.rst b/doc/source/command-objects/volume-transfer-request.rst
new file mode 100644
index 0000000..79d84f7
--- /dev/null
+++ b/doc/source/command-objects/volume-transfer-request.rst
@@ -0,0 +1,21 @@
+=======================
+volume transfer request
+=======================
+
+Block Storage v1, v2
+
+volume transfer request list
+----------------------------
+
+Lists all volume transfer requests.
+
+.. program:: volume transfer request list
+.. code:: bash
+
+ os volume transfer request list
+ --all-projects
+
+.. option:: --all-projects
+
+ Shows detail for all projects. Admin only.
+ (defaults to False) \ No newline at end of file
diff --git a/doc/source/command-objects/volume-type.rst b/doc/source/command-objects/volume-type.rst
index b7aea63..50acf9f 100644
--- a/doc/source/command-objects/volume-type.rst
+++ b/doc/source/command-objects/volume-type.rst
@@ -150,7 +150,7 @@ Unset volume type properties
.. code:: bash
os volume type unset
- [--property <key>]
+ [--property <key> [...] ]
[--project <project>]
[--project-domain <project-domain>]
<volume-type>
diff --git a/doc/source/commands.rst b/doc/source/commands.rst
index 12542d1..9fb0555 100644
--- a/doc/source/commands.rst
+++ b/doc/source/commands.rst
@@ -96,6 +96,7 @@ referring to both Compute and Volume quotas.
* ``hypervisor stats``: (**Compute**) hypervisor statistics over all compute nodes
* ``identity provider``: (**Identity**) a source of users and authentication
* ``image``: (**Image**) a disk image
+* ``ip availability``: (**Network**) - details of IP usage of a network
* ``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
* ``ip floating pool``: (**Compute**, **Network**) - a pool of public IP addresses
@@ -104,6 +105,7 @@ referring to both Compute and Volume quotas.
* ``mapping``: (**Identity**) a definition to translate identity provider attributes to Identity concepts
* ``module``: (**Internal**) - installed Python modules in the OSC process
* ``network``: (**Compute**, **Network**) - a virtual network for connecting servers and other resources
+* ``network segment``: (**Network**) - a segment of a virtual network
* ``object``: (**Object Storage**) a single file in the Object Storage
* ``object store account``: (**Object Storage**) owns a group of Object Storage resources
* ``policy``: (**Identity**) determines authorization
@@ -118,6 +120,7 @@ referring to both Compute and Volume quotas.
* ``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 backup``: (**Compute**) backup server disk image by using snapshot method
* ``server dump``: (**Compute**) a dump file of a server created by features like kdump
* ``server group``: (**Compute**) a grouping of servers
* ``server image``: (**Compute**) saved server disk image
@@ -135,6 +138,7 @@ referring to both Compute and Volume quotas.
* ``volume qos``: (**Volume**) quality-of-service (QoS) specification for volumes
* ``volume type``: (**Volume**) deployment-specific types of volumes available
* ``volume service``: (**Volume**) services to manage block storage operations
+* ``volume transfer request``: (**Volume**) volume owner transfer request
Plugin Objects
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 0869344..5889553 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -37,7 +37,7 @@ Release Notes
.. toctree::
:maxdepth: 1
- releases
+ Release Notes <http://docs.openstack.org/releasenotes/python-openstackclient>
history
Developer Documentation
diff --git a/doc/source/man/openstack.rst b/doc/source/man/openstack.rst
index 8cd10a7..7af380a 100644
--- a/doc/source/man/openstack.rst
+++ b/doc/source/man/openstack.rst
@@ -82,7 +82,7 @@ OPTIONS
Project-level authentication scope (name or ID)
:option:`--os-project-domain-name` <auth-project-domain-name> | :option:`--os-project-domain-id` <auth-project-domain-id>
- Domain name or id containing project
+ Domain name or ID containing project
:option:`--os-username` <auth-username>
Authentication username
@@ -94,13 +94,10 @@ OPTIONS
Authenticated token or service token
:option:`--os-user-domain-name` <auth-user-domain-name> | :option:`--os-user-domain-id` <auth-user-domain-id>
- Domain name or id containing user
-
-:option:`--os-user-domain-name` <auth-user-domain-name> | :option:`--os-user-domain-id` <auth-user-domain-id>
Domain name or ID containing user
:option:`--os-trust-id` <trust-id>
- id of the trust to use as a trustee user
+ ID of the trust to use as a trustee user
:option:`--os-default-domain` <auth-domain>
Default domain ID (Default: 'default')
@@ -135,6 +132,9 @@ OPTIONS
This key should be the value of one of the HMAC keys defined in the
configuration files of OpenStack services to be traced.
+:option:`--os-beta-command`
+ Enable beta commands which are subject to change
+
:option:`--log-file` <LOGFILE>
Specify a file to log output. Disabled by default.
@@ -142,13 +142,10 @@ OPTIONS
Increase verbosity of output. Can be repeated.
:option:`-q, --quiet`
- suppress output except warnings and errors
+ Suppress output except warnings and errors
:option:`--debug`
- show tracebacks on errors and set verbosity to debug
-
-:option:`--enable-beta-commands`
- Enable beta commands which are subject to change
+ Show tracebacks on errors and set verbosity to debug
COMMANDS
========
@@ -350,7 +347,7 @@ The following environment variables can be set to alter the behaviour of :progra
Project-level authentication scope (name or ID)
:envvar:`OS_PROJECT_DOMAIN_NAME`
- Domain name or id containing project
+ Domain name or ID containing project
:envvar:`OS_USERNAME`
Authentication username
@@ -362,10 +359,10 @@ The following environment variables can be set to alter the behaviour of :progra
Authentication password
:envvar:`OS_USER_DOMAIN_NAME`
- Domain name or id containing user
+ Domain name or ID containing user
:envvar:`OS_TRUST_ID`
- id of the trust to use as a trustee user
+ ID of the trust to use as a trustee user
:envvar:`OS_DEFAULT_DOMAIN`
Default domain ID (Default: 'default')
diff --git a/functional/tests/compute/v2/test_server.py b/functional/tests/compute/v2/test_server.py
index 6cb82cb..96c1c1a 100644
--- a/functional/tests/compute/v2/test_server.py
+++ b/functional/tests/compute/v2/test_server.py
@@ -129,6 +129,8 @@ class ServerTests(test.TestCase):
1) Boot server in setUp
2) Set properties for server
3) Check server properties in server show output
+ 4) Unset properties for server
+ 5) Check server properties in server show output
"""
self.wait_for_status("ACTIVE")
# metadata
@@ -138,6 +140,12 @@ class ServerTests(test.TestCase):
raw_output = self.openstack('server show ' + self.NAME + opts)
self.assertEqual(self.NAME + "\na='b', c='d'\n", raw_output)
+ raw_output = self.openstack(
+ 'server unset --property a ' + self.NAME)
+ opts = self.get_show_opts(["name", "properties"])
+ raw_output = self.openstack('server show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\nc='d'\n", raw_output)
+
def test_server_suspend_resume(self):
"""Test server suspend and resume commands.
diff --git a/functional/tests/image/v2/test_image.py b/functional/tests/image/v2/test_image.py
index f0ebc11..6a33ad8 100644
--- a/functional/tests/image/v2/test_image.py
+++ b/functional/tests/image/v2/test_image.py
@@ -65,3 +65,12 @@ class ImageTests(test.TestCase):
self.openstack('image set --property a=b --property c=d ' + self.NAME)
raw_output = self.openstack('image show ' + self.NAME + opts)
self.assertEqual(self.NAME + "\na='b', c='d'\n", raw_output)
+
+ def test_image_unset(self):
+ opts = self.get_show_opts(["name", "tags", "properties"])
+ self.openstack('image set --tag 01 ' + self.NAME)
+ self.openstack('image unset --tag 01 ' + self.NAME)
+ # test_image_metadata has set image properties "a" and "c"
+ self.openstack('image unset --property a --property c ' + self.NAME)
+ raw_output = self.openstack('image show ' + self.NAME + opts)
+ self.assertEqual(self.NAME + "\n\n", raw_output)
diff --git a/functional/tests/network/v2/test_ip_availability.py b/functional/tests/network/v2/test_ip_availability.py
new file mode 100644
index 0000000..f1302d5
--- /dev/null
+++ b/functional/tests/network/v2/test_ip_availability.py
@@ -0,0 +1,53 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import uuid
+
+from functional.common import test
+
+
+class IPAvailabilityTests(test.TestCase):
+ """Functional tests for IP availability. """
+ NAME = uuid.uuid4().hex
+ NETWORK_NAME = uuid.uuid4().hex
+ FIELDS = ['network_name']
+
+ @classmethod
+ def setUpClass(cls):
+ # Create a network for the subnet.
+ cls.openstack('network create ' + cls.NETWORK_NAME)
+ opts = cls.get_show_opts(['name'])
+ raw_output = cls.openstack(
+ 'subnet create --network ' + cls.NETWORK_NAME +
+ ' --subnet-range 10.10.10.0/24 ' +
+ cls.NAME + opts
+ )
+ expected = cls.NAME + '\n'
+ cls.assertOutput(expected, raw_output)
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_subnet = cls.openstack('subnet delete ' + cls.NAME)
+ raw_network = cls.openstack('network delete ' + cls.NETWORK_NAME)
+ cls.assertOutput('', raw_subnet)
+ cls.assertOutput('', raw_network)
+
+ def test_ip_availability_list(self):
+ opts = ' -f csv -c "Network Name"'
+ raw_output = self.openstack('ip availability list' + opts)
+ self.assertIn(self.NETWORK_NAME, raw_output)
+
+ def test_ip_availability_show(self):
+ opts = self.get_show_opts(self.FIELDS)
+ raw_output = self.openstack(
+ 'ip availability show ' + self.NETWORK_NAME + opts)
+ self.assertEqual(self.NETWORK_NAME + "\n", raw_output)
diff --git a/functional/tests/network/v2/test_network_segment.py b/functional/tests/network/v2/test_network_segment.py
new file mode 100644
index 0000000..b5b5dcd
--- /dev/null
+++ b/functional/tests/network/v2/test_network_segment.py
@@ -0,0 +1,60 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import testtools
+import uuid
+
+from functional.common import test
+
+
+# NOTE(rtheis): Routed networks is still a WIP and not enabled by default.
+@testtools.skip("bp/routed-networks")
+class NetworkSegmentTests(test.TestCase):
+ """Functional tests for network segment. """
+ NETWORK_NAME = uuid.uuid4().hex
+ PHYSICAL_NETWORK_NAME = uuid.uuid4().hex
+ NETWORK_SEGMENT_ID = None
+ NETWORK_ID = None
+
+ @classmethod
+ def setUpClass(cls):
+ # Create a network for the segment.
+ opts = cls.get_show_opts(['id'])
+ raw_output = cls.openstack('network create ' + cls.NETWORK_NAME + opts)
+ cls.NETWORK_ID = raw_output.strip('\n')
+
+ # Get the segment for the network.
+ opts = cls.get_show_opts(['ID', 'Network'])
+ raw_output = cls.openstack('--os-beta-command '
+ 'network segment list '
+ ' --network ' + cls.NETWORK_NAME +
+ ' ' + opts)
+ raw_output_row = raw_output.split('\n')[0]
+ cls.NETWORK_SEGMENT_ID = raw_output_row.split(' ')[0]
+
+ @classmethod
+ def tearDownClass(cls):
+ raw_output = cls.openstack('network delete ' + cls.NETWORK_NAME)
+ cls.assertOutput('', raw_output)
+
+ def test_network_segment_list(self):
+ opts = self.get_list_opts(['ID'])
+ raw_output = self.openstack('--os-beta-command '
+ 'network segment list' + opts)
+ self.assertIn(self.NETWORK_SEGMENT_ID, raw_output)
+
+ def test_network_segment_show(self):
+ opts = self.get_show_opts(['network_id'])
+ raw_output = self.openstack('--os-beta-command '
+ 'network segment show ' +
+ self.NETWORK_SEGMENT_ID + opts)
+ self.assertEqual(self.NETWORK_ID + "\n", raw_output)
diff --git a/openstackclient/common/command.py b/openstackclient/common/command.py
index fee4559..144a0db 100644
--- a/openstackclient/common/command.py
+++ b/openstackclient/common/command.py
@@ -20,6 +20,9 @@ from cliff import lister
from cliff import show
import six
+from openstackclient.common import exceptions
+from openstackclient.i18n import _
+
class CommandMeta(abc.ABCMeta):
@@ -37,6 +40,13 @@ class Command(command.Command):
self.log.debug('run(%s)', parsed_args)
return super(Command, self).run(parsed_args)
+ def validate_os_beta_command_enabled(self):
+ if not self.app.options.os_beta_command:
+ msg = _('Caution: This is a beta command and subject to '
+ 'change. Use global option --os-beta-command '
+ 'to enable this command.')
+ raise exceptions.CommandError(msg)
+
class Lister(Command, lister.Lister):
pass
diff --git a/openstackclient/common/quota.py b/openstackclient/common/quota.py
index e177fbc..f85d550 100644
--- a/openstackclient/common/quota.py
+++ b/openstackclient/common/quota.py
@@ -142,7 +142,7 @@ class SetQuota(command.Command):
if (compute_kwargs == {} and volume_kwargs == {}
and network_kwargs == {}):
- sys.stderr.write("No quotas updated")
+ sys.stderr.write("No quotas updated\n")
return
if parsed_args.project:
diff --git a/openstackclient/compute/client.py b/openstackclient/compute/client.py
index 82f09ce..8e6eedc 100644
--- a/openstackclient/compute/client.py
+++ b/openstackclient/compute/client.py
@@ -17,6 +17,7 @@ import logging
from openstackclient.common import exceptions
from openstackclient.common import utils
+from openstackclient.i18n import _
LOG = logging.getLogger(__name__)
@@ -82,9 +83,9 @@ def build_option_parser(parser):
'--os-compute-api-version',
metavar='<compute-api-version>',
default=utils.env('OS_COMPUTE_API_VERSION'),
- help='Compute API version, default=' +
- DEFAULT_API_VERSION +
- ' (Env: OS_COMPUTE_API_VERSION)')
+ help=_("Compute API version, default=%s "
+ "(Env: OS_COMPUTE_API_VERSION)") % DEFAULT_API_VERSION
+ )
return parser
@@ -118,10 +119,9 @@ def check_api_version(check_version):
novaclient.API_MIN_VERSION,
novaclient.API_MAX_VERSION,
):
- raise exceptions.CommandError(
- "versions supported by client: %s - %s" % (
- novaclient.API_MIN_VERSION.get_string(),
- novaclient.API_MAX_VERSION.get_string(),
- ),
- )
+ msg = _("versions supported by client: %(min)s - %(max)s") % {
+ "min": novaclient.API_MIN_VERSION.get_string(),
+ "max": novaclient.API_MAX_VERSION.get_string(),
+ }
+ raise exceptions.CommandError(msg)
return True
diff --git a/openstackclient/compute/v2/agent.py b/openstackclient/compute/v2/agent.py
index e358399..064fe5a 100644
--- a/openstackclient/compute/v2/agent.py
+++ b/openstackclient/compute/v2/agent.py
@@ -18,6 +18,7 @@
import six
from openstackclient.common import command
+from openstackclient.common import exceptions
from openstackclient.common import utils
from openstackclient.i18n import _
@@ -75,20 +76,35 @@ class CreateAgent(command.ShowOne):
class DeleteAgent(command.Command):
- """Delete compute agent command"""
+ """Delete compute agent(s)"""
def get_parser(self, prog_name):
parser = super(DeleteAgent, self).get_parser(prog_name)
parser.add_argument(
"id",
metavar="<id>",
- help=_("ID of agent to delete")
+ nargs='+',
+ help=_("ID of agent(s) to delete")
)
return parser
def take_action(self, parsed_args):
compute_client = self.app.client_manager.compute
- compute_client.agents.delete(parsed_args.id)
+ result = 0
+ for id in parsed_args.id:
+ try:
+ compute_client.agents.delete(id)
+ except Exception as e:
+ result += 1
+ self.app.log.error(_("Failed to delete agent with "
+ "ID '%(id)s': %(e)s")
+ % {'id': id, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.id)
+ msg = (_("%(result)s of %(total)s agents failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListAgent(command.Lister):
diff --git a/openstackclient/compute/v2/flavor.py b/openstackclient/compute/v2/flavor.py
index 37ff831..87909a1 100644
--- a/openstackclient/compute/v2/flavor.py
+++ b/openstackclient/compute/v2/flavor.py
@@ -22,6 +22,7 @@ from openstackclient.common import exceptions
from openstackclient.common import parseractions
from openstackclient.common import utils
from openstackclient.i18n import _
+from openstackclient.identity import common as identity_common
def _find_flavor(compute_client, flavor):
@@ -246,6 +247,11 @@ class SetFlavor(command.Command):
def get_parser(self, prog_name):
parser = super(SetFlavor, self).get_parser(prog_name)
parser.add_argument(
+ "flavor",
+ metavar="<flavor>",
+ help=_("Flavor to modify (name or ID)")
+ )
+ parser.add_argument(
"--property",
metavar="<key=value>",
action=parseractions.KeyValueAction,
@@ -253,16 +259,54 @@ class SetFlavor(command.Command):
"(repeat option to set multiple properties)")
)
parser.add_argument(
- "flavor",
- metavar="<flavor>",
- help=_("Flavor to modify (name or ID)")
+ '--project',
+ metavar='<project>',
+ help=_('Set flavor access to project (name or ID) '
+ '(admin only)'),
)
+ identity_common.add_project_domain_option_to_parser(parser)
+
return parser
def take_action(self, parsed_args):
compute_client = self.app.client_manager.compute
+ identity_client = self.app.client_manager.identity
+
flavor = _find_flavor(compute_client, parsed_args.flavor)
- flavor.set_keys(parsed_args.property)
+
+ if not parsed_args.property and not parsed_args.project:
+ raise exceptions.CommandError(_("Nothing specified to be set."))
+
+ result = 0
+ if parsed_args.property:
+ try:
+ flavor.set_keys(parsed_args.property)
+ except Exception as e:
+ self.app.log.error(
+ _("Failed to set flavor property: %s") % str(e))
+ result += 1
+
+ if parsed_args.project:
+ try:
+ if flavor.is_public:
+ msg = _("Cannot set access for a public flavor")
+ raise exceptions.CommandError(msg)
+ else:
+ project_id = identity_common.find_project(
+ identity_client,
+ parsed_args.project,
+ parsed_args.project_domain,
+ ).id
+ compute_client.flavor_access.add_tenant_access(
+ flavor.id, project_id)
+ except Exception as e:
+ self.app.log.error(_("Failed to set flavor access to"
+ " project: %s") % str(e))
+ result += 1
+
+ if result > 0:
+ raise exceptions.CommandError(_("Command Failed: One or more of"
+ " the operations failed"))
class ShowFlavor(command.ShowOne):
@@ -294,21 +338,63 @@ class UnsetFlavor(command.Command):
def get_parser(self, prog_name):
parser = super(UnsetFlavor, self).get_parser(prog_name)
parser.add_argument(
+ "flavor",
+ metavar="<flavor>",
+ help=_("Flavor to modify (name or ID)")
+ )
+ parser.add_argument(
"--property",
metavar="<key>",
action='append',
- required=True,
help=_("Property to remove from flavor "
"(repeat option to unset multiple properties)")
)
parser.add_argument(
- "flavor",
- metavar="<flavor>",
- help=_("Flavor to modify (name or ID)")
+ '--project',
+ metavar='<project>',
+ help=_('Remove flavor access from project (name or ID) '
+ '(admin only)'),
)
+ identity_common.add_project_domain_option_to_parser(parser)
+
return parser
def take_action(self, parsed_args):
compute_client = self.app.client_manager.compute
+ identity_client = self.app.client_manager.identity
+
flavor = _find_flavor(compute_client, parsed_args.flavor)
- flavor.unset_keys(parsed_args.property)
+
+ if not parsed_args.property and not parsed_args.project:
+ raise exceptions.CommandError(_("Nothing specified to be unset."))
+
+ result = 0
+ if parsed_args.property:
+ try:
+ flavor.unset_keys(parsed_args.property)
+ except Exception as e:
+ self.app.log.error(
+ _("Failed to unset flavor property: %s") % str(e))
+ result += 1
+
+ if parsed_args.project:
+ try:
+ if flavor.is_public:
+ msg = _("Cannot remove access for a public flavor")
+ raise exceptions.CommandError(msg)
+ else:
+ project_id = identity_common.find_project(
+ identity_client,
+ parsed_args.project,
+ parsed_args.project_domain,
+ ).id
+ compute_client.flavor_access.remove_tenant_access(
+ flavor.id, project_id)
+ except Exception as e:
+ self.app.log.error(_("Failed to remove flavor access from"
+ " project: %s") % str(e))
+ result += 1
+
+ if result > 0:
+ raise exceptions.CommandError(_("Command Failed: One or more of"
+ " the operations failed"))
diff --git a/openstackclient/compute/v2/keypair.py b/openstackclient/compute/v2/keypair.py
index 8a58e8f..8af209f 100644
--- a/openstackclient/compute/v2/keypair.py
+++ b/openstackclient/compute/v2/keypair.py
@@ -84,7 +84,7 @@ class DeleteKeypair(command.Command):
parser.add_argument(
'name',
metavar='<key>',
- help=_("Public key to delete")
+ help=_("Public key to delete (name only)")
)
return parser
@@ -118,7 +118,7 @@ class ShowKeypair(command.ShowOne):
parser.add_argument(
'name',
metavar='<key>',
- help=_("Public key to display")
+ help=_("Public key to display (name only)")
)
parser.add_argument(
'--public-key',
diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py
index 781ccb1..5688b55 100644
--- a/openstackclient/compute/v2/server.py
+++ b/openstackclient/compute/v2/server.py
@@ -562,7 +562,7 @@ class CreateServer(command.ShowOne):
else:
self.log.error(_('Error creating server: %s'),
parsed_args.server_name)
- sys.stdout.write(_('\nError creating server'))
+ sys.stdout.write(_('Error creating server\n'))
raise SystemExit
details = _prep_server_detail(compute_client, server)
@@ -646,7 +646,7 @@ class CreateServerImage(command.ShowOne):
else:
self.log.error(_('Error creating snapshot of server: %s'),
parsed_args.server)
- sys.stdout.write(_('\nError creating server snapshot'))
+ sys.stdout.write(_('Error creating server snapshot\n'))
raise SystemExit
image = _prep_image_detail(image_client, image_id)
@@ -688,7 +688,7 @@ class DeleteServer(command.Command):
else:
self.log.error(_('Error deleting server: %s'),
server_obj.id)
- sys.stdout.write(_('\nError deleting server'))
+ sys.stdout.write(_('Error deleting server\n'))
raise SystemExit
@@ -1013,7 +1013,9 @@ class MigrateServer(command.Command):
):
sys.stdout.write(_('Complete\n'))
else:
- sys.stdout.write(_('\nError migrating server'))
+ self.log.error(_('Error migrating server: %s'),
+ server.id)
+ sys.stdout.write(_('Error migrating server\n'))
raise SystemExit
@@ -1085,9 +1087,11 @@ class RebootServer(command.Command):
server.id,
callback=_show_progress,
):
- sys.stdout.write(_('\nReboot complete\n'))
+ sys.stdout.write(_('Complete\n'))
else:
- sys.stdout.write(_('\nError rebooting server\n'))
+ self.log.error(_('Error rebooting server: %s'),
+ server.id)
+ sys.stdout.write(_('Error rebooting server\n'))
raise SystemExit
@@ -1136,9 +1140,11 @@ class RebuildServer(command.ShowOne):
server.id,
callback=_show_progress,
):
- sys.stdout.write(_('\nComplete\n'))
+ sys.stdout.write(_('Complete\n'))
else:
- sys.stdout.write(_('\nError rebuilding server'))
+ self.log.error(_('Error rebuilding server: %s'),
+ server.id)
+ sys.stdout.write(_('Error rebuilding server\n'))
raise SystemExit
details = _prep_server_detail(compute_client, server)
@@ -1290,7 +1296,9 @@ class ResizeServer(command.Command):
):
sys.stdout.write(_('Complete\n'))
else:
- sys.stdout.write(_('\nError resizing server'))
+ self.log.error(_('Error resizing server: %s'),
+ server.id)
+ sys.stdout.write(_('Error resizing server\n'))
raise SystemExit
elif parsed_args.confirm:
compute_client.servers.confirm_resize(server)
@@ -1370,6 +1378,12 @@ class SetServer(command.Command):
help=_('Property to add/change for this server '
'(repeat option to set multiple properties)'),
)
+ parser.add_argument(
+ '--state',
+ metavar='<state>',
+ choices=['active', 'error'],
+ help=_('New server state (valid value: active, error)'),
+ )
return parser
def take_action(self, parsed_args):
@@ -1389,6 +1403,9 @@ class SetServer(command.Command):
parsed_args.property,
)
+ if parsed_args.state:
+ server.reset_state(state=parsed_args.state)
+
if parsed_args.root_password:
p1 = getpass.getpass(_('New password: '))
p2 = getpass.getpass(_('Retype new password: '))
@@ -1447,7 +1464,7 @@ class ShowServer(command.ShowOne):
if parsed_args.diagnostics:
(resp, data) = server.diagnostics()
if not resp.status_code == 200:
- sys.stderr.write(_("Error retrieving diagnostics data"))
+ sys.stderr.write(_("Error retrieving diagnostics data\n"))
return ({}, {})
else:
data = _prep_server_detail(compute_client, server)
diff --git a/openstackclient/compute/v2/server_backup.py b/openstackclient/compute/v2/server_backup.py
new file mode 100644
index 0000000..24d7101
--- /dev/null
+++ b/openstackclient/compute/v2/server_backup.py
@@ -0,0 +1,134 @@
+# Copyright 2012-2013 OpenStack Foundation
+#
+# 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 Server action implementations"""
+
+import sys
+
+from oslo_utils import importutils
+import six
+
+from openstackclient.common import command
+from openstackclient.common import exceptions
+from openstackclient.common import utils
+from openstackclient.i18n import _
+
+
+def _show_progress(progress):
+ if progress:
+ sys.stderr.write('\rProgress: %s' % progress)
+ sys.stderr.flush()
+
+
+class CreateServerBackup(command.ShowOne):
+ """Create a server backup image"""
+
+ IMAGE_API_VERSIONS = {
+ "1": "openstackclient.image.v1.image",
+ "2": "openstackclient.image.v2.image",
+ }
+
+ def get_parser(self, prog_name):
+ parser = super(CreateServerBackup, self).get_parser(prog_name)
+ parser.add_argument(
+ 'server',
+ metavar='<server>',
+ help=_('Server to back up (name or ID)'),
+ )
+ parser.add_argument(
+ '--name',
+ metavar='<image-name>',
+ help=_('Name of the backup image (default: server name)'),
+ )
+ parser.add_argument(
+ '--type',
+ metavar='<backup-type>',
+ help=_(
+ 'Used to populate the backup_type property of the backup '
+ 'image (default: empty)'
+ ),
+ )
+ parser.add_argument(
+ '--rotate',
+ metavar='<count>',
+ type=int,
+ help=_('Number of backups to keep (default: 1)'),
+ )
+ parser.add_argument(
+ '--wait',
+ action='store_true',
+ help=_('Wait for backup image create to complete'),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ compute_client = self.app.client_manager.compute
+
+ server = utils.find_resource(
+ compute_client.servers,
+ parsed_args.server,
+ )
+
+ # Set sane defaults as this API wants all mouths to be fed
+ if parsed_args.name is None:
+ backup_name = server.name
+ else:
+ backup_name = parsed_args.name
+ if parsed_args.type is None:
+ backup_type = ""
+ else:
+ backup_type = parsed_args.type
+ if parsed_args.rotate is None:
+ backup_rotation = 1
+ else:
+ backup_rotation = parsed_args.rotate
+
+ compute_client.servers.backup(
+ server.id,
+ backup_name,
+ backup_type,
+ backup_rotation,
+ )
+
+ image_client = self.app.client_manager.image
+ image = utils.find_resource(
+ image_client.images,
+ backup_name,
+ )
+
+ if parsed_args.wait:
+ if utils.wait_for_status(
+ image_client.images.get,
+ image.id,
+ callback=_show_progress,
+ ):
+ sys.stdout.write('\n')
+ else:
+ msg = _('Error creating server backup: %s') % parsed_args.name
+ raise exceptions.CommandError(msg)
+
+ if self.app.client_manager._api_version['image'] == '1':
+ info = {}
+ info.update(image._info)
+ info['properties'] = utils.format_dict(info.get('properties', {}))
+ else:
+ # Get the right image module to format the output
+ image_module = importutils.import_module(
+ self.IMAGE_API_VERSIONS[
+ self.app.client_manager._api_version['image']
+ ]
+ )
+ info = image_module._format_image(image)
+ return zip(*sorted(six.iteritems(info)))
diff --git a/openstackclient/compute/v2/server_group.py b/openstackclient/compute/v2/server_group.py
index 973095c..2e275b7 100644
--- a/openstackclient/compute/v2/server_group.py
+++ b/openstackclient/compute/v2/server_group.py
@@ -71,7 +71,7 @@ class CreateServerGroup(command.ShowOne):
class DeleteServerGroup(command.Command):
- """Delete an existing server group."""
+ """Delete existing server group(s)."""
def get_parser(self, prog_name):
parser = super(DeleteServerGroup, self).get_parser(prog_name)
@@ -129,15 +129,7 @@ class ListServerGroup(command.Lister):
data = compute_client.server_groups.list(parsed_args.all_projects)
if parsed_args.long:
- column_headers = (
- 'ID',
- 'Name',
- 'Policies',
- 'Members',
- 'Project Id',
- 'User Id',
- )
- columns = (
+ column_headers = columns = (
'ID',
'Name',
'Policies',
diff --git a/openstackclient/compute/v2/service.py b/openstackclient/compute/v2/service.py
index 6093b8c..e7966a8 100644
--- a/openstackclient/compute/v2/service.py
+++ b/openstackclient/compute/v2/service.py
@@ -16,6 +16,7 @@
"""Service action implementations"""
from openstackclient.common import command
+from openstackclient.common import exceptions
from openstackclient.common import utils
from openstackclient.i18n import _
@@ -110,23 +111,20 @@ class SetService(command.Command):
enabled_group = parser.add_mutually_exclusive_group()
enabled_group.add_argument(
"--enable",
- dest="enabled",
- default=True,
action="store_true",
- help=_("Enable a service (default)")
+ help=_("Enable service")
)
enabled_group.add_argument(
"--disable",
- dest="enabled",
- action="store_false",
- help=_("Disable a service")
+ action="store_true",
+ help=_("Disable service")
)
parser.add_argument(
"--disable-reason",
default=None,
metavar="<reason>",
- help=_("Reason for disabling the service (in quotas). Note that "
- "when the service is enabled, this option is ignored.")
+ help=_("Reason for disabling the service (in quotas). "
+ "Should be used with --disable option.")
)
return parser
@@ -134,16 +132,26 @@ class SetService(command.Command):
compute_client = self.app.client_manager.compute
cs = compute_client.services
- if not parsed_args.enabled:
+ if (parsed_args.enable or not parsed_args.disable) and \
+ parsed_args.disable_reason:
+ msg = _("Cannot specify option --disable-reason without "
+ "--disable specified.")
+ raise exceptions.CommandError(msg)
+
+ enabled = None
+ if parsed_args.enable:
+ enabled = True
+ if parsed_args.disable:
+ enabled = False
+
+ if enabled is None:
+ return
+ elif enabled:
+ cs.enable(parsed_args.host, parsed_args.service)
+ else:
if parsed_args.disable_reason:
cs.disable_log_reason(parsed_args.host,
parsed_args.service,
parsed_args.disable_reason)
else:
cs.disable(parsed_args.host, parsed_args.service)
- else:
- if parsed_args.disable_reason:
- msg = _("argument --disable-reason has been ignored")
- self.log.info(msg)
-
- cs.enable(parsed_args.host, parsed_args.service)
diff --git a/openstackclient/identity/v2_0/catalog.py b/openstackclient/identity/v2_0/catalog.py
index 53a6fe3..c8f48cb 100644
--- a/openstackclient/identity/v2_0/catalog.py
+++ b/openstackclient/identity/v2_0/catalog.py
@@ -89,7 +89,7 @@ class ShowCatalog(command.ShowOne):
break
if not data:
- self.app.log.error('service %s not found\n' %
+ self.app.log.error(_('service %s not found\n') %
parsed_args.service)
return ([], [])
diff --git a/openstackclient/identity/v2_0/endpoint.py b/openstackclient/identity/v2_0/endpoint.py
index e515fc9..09ea738 100644
--- a/openstackclient/identity/v2_0/endpoint.py
+++ b/openstackclient/identity/v2_0/endpoint.py
@@ -81,7 +81,8 @@ class DeleteEndpoint(command.Command):
parser.add_argument(
'endpoint',
metavar='<endpoint-id>',
- help=_('Endpoint ID to delete'))
+ help=_('Endpoint ID to delete'),
+ )
return parser
def take_action(self, parsed_args):
@@ -129,8 +130,9 @@ class ShowEndpoint(command.ShowOne):
parser = super(ShowEndpoint, self).get_parser(prog_name)
parser.add_argument(
'endpoint_or_service',
- metavar='<endpoint-id>',
- help=_('Endpoint ID to display'),
+ metavar='<endpoint>',
+ help=_('Endpoint to display (endpoint ID, service ID,'
+ ' service name, service type)'),
)
return parser
diff --git a/openstackclient/identity/v2_0/project.py b/openstackclient/identity/v2_0/project.py
index d90162c..80f88d7 100644
--- a/openstackclient/identity/v2_0/project.py
+++ b/openstackclient/identity/v2_0/project.py
@@ -88,7 +88,7 @@ class CreateProject(command.ShowOne):
identity_client.tenants,
parsed_args.name,
)
- self.log.info('Returning existing project %s', project.name)
+ self.log.info(_('Returning existing project %s'), project.name)
else:
raise e
@@ -231,7 +231,8 @@ class ShowProject(command.ShowOne):
parser.add_argument(
'project',
metavar='<project>',
- help=_('Project to display (name or ID)'))
+ help=_('Project to display (name or ID)'),
+ )
return parser
def take_action(self, parsed_args):
@@ -295,9 +296,9 @@ class UnsetProject(command.Command):
metavar='<key>',
action='append',
default=[],
+ required=True,
help=_('Unset a project property '
'(repeat option to unset multiple properties)'),
- required=True,
)
return parser
@@ -308,7 +309,7 @@ class UnsetProject(command.Command):
parsed_args.project,
)
if not parsed_args.property:
- self.app.log.error("No changes requested\n")
+ self.app.log.error(_("No changes requested\n"))
else:
kwargs = project._info
for key in parsed_args.property:
diff --git a/openstackclient/identity/v2_0/role.py b/openstackclient/identity/v2_0/role.py
index 1fcee15..6b014d8 100644
--- a/openstackclient/identity/v2_0/role.py
+++ b/openstackclient/identity/v2_0/role.py
@@ -95,7 +95,7 @@ class CreateRole(command.ShowOne):
identity_client.roles,
parsed_args.role_name,
)
- self.log.info('Returning existing role %s', role.name)
+ self.log.info(_('Returning existing role %s'), role.name)
else:
raise e
@@ -136,12 +136,12 @@ class ListRole(command.Lister):
parser.add_argument(
'--project',
metavar='<project>',
- help='Filter roles by <project> (name or ID)',
+ help=_('Filter roles by <project> (name or ID)'),
)
parser.add_argument(
'--user',
metavar='<user>',
- help='Filter roles by <user> (name or ID)',
+ help=_('Filter roles by <user> (name or ID)'),
)
return parser
diff --git a/openstackclient/identity/v2_0/user.py b/openstackclient/identity/v2_0/user.py
index bc9bf83..f8f5df2 100644
--- a/openstackclient/identity/v2_0/user.py
+++ b/openstackclient/identity/v2_0/user.py
@@ -104,7 +104,7 @@ class CreateUser(command.ShowOne):
identity_client.users,
parsed_args.name,
)
- self.log.info('Returning existing user %s', user.name)
+ self.log.info(_('Returning existing user %s'), user.name)
else:
raise e
@@ -159,7 +159,8 @@ class ListUser(command.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):
diff --git a/openstackclient/identity/v3/catalog.py b/openstackclient/identity/v3/catalog.py
index 78d71f5..4c79469 100644
--- a/openstackclient/identity/v3/catalog.py
+++ b/openstackclient/identity/v3/catalog.py
@@ -84,7 +84,7 @@ class ShowCatalog(command.ShowOne):
break
if not data:
- self.app.log.error('service %s not found\n' %
+ self.app.log.error(_('service %s not found\n') %
parsed_args.service)
return ([], [])
diff --git a/openstackclient/identity/v3/consumer.py b/openstackclient/identity/v3/consumer.py
index 0da4103..a062b74 100644
--- a/openstackclient/identity/v3/consumer.py
+++ b/openstackclient/identity/v3/consumer.py
@@ -20,6 +20,7 @@ import sys
from openstackclient.common import command
from openstackclient.common import utils
+from openstackclient.i18n import _
class CreateConsumer(command.ShowOne):
@@ -30,7 +31,7 @@ class CreateConsumer(command.ShowOne):
parser.add_argument(
'--description',
metavar='<description>',
- help='New consumer description',
+ help=_('New consumer description'),
)
return parser
@@ -51,7 +52,7 @@ class DeleteConsumer(command.Command):
parser.add_argument(
'consumer',
metavar='<consumer>',
- help='Consumer to delete',
+ help=_('Consumer to delete'),
)
return parser
@@ -83,12 +84,12 @@ class SetConsumer(command.Command):
parser.add_argument(
'consumer',
metavar='<consumer>',
- help='Consumer to modify',
+ help=_('Consumer to modify'),
)
parser.add_argument(
'--description',
metavar='<description>',
- help='New consumer description',
+ help=_('New consumer description'),
)
return parser
@@ -101,7 +102,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\n'))
return
consumer = identity_client.oauth1.consumers.update(
@@ -116,7 +117,7 @@ class ShowConsumer(command.ShowOne):
parser.add_argument(
'consumer',
metavar='<consumer>',
- help='Consumer to display',
+ help=_('Consumer to display'),
)
return parser
diff --git a/openstackclient/identity/v3/credential.py b/openstackclient/identity/v3/credential.py
index b0d2caf..9901347 100644
--- a/openstackclient/identity/v3/credential.py
+++ b/openstackclient/identity/v3/credential.py
@@ -19,6 +19,7 @@ import six
from openstackclient.common import command
from openstackclient.common import utils
+from openstackclient.i18n import _
class CreateCredential(command.ShowOne):
@@ -29,24 +30,25 @@ class CreateCredential(command.ShowOne):
parser.add_argument(
'user',
metavar='<user>',
- help='Name or ID of user that owns the credential',
+ help=_('Name or ID of user that owns the credential'),
)
parser.add_argument(
'--type',
default="cert",
metavar='<type>',
choices=['ec2', 'cert'],
- help='New credential type',
+ help=_('New credential type'),
)
parser.add_argument(
'data',
metavar='<data>',
- help='New credential data',
+ help=_('New credential data'),
)
parser.add_argument(
'--project',
metavar='<project>',
- help='Project name or ID which limits the scope of the credential',
+ help=_('Project name or ID which limits the '
+ 'scope of the credential'),
)
return parser
@@ -77,7 +79,7 @@ class DeleteCredential(command.Command):
parser.add_argument(
'credential',
metavar='<credential-id>',
- help='ID of credential to delete',
+ help=_('ID of credential to delete'),
)
return parser
@@ -108,31 +110,32 @@ class SetCredential(command.Command):
parser.add_argument(
'credential',
metavar='<credential-id>',
- help='ID of credential to change',
+ help=_('ID of credential to change'),
)
parser.add_argument(
'--user',
metavar='<user>',
required=True,
- help='Name or ID of user that owns the credential',
+ help=_('Name or ID of user that owns the credential'),
)
parser.add_argument(
'--type',
metavar='<type>',
choices=['ec2', 'cert'],
required=True,
- help='New credential type',
+ help=_('New credential type'),
)
parser.add_argument(
'--data',
metavar='<data>',
required=True,
- help='New credential data',
+ help=_('New credential data'),
)
parser.add_argument(
'--project',
metavar='<project>',
- help='Project name or ID which limits the scope of the credential',
+ help=_('Project name or ID which limits the '
+ 'scope of the credential'),
)
return parser
@@ -163,7 +166,7 @@ class ShowCredential(command.ShowOne):
parser.add_argument(
'credential',
metavar='<credential-id>',
- help='ID of credential to display',
+ help=_('ID of credential to display'),
)
return parser
diff --git a/openstackclient/identity/v3/domain.py b/openstackclient/identity/v3/domain.py
index 7fcab4f..c345028 100644
--- a/openstackclient/identity/v3/domain.py
+++ b/openstackclient/identity/v3/domain.py
@@ -33,23 +33,23 @@ class CreateDomain(command.ShowOne):
parser.add_argument(
'name',
metavar='<domain-name>',
- help='New domain name',
+ help=_('New domain name'),
)
parser.add_argument(
'--description',
metavar='<description>',
- help='New domain description',
+ help=_('New domain description'),
)
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
'--enable',
action='store_true',
- help='Enable domain (default)',
+ help=_('Enable domain (default)'),
)
enable_group.add_argument(
'--disable',
action='store_true',
- help='Disable domain',
+ help=_('Disable domain'),
)
parser.add_argument(
'--or-show',
@@ -75,7 +75,7 @@ class CreateDomain(command.ShowOne):
if parsed_args.or_show:
domain = utils.find_resource(identity_client.domains,
parsed_args.name)
- self.log.info('Returning existing domain %s', domain.name)
+ self.log.info(_('Returning existing domain %s'), domain.name)
else:
raise e
@@ -91,7 +91,7 @@ class DeleteDomain(command.Command):
parser.add_argument(
'domain',
metavar='<domain>',
- help='Domain to delete (name or ID)',
+ help=_('Domain to delete (name or ID)'),
)
return parser
@@ -123,28 +123,28 @@ class SetDomain(command.Command):
parser.add_argument(
'domain',
metavar='<domain>',
- help='Domain to modify (name or ID)',
+ help=_('Domain to modify (name or ID)'),
)
parser.add_argument(
'--name',
metavar='<name>',
- help='New domain name',
+ help=_('New domain name'),
)
parser.add_argument(
'--description',
metavar='<description>',
- help='New domain description',
+ help=_('New domain description'),
)
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
'--enable',
action='store_true',
- help='Enable domain',
+ help=_('Enable domain'),
)
enable_group.add_argument(
'--disable',
action='store_true',
- help='Disable domain',
+ help=_('Disable domain'),
)
return parser
@@ -164,7 +164,7 @@ class SetDomain(command.Command):
kwargs['enabled'] = False
if not kwargs:
- sys.stdout.write("Domain not updated, no arguments present")
+ sys.stdout.write(_("Domain not updated, no arguments present\n"))
return
identity_client.domains.update(domain.id, **kwargs)
@@ -177,7 +177,7 @@ class ShowDomain(command.ShowOne):
parser.add_argument(
'domain',
metavar='<domain>',
- help='Domain to display (name or ID)',
+ help=_('Domain to display (name or ID)'),
)
return parser
diff --git a/openstackclient/identity/v3/ec2creds.py b/openstackclient/identity/v3/ec2creds.py
index a12b2d3..859ec2a 100644
--- a/openstackclient/identity/v3/ec2creds.py
+++ b/openstackclient/identity/v3/ec2creds.py
@@ -56,18 +56,14 @@ class CreateEC2Creds(command.ShowOne):
parser.add_argument(
'--project',
metavar='<project>',
- help=_(
- 'Create credentials in project '
- '(name or ID; default: current authenticated project)'
- ),
+ help=_('Create credentials in project '
+ '(name or ID; default: current authenticated project)'),
)
parser.add_argument(
'--user',
metavar='<user>',
- help=_(
- 'Create credentials for user '
- '(name or ID; default: current authenticated user)'
- ),
+ help=_('Create credentials for user '
+ '(name or ID; default: current authenticated user)'),
)
common.add_user_domain_option_to_parser(parser)
common.add_project_domain_option_to_parser(parser)
diff --git a/openstackclient/identity/v3/endpoint.py b/openstackclient/identity/v3/endpoint.py
index 6e4b356..39022d2 100644
--- a/openstackclient/identity/v3/endpoint.py
+++ b/openstackclient/identity/v3/endpoint.py
@@ -20,6 +20,7 @@ import sys
from openstackclient.common import command
from openstackclient.common import utils
+from openstackclient.i18n import _
from openstackclient.identity import common
@@ -38,23 +39,23 @@ class CreateEndpoint(command.ShowOne):
parser.add_argument(
'service',
metavar='<service>',
- help='New endpoint service (name or ID)',
+ help=_('New endpoint service (name or ID)'),
)
parser.add_argument(
'interface',
metavar='<interface>',
choices=['admin', 'public', 'internal'],
- help='New endpoint interface type (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-id>',
- help='New endpoint region ID',
+ help=_('New endpoint region ID'),
)
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
@@ -62,13 +63,13 @@ class CreateEndpoint(command.ShowOne):
dest='enabled',
action='store_true',
default=True,
- help='Enable endpoint (default)',
+ help=_('Enable endpoint (default)'),
)
enable_group.add_argument(
'--disable',
dest='enabled',
action='store_false',
- help='Disable endpoint',
+ help=_('Disable endpoint'),
)
return parser
@@ -100,7 +101,7 @@ class DeleteEndpoint(command.Command):
parser.add_argument(
'endpoint',
metavar='<endpoint-id>',
- help='Endpoint ID to delete',
+ help=_('Endpoint ID to delete'),
)
return parser
@@ -119,18 +120,18 @@ class ListEndpoint(command.Lister):
parser.add_argument(
'--service',
metavar='<service>',
- help='Filter by service',
+ help=_('Filter by service'),
)
parser.add_argument(
'--interface',
metavar='<interface>',
choices=['admin', 'public', 'internal'],
- help='Filter by interface type (admin, public or internal)',
+ help=_('Filter by interface type (admin, public or internal)'),
)
parser.add_argument(
'--region',
metavar='<region-id>',
- help='Filter by region ID',
+ help=_('Filter by region ID'),
)
return parser
@@ -167,41 +168,41 @@ class SetEndpoint(command.Command):
parser.add_argument(
'endpoint',
metavar='<endpoint-id>',
- help='Endpoint ID to modify',
+ help=_('Endpoint ID to modify'),
)
parser.add_argument(
'--region',
metavar='<region-id>',
- help='New endpoint region ID',
+ help=_('New endpoint region ID'),
)
parser.add_argument(
'--interface',
metavar='<interface>',
choices=['admin', 'public', 'internal'],
- help='New endpoint interface type (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(
'--service',
metavar='<service>',
- help='New endpoint service (name or ID)',
+ help=_('New endpoint service (name or ID)'),
)
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
'--enable',
dest='enabled',
action='store_true',
- help='Enable endpoint',
+ help=_('Enable endpoint'),
)
enable_group.add_argument(
'--disable',
dest='disabled',
action='store_true',
- help='Disable endpoint',
+ help=_('Disable endpoint'),
)
return parser
@@ -213,7 +214,7 @@ class SetEndpoint(command.Command):
if (not parsed_args.interface and not parsed_args.url
and not parsed_args.service and not parsed_args.region
and not parsed_args.enabled and not parsed_args.disabled):
- sys.stdout.write("Endpoint not updated, no arguments present")
+ sys.stdout.write(_("Endpoint not updated, no arguments present\n"))
return
service_id = None
@@ -243,8 +244,9 @@ class ShowEndpoint(command.ShowOne):
parser = super(ShowEndpoint, self).get_parser(prog_name)
parser.add_argument(
'endpoint',
- metavar='<endpoint-id>',
- help='Endpoint ID to display',
+ metavar='<endpoint>',
+ help=_('Endpoint to display (endpoint ID, service ID,'
+ ' service name, service type)'),
)
return parser
diff --git a/openstackclient/identity/v3/federation_protocol.py b/openstackclient/identity/v3/federation_protocol.py
index 27c837c..c0f4bc9 100644
--- a/openstackclient/identity/v3/federation_protocol.py
+++ b/openstackclient/identity/v3/federation_protocol.py
@@ -18,6 +18,7 @@ import six
from openstackclient.common import command
from openstackclient.common import utils
+from openstackclient.i18n import _
class CreateProtocol(command.ShowOne):
@@ -28,19 +29,22 @@ class CreateProtocol(command.ShowOne):
parser.add_argument(
'federation_protocol',
metavar='<name>',
- help='New federation protocol name (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>',
required=True,
- help='Identity provider that will support the new federation '
- ' protocol (name or ID) (required)')
+ help=_('Identity provider that will support the new federation '
+ ' protocol (name or ID) (required)'),
+ )
parser.add_argument(
'--mapping',
metavar='<mapping>',
required=True,
- help='Mapping that is to be used (name or ID) (required)')
+ help=_('Mapping that is to be used (name or ID) (required)'),
+ )
return parser
@@ -69,13 +73,15 @@ class DeleteProtocol(command.Command):
parser.add_argument(
'federation_protocol',
metavar='<federation-protocol>',
- help='Federation protocol to delete (name or ID)')
+ help=_('Federation protocol to delete (name or ID)'),
+ )
parser.add_argument(
'--identity-provider',
metavar='<identity-provider>',
required=True,
- help='Identity provider that supports <federation-protocol> '
- '(name or ID) (required)')
+ help=_('Identity provider that supports <federation-protocol> '
+ '(name or ID) (required)'),
+ )
return parser
@@ -94,7 +100,8 @@ class ListProtocols(command.Lister):
'--identity-provider',
metavar='<identity-provider>',
required=True,
- help='Identity provider to list (name or ID) (required)')
+ help=_('Identity provider to list (name or ID) (required)'),
+ )
return parser
@@ -118,24 +125,27 @@ class SetProtocol(command.Command):
parser.add_argument(
'federation_protocol',
metavar='<name>',
- help='Federation protocol to modify (name or ID)')
+ help=_('Federation protocol to modify (name or ID)'),
+ )
parser.add_argument(
'--identity-provider',
metavar='<identity-provider>',
required=True,
- help='Identity provider that supports <federation-protocol> '
- '(name or ID) (required)')
+ help=_('Identity provider that supports <federation-protocol> '
+ '(name or ID) (required)'),
+ )
parser.add_argument(
'--mapping',
metavar='<mapping>',
- help='Mapping that is to be used (name or ID)')
+ 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")
+ self.app.log.error(_("No changes requested"))
return
protocol = identity_client.federation.protocols.update(
@@ -159,13 +169,15 @@ class ShowProtocol(command.ShowOne):
parser.add_argument(
'federation_protocol',
metavar='<federation-protocol>',
- help='Federation protocol to display (name or ID)')
+ help=_('Federation protocol to display (name or ID)'),
+ )
parser.add_argument(
'--identity-provider',
metavar='<identity-provider>',
required=True,
- help=('Identity provider that supports <federation-protocol> '
- '(name or ID) (required)'))
+ 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 3c24353..fdb94da 100644
--- a/openstackclient/identity/v3/group.py
+++ b/openstackclient/identity/v3/group.py
@@ -34,12 +34,12 @@ class AddUserToGroup(command.Command):
parser.add_argument(
'group',
metavar='<group>',
- help='Group to contain <user> (name or ID)',
+ help=_('Group to contain <user> (name or ID)'),
)
parser.add_argument(
'user',
metavar='<user>',
- help='User to add to <group> (name or ID)',
+ help=_('User to add to <group> (name or ID)'),
)
common.add_group_domain_option_to_parser(parser)
common.add_user_domain_option_to_parser(parser)
@@ -58,11 +58,17 @@ class AddUserToGroup(command.Command):
try:
identity_client.users.add_to_group(user_id, group_id)
except Exception:
- sys.stderr.write("%s not added to group %s\n" %
- (parsed_args.user, parsed_args.group))
+ msg = _("%(user)s not added to group %(group)s\n") % {
+ 'user': parsed_args.user,
+ 'group': parsed_args.group,
+ }
+ sys.stderr.write(msg)
else:
- sys.stdout.write("%s added to group %s\n" %
- (parsed_args.user, parsed_args.group))
+ msg = _("%(user)s added to group %(group)s\n") % {
+ 'user': parsed_args.user,
+ 'group': parsed_args.group,
+ }
+ sys.stdout.write(msg)
class CheckUserInGroup(command.Command):
@@ -73,12 +79,12 @@ class CheckUserInGroup(command.Command):
parser.add_argument(
'group',
metavar='<group>',
- help='Group to check (name or ID)',
+ help=_('Group to check (name or ID)'),
)
parser.add_argument(
'user',
metavar='<user>',
- help='User to check (name or ID)',
+ help=_('User to check (name or ID)'),
)
common.add_group_domain_option_to_parser(parser)
common.add_user_domain_option_to_parser(parser)
@@ -97,11 +103,17 @@ class CheckUserInGroup(command.Command):
try:
identity_client.users.check_in_group(user_id, group_id)
except Exception:
- sys.stderr.write("%s not in group %s\n" %
- (parsed_args.user, parsed_args.group))
+ msg = _("%(user)s not in group %(group)s\n") % {
+ 'user': parsed_args.user,
+ 'group': parsed_args.group,
+ }
+ sys.stderr.write(msg)
else:
- sys.stdout.write("%s in group %s\n" %
- (parsed_args.user, parsed_args.group))
+ msg = _("%(user)s in group %(group)s\n") % {
+ 'user': parsed_args.user,
+ 'group': parsed_args.group,
+ }
+ sys.stdout.write(msg)
class CreateGroup(command.ShowOne):
@@ -112,17 +124,17 @@ class CreateGroup(command.ShowOne):
parser.add_argument(
'name',
metavar='<group-name>',
- help='New group name',
+ help=_('New group name'),
)
parser.add_argument(
'--domain',
metavar='<domain>',
- help='Domain to contain new group (name or ID)',
+ help=_('Domain to contain new group (name or ID)'),
)
parser.add_argument(
'--description',
metavar='<description>',
- help='New group description',
+ help=_('New group description'),
)
parser.add_argument(
'--or-show',
@@ -149,7 +161,7 @@ class CreateGroup(command.ShowOne):
group = utils.find_resource(identity_client.groups,
parsed_args.name,
domain_id=domain)
- self.log.info('Returning existing group %s', group.name)
+ self.log.info(_('Returning existing group %s'), group.name)
else:
raise e
@@ -166,11 +178,12 @@ class DeleteGroup(command.Command):
'groups',
metavar='<group>',
nargs="+",
- help='Group(s) to delete (name or ID)')
+ help=_('Group(s) to delete (name or ID)'),
+ )
parser.add_argument(
'--domain',
metavar='<domain>',
- help='Domain containing group(s) (name or ID)',
+ help=_('Domain containing group(s) (name or ID)'),
)
return parser
@@ -192,19 +205,19 @@ class ListGroup(command.Lister):
parser.add_argument(
'--domain',
metavar='<domain>',
- help='Filter group list by <domain> (name or ID)',
+ help=_('Filter group list by <domain> (name or ID)'),
)
parser.add_argument(
'--user',
metavar='<user>',
- help='Filter group list by <user> (name or ID)',
+ help=_('Filter group list by <user> (name or ID)'),
)
common.add_user_domain_option_to_parser(parser)
parser.add_argument(
'--long',
action='store_true',
default=False,
- help='List additional fields in output',
+ help=_('List additional fields in output'),
)
return parser
@@ -252,12 +265,12 @@ class RemoveUserFromGroup(command.Command):
parser.add_argument(
'group',
metavar='<group>',
- help='Group containing <user> (name or ID)',
+ help=_('Group containing <user> (name or ID)'),
)
parser.add_argument(
'user',
metavar='<user>',
- help='User to remove from <group> (name or ID)',
+ help=_('User to remove from <group> (name or ID)'),
)
common.add_group_domain_option_to_parser(parser)
common.add_user_domain_option_to_parser(parser)
@@ -276,11 +289,17 @@ class RemoveUserFromGroup(command.Command):
try:
identity_client.users.remove_from_group(user_id, group_id)
except Exception:
- sys.stderr.write("%s not removed from group %s\n" %
- (parsed_args.user, parsed_args.group))
+ msg = _("%(user)s not removed from group %(group)s\n") % {
+ 'user': parsed_args.user,
+ 'group': parsed_args.group,
+ }
+ sys.stderr.write(msg)
else:
- sys.stdout.write("%s removed from group %s\n" %
- (parsed_args.user, parsed_args.group))
+ msg = _("%(user)s removed from group %(group)s\n") % {
+ 'user': parsed_args.user,
+ 'group': parsed_args.group,
+ }
+ sys.stdout.write(msg)
class SetGroup(command.Command):
@@ -291,20 +310,23 @@ class SetGroup(command.Command):
parser.add_argument(
'group',
metavar='<group>',
- help='Group to modify (name or ID)')
+ help=_('Group to modify (name or ID)'),
+ )
parser.add_argument(
'--domain',
metavar='<domain>',
- help='Domain containing <group> (name or ID)',
+ help=_('Domain containing <group> (name or ID)'),
)
parser.add_argument(
'--name',
metavar='<name>',
- help='New group name')
+ help=_('New group name'),
+ )
parser.add_argument(
'--description',
metavar='<description>',
- help='New group description')
+ help=_('New group description'),
+ )
return parser
def take_action(self, parsed_args):
@@ -318,7 +340,7 @@ class SetGroup(command.Command):
kwargs['description'] = parsed_args.description
if not len(kwargs):
- sys.stderr.write("Group not updated, no arguments present")
+ sys.stderr.write("Group not updated, no arguments present\n")
return
identity_client.groups.update(group.id, **kwargs)
@@ -331,12 +353,12 @@ class ShowGroup(command.ShowOne):
parser.add_argument(
'group',
metavar='<group>',
- help='Group to display (name or ID)',
+ help=_('Group to display (name or ID)'),
)
parser.add_argument(
'--domain',
metavar='<domain>',
- help='Domain containing <group> (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 39f440f..3749aa3 100644
--- a/openstackclient/identity/v3/identity_provider.py
+++ b/openstackclient/identity/v3/identity_provider.py
@@ -17,6 +17,7 @@ import six
from openstackclient.common import command
from openstackclient.common import utils
+from openstackclient.i18n import _
class CreateIdentityProvider(command.ShowOne):
@@ -27,26 +28,26 @@ class CreateIdentityProvider(command.ShowOne):
parser.add_argument(
'identity_provider_id',
metavar='<name>',
- help='New identity provider name (must be unique)'
+ help=_('New identity provider name (must be unique)'),
)
identity_remote_id_provider = parser.add_mutually_exclusive_group()
identity_remote_id_provider.add_argument(
'--remote-id',
metavar='<remote-id>',
action='append',
- help='Remote IDs to associate with the Identity Provider '
- '(repeat option to provide multiple values)'
+ help=_('Remote IDs to associate with the Identity Provider '
+ '(repeat option to provide multiple values)'),
)
identity_remote_id_provider.add_argument(
'--remote-id-file',
metavar='<file-name>',
- help='Name of a file that contains many remote IDs to associate '
- 'with the identity provider, one per line'
+ help=_('Name of a file that contains many remote IDs to associate '
+ 'with the identity provider, one per line'),
)
parser.add_argument(
'--description',
metavar='<description>',
- help='New identity provider description',
+ help=_('New identity provider description'),
)
enable_identity_provider = parser.add_mutually_exclusive_group()
enable_identity_provider.add_argument(
@@ -54,13 +55,13 @@ class CreateIdentityProvider(command.ShowOne):
dest='enabled',
action='store_true',
default=True,
- help='Enable identity provider (default)',
+ help=_('Enable identity provider (default)'),
)
enable_identity_provider.add_argument(
'--disable',
dest='enabled',
action='store_false',
- help='Disable the identity provider',
+ help=_('Disable the identity provider'),
)
return parser
@@ -94,7 +95,7 @@ class DeleteIdentityProvider(command.Command):
parser.add_argument(
'identity_provider',
metavar='<identity-provider>',
- help='Identity provider to delete',
+ help=_('Identity provider to delete'),
)
return parser
@@ -126,37 +127,37 @@ class SetIdentityProvider(command.Command):
parser.add_argument(
'identity_provider',
metavar='<identity-provider>',
- help='Identity provider to modify',
+ help=_('Identity provider to modify'),
)
parser.add_argument(
'--description',
metavar='<description>',
- help='Set identity provider description',
+ help=_('Set identity provider description'),
)
identity_remote_id_provider = parser.add_mutually_exclusive_group()
identity_remote_id_provider.add_argument(
'--remote-id',
metavar='<remote-id>',
action='append',
- help='Remote IDs to associate with the Identity Provider '
- '(repeat option to provide multiple values)'
+ help=_('Remote IDs to associate with the Identity Provider '
+ '(repeat option to provide multiple values)'),
)
identity_remote_id_provider.add_argument(
'--remote-id-file',
metavar='<file-name>',
- help='Name of a file that contains many remote IDs to associate '
- 'with the identity provider, one per line'
+ help=_('Name of a file that contains many remote IDs to associate '
+ 'with the identity provider, one per line'),
)
enable_identity_provider = parser.add_mutually_exclusive_group()
enable_identity_provider.add_argument(
'--enable',
action='store_true',
- help='Enable the identity provider',
+ help=_('Enable the identity provider'),
)
enable_identity_provider.add_argument(
'--disable',
action='store_true',
- help='Disable the identity provider',
+ help=_('Disable the identity provider'),
)
return parser
@@ -168,7 +169,7 @@ class SetIdentityProvider(command.Command):
not parsed_args.remote_id and
not parsed_args.remote_id_file and
not parsed_args.description):
- self.log.error('No changes requested')
+ self.log.error(_('No changes requested'))
return (None, None)
# Always set remote_ids if either is passed in
@@ -206,7 +207,7 @@ class ShowIdentityProvider(command.ShowOne):
parser.add_argument(
'identity_provider',
metavar='<identity-provider>',
- help='Identity provider to display',
+ help=_('Identity provider to display'),
)
return parser
diff --git a/openstackclient/identity/v3/mapping.py b/openstackclient/identity/v3/mapping.py
index 3cdc8af..c45796e 100644
--- a/openstackclient/identity/v3/mapping.py
+++ b/openstackclient/identity/v3/mapping.py
@@ -22,6 +22,7 @@ import six
from openstackclient.common import command
from openstackclient.common import exceptions
from openstackclient.common import utils
+from openstackclient.i18n import _
class _RulesReader(object):
@@ -69,9 +70,9 @@ class _RulesReader(object):
try:
rules = json.loads(blob)
except ValueError as e:
- raise exceptions.CommandError(
- 'An error occurred when reading '
- 'rules from file %s: %s' % (path, e))
+ msg = _("An error occurred when reading rules from file "
+ "%(path)s: %(error)s") % {"path": path, "error": e}
+ raise exceptions.CommandError(msg)
else:
return rules
@@ -84,12 +85,12 @@ class CreateMapping(command.ShowOne, _RulesReader):
parser.add_argument(
'mapping',
metavar='<name>',
- help='New mapping name (must be unique)',
+ help=_('New mapping name (must be unique)'),
)
parser.add_argument(
'--rules',
metavar='<filename>', required=True,
- help='Filename that contains a set of mapping rules (required)',
+ help=_('Filename that contains a set of mapping rules (required)'),
)
return parser
@@ -113,7 +114,7 @@ class DeleteMapping(command.Command):
parser.add_argument(
'mapping',
metavar='<mapping>',
- help='Mapping to delete',
+ help=_('Mapping to delete'),
)
return parser
@@ -145,12 +146,12 @@ class SetMapping(command.Command, _RulesReader):
parser.add_argument(
'mapping',
metavar='<name>',
- help='Mapping to modify',
+ help=_('Mapping to modify'),
)
parser.add_argument(
'--rules',
metavar='<filename>',
- help='Filename that contains a new set of mapping rules',
+ help=_('Filename that contains a new set of mapping rules'),
)
return parser
@@ -158,7 +159,7 @@ class SetMapping(command.Command, _RulesReader):
identity_client = self.app.client_manager.identity
if not parsed_args.rules:
- self.app.log.error("No changes requested")
+ self.app.log.error(_("No changes requested"))
return
rules = self._read_rules(parsed_args.rules)
@@ -179,7 +180,7 @@ class ShowMapping(command.ShowOne):
parser.add_argument(
'mapping',
metavar='<mapping>',
- help='Mapping to display',
+ help=_('Mapping to display'),
)
return parser
diff --git a/openstackclient/identity/v3/policy.py b/openstackclient/identity/v3/policy.py
index 3c2d1a7..74a783b 100644
--- a/openstackclient/identity/v3/policy.py
+++ b/openstackclient/identity/v3/policy.py
@@ -20,6 +20,7 @@ import sys
from openstackclient.common import command
from openstackclient.common import utils
+from openstackclient.i18n import _
class CreatePolicy(command.ShowOne):
@@ -31,13 +32,13 @@ class CreatePolicy(command.ShowOne):
'--type',
metavar='<type>',
default="application/json",
- help='New MIME type of the policy rules file '
- '(defaults to application/json)',
+ help=_('New MIME type of the policy rules file '
+ '(defaults to application/json)'),
)
parser.add_argument(
'rules',
metavar='<filename>',
- help='New serialized policy rules file',
+ help=_('New serialized policy rules file'),
)
return parser
@@ -62,7 +63,7 @@ class DeletePolicy(command.Command):
parser.add_argument(
'policy',
metavar='<policy>',
- help='Policy to delete',
+ help=_('Policy to delete'),
)
return parser
@@ -80,7 +81,7 @@ class ListPolicy(command.Lister):
'--long',
action='store_true',
default=False,
- help='List additional fields in output',
+ help=_('List additional fields in output'),
)
return parser
@@ -107,17 +108,17 @@ class SetPolicy(command.Command):
parser.add_argument(
'policy',
metavar='<policy>',
- help='Policy to modify',
+ help=_('Policy to modify'),
)
parser.add_argument(
'--type',
metavar='<type>',
- help='New MIME type of the policy rules file',
+ help=_('New MIME type of the policy rules file'),
)
parser.add_argument(
'--rules',
metavar='<filename>',
- help='New serialized policy rules file',
+ help=_('New serialized policy rules file'),
)
return parser
@@ -135,7 +136,7 @@ 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)
@@ -148,7 +149,7 @@ class ShowPolicy(command.ShowOne):
parser.add_argument(
'policy',
metavar='<policy>',
- help='Policy to display',
+ help=_('Policy to display'),
)
return parser
diff --git a/openstackclient/identity/v3/project.py b/openstackclient/identity/v3/project.py
index 4990b1b..acf639f 100644
--- a/openstackclient/identity/v3/project.py
+++ b/openstackclient/identity/v3/project.py
@@ -34,40 +34,40 @@ class CreateProject(command.ShowOne):
parser.add_argument(
'name',
metavar='<project-name>',
- help='New project name',
+ help=_('New project name'),
)
parser.add_argument(
'--domain',
metavar='<domain>',
- help='Domain owning the project (name or ID)',
+ help=_('Domain owning the project (name or ID)'),
)
parser.add_argument(
'--parent',
metavar='<project>',
- help='Parent of the project (name or ID)',
+ help=_('Parent of the project (name or ID)'),
)
parser.add_argument(
'--description',
metavar='<description>',
- help='Project description',
+ help=_('Project description'),
)
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
'--enable',
action='store_true',
- help='Enable project',
+ help=_('Enable project'),
)
enable_group.add_argument(
'--disable',
action='store_true',
- help='Disable project',
+ help=_('Disable project'),
)
parser.add_argument(
'--property',
metavar='<key=value>',
action=parseractions.KeyValueAction,
- help='Add a property to <name> '
- '(repeat option to set multiple properties)',
+ help=_('Add a property to <name> '
+ '(repeat option to set multiple properties)'),
)
parser.add_argument(
'--or-show',
@@ -112,7 +112,7 @@ class CreateProject(command.ShowOne):
project = utils.find_resource(identity_client.projects,
parsed_args.name,
domain_id=domain)
- self.log.info('Returning existing project %s', project.name)
+ self.log.info(_('Returning existing project %s'), project.name)
else:
raise e
@@ -129,12 +129,12 @@ class DeleteProject(command.Command):
'projects',
metavar='<project>',
nargs="+",
- help='Project(s) to delete (name or ID)',
+ help=_('Project(s) to delete (name or ID)'),
)
parser.add_argument(
'--domain',
metavar='<domain>',
- help='Domain owning <project> (name or ID)',
+ help=_('Domain owning <project> (name or ID)'),
)
return parser
@@ -163,18 +163,18 @@ class ListProject(command.Lister):
parser.add_argument(
'--domain',
metavar='<domain>',
- help='Filter projects by <domain> (name or ID)',
+ help=_('Filter projects by <domain> (name or ID)'),
)
parser.add_argument(
'--user',
metavar='<user>',
- help='Filter projects by <user> (name or ID)',
+ help=_('Filter projects by <user> (name or ID)'),
)
parser.add_argument(
'--long',
action='store_true',
default=False,
- help='List additional fields in output',
+ help=_('List additional fields in output'),
)
return parser
@@ -219,40 +219,40 @@ class SetProject(command.Command):
parser.add_argument(
'project',
metavar='<project>',
- help='Project to modify (name or ID)',
+ help=_('Project to modify (name or ID)'),
)
parser.add_argument(
'--name',
metavar='<name>',
- help='Set project name',
+ help=_('Set project name'),
)
parser.add_argument(
'--domain',
metavar='<domain>',
- help='Domain owning <project> (name or ID)',
+ help=_('Domain owning <project> (name or ID)'),
)
parser.add_argument(
'--description',
metavar='<description>',
- help='Set project description',
+ help=_('Set project description'),
)
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
'--enable',
action='store_true',
- help='Enable project',
+ help=_('Enable project'),
)
enable_group.add_argument(
'--disable',
action='store_true',
- help='Disable project',
+ help=_('Disable project'),
)
parser.add_argument(
'--property',
metavar='<key=value>',
action=parseractions.KeyValueAction,
- help='Set a property on <project> '
- '(repeat option to set multiple properties)',
+ help=_('Set a property on <project> '
+ '(repeat option to set multiple properties)'),
)
return parser
@@ -293,24 +293,24 @@ class ShowProject(command.ShowOne):
parser.add_argument(
'project',
metavar='<project>',
- help='Project to display (name or ID)',
+ help=_('Project to display (name or ID)'),
)
parser.add_argument(
'--domain',
metavar='<domain>',
- help='Domain owning <project> (name or ID)',
+ help=_('Domain owning <project> (name or ID)'),
)
parser.add_argument(
'--parents',
action='store_true',
default=False,
- help='Show the project\'s parents as a list',
+ help=_('Show the project\'s parents as a list'),
)
parser.add_argument(
'--children',
action='store_true',
default=False,
- help='Show project\'s subtree (children) as a list',
+ help=_('Show project\'s subtree (children) as a list'),
)
return parser
diff --git a/openstackclient/identity/v3/role.py b/openstackclient/identity/v3/role.py
index f93c9d8..e7078f4 100644
--- a/openstackclient/identity/v3/role.py
+++ b/openstackclient/identity/v3/role.py
@@ -31,23 +31,23 @@ def _add_identity_and_resource_options_to_parser(parser):
domain_or_project.add_argument(
'--domain',
metavar='<domain>',
- help='Include <domain> (name or ID)',
+ help=_('Include <domain> (name or ID)'),
)
domain_or_project.add_argument(
'--project',
metavar='<project>',
- help='Include <project> (name or ID)',
+ help=_('Include <project> (name or ID)'),
)
user_or_group = parser.add_mutually_exclusive_group()
user_or_group.add_argument(
'--user',
metavar='<user>',
- help='Include <user> (name or ID)',
+ help=_('Include <user> (name or ID)'),
)
user_or_group.add_argument(
'--group',
metavar='<group>',
- help='Include <group> (name or ID)',
+ help=_('Include <group> (name or ID)'),
)
common.add_group_domain_option_to_parser(parser)
common.add_project_domain_option_to_parser(parser)
@@ -112,7 +112,7 @@ class AddRole(command.Command):
parser.add_argument(
'role',
metavar='<role>',
- help='Role to add to <user> (name or ID)',
+ help=_('Role to add to <user> (name or ID)'),
)
_add_identity_and_resource_options_to_parser(parser)
return parser
@@ -131,9 +131,9 @@ class AddRole(command.Command):
kwargs = _process_identity_and_resource_options(
parsed_args, self.app.client_manager.identity)
if not kwargs:
- sys.stderr.write("Role not added, incorrect set of arguments "
- "provided. See openstack --help for more "
- "details\n")
+ sys.stderr.write(_("Role not added, incorrect set of arguments "
+ "provided. See openstack --help for more "
+ "details\n"))
return
identity_client.roles.grant(role.id, **kwargs)
@@ -147,7 +147,7 @@ class CreateRole(command.ShowOne):
parser.add_argument(
'name',
metavar='<role-name>',
- help='New role name',
+ help=_('New role name'),
)
parser.add_argument(
'--or-show',
@@ -165,7 +165,7 @@ class CreateRole(command.ShowOne):
if parsed_args.or_show:
role = utils.find_resource(identity_client.roles,
parsed_args.name)
- self.log.info('Returning existing role %s', role.name)
+ self.log.info(_('Returning existing role %s'), role.name)
else:
raise e
@@ -182,7 +182,7 @@ class DeleteRole(command.Command):
'roles',
metavar='<role>',
nargs="+",
- help='Role(s) to delete (name or ID)',
+ help=_('Role(s) to delete (name or ID)'),
)
return parser
@@ -285,9 +285,9 @@ class ListRole(command.Lister):
group_role.group = group.name
group_role.project = project.name
else:
- sys.stderr.write("Error: If a user or group is specified, either "
- "--domain or --project must also be specified to "
- "list role grants.\n")
+ sys.stderr.write(_("Error: If a user or group is specified, "
+ "either --domain or --project must also be "
+ "specified to list role grants.\n"))
return ([], [])
return (columns,
@@ -305,7 +305,7 @@ class RemoveRole(command.Command):
parser.add_argument(
'role',
metavar='<role>',
- help='Role to remove (name or ID)',
+ help=_('Role to remove (name or ID)'),
)
_add_identity_and_resource_options_to_parser(parser)
return parser
@@ -315,9 +315,8 @@ class RemoveRole(command.Command):
if (not parsed_args.user and not parsed_args.domain
and not parsed_args.group and not parsed_args.project):
- sys.stderr.write("Incorrect set of arguments "
- "provided. See openstack --help for more "
- "details\n")
+ sys.stderr.write(_("Incorrect set of arguments provided. "
+ "See openstack --help for more details\n"))
return
role = utils.find_resource(
identity_client.roles,
@@ -327,8 +326,9 @@ class RemoveRole(command.Command):
kwargs = _process_identity_and_resource_options(
parsed_args, self.app.client_manager.identity)
if not kwargs:
- sys.stderr.write("Role not removed, incorrect set of arguments \
- provided. See openstack --help for more details\n")
+ sys.stderr.write(_("Role not removed, incorrect set of arguments "
+ "provided. See openstack --help for more "
+ "details\n"))
return
identity_client.roles.revoke(role.id, **kwargs)
@@ -341,12 +341,12 @@ class SetRole(command.Command):
parser.add_argument(
'role',
metavar='<role>',
- help='Role to modify (name or ID)',
+ help=_('Role to modify (name or ID)'),
)
parser.add_argument(
'--name',
metavar='<name>',
- help='Set role name',
+ help=_('Set role name'),
)
return parser
@@ -354,9 +354,8 @@ class SetRole(command.Command):
identity_client = self.app.client_manager.identity
if not parsed_args.name:
- sys.stderr.write("Incorrect set of arguments "
- "provided. See openstack --help for more "
- "details\n")
+ sys.stderr.write(_("Incorrect set of arguments provided. "
+ "See openstack --help for more details\n"))
return
role = utils.find_resource(
identity_client.roles,
@@ -374,7 +373,7 @@ class ShowRole(command.ShowOne):
parser.add_argument(
'role',
metavar='<role>',
- help='Role to display (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 a1418a8..521075f 100644
--- a/openstackclient/identity/v3/role_assignment.py
+++ b/openstackclient/identity/v3/role_assignment.py
@@ -15,6 +15,7 @@
from openstackclient.common import command
from openstackclient.common import utils
+from openstackclient.i18n import _
from openstackclient.identity import common
@@ -27,41 +28,41 @@ class ListRoleAssignment(command.Lister):
'--effective',
action="store_true",
default=False,
- help='Returns only effective role assignments',
+ help=_('Returns only effective role assignments'),
)
parser.add_argument(
'--role',
metavar='<role>',
- help='Role to filter (name or ID)',
+ help=_('Role to filter (name or ID)'),
)
parser.add_argument(
'--names',
action="store_true",
- help='Display names instead of IDs',
+ help=_('Display names instead of IDs'),
)
user_or_group = parser.add_mutually_exclusive_group()
user_or_group.add_argument(
'--user',
metavar='<user>',
- help='User to filter (name or ID)',
+ help=_('User to filter (name or ID)'),
)
common.add_user_domain_option_to_parser(parser)
user_or_group.add_argument(
'--group',
metavar='<group>',
- help='Group to filter (name or ID)',
+ help=_('Group to filter (name or ID)'),
)
common.add_group_domain_option_to_parser(parser)
domain_or_project = parser.add_mutually_exclusive_group()
domain_or_project.add_argument(
'--domain',
metavar='<domain>',
- help='Domain to filter (name or ID)',
+ help=_('Domain to filter (name or ID)'),
)
domain_or_project.add_argument(
'--project',
metavar='<project>',
- help='Project to filter (name or ID)',
+ help=_('Project to filter (name or ID)'),
)
common.add_project_domain_option_to_parser(parser)
common.add_inherited_option_to_parser(parser)
diff --git a/openstackclient/identity/v3/service.py b/openstackclient/identity/v3/service.py
index f43ada5..35507a6 100644
--- a/openstackclient/identity/v3/service.py
+++ b/openstackclient/identity/v3/service.py
@@ -20,6 +20,7 @@ import sys
from openstackclient.common import command
from openstackclient.common import utils
+from openstackclient.i18n import _
from openstackclient.identity import common
@@ -31,28 +32,28 @@ class CreateService(command.ShowOne):
parser.add_argument(
'type',
metavar='<type>',
- help='New service type (compute, image, identity, volume, etc)',
+ help=_('New service type (compute, image, identity, volume, etc)'),
)
parser.add_argument(
'--name',
metavar='<name>',
- help='New service name',
+ help=_('New service name'),
)
parser.add_argument(
'--description',
metavar='<description>',
- help='New service description',
+ help=_('New service description'),
)
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
'--enable',
action='store_true',
- help='Enable service (default)',
+ help=_('Enable service (default)'),
)
enable_group.add_argument(
'--disable',
action='store_true',
- help='Disable service',
+ help=_('Disable service'),
)
return parser
@@ -82,7 +83,7 @@ class DeleteService(command.Command):
parser.add_argument(
'service',
metavar='<service>',
- help='Service to delete (type, name or ID)',
+ help=_('Service to delete (type, name or ID)'),
)
return parser
@@ -103,7 +104,7 @@ class ListService(command.Lister):
'--long',
action='store_true',
default=False,
- help='List additional fields in output',
+ help=_('List additional fields in output'),
)
return parser
@@ -128,33 +129,33 @@ class SetService(command.Command):
parser.add_argument(
'service',
metavar='<service>',
- help='Service to update (type, name or ID)',
+ help=_('Service to update (type, name or ID)'),
)
parser.add_argument(
'--type',
metavar='<type>',
- help='New service type (compute, image, identity, volume, etc)',
+ help=_('New service type (compute, image, identity, volume, etc)'),
)
parser.add_argument(
'--name',
metavar='<service-name>',
- help='New service name',
+ help=_('New service name'),
)
parser.add_argument(
'--description',
metavar='<description>',
- help='New service description',
+ help=_('New service description'),
)
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
'--enable',
action='store_true',
- help='Enable service',
+ help=_('Enable service'),
)
enable_group.add_argument(
'--disable',
action='store_true',
- help='Disable service',
+ help=_('Disable service'),
)
return parser
@@ -166,9 +167,8 @@ class SetService(command.Command):
and not parsed_args.description
and not parsed_args.enable
and not parsed_args.disable):
- sys.stderr.write("Incorrect set of arguments "
- "provided. See openstack --help for more "
- "details\n")
+ sys.stderr.write(_("Incorrect set of arguments provided. "
+ "See openstack --help for more details\n"))
return
service = common.find_service(identity_client,
parsed_args.service)
@@ -198,7 +198,7 @@ class ShowService(command.ShowOne):
parser.add_argument(
'service',
metavar='<service>',
- help='Service to display (type, name or ID)',
+ help=_('Service to display (type, name or ID)'),
)
return parser
diff --git a/openstackclient/identity/v3/service_provider.py b/openstackclient/identity/v3/service_provider.py
index 8b433b4..f1e9f35 100644
--- a/openstackclient/identity/v3/service_provider.py
+++ b/openstackclient/identity/v3/service_provider.py
@@ -18,6 +18,7 @@ import sys
from openstackclient.common import command
from openstackclient.common import utils
+from openstackclient.i18n import _
class CreateServiceProvider(command.ShowOne):
@@ -28,26 +29,26 @@ class CreateServiceProvider(command.ShowOne):
parser.add_argument(
'service_provider_id',
metavar='<name>',
- help='New service provider name (must be unique)'
+ help=_('New service provider name (must be unique)'),
)
parser.add_argument(
'--auth-url',
metavar='<auth-url>',
required=True,
- help='Authentication URL of remote federated service provider '
- '(required)',
+ help=_('Authentication URL of remote federated service provider '
+ '(required)'),
)
parser.add_argument(
'--description',
metavar='<description>',
- help='New service provider description',
+ help=_('New service provider description'),
)
parser.add_argument(
'--service-provider-url',
metavar='<sp-url>',
required=True,
- help='A service URL where SAML assertions are being sent '
- '(required)',
+ help=_('A service URL where SAML assertions are being sent '
+ '(required)'),
)
enable_service_provider = parser.add_mutually_exclusive_group()
@@ -56,13 +57,13 @@ class CreateServiceProvider(command.ShowOne):
dest='enabled',
action='store_true',
default=True,
- help='Enable the service provider (default)',
+ help=_('Enable the service provider (default)'),
)
enable_service_provider.add_argument(
'--disable',
dest='enabled',
action='store_false',
- help='Disable the service provider',
+ help=_('Disable the service provider'),
)
return parser
@@ -88,7 +89,7 @@ class DeleteServiceProvider(command.Command):
parser.add_argument(
'service_provider',
metavar='<service-provider>',
- help='Service provider to delete',
+ help=_('Service provider to delete'),
)
return parser
@@ -121,34 +122,35 @@ class SetServiceProvider(command.Command):
parser.add_argument(
'service_provider',
metavar='<service-provider>',
- help='Service provider to modify',
+ help=_('Service provider to modify'),
)
parser.add_argument(
'--auth-url',
metavar='<auth-url>',
- help='New Authentication URL of remote federated service provider',
+ help=_('New Authentication URL of remote '
+ 'federated service provider'),
)
parser.add_argument(
'--description',
metavar='<description>',
- help='New service provider description',
+ help=_('New service provider description'),
)
parser.add_argument(
'--service-provider-url',
metavar='<sp-url>',
- help='New service provider URL, where SAML assertions are sent',
+ help=_('New service provider URL, where SAML assertions are sent'),
)
enable_service_provider = parser.add_mutually_exclusive_group()
enable_service_provider.add_argument(
'--enable',
action='store_true',
- help='Enable the service provider',
+ help=_('Enable the service provider'),
)
enable_service_provider.add_argument(
'--disable',
action='store_true',
- help='Disable the service provider',
+ help=_('Disable the service provider'),
)
return parser
@@ -164,8 +166,8 @@ class SetServiceProvider(command.Command):
if not any((enabled is not None, parsed_args.description,
parsed_args.service_provider_url,
parsed_args.auth_url)):
- sys.stdout.write("Service Provider not updated, no arguments "
- "present")
+ sys.stdout.write(_("Service Provider not updated, no arguments "
+ "present\n"))
return (None, None)
service_provider = federation_client.service_providers.update(
@@ -184,7 +186,7 @@ class ShowServiceProvider(command.ShowOne):
parser.add_argument(
'service_provider',
metavar='<service-provider>',
- help='Service provider to display',
+ help=_('Service provider to display'),
)
return parser
diff --git a/openstackclient/identity/v3/token.py b/openstackclient/identity/v3/token.py
index bdc5e95..56a7497 100644
--- a/openstackclient/identity/v3/token.py
+++ b/openstackclient/identity/v3/token.py
@@ -20,6 +20,7 @@ import six
from openstackclient.common import command
from openstackclient.common import exceptions
from openstackclient.common import utils
+from openstackclient.i18n import _
from openstackclient.identity import common
@@ -31,17 +32,17 @@ class AuthorizeRequestToken(command.ShowOne):
parser.add_argument(
'--request-key',
metavar='<request-key>',
- help='Request token to authorize (ID only) (required)',
- required=True
+ required=True,
+ help=_('Request token to authorize (ID only) (required)'),
)
parser.add_argument(
'--role',
metavar='<role>',
action='append',
default=[],
- help='Roles to authorize (name or ID) '
- '(repeat option to set multiple values, required)',
- required=True
+ required=True,
+ help=_('Roles to authorize (name or ID) '
+ '(repeat option to set multiple values, required)'),
)
return parser
@@ -72,31 +73,31 @@ class CreateAccessToken(command.ShowOne):
parser.add_argument(
'--consumer-key',
metavar='<consumer-key>',
- help='Consumer key (required)',
+ help=_('Consumer key (required)'),
required=True
)
parser.add_argument(
'--consumer-secret',
metavar='<consumer-secret>',
- help='Consumer secret (required)',
+ help=_('Consumer secret (required)'),
required=True
)
parser.add_argument(
'--request-key',
metavar='<request-key>',
- help='Request token to exchange for access token (required)',
+ help=_('Request token to exchange for access token (required)'),
required=True
)
parser.add_argument(
'--request-secret',
metavar='<request-secret>',
- help='Secret associated with <request-key> (required)',
+ help=_('Secret associated with <request-key> (required)'),
required=True
)
parser.add_argument(
'--verifier',
metavar='<verifier>',
- help='Verifier associated with <request-key> (required)',
+ help=_('Verifier associated with <request-key> (required)'),
required=True
)
return parser
@@ -118,26 +119,26 @@ class CreateRequestToken(command.ShowOne):
parser.add_argument(
'--consumer-key',
metavar='<consumer-key>',
- help='Consumer key (required)',
+ help=_('Consumer key (required)'),
required=True
)
parser.add_argument(
'--consumer-secret',
metavar='<consumer-secret>',
- help='Consumer secret (required)',
+ help=_('Consumer secret (required)'),
required=True
)
parser.add_argument(
'--project',
metavar='<project>',
- help='Project that consumer wants to access (name or ID)'
- ' (required)',
+ 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)',
+ help=_('Domain owning <project> (name or ID)'),
)
return parser
@@ -175,7 +176,7 @@ class IssueToken(command.ShowOne):
def take_action(self, parsed_args):
if not self.app.client_manager.auth_ref:
raise exceptions.AuthorizationFailure(
- "Only an authorized user may issue a new token.")
+ _("Only an authorized user may issue a new token."))
token = self.app.client_manager.auth_ref.service_catalog.get_token()
if 'tenant_id' in token:
token['project_id'] = token.pop('tenant_id')
@@ -190,7 +191,7 @@ class RevokeToken(command.Command):
parser.add_argument(
'token',
metavar='<token>',
- help='Token to be deleted',
+ help=_('Token to be deleted'),
)
return parser
diff --git a/openstackclient/identity/v3/trust.py b/openstackclient/identity/v3/trust.py
index b6f5c6b..336b703 100644
--- a/openstackclient/identity/v3/trust.py
+++ b/openstackclient/identity/v3/trust.py
@@ -18,6 +18,7 @@ import six
from openstackclient.common import command
from openstackclient.common import utils
+from openstackclient.i18n import _
from openstackclient.identity import common
@@ -29,26 +30,26 @@ class CreateTrust(command.ShowOne):
parser.add_argument(
'trustor',
metavar='<trustor-user>',
- help='User that is delegating authorization (name or ID)',
+ help=_('User that is delegating authorization (name or ID)'),
)
parser.add_argument(
'trustee',
metavar='<trustee-user>',
- help='User that is assuming authorization (name or ID)',
+ help=_('User that is assuming authorization (name or ID)'),
)
parser.add_argument(
'--project',
metavar='<project>',
required=True,
- help='Project being delegated (name or ID) (required)',
+ help=_('Project being delegated (name or ID) (required)'),
)
parser.add_argument(
'--role',
metavar='<role>',
action='append',
default=[],
- help='Roles to authorize (name or ID) '
- '(repeat option to set multiple values, required)',
+ help=_('Roles to authorize (name or ID) '
+ '(repeat option to set multiple values, required)'),
required=True
)
parser.add_argument(
@@ -56,25 +57,25 @@ class CreateTrust(command.ShowOne):
dest='impersonate',
action='store_true',
default=False,
- help='Tokens generated from the trust will represent <trustor>'
- ' (defaults to False)',
+ help=_('Tokens generated from the trust will represent <trustor>'
+ ' (defaults to False)'),
)
parser.add_argument(
'--expiration',
metavar='<expiration>',
- help='Sets an expiration date for the trust'
- ' (format of YYYY-mm-ddTHH:MM:SS)',
+ help=_('Sets an expiration date for the trust'
+ ' (format of YYYY-mm-ddTHH:MM:SS)'),
)
common.add_project_domain_option_to_parser(parser)
parser.add_argument(
'--trustor-domain',
metavar='<trustor-domain>',
- help='Domain that contains <trustor> (name or ID)',
+ help=_('Domain that contains <trustor> (name or ID)'),
)
parser.add_argument(
'--trustee-domain',
metavar='<trustee-domain>',
- help='Domain that contains <trustee> (name or ID)',
+ help=_('Domain that contains <trustee> (name or ID)'),
)
return parser
@@ -136,8 +137,8 @@ class DeleteTrust(command.Command):
parser.add_argument(
'trust',
metavar='<trust>',
- help='Trust(s) to delete',
nargs="+",
+ help=_('Trust(s) to delete'),
)
return parser
@@ -170,7 +171,7 @@ class ShowTrust(command.ShowOne):
parser.add_argument(
'trust',
metavar='<trust>',
- help='Trust to display',
+ help=_('Trust to display'),
)
return parser
diff --git a/openstackclient/identity/v3/unscoped_saml.py b/openstackclient/identity/v3/unscoped_saml.py
index 8e2616a..5cb8e48 100644
--- a/openstackclient/identity/v3/unscoped_saml.py
+++ b/openstackclient/identity/v3/unscoped_saml.py
@@ -20,6 +20,7 @@ a scoped token."""
from openstackclient.common import command
from openstackclient.common import exceptions
from openstackclient.common import utils
+from openstackclient.i18n import _
UNSCOPED_AUTH_PLUGINS = ['v3unscopedsaml', 'v3unscopedadfs', 'v3oidc']
@@ -33,10 +34,10 @@ def auth_with_unscoped_saml(func):
if auth_plugin_name in UNSCOPED_AUTH_PLUGINS:
return func(self, parsed_args)
else:
- msg = ('This command requires the use of an unscoped SAML '
- 'authentication plugin. Please use argument '
- '--os-auth-type with one of the following '
- 'plugins: ' + ', '.join(UNSCOPED_AUTH_PLUGINS))
+ msg = (_('This command requires the use of an unscoped SAML '
+ 'authentication plugin. Please use argument '
+ '--os-auth-type with one of the following '
+ 'plugins: %s') % ', '.join(UNSCOPED_AUTH_PLUGINS))
raise exceptions.CommandError(msg)
return _decorated
diff --git a/openstackclient/identity/v3/user.py b/openstackclient/identity/v3/user.py
index 9a7ced9..a71b4b7 100644
--- a/openstackclient/identity/v3/user.py
+++ b/openstackclient/identity/v3/user.py
@@ -35,50 +35,50 @@ class CreateUser(command.ShowOne):
parser.add_argument(
'name',
metavar='<name>',
- help='New user name',
+ help=_('New user name'),
)
parser.add_argument(
'--domain',
metavar='<domain>',
- help='Default domain (name or ID)',
+ help=_('Default domain (name or ID)'),
)
parser.add_argument(
'--project',
metavar='<project>',
- help='Default project (name or ID)',
+ help=_('Default project (name or ID)'),
)
common.add_project_domain_option_to_parser(parser)
parser.add_argument(
'--password',
metavar='<password>',
- help='Set user password',
+ help=_('Set user password'),
)
parser.add_argument(
'--password-prompt',
dest="password_prompt",
action="store_true",
- help='Prompt interactively for password',
+ help=_('Prompt interactively for password'),
)
parser.add_argument(
'--email',
metavar='<email-address>',
- help='Set user email address',
+ help=_('Set user email address'),
)
parser.add_argument(
'--description',
metavar='<description>',
- help='User description',
+ help=_('User description'),
)
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
'--enable',
action='store_true',
- help='Enable user (default)',
+ help=_('Enable user (default)'),
)
enable_group.add_argument(
'--disable',
action='store_true',
- help='Disable user',
+ help=_('Disable user'),
)
parser.add_argument(
'--or-show',
@@ -122,7 +122,7 @@ class CreateUser(command.ShowOne):
user = utils.find_resource(identity_client.users,
parsed_args.name,
domain_id=domain_id)
- self.log.info('Returning existing user %s', user.name)
+ self.log.info(_('Returning existing user %s'), user.name)
else:
raise e
@@ -139,12 +139,12 @@ class DeleteUser(command.Command):
'users',
metavar='<user>',
nargs="+",
- help='User(s) to delete (name or ID)',
+ help=_('User(s) to delete (name or ID)'),
)
parser.add_argument(
'--domain',
metavar='<domain>',
- help='Domain owning <user> (name or ID)',
+ help=_('Domain owning <user> (name or ID)'),
)
return parser
@@ -173,24 +173,24 @@ class ListUser(command.Lister):
parser.add_argument(
'--domain',
metavar='<domain>',
- help='Filter users by <domain> (name or ID)',
+ help=_('Filter users by <domain> (name or ID)'),
)
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)',
+ 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)',
+ help=_('Filter users by <project> (name or ID)'),
)
parser.add_argument(
'--long',
action='store_true',
default=False,
- help='List additional fields in output',
+ help=_('List additional fields in output'),
)
return parser
@@ -273,50 +273,50 @@ class SetUser(command.Command):
parser.add_argument(
'user',
metavar='<user>',
- help='User to change (name or ID)',
+ help=_('User to change (name or ID)'),
)
parser.add_argument(
'--name',
metavar='<name>',
- help='Set user name',
+ help=_('Set user name'),
)
parser.add_argument(
'--project',
metavar='<project>',
- help='Set default project (name or ID)',
+ help=_('Set default project (name or ID)'),
)
common.add_project_domain_option_to_parser(parser)
parser.add_argument(
'--password',
metavar='<password>',
- help='Set user password',
+ help=_('Set user password'),
)
parser.add_argument(
'--password-prompt',
dest="password_prompt",
action="store_true",
- help='Prompt interactively for password',
+ help=_('Prompt interactively for password'),
)
parser.add_argument(
'--email',
metavar='<email-address>',
- help='Set user email address',
+ help=_('Set user email address'),
)
parser.add_argument(
'--description',
metavar='<description>',
- help='Set user description',
+ help=_('Set user description'),
)
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
'--enable',
action='store_true',
- help='Enable user (default)',
+ help=_('Enable user (default)'),
)
enable_group.add_argument(
'--disable',
action='store_true',
- help='Disable user',
+ help=_('Disable user'),
)
return parser
@@ -334,9 +334,8 @@ class SetUser(command.Command):
and not parsed_args.description
and not parsed_args.enable
and not parsed_args.disable):
- sys.stderr.write("Incorrect set of arguments "
- "provided. See openstack --help for more "
- "details\n")
+ sys.stderr.write(_("Incorrect set of arguments provided. "
+ "See openstack --help for more details\n"))
return
user = utils.find_resource(
@@ -369,17 +368,19 @@ class SetUser(command.Command):
class SetPasswordUser(command.Command):
"""Change current user password"""
+ required_scope = False
+
def get_parser(self, prog_name):
parser = super(SetPasswordUser, self).get_parser(prog_name)
parser.add_argument(
'--password',
metavar='<new-password>',
- help='New user password'
+ help=_('New user password'),
)
parser.add_argument(
'--original-password',
metavar='<original-password>',
- help='Original user password'
+ help=_('Original user password'),
)
return parser
@@ -427,12 +428,12 @@ class ShowUser(command.ShowOne):
parser.add_argument(
'user',
metavar='<user>',
- help='User to display (name or ID)',
+ help=_('User to display (name or ID)'),
)
parser.add_argument(
'--domain',
metavar='<domain>',
- help='Domain owning <user> (name or ID)',
+ help=_('Domain owning <user> (name or ID)'),
)
return parser
diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py
index a9c0f1f..fa1de42 100644
--- a/openstackclient/image/v2/image.py
+++ b/openstackclient/image/v2/image.py
@@ -805,8 +805,8 @@ class SetImage(command.Command):
# Checks if anything that requires getting the image
if not (kwargs or parsed_args.deactivate or parsed_args.activate):
- self.log.warning(_("No arguments specified"))
- return {}, {}
+ msg = _("No arguments specified")
+ raise exceptions.CommandError(msg)
image = utils.find_resource(
image_client.images, parsed_args.image)
@@ -856,3 +856,88 @@ class ShowImage(command.ShowOne):
info = _format_image(image)
return zip(*sorted(six.iteritems(info)))
+
+
+class UnsetImage(command.Command):
+ """Unset image tags and properties"""
+
+ def get_parser(self, prog_name):
+ parser = super(UnsetImage, self).get_parser(prog_name)
+ parser.add_argument(
+ "image",
+ metavar="<image>",
+ help=_("Image to modify (name or ID)"),
+ )
+ parser.add_argument(
+ "--tag",
+ dest="tags",
+ metavar="<tag>",
+ default=[],
+ action='append',
+ help=_("Unset a tag on this image "
+ "(repeat option to set multiple tags)"),
+ )
+ parser.add_argument(
+ "--property",
+ dest="properties",
+ metavar="<property_key>",
+ default=[],
+ action='append',
+ help=_("Unset a property on this image "
+ "(repeat option to set multiple properties)"),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ image_client = self.app.client_manager.image
+ image = utils.find_resource(
+ image_client.images,
+ parsed_args.image,
+ )
+
+ if not (parsed_args.tags or parsed_args.properties):
+ msg = _("No arguments specified")
+ raise exceptions.CommandError(msg)
+
+ kwargs = {}
+ tagret = 0
+ propret = 0
+ if parsed_args.tags:
+ for k in parsed_args.tags:
+ try:
+ image_client.image_tags.delete(image.id, k)
+ except Exception:
+ self.log.error(_("tag unset failed,"
+ " '%s' is a nonexistent tag ") % k)
+ tagret += 1
+
+ if parsed_args.properties:
+ for k in parsed_args.properties:
+ try:
+ assert(k in image.keys())
+ except AssertionError:
+ self.log.error(_("property unset failed,"
+ " '%s' is a nonexistent property ") % k)
+ propret += 1
+ image_client.images.update(
+ image.id,
+ parsed_args.properties,
+ **kwargs)
+
+ tagtotal = len(parsed_args.tags)
+ proptotal = len(parsed_args.properties)
+ if (tagret > 0 and propret > 0):
+ msg = (_("Failed to unset %(tagret)s of %(tagtotal)s tags,"
+ "Failed to unset %(propret)s of %(proptotal)s properties.")
+ % {'tagret': tagret, 'tagtotal': tagtotal,
+ 'propret': propret, 'proptotal': proptotal})
+ raise exceptions.CommandError(msg)
+ elif tagret > 0:
+ msg = (_("Failed to unset %(tagret)s of %(tagtotal)s tags.")
+ % {'tagret': tagret, 'tagtotal': tagtotal})
+ raise exceptions.CommandError(msg)
+ elif propret > 0:
+ msg = (_("Failed to unset %(propret)s of %(proptotal)s"
+ " properties.")
+ % {'propret': propret, 'proptotal': proptotal})
+ raise exceptions.CommandError(msg)
diff --git a/openstackclient/locale/de/LC_MESSAGES/openstackclient.po b/openstackclient/locale/de/LC_MESSAGES/openstackclient.po
index f7445b1..06f1c8d 100644
--- a/openstackclient/locale/de/LC_MESSAGES/openstackclient.po
+++ b/openstackclient/locale/de/LC_MESSAGES/openstackclient.po
@@ -8,13 +8,13 @@
# Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
msgid ""
msgstr ""
-"Project-Id-Version: python-openstackclient 2.2.1.dev235\n"
+"Project-Id-Version: python-openstackclient 2.5.1.dev51\n"
"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-04-19 05:02+0000\n"
+"POT-Creation-Date: 2016-06-03 19:37+0000\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"PO-Revision-Date: 2015-09-19 07:10+0000\n"
+"PO-Revision-Date: 2016-06-02 01:43+0000\n"
"Last-Translator: Andreas Jaeger <jaegerandi@gmail.com>\n"
"Language: de\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@@ -22,69 +22,6 @@ msgstr ""
"X-Generator: Zanata 3.7.3\n"
"Language-Team: German\n"
-msgid ""
-"\n"
-"Complete\n"
-msgstr ""
-"\n"
-"Fertig\n"
-
-msgid ""
-"\n"
-"Error creating server"
-msgstr ""
-"\n"
-"Fehler beim Erstellen des Servers"
-
-msgid ""
-"\n"
-"Error creating server snapshot"
-msgstr ""
-"\n"
-"Fehler beim Erstellen der Server-Schattenkopie"
-
-msgid ""
-"\n"
-"Error deleting server"
-msgstr ""
-"\n"
-"Fehler beim Löschen des Servers"
-
-msgid ""
-"\n"
-"Error migrating server"
-msgstr ""
-"\n"
-"Fehler beim Migrieren des Servers"
-
-msgid ""
-"\n"
-"Error rebooting server\n"
-msgstr ""
-"\n"
-"Fehler beim Neustarten des Servers\n"
-
-msgid ""
-"\n"
-"Error rebuilding server"
-msgstr ""
-"\n"
-"Fehler bei der Wiederherstellung des Servers"
-
-msgid ""
-"\n"
-"Error resizing server"
-msgstr ""
-"\n"
-"Fehler bei der Größenänderung des Servers"
-
-msgid ""
-"\n"
-"Reboot complete\n"
-msgstr ""
-"\n"
-"Neustart abgeschlossen\n"
-
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 "
@@ -93,6 +30,9 @@ msgstr ""
msgid "Allow disk over-commit on the destination host"
msgstr "Festplattenüberladung auf dem Zielhost erlauben"
+msgid "Availability zone name"
+msgstr "Name der Verfügbarkeitszone"
+
msgid "Complete\n"
msgstr "Fertig\n"
@@ -138,6 +78,9 @@ msgstr "Anmeldedaten für Benutzer löschen (name or ID)"
msgid "Destination port (ssh -p option)"
msgstr "Zielport (ssh -p Option)"
+msgid "Disable a service"
+msgstr "Dienst deaktivieren"
+
msgid "Disable project"
msgstr "Projekt deaktivieren"
@@ -162,13 +105,19 @@ msgstr "Benutzer aktivieren (Standardeinstellung)"
msgid "Endpoint ID to delete"
msgstr "Zu löschende Endpunktkennung"
-msgid "Endpoint ID to display"
-msgstr "Anzuzeigende Endpunktkennung"
+msgid "Error creating server\n"
+msgstr "Fehler beim Erstellen des Servers\n"
+
+msgid "Error creating server snapshot\n"
+msgstr "Fehler beim Erstellen der Server-Schattenkopie\n"
#, python-format
msgid "Error creating server: %s"
msgstr "Fehler beim Erstellen des Servers: %s"
+msgid "Error deleting server\n"
+msgstr "Fehler beim Löschen des Servers\n"
+
#, python-format
msgid "Error deleting server: %s"
msgstr "Fehler beim Löschen des Servers: %s"
@@ -188,6 +137,9 @@ msgstr "Benutzer nach <project> filtern (Name oder Kennung)"
msgid "Filter users by project (name or ID)"
msgstr "Benutzer nach Projekt filtern (Name oder Kennung)"
+msgid "Floating IP address"
+msgstr "Bewegliche IP-Adresse"
+
msgid "Hints for the scheduler (optional extension)"
msgstr "Hinweise für den Planer (optionale Erweiterung)"
@@ -209,6 +161,9 @@ msgstr "Zusätzliche Felder in der Ausgabe auflisten"
msgid "Login name (ssh -l option)"
msgstr "Anmeldename (ssh -l Option)"
+msgid "MD5 hash"
+msgstr "MD5-Hashwert"
+
msgid ""
"Map block devices; map is <id>:<type>:<size(GB)>:<delete_on_terminate> "
"(optional extension)"
@@ -442,27 +397,27 @@ msgstr ""
"OS_DOMAIN_NAME oder auth.domain_name."
msgid ""
-"Set a service AUTH_URL, with --os-auth-url, OS_AUTH_URL or auth.auth_url\n"
+"Set a service AUTH_URL, with --os-auth-url, OS_AUTH_URL or auth.auth_url"
msgstr ""
"Legen Sie eine Dienst-AUTH_URL mit --os-auth-url, OS_AUTH_URL oder auth."
-"auth_url fest\n"
+"auth_url fest"
-msgid "Set a service URL, with --os-url, OS_URL or auth.url\n"
-msgstr "Legen Sie eine Dienst-URL mit --os-url, OS_URL oder auth.url fest\n"
+msgid "Set a service URL, with --os-url, OS_URL or auth.url"
+msgstr "Legen Sie eine Dienst-URL mit --os-url, OS_URL oder auth.url fest"
-msgid "Set a token with --os-token, OS_TOKEN or auth.token\n"
-msgstr "Legen Sie einen Token mit --os-token, OS_TOKEN oder auth.token fest\n"
+msgid "Set a token with --os-token, OS_TOKEN or auth.token"
+msgstr "Legen Sie einen Token mit --os-token, OS_TOKEN oder auth.token fest"
-msgid "Set a username with --os-username, OS_USERNAME, or auth.username\n"
+msgid "Set a username with --os-username, OS_USERNAME, or auth.username"
msgstr ""
"Legen Sie einen Benutzernamen mit --os-username, OS_USERNAME oder auth."
-"username fest\n"
+"username fest"
msgid ""
-"Set an authentication URL, with --os-auth-url, OS_AUTH_URL or auth.auth_url\n"
+"Set an authentication URL, with --os-auth-url, OS_AUTH_URL or auth.auth_url"
msgstr ""
"Legen Sie eine Authentifizierungs-URL mit --os-auth-url, OS_AUTH_URL oder "
-"auth.auth_url fest\n"
+"auth.auth_url fest"
msgid "Set default project (name or ID)"
msgstr "Standardprojekt festlegen (Name oder Kennung)"
@@ -504,6 +459,9 @@ msgstr ""
msgid "Token to be deleted"
msgstr "Zu löschender Token"
+msgid "URL"
+msgstr "URL"
+
msgid "Use only IPv4 addresses"
msgstr "Nur IPv4-Adressen verwenden"
@@ -543,6 +501,9 @@ msgstr "Aufzulistender Benutzer (Name oder Kennung)"
msgid "User(s) to delete (name or ID)"
msgstr "Zu löschende(r) Benutzer (Name oder Kennung)"
+msgid "Version"
+msgstr "Version"
+
msgid "Volume to add (name or ID)"
msgstr "Zu hinzufügender Datenträger (Name oder Kennung)"
diff --git a/openstackclient/locale/openstackclient.pot b/openstackclient/locale/openstackclient.pot
deleted file mode 100644
index e197fa7..0000000
--- a/openstackclient/locale/openstackclient.pot
+++ /dev/null
@@ -1,1410 +0,0 @@
-# Translations template for python-openstackclient.
-# Copyright (C) 2016 ORGANIZATION
-# This file is distributed under the same license as the
-# python-openstackclient project.
-# FIRST AUTHOR <EMAIL@ADDRESS>, 2016.
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: python-openstackclient 2.2.1.dev235\n"
-"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-04-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"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Generated-By: Babel 2.2.0\n"
-
-#: openstackclient/api/auth.py:148
-msgid "Set a username with --os-username, OS_USERNAME, or auth.username\n"
-msgstr ""
-
-#: openstackclient/api/auth.py:151
-msgid ""
-"Set an authentication URL, with --os-auth-url, OS_AUTH_URL or "
-"auth.auth_url\n"
-msgstr ""
-
-#: openstackclient/api/auth.py:160
-msgid ""
-"Set a scope, such as a project or domain, set a project scope with --os-"
-"project-name, OS_PROJECT_NAME or auth.project_name, set a domain scope "
-"with --os-domain-name, OS_DOMAIN_NAME or auth.domain_name"
-msgstr ""
-
-#: openstackclient/api/auth.py:166 openstackclient/api/auth.py:172
-msgid "Set a token with --os-token, OS_TOKEN or auth.token\n"
-msgstr ""
-
-#: openstackclient/api/auth.py:168
-msgid "Set a service AUTH_URL, with --os-auth-url, OS_AUTH_URL or auth.auth_url\n"
-msgstr ""
-
-#: openstackclient/api/auth.py:174
-msgid "Set a service URL, with --os-url, OS_URL or auth.url\n"
-msgstr ""
-
-#: openstackclient/common/availability_zone.py:110
-#: openstackclient/compute/v2/server.py:757
-#: openstackclient/identity/v2_0/endpoint.py:101
-#: openstackclient/identity/v2_0/project.py:133
-#: openstackclient/identity/v2_0/service.py:115
-#: openstackclient/identity/v2_0/user.py:162
-#: openstackclient/network/v2/router.py:230
-#: openstackclient/network/v2/subnet.py:299
-#: openstackclient/network/v2/subnet_pool.py:165
-msgid "List additional fields in output"
-msgstr ""
-
-#: openstackclient/common/parseractions.py:99
-#, python-format
-msgid ""
-"Invalid keys %(invalid_keys)s specified.\n"
-"Valid keys are: %(valid_keys)s."
-msgstr ""
-
-#: openstackclient/common/parseractions.py:109
-#, python-format
-msgid ""
-"Missing required keys %(missing_keys)s.\n"
-"Required keys are: %(required_keys)s."
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:195
-#: openstackclient/compute/v2/server.py:227
-#: openstackclient/compute/v2/server.py:598
-#: openstackclient/compute/v2/server.py:937
-#: openstackclient/compute/v2/server.py:1039
-#: openstackclient/compute/v2/server.py:1091
-#: openstackclient/compute/v2/server.py:1177
-#: openstackclient/compute/v2/server.py:1213
-#: openstackclient/compute/v2/server.py:1236
-#: openstackclient/compute/v2/server.py:1343
-#: openstackclient/compute/v2/server.py:1421
-#: openstackclient/compute/v2/server.py:1455
-#: openstackclient/compute/v2/server.py:1712
-#: openstackclient/compute/v2/server.py:1733
-msgid "Server (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:200
-msgid "Security group to add (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:232
-msgid "Volume to add (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:237
-msgid "Server internal device name for volume"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:269
-#: openstackclient/compute/v2/server.py:1348
-msgid "New server name"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:277
-msgid "Create server from this image (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:282
-msgid "Create server from this volume (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:288
-msgid "Create server with this flavor (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:295
-msgid ""
-"Security group to assign to this server (name or ID) (repeat option to "
-"set multiple groups)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:301
-msgid "Keypair to inject into this server (optional extension)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:307
-msgid "Set a property on this server (repeat option to set multiple values)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:315
-msgid ""
-"File to inject into image before boot (repeat option to set multiple "
-"files)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:321
-msgid "User data file to serve from the metadata server"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:326
-msgid "Select an availability zone for the server"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:333
-msgid ""
-"Map block devices; map is <id>:<type>:<size(GB)>:<delete_on_terminate> "
-"(optional extension)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:343
-msgid ""
-"Create a NIC on the server. Specify option multiple times to create "
-"multiple NICs. Either net-id or port-id must be provided, but not both. "
-"net-id: attach NIC to network with this UUID, port-id: attach NIC to port"
-" with this UUID, v4-fixed-ip: IPv4 fixed address for NIC (optional), v6"
-"-fixed-ip: IPv6 fixed address for NIC (optional)."
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:356
-msgid "Hints for the scheduler (optional extension)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:362
-msgid ""
-"Use specified volume as the config drive, or 'True' to use an ephemeral "
-"drive"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:370
-msgid "Minimum number of servers to launch (default=1)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:377
-msgid "Maximum number of servers to launch (default=1)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:382
-msgid "Wait for build to complete"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:421
-msgid "min instances should be <= max instances"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:424
-msgid "min instances should be > 0"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:427
-msgid "max instances should be > 0"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:456
-msgid "Volume name or ID must be specified if --block-device-mapping is specified"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:468
-msgid "either net-id or port-id should be specified but not both"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:488
-msgid "can't create server with port specified since network endpoint not enabled"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:553
-#, python-format
-msgid "Error creating server: %s"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:555
-msgid ""
-"\n"
-"Error creating server"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:577
-msgid "Server(s) to create dump file (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:603
-msgid "Name of new image (default is server name)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:608
-msgid "Wait for image create to complete"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:637
-#, python-format
-msgid "Error creating snapshot of server: %s"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:639
-msgid ""
-"\n"
-"Error creating server snapshot"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:656
-msgid "Server(s) to delete (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:661
-msgid "Wait for delete to complete"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:679
-#, python-format
-msgid "Error deleting server: %s"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:681
-msgid ""
-"\n"
-"Error deleting server"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:693
-msgid "Only return instances that match the reservation"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:698
-msgid "Regular expression to match IP addresses"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:703
-msgid "Regular expression to match IPv6 addresses"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:708
-msgid "Regular expression to match names"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:713
-msgid "Regular expression to match instance name (admin only)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:719
-msgid "Search by server status"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:724
-msgid "Search by flavor (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:729
-msgid "Search by image (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:734
-msgid "Search by hostname"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:740
-msgid "Include all projects (admin only)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:750
-msgid "Search by user (admin only) (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:905
-msgid "Server(s) to lock (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:942
-msgid "Target hostname"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:950
-msgid "Perform a shared live migration (default)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:956
-msgid "Perform a block live migration"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:963
-msgid "Allow disk over-commit on the destination host"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:970
-msgid "Do not over-commit disk on the destination host (default)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:976
-#: openstackclient/compute/v2/server.py:1256
-msgid "Wait for resize to complete"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1003
-#: openstackclient/compute/v2/server.py:1280
-msgid "Complete\n"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1005
-msgid ""
-"\n"
-"Error migrating server"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1018
-msgid "Server(s) to pause (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1048
-msgid "Perform a hard reboot"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1056
-msgid "Perform a soft reboot"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1061
-msgid "Wait for reboot to complete"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1077
-msgid ""
-"\n"
-"Reboot complete\n"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1079
-msgid ""
-"\n"
-"Error rebooting server\n"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1096
-msgid ""
-"Recreate server from the specified image (name or ID). Defaults to the "
-"currently used one."
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1107
-msgid "Wait for rebuild to complete"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1128
-msgid ""
-"\n"
-"Complete\n"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1130
-msgid ""
-"\n"
-"Error rebuilding server"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1145
-msgid "Name or ID of server to use"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1150
-msgid "Name or ID of security group to remove from server"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1182
-msgid "Volume to remove (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1241
-msgid "Resize server to specified flavor"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1246
-msgid "Confirm server resize is complete"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1251
-msgid "Restore server state before resize"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1282
-msgid ""
-"\n"
-"Error resizing server"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1299
-msgid "Server(s) to restore (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1321
-msgid "Server(s) to resume (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1353
-msgid "Set new root password (interactive only)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1359
-msgid ""
-"Property to add/change for this server (repeat option to set multiple "
-"properties)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1382
-msgid "New password: "
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1383
-msgid "Retype new password: "
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1387
-msgid "Passwords do not match, password unchanged"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1400
-msgid "Server(s) to shelve (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1427
-msgid "Display server diagnostics information"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1439
-msgid "Error retrieving diagnostics data"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1460
-msgid "Login name (ssh -l option)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1472
-msgid "Destination port (ssh -p option)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1484
-msgid "Private key file (ssh -i option)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1495
-msgid "Options in ssh_config(5) format (ssh -o option)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1509
-msgid "Use only IPv4 addresses"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1516
-msgid "Use only IPv6 addresses"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1525
-msgid "Use public IP address"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1533
-msgid "Use private IP address"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1540
-msgid "Use other IP address (public, private, etc)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1600
-msgid "Server(s) to start (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1622
-msgid "Server(s) to stop (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1644
-msgid "Server(s) to suspend (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1667
-msgid "Server(s) to unlock (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1690
-msgid "Server(s) to unpause (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1740
-msgid ""
-"Property key to remove from server (repeat option to remove multiple "
-"values)"
-msgstr ""
-
-#: openstackclient/compute/v2/server.py:1768
-msgid "Server(s) to unshelve (name or ID)"
-msgstr ""
-
-#: openstackclient/compute/v2/service.py:138
-msgid "argument --disable-reason has been ignored"
-msgstr ""
-
-#: openstackclient/identity/v2_0/catalog.py:67
-#: openstackclient/identity/v3/catalog.py:64
-msgid "Service to display (type or name)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/ec2creds.py:34
-#: openstackclient/identity/v3/ec2creds.py:59
-msgid ""
-"Create credentials in project (name or ID; default: current authenticated"
-" project)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/ec2creds.py:42
-#: openstackclient/identity/v3/ec2creds.py:67
-msgid ""
-"Create credentials for user (name or ID; default: current authenticated "
-"user)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/ec2creds.py:90
-#: openstackclient/identity/v2_0/ec2creds.py:157
-#: openstackclient/identity/v3/ec2creds.py:120
-#: openstackclient/identity/v3/ec2creds.py:172
-msgid "Credentials access key"
-msgstr ""
-
-#: openstackclient/identity/v2_0/ec2creds.py:95
-#: openstackclient/identity/v3/ec2creds.py:125
-msgid "Delete credentials for user (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/ec2creds.py:122
-#: openstackclient/identity/v3/ec2creds.py:144
-msgid "Filter list by user (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/ec2creds.py:162
-#: openstackclient/identity/v3/ec2creds.py:177
-msgid "Show credentials for user (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/endpoint.py:34
-msgid "New endpoint service (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/endpoint.py:40
-msgid "New endpoint public URL (required)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/endpoint.py:45
-msgid "New endpoint admin URL"
-msgstr ""
-
-#: openstackclient/identity/v2_0/endpoint.py:50
-msgid "New endpoint internal URL"
-msgstr ""
-
-#: openstackclient/identity/v2_0/endpoint.py:55
-msgid "New endpoint region ID"
-msgstr ""
-
-#: openstackclient/identity/v2_0/endpoint.py:84
-msgid "Endpoint ID to delete"
-msgstr ""
-
-#: openstackclient/identity/v2_0/endpoint.py:133
-msgid "Endpoint ID to display"
-msgstr ""
-
-#: openstackclient/identity/v2_0/project.py:36
-msgid "New project name"
-msgstr ""
-
-#: openstackclient/identity/v2_0/project.py:41
-msgid "Project description"
-msgstr ""
-
-#: openstackclient/identity/v2_0/project.py:47
-msgid "Enable project (default)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/project.py:52
-#: openstackclient/identity/v2_0/project.py:179
-msgid "Disable project"
-msgstr ""
-
-#: openstackclient/identity/v2_0/project.py:58
-msgid "Add a property to <name> (repeat option to set multiple properties)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/project.py:64
-#: openstackclient/identity/v3/project.py:75
-msgid "Return existing project"
-msgstr ""
-
-#: openstackclient/identity/v2_0/project.py:109
-msgid "Project(s) to delete (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/project.py:158
-#: openstackclient/identity/v2_0/project.py:291
-msgid "Project to modify (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/project.py:163
-msgid "Set project name"
-msgstr ""
-
-#: openstackclient/identity/v2_0/project.py:168
-msgid "Set project description"
-msgstr ""
-
-#: openstackclient/identity/v2_0/project.py:174
-msgid "Enable project"
-msgstr ""
-
-#: openstackclient/identity/v2_0/project.py:185
-msgid "Set a project property (repeat option to set multiple properties)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/project.py:234
-msgid "Project to display (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/project.py:298
-msgid "Unset a project property (repeat option to unset multiple properties)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/role.py:36
-msgid "Role to add to <project>:<user> (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/role.py:42
-#: openstackclient/identity/v2_0/role.py:288
-msgid "Include <project> (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/role.py:48
-#: openstackclient/identity/v2_0/role.py:294
-msgid "Include <user> (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/role.py:79
-msgid "New role name"
-msgstr ""
-
-#: openstackclient/identity/v2_0/role.py:84
-#: openstackclient/identity/v3/role.py:155
-msgid "Return existing role"
-msgstr ""
-
-#: openstackclient/identity/v2_0/role.py:116
-msgid "Role(s) to delete (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/role.py:178
-#: openstackclient/identity/v2_0/role.py:238
-msgid "Project must be specified"
-msgstr ""
-
-#: openstackclient/identity/v2_0/role.py:192
-#: openstackclient/identity/v2_0/role.py:244
-msgid "User must be specified"
-msgstr ""
-
-#: openstackclient/identity/v2_0/role.py:218
-msgid "User to list (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/role.py:223
-msgid "Filter users by <project> (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/role.py:282
-msgid "Role to remove (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/role.py:320
-msgid "Role to display (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/service.py:36
-msgid "New service type (compute, image, identity, volume, etc)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/service.py:47
-msgid "New service name"
-msgstr ""
-
-#: openstackclient/identity/v2_0/service.py:52
-msgid "New service description"
-msgstr ""
-
-#: openstackclient/identity/v2_0/service.py:71
-msgid ""
-"The argument --type is deprecated, use service create --name <service-"
-"name> type instead."
-msgstr ""
-
-#: openstackclient/identity/v2_0/service.py:96
-msgid "Service to delete (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/service.py:140
-msgid "Service to display (type, name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/service.py:146
-msgid "Show service catalog information"
-msgstr ""
-
-#: openstackclient/identity/v2_0/service.py:163
-#, python-format
-msgid "No service catalog with a type, name or ID of '%s' exists."
-msgstr ""
-
-#: openstackclient/identity/v2_0/token.py:50
-msgid "Token to be deleted"
-msgstr ""
-
-#: openstackclient/identity/v2_0/user.py:35
-msgid "New user name"
-msgstr ""
-
-#: openstackclient/identity/v2_0/user.py:40
-msgid "Default project (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/user.py:45
-#: openstackclient/identity/v2_0/user.py:258
-msgid "Set user password"
-msgstr ""
-
-#: openstackclient/identity/v2_0/user.py:51
-#: openstackclient/identity/v2_0/user.py:264
-msgid "Prompt interactively for password"
-msgstr ""
-
-#: openstackclient/identity/v2_0/user.py:56
-#: openstackclient/identity/v2_0/user.py:269
-msgid "Set user email address"
-msgstr ""
-
-#: openstackclient/identity/v2_0/user.py:62
-#: openstackclient/identity/v2_0/user.py:275
-msgid "Enable user (default)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/user.py:67
-#: openstackclient/identity/v2_0/user.py:280
-msgid "Disable user"
-msgstr ""
-
-#: openstackclient/identity/v2_0/user.py:72
-#: openstackclient/identity/v3/user.py:86
-msgid "Return existing user"
-msgstr ""
-
-#: openstackclient/identity/v2_0/user.py:133
-msgid "User(s) to delete (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/user.py:156
-msgid "Filter users by project (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/user.py:243
-msgid "User to change (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/user.py:248
-msgid "Set user name"
-msgstr ""
-
-#: openstackclient/identity/v2_0/user.py:253
-msgid "Set default project (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v2_0/user.py:342
-msgid "User to display (name or ID)"
-msgstr ""
-
-#: openstackclient/identity/v3/domain.py:57
-msgid "Return existing domain"
-msgstr ""
-
-#: openstackclient/identity/v3/group.py:130
-msgid "Return existing group"
-msgstr ""
-
-#: openstackclient/identity/v3/region.py:33
-msgid "New region ID"
-msgstr ""
-
-#: openstackclient/identity/v3/region.py:38
-msgid "Parent region ID"
-msgstr ""
-
-#: openstackclient/identity/v3/region.py:43
-#: openstackclient/identity/v3/region.py:128
-msgid "New region description"
-msgstr ""
-
-#: openstackclient/identity/v3/region.py:70
-msgid "Region ID to delete"
-msgstr ""
-
-#: openstackclient/identity/v3/region.py:88
-msgid "Filter by parent region ID"
-msgstr ""
-
-#: openstackclient/identity/v3/region.py:118
-msgid "Region to modify"
-msgstr ""
-
-#: openstackclient/identity/v3/region.py:123
-msgid "New parent region ID"
-msgstr ""
-
-#: openstackclient/identity/v3/region.py:154
-msgid "Region to display"
-msgstr ""
-
-#: openstackclient/image/v1/image.py:191 openstackclient/image/v1/image.py:609
-#: openstackclient/image/v2/image.py:283 openstackclient/image/v2/image.py:794
-msgid "The --owner option is deprecated, please use --project instead."
-msgstr ""
-
-#: openstackclient/network/v2/floating_ip.py:67
-msgid "Network to allocate floating IP from (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/floating_ip.py:75
-msgid "Subnet on which you want to create the floating IP (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/floating_ip.py:81
-msgid "Port to be associated with the floating IP (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/floating_ip.py:88
-msgid "Floating IP address"
-msgstr ""
-
-#: openstackclient/network/v2/floating_ip.py:94
-msgid "Fixed IP address mapped to the floating IP"
-msgstr ""
-
-#: openstackclient/network/v2/floating_ip.py:119
-msgid "Floating IP to delete (IP address or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/floating_ip.py:193
-msgid "Floating IP to display (IP address or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:114
-msgid "New network name"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:121
-#: openstackclient/network/v2/network.py:385
-msgid "Share the network between projects"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:126
-#: openstackclient/network/v2/network.py:390
-msgid "Do not share the network between projects"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:136
-msgid "Enable network (default)"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:141
-#: openstackclient/network/v2/network.py:378
-msgid "Disable network"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:146
-#: openstackclient/network/v2/port.py:246
-#: openstackclient/network/v2/router.py:174
-#: openstackclient/network/v2/security_group.py:116
-#: openstackclient/network/v2/security_group_rule.py:127
-#: openstackclient/network/v2/subnet.py:183
-#: openstackclient/network/v2/subnet_pool.py:114
-msgid "Owner's project (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:154
-msgid ""
-"Availability Zone in which to create this network (Network Availability "
-"Zone extension required, repeat option to set multiple availability "
-"zones)"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:162
-#: openstackclient/network/v2/network.py:396
-msgid "Set this network as an external network (external-net extension required)"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:168
-msgid "Set this network as an internal network (default)"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:174
-msgid "Specify if this network should be used as the default external network"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:180
-msgid "Do not use the network as the default external network. (default)"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:188
-msgid ""
-"The physical mechanism by which the virtual network is implemented. The "
-"supported options are: flat, gre, local, vlan, vxlan"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:196
-msgid "Name of the physical network over which the virtual network is implemented"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:203
-msgid "VLAN ID for VLAN networks or Tunnel ID for GRE/VXLAN networks"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:212
-msgid "IPv4 subnet for fixed IPs (in CIDR notation)"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:361
-msgid "Network to modify (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:366
-msgid "Set network name"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:373
-msgid "Enable network"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:402
-msgid "Set this network as an internal network"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:408
-msgid "Set the network as the default external network"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:413
-msgid "Do not use the network as the default external network"
-msgstr ""
-
-#: openstackclient/network/v2/network.py:436
-msgid "Network to display (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:73
-msgid "The --device-id option is deprecated, please use --device instead."
-msgstr ""
-
-#: openstackclient/network/v2/port.py:79
-msgid "The --host-id option is deprecated, please use --host instead."
-msgstr ""
-
-#: openstackclient/network/v2/port.py:161
-msgid "Port device ID"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:171
-msgid "Device owner of this port"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:178
-msgid ""
-"VNIC type for this port (direct | direct-physical | macvtap | normal | "
-"baremetal, default: normal)"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:187
-msgid "Allocate port on host <host-id> (ID only)"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:206
-msgid "Network this port belongs to (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:214
-#: openstackclient/network/v2/port.py:365
-msgid ""
-"Desired IP and/or subnet (name or ID) for this port: subnet=<subnet>,ip-"
-"address=<ip-address> (repeat option to set multiple fixed IP addresses)"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:222
-#: openstackclient/network/v2/port.py:379
-msgid ""
-"Custom data to be passed as binding:profile: <key>=<value> (repeat option"
-" to set multiple binding:profile data)"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:231
-msgid "Enable port (default)"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:236
-#: openstackclient/network/v2/port.py:352
-msgid "Disable port"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:241
-msgid "MAC address of this port"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:280
-msgid "Port(s) to delete (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:301
-msgid "List only ports attached to this router (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:347
-msgid "Enable port"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:357
-msgid "Set port name"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:372
-msgid "Clear existing information of fixed IP addresses"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:386
-msgid "Clear existing information of binding:profile"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:391
-msgid "Port to modify (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/port.py:429
-msgid "Port to display (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:99
-msgid "Router to which port will be added (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:104
-msgid "Port to be added (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:123
-msgid "Router to which subnet will be added (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:128
-msgid "Subnet to be added (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:150
-msgid "New router name"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:157
-msgid "Enable router (default)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:162
-#: openstackclient/network/v2/router.py:351
-msgid "Disable router"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:169
-msgid "Create a distributed router"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:182
-msgid ""
-"Availability Zone in which to create this router (Router Availability "
-"Zone extension required, repeat option to set multiple availability "
-"zones)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:210
-msgid "Router(s) to delete (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:283
-msgid "Router from which port will be removed (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:288
-msgid "Port to be removed (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:307
-msgid "Router from which the subnet will be removed (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:312
-msgid "Subnet to be removed (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:334
-msgid "Router to modify (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:339
-msgid "Set router name"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:346
-msgid "Enable router"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:357
-msgid "Set router to distributed mode (disabled router only)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:362
-msgid "Set router to centralized mode (disabled router only)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:372
-msgid ""
-"Routes associated with the router destination: destination subnet (in "
-"CIDR notation) gateway: nexthop IP address (repeat option to set multiple"
-" routes)"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:380
-msgid "Clear routes associated with the router"
-msgstr ""
-
-#: openstackclient/network/v2/router.py:412
-msgid "Router to display (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/security_group.py:103
-#: openstackclient/network/v2/security_group.py:249
-msgid "New security group name"
-msgstr ""
-
-#: openstackclient/network/v2/security_group.py:108
-msgid "Security group description"
-msgstr ""
-
-#: openstackclient/network/v2/security_group.py:173
-msgid "Security group to delete (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/security_group.py:208
-msgid "Display information from all projects (admin only)"
-msgstr ""
-
-#: openstackclient/network/v2/security_group.py:244
-msgid "Security group to modify (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/security_group.py:254
-msgid "New security group description"
-msgstr ""
-
-#: openstackclient/network/v2/security_group.py:299
-msgid "Security group to display (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/security_group_rule.py:82
-msgid "IP protocol (icmp, tcp, udp; default: tcp)"
-msgstr ""
-
-#: openstackclient/network/v2/security_group_rule.py:88
-msgid ""
-"Source IP address block (may use CIDR notation; default for IPv4 rule: "
-"0.0.0.0/0)"
-msgstr ""
-
-#: openstackclient/network/v2/security_group_rule.py:94
-msgid "Source security group (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/security_group_rule.py:101
-msgid ""
-"Destination port, may be a single port or port range: 137:139 (only "
-"required for IP protocols tcp and udp)"
-msgstr ""
-
-#: openstackclient/network/v2/security_group_rule.py:111
-msgid "Rule applies to incoming network traffic (default)"
-msgstr ""
-
-#: openstackclient/network/v2/security_group_rule.py:116
-msgid "Rule applies to outgoing network traffic"
-msgstr ""
-
-#: openstackclient/network/v2/security_group_rule.py:122
-msgid "Ethertype of network traffic (IPv4, IPv6; default: IPv4)"
-msgstr ""
-
-#: openstackclient/network/v2/security_group_rule.py:221
-msgid "Security group rule to delete (ID only)"
-msgstr ""
-
-#: openstackclient/network/v2/security_group_rule.py:241
-msgid "List all rules in this security group (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/security_group_rule.py:336
-msgid "Security group rule to display (ID only)"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:54
-msgid ""
-"Allocation pool IP addresses for this subnet e.g.: "
-"start=192.168.199.2,end=192.168.199.254 (repeat option to add multiple IP"
-" addresses)"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:63
-msgid "DNS server for this subnet (repeat option to set multiple DNS servers)"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:72
-msgid ""
-"Additional route for this subnet e.g.: "
-"destination=10.10.0.0/16,gateway=192.168.71.254 destination: destination "
-"subnet (in CIDR notation) gateway: nexthop IP address (repeat option to "
-"add multiple routes)"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:178
-msgid "New subnet name"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:190
-msgid "Subnet pool from which this subnet will obtain a CIDR (Name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:196
-msgid "Use default subnet pool for --ip-version"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:201
-msgid "Prefix length for subnet allocation from subnet pool"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:206
-msgid ""
-"Subnet range in CIDR notation (required if --subnet-pool is not "
-"specified, optional otherwise)"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:215
-msgid "Enable DHCP (default)"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:220
-#: openstackclient/network/v2/subnet.py:348
-msgid "Disable DHCP"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:226
-msgid ""
-"Specify a gateway for the subnet. The three options are: <ip-address>: "
-"Specific IP address to use as the gateway, 'auto': Gateway address should"
-" automatically be chosen from within the subnet itself, 'none': This "
-"subnet will not use a gateway, e.g.: --gateway 192.168.9.1, --gateway "
-"auto, --gateway none (default is 'auto')"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:238
-msgid ""
-"IP version (default is 4). Note that when subnet pool is specified, IP "
-"version is determined from the subnet pool and this option is ignored"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:245
-msgid ""
-"IPv6 RA (Router Advertisement) mode, valid modes: [dhcpv6-stateful, "
-"dhcpv6-stateless, slaac]"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:251
-msgid "IPv6 address mode, valid modes: [dhcpv6-stateful, dhcpv6-stateless, slaac]"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:258
-msgid "Network this subnet belongs to (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:280
-msgid "Subnet to delete (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:331
-msgid "Subnet to modify (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:336
-msgid "Updated name of the subnet"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:343
-msgid "Enable DHCP"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:353
-msgid ""
-"Specify a gateway for the subnet. The options are: <ip-address>: Specific"
-" IP address to use as the gateway, 'none': This subnet will not use a "
-"gateway, e.g.: --gateway 192.168.9.1, --gateway none"
-msgstr ""
-
-#: openstackclient/network/v2/subnet.py:387
-msgid "Subnet to display (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/subnet_pool.py:77
-msgid ""
-"Set subnet pool prefixes (in CIDR notation) (repeat option to set "
-"multiple prefixes)"
-msgstr ""
-
-#: openstackclient/network/v2/subnet_pool.py:84
-msgid "Set subnet pool default prefix length"
-msgstr ""
-
-#: openstackclient/network/v2/subnet_pool.py:90
-msgid "Set subnet pool minimum prefix length"
-msgstr ""
-
-#: openstackclient/network/v2/subnet_pool.py:96
-msgid "Set subnet pool maximum prefix length"
-msgstr ""
-
-#: openstackclient/network/v2/subnet_pool.py:108
-msgid "Name of the new subnet pool"
-msgstr ""
-
-#: openstackclient/network/v2/subnet_pool.py:120
-#: openstackclient/network/v2/subnet_pool.py:226
-msgid ""
-"Set address scope associated with the subnet pool (name or ID), prefixes "
-"must be unique across address scopes"
-msgstr ""
-
-#: openstackclient/network/v2/subnet_pool.py:146
-msgid "Subnet pool to delete (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/subnet_pool.py:214
-msgid "Subnet pool to modify (name or ID)"
-msgstr ""
-
-#: openstackclient/network/v2/subnet_pool.py:219
-msgid "Set subnet pool name"
-msgstr ""
-
-#: openstackclient/network/v2/subnet_pool.py:233
-msgid "Remove address scope associated with the subnet pool"
-msgstr ""
-
-#: openstackclient/network/v2/subnet_pool.py:262
-msgid "Subnet pool to display (name or ID)"
-msgstr ""
-
diff --git a/openstackclient/locale/zh_TW/LC_MESSAGES/openstackclient.po b/openstackclient/locale/zh_TW/LC_MESSAGES/openstackclient.po
index a121aca..d9bbf6f 100644
--- a/openstackclient/locale/zh_TW/LC_MESSAGES/openstackclient.po
+++ b/openstackclient/locale/zh_TW/LC_MESSAGES/openstackclient.po
@@ -7,9 +7,9 @@
# Andreas Jaeger <jaegerandi@gmail.com>, 2016. #zanata
msgid ""
msgstr ""
-"Project-Id-Version: python-openstackclient 2.2.1.dev235\n"
+"Project-Id-Version: python-openstackclient 2.5.1.dev51\n"
"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
-"POT-Creation-Date: 2016-04-19 05:02+0000\n"
+"POT-Creation-Date: 2016-06-03 19:37+0000\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -21,62 +21,6 @@ msgstr ""
"X-Generator: Zanata 3.7.3\n"
"Language-Team: Chinese (Taiwan)\n"
-msgid ""
-"\n"
-"Complete\n"
-msgstr ""
-"\n"
-"完成\n"
-
-msgid ""
-"\n"
-"Error creating server"
-msgstr ""
-"\n"
-"新增雲實例時出錯"
-
-msgid ""
-"\n"
-"Error creating server snapshot"
-msgstr ""
-"\n"
-"新增雲實例即時存檔時出錯"
-
-msgid ""
-"\n"
-"Error migrating server"
-msgstr ""
-"\n"
-"轉移雲實例出錯"
-
-msgid ""
-"\n"
-"Error rebooting server\n"
-msgstr ""
-"\n"
-"重開雲實例出錯\n"
-
-msgid ""
-"\n"
-"Error rebuilding server"
-msgstr ""
-"\n"
-"重建雲實例出錯"
-
-msgid ""
-"\n"
-"Error resizing server"
-msgstr ""
-"\n"
-"調整雲實例容量時出錯"
-
-msgid ""
-"\n"
-"Reboot complete\n"
-msgstr ""
-"\n"
-"重開機完成\n"
-
msgid "Add a property to <name> (repeat option to set multiple properties)"
msgstr "加入屬性到 <name>(重復這選項來設定多個屬性)"
@@ -122,9 +66,6 @@ msgstr "啟用用戶(預設)"
msgid "Endpoint ID to delete"
msgstr "要刪除的端點識別號"
-msgid "Endpoint ID to display"
-msgstr "要顯示的端點識別號"
-
#, python-format
msgid "Error creating server: %s"
msgstr "新增雲實例時出錯:%s"
diff --git a/openstackclient/network/client.py b/openstackclient/network/client.py
index be06d2b..d711f4f 100644
--- a/openstackclient/network/client.py
+++ b/openstackclient/network/client.py
@@ -17,6 +17,7 @@ from openstack import connection
from openstack import profile
from openstackclient.common import utils
+from openstackclient.i18n import _
LOG = logging.getLogger(__name__)
@@ -51,7 +52,7 @@ def build_option_parser(parser):
'--os-network-api-version',
metavar='<network-api-version>',
default=utils.env('OS_NETWORK_API_VERSION'),
- help='Network API version, default=' +
- DEFAULT_API_VERSION +
- ' (Env: OS_NETWORK_API_VERSION)')
+ help=_("Network API version, default=%s "
+ "(Env: OS_NETWORK_API_VERSION)") % DEFAULT_API_VERSION
+ )
return parser
diff --git a/openstackclient/network/common.py b/openstackclient/network/common.py
index a3047d8..4028ac0 100644
--- a/openstackclient/network/common.py
+++ b/openstackclient/network/common.py
@@ -16,6 +16,7 @@ import six
from openstackclient.common import command
from openstackclient.common import exceptions
+from openstackclient.i18n import _
@six.add_metaclass(abc.ABCMeta)
@@ -94,14 +95,22 @@ class NetworkAndComputeDelete(NetworkAndComputeCommand):
self.take_action_compute(self.app.client_manager.compute,
parsed_args)
except Exception as e:
- self.app.log.error("Failed to delete %s with name or ID "
- "'%s': %s" % (self.resource, r, e))
+ msg = _("Failed to delete %(resource)s with name or ID "
+ "'%(name_or_id)s': %(e)s") % {
+ "resource": self.resource,
+ "name_or_id": r,
+ "e": e,
+ }
+ self.app.log.error(msg)
ret += 1
if ret:
total = len(resources)
- msg = "%s of %s %ss failed to delete." % (ret, total,
- self.resource)
+ msg = _("%(num)s of %(total)s %(resource)s failed to delete.") % {
+ "num": ret,
+ "total": total,
+ "resource": self.resource,
+ }
raise exceptions.CommandError(msg)
diff --git a/openstackclient/network/v2/address_scope.py b/openstackclient/network/v2/address_scope.py
index 614900c..dbc6865 100644
--- a/openstackclient/network/v2/address_scope.py
+++ b/openstackclient/network/v2/address_scope.py
@@ -98,22 +98,38 @@ class CreateAddressScope(command.ShowOne):
class DeleteAddressScope(command.Command):
- """Delete an address scope"""
+ """Delete address scope(s)"""
def get_parser(self, prog_name):
parser = super(DeleteAddressScope, self).get_parser(prog_name)
parser.add_argument(
'address_scope',
metavar="<address-scope>",
- help=_("Address scope to delete (name or ID)")
+ nargs='+',
+ help=_("Address scope(s) to delete (name or ID)")
)
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.network
- obj = client.find_address_scope(parsed_args.address_scope)
- client.delete_address_scope(obj)
+ result = 0
+
+ for scope in parsed_args.address_scope:
+ try:
+ obj = client.find_address_scope(scope, ignore_missing=False)
+ client.delete_address_scope(obj)
+ except Exception as e:
+ result += 1
+ self.app.log.error(_("Failed to delete address scope with "
+ "name or ID '%(scope)s': %(e)s")
+ % {'scope': scope, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.address_scope)
+ msg = (_("%(result)s of %(total)s address scopes failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListAddressScope(command.Lister):
diff --git a/openstackclient/network/v2/ip_availability.py b/openstackclient/network/v2/ip_availability.py
new file mode 100644
index 0000000..cc24033
--- /dev/null
+++ b/openstackclient/network/v2/ip_availability.py
@@ -0,0 +1,109 @@
+# 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.
+#
+
+"""IP Availability Info implementations"""
+
+from openstackclient.common import command
+from openstackclient.common import utils
+from openstackclient.i18n import _
+from openstackclient.identity import common as identity_common
+
+
+_formatters = {
+ 'subnet_ip_availability': utils.format_list_of_dicts,
+}
+
+
+def _get_columns(item):
+ columns = list(item.keys())
+ if 'tenant_id' in columns:
+ columns.remove('tenant_id')
+ columns.append('project_id')
+ return tuple(sorted(columns))
+
+
+class ListIPAvailability(command.Lister):
+ """List IP availability for network"""
+
+ def get_parser(self, prog_name):
+ parser = super(ListIPAvailability, self).get_parser(prog_name)
+ parser.add_argument(
+ '--ip-version',
+ type=int,
+ choices=[4, 6],
+ metavar='<ip-version>',
+ dest='ip_version',
+ help=_("List IP availability of given IP version networks"),
+ )
+ parser.add_argument(
+ '--project',
+ metavar='<project>',
+ help=_("List IP availability of given project"),
+ )
+ identity_common.add_project_domain_option_to_parser(parser)
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+
+ columns = (
+ 'network_id',
+ 'network_name',
+ 'total_ips',
+ 'used_ips',
+ )
+ column_headers = (
+ 'Network ID',
+ 'Network Name',
+ 'Total IPs',
+ 'Used IPs',
+ )
+
+ filters = {}
+ if parsed_args.ip_version:
+ filters['ip_version'] = parsed_args.ip_version
+
+ if parsed_args.project:
+ identity_client = self.app.client_manager.identity
+ project_id = identity_common.find_project(
+ identity_client,
+ parsed_args.project,
+ parsed_args.project_domain,
+ ).id
+ filters['tenant_id'] = project_id
+ data = client.network_ip_availabilities(**filters)
+ return (column_headers,
+ (utils.get_item_properties(
+ s, columns,
+ ) for s in data))
+
+
+class ShowIPAvailability(command.ShowOne):
+ """Show network IP availability details"""
+
+ def get_parser(self, prog_name):
+ parser = super(ShowIPAvailability, self).get_parser(prog_name)
+ parser.add_argument(
+ 'network',
+ metavar="<network>",
+ help=_("Show IP availability for a specific network (name or ID)"),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ obj = client.find_network_ip_availability(parsed_args.network,
+ ignore_missing=False)
+ columns = _get_columns(obj)
+ data = utils.get_item_properties(obj, columns, formatters=_formatters)
+ return columns, data
diff --git a/openstackclient/network/v2/network_segment.py b/openstackclient/network/v2/network_segment.py
new file mode 100644
index 0000000..818ffc0
--- /dev/null
+++ b/openstackclient/network/v2/network_segment.py
@@ -0,0 +1,115 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+"""Network segment action implementations"""
+
+# TODO(rtheis): Add description and name properties when support is available.
+
+from openstackclient.common import command
+from openstackclient.common import utils
+from openstackclient.i18n import _
+
+
+class ListNetworkSegment(command.Lister):
+ """List network segments
+
+ (Caution: This is a beta command and subject to change.
+ Use global option --os-beta-command to enable
+ this command)
+ """
+
+ def get_parser(self, prog_name):
+ parser = super(ListNetworkSegment, self).get_parser(prog_name)
+ parser.add_argument(
+ '--long',
+ action='store_true',
+ default=False,
+ help=_('List additional fields in output'),
+ )
+ parser.add_argument(
+ '--network',
+ metavar='<network>',
+ help=_('List network segments that belong to this '
+ 'network (name or ID)'),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ self.validate_os_beta_command_enabled()
+
+ network_client = self.app.client_manager.network
+
+ filters = {}
+ if parsed_args.network:
+ _network = network_client.find_network(
+ parsed_args.network,
+ ignore_missing=False
+ )
+ filters = {'network_id': _network.id}
+ data = network_client.segments(**filters)
+
+ headers = (
+ 'ID',
+ 'Network',
+ 'Network Type',
+ 'Segment',
+ )
+ columns = (
+ 'id',
+ 'network_id',
+ 'network_type',
+ 'segmentation_id',
+ )
+ if parsed_args.long:
+ headers = headers + (
+ 'Physical Network',
+ )
+ columns = columns + (
+ 'physical_network',
+ )
+
+ return (headers,
+ (utils.get_item_properties(
+ s, columns,
+ formatters={},
+ ) for s in data))
+
+
+class ShowNetworkSegment(command.ShowOne):
+ """Display network segment details
+
+ (Caution: This is a beta command and subject to change.
+ Use global option --os-beta-command to enable
+ this command)
+ """
+
+ def get_parser(self, prog_name):
+ parser = super(ShowNetworkSegment, self).get_parser(prog_name)
+ parser.add_argument(
+ 'network_segment',
+ metavar='<network-segment>',
+ help=_('Network segment to display (ID only)'),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ self.validate_os_beta_command_enabled()
+
+ client = self.app.client_manager.network
+ obj = client.find_segment(
+ parsed_args.network_segment,
+ ignore_missing=False
+ )
+ columns = tuple(sorted(obj.keys()))
+ data = utils.get_item_properties(obj, columns)
+ return (columns, data)
diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py
index ca02281..7ef3964 100644
--- a/openstackclient/network/v2/port.py
+++ b/openstackclient/network/v2/port.py
@@ -284,10 +284,23 @@ class DeletePort(command.Command):
def take_action(self, parsed_args):
client = self.app.client_manager.network
+ result = 0
for port in parsed_args.port:
- res = client.find_port(port)
- client.delete_port(res)
+ try:
+ obj = client.find_port(port, ignore_missing=False)
+ client.delete_port(obj)
+ except Exception as e:
+ result += 1
+ self.app.log.error(_("Failed to delete port with "
+ "name or ID '%(port)s': %(e)s")
+ % {'port': port, 'e': e})
+
+ if result > 0:
+ total = len(parsed_args.port)
+ msg = (_("%(result)s of %(total)s ports failed "
+ "to delete.") % {'result': result, 'total': total})
+ raise exceptions.CommandError(msg)
class ListPort(command.Lister):
diff --git a/openstackclient/releasenotes/notes/bug-1543222-6f8579344ff5c958.yaml b/openstackclient/releasenotes/notes/bug-1543222-6f8579344ff5c958.yaml
new file mode 100644
index 0000000..c783d01
--- /dev/null
+++ b/openstackclient/releasenotes/notes/bug-1543222-6f8579344ff5c958.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+ - Keystone V3 `user password set` is a self-service operation. It should
+ not required a scoped token as it is not considered a `scoped operation`.
+ [Bug `1543222 <https://bugs.launchpad.net/bugs/1543222>`_]
+
diff --git a/openstackclient/shell.py b/openstackclient/shell.py
index 9968d73..9179ad0 100644
--- a/openstackclient/shell.py
+++ b/openstackclient/shell.py
@@ -251,7 +251,7 @@ class OpenStackShell(app.App):
help="Print API call timing info",
)
parser.add_argument(
- '--enable-beta-commands',
+ '--os-beta-command',
action='store_true',
help="Enable beta commands which are subject to change",
)
diff --git a/openstackclient/tests/common/test_command.py b/openstackclient/tests/common/test_command.py
index 7467d9e..722a4c0 100644
--- a/openstackclient/tests/common/test_command.py
+++ b/openstackclient/tests/common/test_command.py
@@ -15,6 +15,8 @@
import mock
from openstackclient.common import command
+from openstackclient.common import exceptions
+from openstackclient.tests import fakes as test_fakes
from openstackclient.tests import utils as test_utils
@@ -31,3 +33,16 @@ class TestCommand(test_utils.TestCase):
self.assertTrue(hasattr(cmd, 'log'))
self.assertEqual('openstackclient.tests.common.test_command.'
'FakeCommand', cmd.log.name)
+
+ def test_validate_os_beta_command_enabled(self):
+ cmd = FakeCommand(mock.Mock(), mock.Mock())
+ cmd.app = mock.Mock()
+ cmd.app.options = test_fakes.FakeOptions()
+
+ # No exception is raised when enabled.
+ cmd.app.options.os_beta_command = True
+ cmd.validate_os_beta_command_enabled()
+
+ cmd.app.options.os_beta_command = False
+ self.assertRaises(exceptions.CommandError,
+ cmd.validate_os_beta_command_enabled)
diff --git a/openstackclient/tests/compute/v2/fakes.py b/openstackclient/tests/compute/v2/fakes.py
index 62a46b1..c9e2025 100644
--- a/openstackclient/tests/compute/v2/fakes.py
+++ b/openstackclient/tests/compute/v2/fakes.py
@@ -111,6 +111,9 @@ class FakeAggregate(object):
class FakeComputev2Client(object):
def __init__(self, **kwargs):
+ self.agents = mock.Mock()
+ self.agents.resource_class = fakes.FakeResource(None, {})
+
self.aggregates = mock.Mock()
self.aggregates.resource_class = fakes.FakeResource(None, {})
@@ -132,6 +135,9 @@ class FakeComputev2Client(object):
self.flavors = mock.Mock()
self.flavors.resource_class = fakes.FakeResource(None, {})
+ self.flavor_access = mock.Mock()
+ self.flavor_access.resource_class = fakes.FakeResource(None, {})
+
self.quotas = mock.Mock()
self.quotas.resource_class = fakes.FakeResource(None, {})
@@ -204,6 +210,55 @@ class TestComputev2(utils.TestCommand):
)
+class FakeAgent(object):
+ """Fake one or more agent."""
+
+ @staticmethod
+ def create_one_agent(attrs=None):
+ """Create a fake agent.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object, with agent_id, os, and so on
+ """
+
+ attrs = attrs or {}
+
+ # set default attributes.
+ agent_info = {
+ 'agent_id': 'agent-id-' + uuid.uuid4().hex,
+ 'os': 'agent-os-' + uuid.uuid4().hex,
+ 'architecture': 'agent-architecture',
+ 'version': '8.0',
+ 'url': 'http://127.0.0.1',
+ 'md5hash': 'agent-md5hash',
+ 'hypervisor': 'hypervisor',
+ }
+ agent_info.update(attrs)
+
+ agent = fakes.FakeResource(info=copy.deepcopy(agent_info),
+ loaded=True)
+ return agent
+
+ @staticmethod
+ def create_agents(attrs=None, count=2):
+ """Create multiple fake agents.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of agents to fake
+ :return:
+ A list of FakeResource objects faking the agents
+ """
+ agents = []
+ for i in range(0, count):
+ agents.append(FakeAgent.create_one_agent(attrs))
+
+ return agents
+
+
class FakeHypervisor(object):
"""Fake one or more hypervisor."""
diff --git a/openstackclient/tests/compute/v2/test_agent.py b/openstackclient/tests/compute/v2/test_agent.py
new file mode 100644
index 0000000..d3d1ff2
--- /dev/null
+++ b/openstackclient/tests/compute/v2/test_agent.py
@@ -0,0 +1,254 @@
+# Copyright 2016 Easystack. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+import mock
+
+from mock import call
+from openstackclient.common import exceptions
+from openstackclient.compute.v2 import agent
+from openstackclient.tests.compute.v2 import fakes as compute_fakes
+
+
+class TestAgent(compute_fakes.TestComputev2):
+
+ fake_agent = compute_fakes.FakeAgent.create_one_agent()
+
+ columns = (
+ 'agent_id',
+ 'architecture',
+ 'hypervisor',
+ 'md5hash',
+ 'os',
+ 'url',
+ 'version',
+ )
+
+ data = (
+ fake_agent.agent_id,
+ fake_agent.architecture,
+ fake_agent.hypervisor,
+ fake_agent.md5hash,
+ fake_agent.os,
+ fake_agent.url,
+ fake_agent.version,
+ )
+
+ def setUp(self):
+ super(TestAgent, self).setUp()
+
+ self.agents_mock = self.app.client_manager.compute.agents
+ self.agents_mock.reset_mock()
+
+
+class TestAgentCreate(TestAgent):
+
+ def setUp(self):
+ super(TestAgentCreate, self).setUp()
+
+ self.agents_mock.create.return_value = self.fake_agent
+ self.cmd = agent.CreateAgent(self.app, None)
+
+ def test_agent_create(self):
+ arglist = [
+ self.fake_agent.os,
+ self.fake_agent.architecture,
+ self.fake_agent.version,
+ self.fake_agent.url,
+ self.fake_agent.md5hash,
+ self.fake_agent.hypervisor,
+ ]
+
+ verifylist = [
+ ('os', self.fake_agent.os),
+ ('architecture', self.fake_agent.architecture),
+ ('version', self.fake_agent.version),
+ ('url', self.fake_agent.url),
+ ('md5hash', self.fake_agent.md5hash),
+ ('hypervisor', self.fake_agent.hypervisor),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.agents_mock.create.assert_called_with(parsed_args.os,
+ parsed_args.architecture,
+ parsed_args.version,
+ parsed_args.url,
+ parsed_args.md5hash,
+ parsed_args.hypervisor)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
+
+
+class TestAgentDelete(TestAgent):
+
+ fake_agents = compute_fakes.FakeAgent.create_agents(count=2)
+
+ def setUp(self):
+ super(TestAgentDelete, self).setUp()
+
+ self.agents_mock.get.return_value = self.fake_agents
+ self.cmd = agent.DeleteAgent(self.app, None)
+
+ def test_delete_one_agent(self):
+ arglist = [
+ self.fake_agents[0].agent_id
+ ]
+
+ verifylist = [
+ ('id', [self.fake_agents[0].agent_id]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.agents_mock.delete.assert_called_with(
+ self.fake_agents[0].agent_id)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_agents(self):
+ arglist = []
+ for n in self.fake_agents:
+ arglist.append(n.agent_id)
+ verifylist = [
+ ('id', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for n in self.fake_agents:
+ calls.append(call(n.agent_id))
+ self.agents_mock.delete.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_delete_multiple_agents_exception(self):
+ arglist = [
+ self.fake_agents[0].agent_id,
+ self.fake_agents[1].agent_id,
+ 'x-y-z',
+ ]
+ verifylist = [
+ ('id', arglist),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ ret_delete = [
+ None,
+ None,
+ exceptions.NotFound('404')
+ ]
+ self.agents_mock.delete = mock.Mock(side_effect=ret_delete)
+
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+ calls = [
+ call(self.fake_agents[0].agent_id),
+ call(self.fake_agents[1].agent_id),
+ ]
+ self.agents_mock.delete.assert_has_calls(calls)
+
+
+class TestAgentList(TestAgent):
+
+ agents = compute_fakes.FakeAgent.create_agents(count=3)
+ list_columns = (
+ "Agent ID",
+ "Hypervisor",
+ "OS",
+ "Architecture",
+ "Version",
+ "Md5Hash",
+ "URL",
+ )
+
+ list_data = []
+ for _agent in agents:
+ list_data.append((
+ _agent.agent_id,
+ _agent.hypervisor,
+ _agent.os,
+ _agent.architecture,
+ _agent.version,
+ _agent.md5hash,
+ _agent.url,
+ ))
+
+ def setUp(self):
+
+ super(TestAgentList, self).setUp()
+
+ self.agents_mock.list.return_value = self.agents
+ self.cmd = agent.ListAgent(self.app, None)
+
+ def test_agent_list(self):
+
+ arglist = []
+ verifylist = []
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.list_columns, columns)
+ self.assertEqual(self.list_data, list(data))
+
+ def test_agent_list_with_hypervisor(self):
+
+ arglist = [
+ '--hypervisor',
+ 'hypervisor',
+ ]
+ verifylist = [
+ ('hypervisor', 'hypervisor'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.assertEqual(self.list_columns, columns)
+ self.assertEqual(self.list_data, list(data))
+
+
+class TestAgentSet(TestAgent):
+
+ def setUp(self):
+ super(TestAgentSet, self).setUp()
+
+ self.agents_mock.update.return_value = self.fake_agent
+ self.cmd = agent.SetAgent(self.app, None)
+
+ def test_agent_set(self):
+ arglist = [
+ 'id',
+ 'new-version',
+ 'new-url',
+ 'new-md5hash',
+ ]
+
+ verifylist = [
+ ('id', 'id'),
+ ('version', 'new-version'),
+ ('url', 'new-url'),
+ ('md5hash', 'new-md5hash'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.agents_mock.update.assert_called_with(parsed_args.id,
+ parsed_args.version,
+ parsed_args.url,
+ parsed_args.md5hash)
+ self.assertIsNone(result)
diff --git a/openstackclient/tests/compute/v2/test_flavor.py b/openstackclient/tests/compute/v2/test_flavor.py
index 6f507b1..434d5f9 100644
--- a/openstackclient/tests/compute/v2/test_flavor.py
+++ b/openstackclient/tests/compute/v2/test_flavor.py
@@ -13,10 +13,14 @@
# under the License.
#
+import copy
+
from openstackclient.common import exceptions
from openstackclient.common import utils
from openstackclient.compute.v2 import flavor
from openstackclient.tests.compute.v2 import fakes as compute_fakes
+from openstackclient.tests import fakes
+from openstackclient.tests.identity.v3 import fakes as identity_fakes
from openstackclient.tests import utils as tests_utils
@@ -29,6 +33,13 @@ class TestFlavor(compute_fakes.TestComputev2):
self.flavors_mock = self.app.client_manager.compute.flavors
self.flavors_mock.reset_mock()
+ # Get a shortcut to the FlavorAccessManager Mock
+ self.flavor_access_mock = self.app.client_manager.compute.flavor_access
+ self.flavor_access_mock.reset_mock()
+
+ self.projects_mock = self.app.client_manager.identity.projects
+ self.projects_mock.reset_mock()
+
class TestFlavorCreate(TestFlavor):
@@ -427,16 +438,23 @@ class TestFlavorList(TestFlavor):
class TestFlavorSet(TestFlavor):
# Return value of self.flavors_mock.find().
- flavor = compute_fakes.FakeFlavor.create_one_flavor()
+ flavor = compute_fakes.FakeFlavor.create_one_flavor(
+ attrs={'os-flavor-access:is_public': False})
def setUp(self):
super(TestFlavorSet, self).setUp()
self.flavors_mock.find.return_value = self.flavor
self.flavors_mock.get.side_effect = exceptions.NotFound(None)
+ # Return a project
+ self.projects_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.PROJECT),
+ loaded=True,
+ )
self.cmd = flavor.SetFlavor(self.app, None)
- def test_flavor_set(self):
+ def test_flavor_set_property(self):
arglist = [
'--property', 'FOO="B A R"',
'baremetal'
@@ -452,6 +470,81 @@ class TestFlavorSet(TestFlavor):
is_public=None)
self.assertIsNone(result)
+ def test_flavor_set_project(self):
+ arglist = [
+ '--project', identity_fakes.project_id,
+ self.flavor.id,
+ ]
+ verifylist = [
+ ('project', identity_fakes.project_id),
+ ('flavor', self.flavor.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.assertIsNone(result)
+
+ self.flavor_access_mock.add_tenant_access.assert_called_with(
+ self.flavor.id,
+ identity_fakes.project_id,
+ )
+
+ def test_flavor_set_no_project(self):
+ arglist = [
+ '--project',
+ self.flavor.id,
+ ]
+ verifylist = [
+ ('project', ''),
+ ('flavor', self.flavor.id),
+ ]
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_flavor_set_no_flavor(self):
+ arglist = [
+ '--project', identity_fakes.project_id,
+ ]
+ verifylist = [
+ ('project', identity_fakes.project_id),
+ ]
+
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
+
+ def test_flavor_set_with_unexist_flavor(self):
+ self.flavors_mock.get.side_effect = exceptions.NotFound(None)
+ self.flavors_mock.find.side_effect = exceptions.NotFound(None)
+
+ arglist = [
+ '--project', identity_fakes.project_id,
+ 'unexist_flavor',
+ ]
+ verifylist = [
+ ('project', identity_fakes.project_id),
+ ('flavor', 'unexist_flavor'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+
+ def test_flavor_set_nothing(self):
+ arglist = [
+ self.flavor.id,
+ ]
+ verifylist = [
+ ('flavor', self.flavor.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+
class TestFlavorShow(TestFlavor):
@@ -521,16 +614,23 @@ class TestFlavorShow(TestFlavor):
class TestFlavorUnset(TestFlavor):
# Return value of self.flavors_mock.find().
- flavor = compute_fakes.FakeFlavor.create_one_flavor()
+ flavor = compute_fakes.FakeFlavor.create_one_flavor(
+ attrs={'os-flavor-access:is_public': False})
def setUp(self):
super(TestFlavorUnset, self).setUp()
self.flavors_mock.find.return_value = self.flavor
self.flavors_mock.get.side_effect = exceptions.NotFound(None)
+ # Return a project
+ self.projects_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.PROJECT),
+ loaded=True,
+ )
self.cmd = flavor.UnsetFlavor(self.app, None)
- def test_flavor_unset(self):
+ def test_flavor_unset_property(self):
arglist = [
'--property', 'property',
'baremetal'
@@ -545,3 +645,80 @@ class TestFlavorUnset(TestFlavor):
self.flavors_mock.find.assert_called_with(name=parsed_args.flavor,
is_public=None)
self.assertIsNone(result)
+
+ def test_flavor_unset_project(self):
+ arglist = [
+ '--project', identity_fakes.project_id,
+ self.flavor.id,
+ ]
+ verifylist = [
+ ('project', identity_fakes.project_id),
+ ('flavor', self.flavor.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.assertIsNone(result)
+
+ self.flavor_access_mock.remove_tenant_access.assert_called_with(
+ self.flavor.id,
+ identity_fakes.project_id,
+ )
+
+ def test_flavor_unset_no_project(self):
+ arglist = [
+ '--project', '',
+ self.flavor.id,
+ ]
+ verifylist = [
+ ('project', ''),
+ ('flavor', self.flavor.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+
+ def test_flavor_unset_no_flavor(self):
+ arglist = [
+ '--project', identity_fakes.project_id,
+ ]
+ verifylist = [
+ ('project', identity_fakes.project_id),
+ ]
+
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser,
+ self.cmd,
+ arglist,
+ verifylist)
+
+ def test_flavor_unset_with_unexist_flavor(self):
+ self.flavors_mock.get.side_effect = exceptions.NotFound(None)
+ self.flavors_mock.find.side_effect = exceptions.NotFound(None)
+
+ arglist = [
+ '--project', identity_fakes.project_id,
+ 'unexist_flavor',
+ ]
+ verifylist = [
+ ('project', identity_fakes.project_id),
+ ('flavor', 'unexist_flavor'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args)
+
+ def test_flavor_unset_nothing(self):
+ arglist = [
+ self.flavor.id,
+ ]
+ verifylist = [
+ ('flavor', self.flavor.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
diff --git a/openstackclient/tests/compute/v2/test_server.py b/openstackclient/tests/compute/v2/test_server.py
index 7d184b3..d642e6d 100644
--- a/openstackclient/tests/compute/v2/test_server.py
+++ b/openstackclient/tests/compute/v2/test_server.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
#
+import getpass
import mock
from mock import call
@@ -1213,6 +1214,114 @@ class TestServerResume(TestServer):
self.run_method_with_servers('resume', 3)
+class TestServerSet(TestServer):
+
+ def setUp(self):
+ super(TestServerSet, self).setUp()
+
+ self.methods = {
+ 'update': None,
+ 'reset_state': None,
+ 'change_password': None,
+ }
+
+ self.fake_servers = self.setup_servers_mock(2)
+
+ # Get the command object to test
+ self.cmd = server.SetServer(self.app, None)
+
+ def test_server_set_no_option(self):
+ arglist = [
+ 'foo_vm'
+ ]
+ verifylist = [
+ ('server', 'foo_vm')
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.assertNotCalled(self.fake_servers[0].update)
+ self.assertNotCalled(self.fake_servers[0].reset_state)
+ self.assertNotCalled(self.fake_servers[0].change_password)
+ self.assertNotCalled(self.servers_mock.set_meta)
+ self.assertIsNone(result)
+
+ def test_server_set_with_state(self):
+ for index, state in enumerate(['active', 'error']):
+ arglist = [
+ '--state', state,
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('state', state),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.fake_servers[index].reset_state.assert_called_once_with(
+ state=state)
+ self.assertIsNone(result)
+
+ def test_server_set_with_invalid_state(self):
+ arglist = [
+ '--state', 'foo_state',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('state', 'foo_state'),
+ ('server', 'foo_vm'),
+ ]
+ self.assertRaises(utils.ParserException,
+ self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_server_set_with_name(self):
+ arglist = [
+ '--name', 'foo_name',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('name', 'foo_name'),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.fake_servers[0].update.assert_called_once_with(name='foo_name')
+ self.assertIsNone(result)
+
+ def test_server_set_with_property(self):
+ arglist = [
+ '--property', 'key1=value1',
+ '--property', 'key2=value2',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('property', {'key1': 'value1', 'key2': 'value2'}),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.servers_mock.set_meta.assert_called_once_with(
+ self.fake_servers[0], parsed_args.property)
+ self.assertIsNone(result)
+
+ @mock.patch.object(getpass, 'getpass',
+ return_value=mock.sentinel.fake_pass)
+ def test_server_set_with_root_password(self, mock_getpass):
+ arglist = [
+ '--root-password',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('root_password', True),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.fake_servers[0].change_password.assert_called_once_with(
+ mock.sentinel.fake_pass)
+ self.assertIsNone(result)
+
+
class TestServerShelve(TestServer):
def setUp(self):
@@ -1428,6 +1537,45 @@ class TestServerUnpause(TestServer):
self.run_method_with_servers('unpause', 3)
+class TestServerUnset(TestServer):
+
+ def setUp(self):
+ super(TestServerUnset, self).setUp()
+
+ self.fake_server = self.setup_servers_mock(1)[0]
+
+ # Get the command object to test
+ self.cmd = server.UnsetServer(self.app, None)
+
+ def test_server_unset_no_option(self):
+ arglist = [
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.assertNotCalled(self.servers_mock.delete_meta)
+ self.assertIsNone(result)
+
+ def test_server_unset_with_property(self):
+ arglist = [
+ '--property', 'key1',
+ '--property', 'key2',
+ 'foo_vm',
+ ]
+ verifylist = [
+ ('property', ['key1', 'key2']),
+ ('server', 'foo_vm'),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+ self.servers_mock.delete_meta.assert_called_once_with(
+ self.fake_server, ['key1', 'key2'])
+ self.assertIsNone(result)
+
+
class TestServerUnshelve(TestServer):
def setUp(self):
diff --git a/openstackclient/tests/compute/v2/test_server_backup.py b/openstackclient/tests/compute/v2/test_server_backup.py
new file mode 100644
index 0000000..b35f9f5
--- /dev/null
+++ b/openstackclient/tests/compute/v2/test_server_backup.py
@@ -0,0 +1,270 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+import mock
+
+from openstackclient.common import exceptions
+from openstackclient.common import utils as common_utils
+from openstackclient.compute.v2 import server_backup
+from openstackclient.tests.compute.v2 import fakes as compute_fakes
+from openstackclient.tests.image.v2 import fakes as image_fakes
+
+
+class TestServerBackup(compute_fakes.TestComputev2):
+
+ def setUp(self):
+ super(TestServerBackup, self).setUp()
+
+ # Get a shortcut to the compute client ServerManager Mock
+ self.servers_mock = self.app.client_manager.compute.servers
+ self.servers_mock.reset_mock()
+
+ # Get a shortcut to the image client ImageManager Mock
+ self.images_mock = self.app.client_manager.image.images
+ self.images_mock.reset_mock()
+
+ # Set object attributes to be tested. Could be overwriten in subclass.
+ self.attrs = {}
+
+ # Set object methods to be tested. Could be overwriten in subclass.
+ self.methods = {}
+
+ def setup_servers_mock(self, count):
+ servers = compute_fakes.FakeServer.create_servers(
+ attrs=self.attrs,
+ methods=self.methods,
+ count=count,
+ )
+
+ # This is the return value for utils.find_resource()
+ self.servers_mock.get = compute_fakes.FakeServer.get_servers(
+ servers,
+ 0,
+ )
+ return servers
+
+
+class TestServerBackupCreate(TestServerBackup):
+
+ # Just return whatever Image is testing with these days
+ def image_columns(self, image):
+ columnlist = tuple(sorted(image.keys()))
+ return columnlist
+
+ def image_data(self, image):
+ datalist = (
+ image['id'],
+ image['name'],
+ image['owner'],
+ image['protected'],
+ 'active',
+ common_utils.format_list(image.get('tags')),
+ image['visibility'],
+ )
+ return datalist
+
+ def setUp(self):
+ super(TestServerBackupCreate, self).setUp()
+
+ # Get the command object to test
+ self.cmd = server_backup.CreateServerBackup(self.app, None)
+
+ self.methods = {
+ 'backup': None,
+ }
+
+ def setup_images_mock(self, count, servers=None):
+ if servers:
+ images = image_fakes.FakeImage.create_images(
+ attrs={
+ 'name': servers[0].name,
+ 'status': 'active',
+ },
+ count=count,
+ )
+ else:
+ images = image_fakes.FakeImage.create_images(
+ attrs={
+ 'status': 'active',
+ },
+ count=count,
+ )
+
+ self.images_mock.get = mock.MagicMock(side_effect=images)
+ return images
+
+ def test_server_backup_defaults(self):
+ servers = self.setup_servers_mock(count=1)
+ images = self.setup_images_mock(count=1, servers=servers)
+
+ arglist = [
+ servers[0].id,
+ ]
+ verifylist = [
+ ('name', None),
+ ('type', None),
+ ('rotate', None),
+ ('wait', False),
+ ('server', servers[0].id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServerManager.backup(server, backup_name, backup_type, rotation)
+ self.servers_mock.backup.assert_called_with(
+ servers[0].id,
+ servers[0].name,
+ '',
+ 1,
+ )
+
+ self.assertEqual(self.image_columns(images[0]), columns)
+ self.assertEqual(self.image_data(images[0]), data)
+
+ def test_server_backup_create_options(self):
+ servers = self.setup_servers_mock(count=1)
+ images = self.setup_images_mock(count=1, servers=servers)
+
+ arglist = [
+ '--name', 'image',
+ '--type', 'daily',
+ '--rotate', '2',
+ servers[0].id,
+ ]
+ verifylist = [
+ ('name', 'image'),
+ ('type', 'daily'),
+ ('rotate', 2),
+ ('server', servers[0].id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServerManager.backup(server, backup_name, backup_type, rotation)
+ self.servers_mock.backup.assert_called_with(
+ servers[0].id,
+ 'image',
+ 'daily',
+ 2,
+ )
+
+ self.assertEqual(self.image_columns(images[0]), columns)
+ self.assertEqual(self.image_data(images[0]), data)
+
+ @mock.patch.object(common_utils, 'wait_for_status', return_value=False)
+ def test_server_backup_wait_fail(self, mock_wait_for_status):
+ servers = self.setup_servers_mock(count=1)
+ images = image_fakes.FakeImage.create_images(
+ attrs={
+ 'name': servers[0].name,
+ 'status': 'active',
+ },
+ count=5,
+ )
+
+ self.images_mock.get = mock.MagicMock(
+ side_effect=images,
+ )
+
+ arglist = [
+ '--name', 'image',
+ '--type', 'daily',
+ '--wait',
+ servers[0].id,
+ ]
+ verifylist = [
+ ('name', 'image'),
+ ('type', 'daily'),
+ ('wait', True),
+ ('server', servers[0].id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.assertRaises(
+ exceptions.CommandError,
+ self.cmd.take_action,
+ parsed_args,
+ )
+
+ # ServerManager.backup(server, backup_name, backup_type, rotation)
+ self.servers_mock.backup.assert_called_with(
+ servers[0].id,
+ 'image',
+ 'daily',
+ 1,
+ )
+
+ mock_wait_for_status.assert_called_once_with(
+ self.images_mock.get,
+ images[0].id,
+ callback=mock.ANY
+ )
+
+ @mock.patch.object(common_utils, 'wait_for_status', return_value=True)
+ def test_server_backup_wait_ok(self, mock_wait_for_status):
+ servers = self.setup_servers_mock(count=1)
+ images = image_fakes.FakeImage.create_images(
+ attrs={
+ 'name': servers[0].name,
+ 'status': 'active',
+ },
+ count=5,
+ )
+
+ self.images_mock.get = mock.MagicMock(
+ side_effect=images,
+ )
+
+ arglist = [
+ '--name', 'image',
+ '--type', 'daily',
+ '--wait',
+ servers[0].id,
+ ]
+ verifylist = [
+ ('name', 'image'),
+ ('type', 'daily'),
+ ('wait', True),
+ ('server', servers[0].id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class ShowOne in cliff, abstract method take_action()
+ # returns a two-part tuple with a tuple of column names and a tuple of
+ # data to be shown.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # ServerManager.backup(server, backup_name, backup_type, rotation)
+ self.servers_mock.backup.assert_called_with(
+ servers[0].id,
+ 'image',
+ 'daily',
+ 1,
+ )
+
+ mock_wait_for_status.assert_called_once_with(
+ self.images_mock.get,
+ images[0].id,
+ callback=mock.ANY
+ )
+
+ self.assertEqual(self.image_columns(images[0]), columns)
+ self.assertEqual(self.image_data(images[0]), data)
diff --git a/openstackclient/tests/compute/v2/test_service.py b/openstackclient/tests/compute/v2/test_service.py
index 7a5a840..cf53497 100644
--- a/openstackclient/tests/compute/v2/test_service.py
+++ b/openstackclient/tests/compute/v2/test_service.py
@@ -13,8 +13,7 @@
# under the License.
#
-import mock
-
+from openstackclient.common import exceptions
from openstackclient.compute.v2 import service
from openstackclient.tests.compute.v2 import fakes as compute_fakes
@@ -128,6 +127,23 @@ class TestServiceSet(TestService):
self.cmd = service.SetService(self.app, None)
+ def test_set_nothing(self):
+ arglist = [
+ self.service.host,
+ self.service.binary,
+ ]
+ verifylist = [
+ ('host', self.service.host),
+ ('service', self.service.binary),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_mock.enable.assert_not_called()
+ self.service_mock.disable.assert_not_called()
+ self.service_mock.disable_log_reason.assert_not_called()
+ self.assertIsNone(result)
+
def test_service_set_enable(self):
arglist = [
'--enable',
@@ -135,7 +151,7 @@ class TestServiceSet(TestService):
self.service.binary,
]
verifylist = [
- ('enabled', True),
+ ('enable', True),
('host', self.service.host),
('service', self.service.binary),
]
@@ -156,7 +172,7 @@ class TestServiceSet(TestService):
self.service.binary,
]
verifylist = [
- ('enabled', False),
+ ('disable', True),
('host', self.service.host),
('service', self.service.binary),
]
@@ -179,7 +195,7 @@ class TestServiceSet(TestService):
self.service.binary,
]
verifylist = [
- ('enabled', False),
+ ('disable', True),
('disable_reason', reason),
('host', self.service.host),
('service', self.service.binary),
@@ -203,24 +219,13 @@ class TestServiceSet(TestService):
self.service.binary,
]
verifylist = [
- ('enabled', True),
('disable_reason', reason),
('host', self.service.host),
('service', self.service.binary),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
- with mock.patch.object(self.cmd.log, 'info') as mock_log:
- result = self.cmd.take_action(parsed_args)
-
- msg = "argument --disable-reason has been ignored"
- mock_log.assert_called_once_with(msg)
-
- self.service_mock.enable.assert_called_with(
- self.service.host,
- self.service.binary
- )
- self.assertIsNone(result)
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
def test_service_set_enable_with_disable_reason(self):
reason = 'earthquake'
@@ -231,21 +236,11 @@ class TestServiceSet(TestService):
self.service.binary,
]
verifylist = [
- ('enabled', True),
+ ('enable', True),
('disable_reason', reason),
('host', self.service.host),
('service', self.service.binary),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
- with mock.patch.object(self.cmd.log, 'info') as mock_log:
- result = self.cmd.take_action(parsed_args)
-
- msg = "argument --disable-reason has been ignored"
- mock_log.assert_called_once_with(msg)
-
- self.service_mock.enable.assert_called_with(
- self.service.host,
- self.service.binary
- )
- self.assertIsNone(result)
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
diff --git a/openstackclient/tests/fakes.py b/openstackclient/tests/fakes.py
index 229b465..ad4705a 100644
--- a/openstackclient/tests/fakes.py
+++ b/openstackclient/tests/fakes.py
@@ -97,6 +97,11 @@ class FakeApp(object):
self.log = _log
+class FakeOptions(object):
+ def __init__(self, **kwargs):
+ self.os_beta_command = False
+
+
class FakeClient(object):
def __init__(self, **kwargs):
@@ -105,6 +110,9 @@ class FakeClient(object):
class FakeClientManager(object):
+ _api_version = {
+ 'image': '2',
+ }
def __init__(self):
self.compute = None
diff --git a/openstackclient/tests/image/v2/fakes.py b/openstackclient/tests/image/v2/fakes.py
index a662a58..24aaec5 100644
--- a/openstackclient/tests/image/v2/fakes.py
+++ b/openstackclient/tests/image/v2/fakes.py
@@ -157,6 +157,8 @@ class FakeImagev2Client(object):
self.images.resource_class = fakes.FakeResource(None, {})
self.image_members = mock.Mock()
self.image_members.resource_class = fakes.FakeResource(None, {})
+ self.image_tags = mock.Mock()
+ self.image_tags.resource_class = fakes.FakeResource(None, {})
self.auth_token = kwargs['token']
self.management_url = kwargs['endpoint']
diff --git a/openstackclient/tests/image/v2/test_image.py b/openstackclient/tests/image/v2/test_image.py
index beebdef..ca20d83 100644
--- a/openstackclient/tests/image/v2/test_image.py
+++ b/openstackclient/tests/image/v2/test_image.py
@@ -37,6 +37,8 @@ class TestImage(image_fakes.TestImagev2):
self.images_mock.reset_mock()
self.image_members_mock = self.app.client_manager.image.image_members
self.image_members_mock.reset_mock()
+ self.image_tags_mock = self.app.client_manager.image.image_tags
+ self.image_tags_mock.reset_mock()
# Get shortcut to the Mocks in identity client
self.project_mock = self.app.client_manager.identity.projects
@@ -1184,3 +1186,94 @@ class TestImageShow(TestImage):
self.assertEqual(image_fakes.IMAGE_columns, columns)
self.assertEqual(image_fakes.IMAGE_SHOW_data, data)
+
+
+class TestImageUnset(TestImage):
+
+ attrs = {}
+ attrs['tags'] = ['test']
+ attrs['prop'] = 'test'
+ image = image_fakes.FakeImage.create_one_image(attrs)
+
+ def setUp(self):
+ super(TestImageUnset, self).setUp()
+
+ # Set up the schema
+ self.model = warlock.model_factory(
+ image_fakes.IMAGE_schema,
+ schemas.SchemaBasedModel,
+ )
+
+ self.images_mock.get.return_value = self.image
+ self.image_tags_mock.delete.return_value = self.image
+
+ # Get the command object to test
+ self.cmd = image.UnsetImage(self.app, None)
+
+ def test_image_unset_tag_option(self):
+
+ arglist = [
+ '--tag', 'test',
+ self.image.id,
+ ]
+
+ verifylist = [
+ ('tags', ['test']),
+ ('image', self.image.id),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.image_tags_mock.delete.assert_called_with(
+ self.image.id, 'test'
+ )
+ self.assertIsNone(result)
+
+ def test_image_unset_property_option(self):
+
+ arglist = [
+ '--property', 'prop',
+ self.image.id,
+ ]
+
+ verifylist = [
+ ('properties', ['prop']),
+ ('image', self.image.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {}
+ self.images_mock.update.assert_called_with(
+ self.image.id,
+ parsed_args.properties,
+ **kwargs)
+
+ self.assertIsNone(result)
+
+ def test_image_unset_mixed_option(self):
+
+ arglist = [
+ '--tag', 'test',
+ '--property', 'prop',
+ self.image.id,
+ ]
+
+ verifylist = [
+ ('tags', ['test']),
+ ('properties', ['prop']),
+ ('image', self.image.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ kwargs = {}
+ self.images_mock.update.assert_called_with(
+ self.image.id,
+ parsed_args.properties,
+ **kwargs)
+
+ self.image_tags_mock.delete.assert_called_with(
+ self.image.id, 'test'
+ )
+ self.assertIsNone(result)
diff --git a/openstackclient/tests/network/v2/fakes.py b/openstackclient/tests/network/v2/fakes.py
index 417cf26..ccbe395 100644
--- a/openstackclient/tests/network/v2/fakes.py
+++ b/openstackclient/tests/network/v2/fakes.py
@@ -127,6 +127,25 @@ class FakeAddressScope(object):
return address_scopes
+ @staticmethod
+ def get_address_scopes(address_scopes=None, count=2):
+ """Get an iterable MagicMock object with a list of faked address scopes.
+
+ If address scopes list is provided, then initialize the Mock object
+ with the list. Otherwise create one.
+
+ :param List address scopes:
+ A list of FakeResource objects faking address scopes
+ :param int count:
+ The number of address scopes to fake
+ :return:
+ An iterable Mock object with side_effect set to a list of faked
+ address scopes
+ """
+ if address_scopes is None:
+ address_scopes = FakeAddressScope.create_address_scopes(count)
+ return mock.MagicMock(side_effect=address_scopes)
+
class FakeAvailabilityZone(object):
"""Fake one or more network availability zones (AZs)."""
@@ -177,6 +196,50 @@ class FakeAvailabilityZone(object):
return availability_zones
+class FakeIPAvailability(object):
+ """Fake one or more network ip availabilities."""
+
+ @staticmethod
+ def create_one_ip_availability():
+ """Create a fake list with ip availability stats of a network.
+
+ :return:
+ A FakeResource object with network_name, network_id, etc.
+ """
+
+ # Set default attributes.
+ network_ip_availability = {
+ 'network_id': 'network-id-' + uuid.uuid4().hex,
+ 'network_name': 'network-name-' + uuid.uuid4().hex,
+ 'tenant_id': '',
+ 'subnet_ip_availability': [],
+ 'total_ips': 254,
+ 'used_ips': 6,
+ }
+
+ network_ip_availability = fakes.FakeResource(
+ info=copy.deepcopy(network_ip_availability),
+ loaded=True)
+ return network_ip_availability
+
+ @staticmethod
+ def create_ip_availability(count=2):
+ """Create fake list of ip availability stats of multiple networks.
+
+ :param int count:
+ The number of networks to fake
+ :return:
+ A list of FakeResource objects faking network ip availability stats
+ """
+ network_ip_availabilities = []
+ for i in range(0, count):
+ network_ip_availability = \
+ FakeIPAvailability.create_one_ip_availability()
+ network_ip_availabilities.append(network_ip_availability)
+
+ return network_ip_availabilities
+
+
class FakeNetwork(object):
"""Fake one or more networks."""
@@ -256,6 +319,58 @@ class FakeNetwork(object):
return mock.MagicMock(side_effect=networks)
+class FakeNetworkSegment(object):
+ """Fake one or more network segments."""
+
+ @staticmethod
+ def create_one_network_segment(attrs=None):
+ """Create a fake network segment.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object faking the network segment
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ network_segment_attrs = {
+ 'id': 'segment-id-' + uuid.uuid4().hex,
+ 'network_id': 'network-id-' + uuid.uuid4().hex,
+ 'network_type': 'vlan',
+ 'physical_network': 'physical-network-name-' + uuid.uuid4().hex,
+ 'segmentation_id': 1024,
+ }
+
+ # Overwrite default attributes.
+ network_segment_attrs.update(attrs)
+
+ network_segment = fakes.FakeResource(
+ info=copy.deepcopy(network_segment_attrs),
+ loaded=True
+ )
+
+ return network_segment
+
+ @staticmethod
+ def create_network_segments(attrs=None, count=2):
+ """Create multiple fake network segments.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of network segments to fake
+ :return:
+ A list of FakeResource objects faking the network segments
+ """
+ network_segments = []
+ for i in range(0, count):
+ network_segments.append(
+ FakeNetworkSegment.create_one_network_segment(attrs)
+ )
+ return network_segments
+
+
class FakePort(object):
"""Fake one or more ports."""
diff --git a/openstackclient/tests/network/v2/test_address_scope.py b/openstackclient/tests/network/v2/test_address_scope.py
index ac94b48..b4f4fa8 100644
--- a/openstackclient/tests/network/v2/test_address_scope.py
+++ b/openstackclient/tests/network/v2/test_address_scope.py
@@ -14,6 +14,7 @@
import copy
import mock
+from mock import call
from openstackclient.common import exceptions
from openstackclient.network.v2 import address_scope
from openstackclient.tests import fakes
@@ -168,33 +169,86 @@ class TestCreateAddressScope(TestAddressScope):
class TestDeleteAddressScope(TestAddressScope):
# The address scope to delete.
- _address_scope = (
- network_fakes.FakeAddressScope.create_one_address_scope())
+ _address_scopes = (
+ network_fakes.FakeAddressScope.create_address_scopes(count=2))
def setUp(self):
super(TestDeleteAddressScope, self).setUp()
self.network.delete_address_scope = mock.Mock(return_value=None)
- self.network.find_address_scope = mock.Mock(
- return_value=self._address_scope)
+ self.network.find_address_scope = (
+ network_fakes.FakeAddressScope.get_address_scopes(
+ address_scopes=self._address_scopes)
+ )
# Get the command object to test
self.cmd = address_scope.DeleteAddressScope(self.app, self.namespace)
- def test_delete(self):
+ def test_address_scope_delete(self):
arglist = [
- self._address_scope.name,
+ self._address_scopes[0].name,
]
verifylist = [
- ('address_scope', self._address_scope.name),
+ ('address_scope', [self._address_scopes[0].name]),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
+ self.network.find_address_scope.assert_called_once_with(
+ self._address_scopes[0].name, ignore_missing=False)
self.network.delete_address_scope.assert_called_once_with(
- self._address_scope)
+ self._address_scopes[0])
self.assertIsNone(result)
+ def test_multi_address_scopes_delete(self):
+ arglist = []
+ verifylist = []
+
+ for a in self._address_scopes:
+ arglist.append(a.name)
+ verifylist = [
+ ('address_scope', arglist),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ calls = []
+ for a in self._address_scopes:
+ calls.append(call(a))
+ self.network.delete_address_scope.assert_has_calls(calls)
+ self.assertIsNone(result)
+
+ def test_multi_address_scopes_delete_with_exception(self):
+ arglist = [
+ self._address_scopes[0].name,
+ 'unexist_address_scope',
+ ]
+ verifylist = [
+ ('address_scope',
+ [self._address_scopes[0].name, 'unexist_address_scope']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self._address_scopes[0], exceptions.CommandError]
+ self.network.find_address_scope = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 address scopes failed to delete.', str(e))
+
+ self.network.find_address_scope.assert_any_call(
+ self._address_scopes[0].name, ignore_missing=False)
+ self.network.find_address_scope.assert_any_call(
+ 'unexist_address_scope', ignore_missing=False)
+ self.network.delete_address_scope.assert_called_once_with(
+ self._address_scopes[0]
+ )
+
class TestListAddressScope(TestAddressScope):
diff --git a/openstackclient/tests/network/v2/test_ip_availability.py b/openstackclient/tests/network/v2/test_ip_availability.py
new file mode 100644
index 0000000..04979e7
--- /dev/null
+++ b/openstackclient/tests/network/v2/test_ip_availability.py
@@ -0,0 +1,180 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+import copy
+import mock
+
+from openstackclient.common import utils as osc_utils
+from openstackclient.network.v2 import ip_availability
+from openstackclient.tests import fakes
+from openstackclient.tests.identity.v3 import fakes as identity_fakes
+from openstackclient.tests.network.v2 import fakes as network_fakes
+from openstackclient.tests import utils as tests_utils
+
+
+class TestIPAvailability(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestIPAvailability, self).setUp()
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+
+ # Set identity client v3. And get a shortcut to Identity client.
+ identity_client = identity_fakes.FakeIdentityv3Client(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN,
+ )
+ self.app.client_manager.identity = identity_client
+ self.identity = self.app.client_manager.identity
+
+ # Get a shortcut to the ProjectManager Mock
+ self.projects_mock = self.identity.projects
+ self.projects_mock.get.return_value = fakes.FakeResource(
+ None,
+ copy.deepcopy(identity_fakes.PROJECT),
+ loaded=True,
+ )
+
+
+class TestListIPAvailability(TestIPAvailability):
+
+ _ip_availability = \
+ network_fakes.FakeIPAvailability.create_ip_availability(count=3)
+ columns = (
+ 'Network ID',
+ 'Network Name',
+ 'Total IPs',
+ 'Used IPs',
+ )
+ data = []
+ for net in _ip_availability:
+ data.append((
+ net.network_id,
+ net.network_name,
+ net.total_ips,
+ net.used_ips,
+ ))
+
+ def setUp(self):
+ super(TestListIPAvailability, self).setUp()
+
+ self.cmd = ip_availability.ListIPAvailability(
+ self.app, self.namespace)
+ self.network.network_ip_availabilities = mock.Mock(
+ return_value=self._ip_availability)
+
+ def test_list_no_options(self):
+ arglist = []
+ verifylist = []
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.network_ip_availabilities.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_list_ip_version(self):
+ arglist = [
+ '--ip-version', str(4),
+ ]
+ verifylist = [
+ ('ip_version', 4)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'ip_version': 4}
+
+ self.network.network_ip_availabilities.assert_called_once_with(
+ **filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_list_project(self):
+ arglist = [
+ '--project', identity_fakes.project_name
+ ]
+ verifylist = [
+ ('project', identity_fakes.project_name)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+ filters = {'tenant_id': identity_fakes.project_id}
+
+ self.network.network_ip_availabilities.assert_called_once_with(
+ **filters)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestShowIPAvailability(TestIPAvailability):
+
+ _ip_availability = \
+ network_fakes.FakeIPAvailability.create_one_ip_availability()
+
+ columns = (
+ 'network_id',
+ 'network_name',
+ 'project_id',
+ 'subnet_ip_availability',
+ 'total_ips',
+ 'used_ips',
+ )
+ data = (
+ _ip_availability.network_id,
+ _ip_availability.network_name,
+ _ip_availability.tenant_id,
+ osc_utils.format_list(
+ _ip_availability.subnet_ip_availability),
+ _ip_availability.total_ips,
+ _ip_availability.used_ips,
+ )
+
+ def setUp(self):
+ super(TestShowIPAvailability, self).setUp()
+
+ self.network.find_network_ip_availability = mock.Mock(
+ return_value=self._ip_availability)
+
+ # Get the command object to test
+ self.cmd = ip_availability.ShowIPAvailability(
+ self.app, self.namespace)
+
+ def test_show_no_option(self):
+ arglist = []
+ verifylist = []
+
+ self.assertRaises(tests_utils.ParserException,
+ self.check_parser, self.cmd, arglist, verifylist)
+
+ def test_show_all_options(self):
+ arglist = [
+ self._ip_availability.network_name,
+ ]
+ verifylist = [
+ ('network', self._ip_availability.network_name)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+ self.network.find_network_ip_availability.assert_called_once_with(
+ self._ip_availability.network_name,
+ ignore_missing=False)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/network/v2/test_network_segment.py b/openstackclient/tests/network/v2/test_network_segment.py
new file mode 100644
index 0000000..0a99ece
--- /dev/null
+++ b/openstackclient/tests/network/v2/test_network_segment.py
@@ -0,0 +1,199 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+import mock
+
+from openstackclient.common import exceptions
+from openstackclient.network.v2 import network_segment
+from openstackclient.tests.network.v2 import fakes as network_fakes
+from openstackclient.tests import utils as tests_utils
+
+
+class TestNetworkSegment(network_fakes.TestNetworkV2):
+
+ def setUp(self):
+ super(TestNetworkSegment, self).setUp()
+
+ # Enable beta commands.
+ self.app.options.os_beta_command = True
+
+ # Get a shortcut to the network client
+ self.network = self.app.client_manager.network
+
+
+class TestListNetworkSegment(TestNetworkSegment):
+ _network = network_fakes.FakeNetwork.create_one_network()
+ _network_segments = \
+ network_fakes.FakeNetworkSegment.create_network_segments(count=3)
+
+ columns = (
+ 'ID',
+ 'Network',
+ 'Network Type',
+ 'Segment',
+ )
+ columns_long = columns + (
+ 'Physical Network',
+ )
+
+ data = []
+ for _network_segment in _network_segments:
+ data.append((
+ _network_segment.id,
+ _network_segment.network_id,
+ _network_segment.network_type,
+ _network_segment.segmentation_id,
+ ))
+
+ data_long = []
+ for _network_segment in _network_segments:
+ data_long.append((
+ _network_segment.id,
+ _network_segment.network_id,
+ _network_segment.network_type,
+ _network_segment.segmentation_id,
+ _network_segment.physical_network,
+ ))
+
+ def setUp(self):
+ super(TestListNetworkSegment, self).setUp()
+
+ # Get the command object to test
+ self.cmd = network_segment.ListNetworkSegment(self.app, self.namespace)
+
+ self.network.find_network = mock.Mock(return_value=self._network)
+ self.network.segments = mock.Mock(return_value=self._network_segments)
+
+ def test_list_no_option(self):
+ arglist = []
+ verifylist = [
+ ('long', False),
+ ('network', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.segments.assert_called_once_with()
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_list_no_beta_commands(self):
+ self.app.options.os_beta_command = False
+ parsed_args = self.check_parser(self.cmd, [], [])
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+
+ def test_list_long(self):
+ arglist = [
+ '--long',
+ ]
+ verifylist = [
+ ('long', True),
+ ('network', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.segments.assert_called_once_with()
+ self.assertEqual(self.columns_long, columns)
+ self.assertEqual(self.data_long, list(data))
+
+ def test_list_network(self):
+ arglist = [
+ '--network',
+ self._network.id,
+ ]
+ verifylist = [
+ ('long', False),
+ ('network', self._network.id)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.segments.assert_called_once_with(
+ **{'network_id': self._network.id}
+ )
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+
+class TestShowNetworkSegment(TestNetworkSegment):
+
+ # The network segment to show.
+ _network_segment = \
+ network_fakes.FakeNetworkSegment.create_one_network_segment()
+
+ columns = (
+ 'id',
+ 'network_id',
+ 'network_type',
+ 'physical_network',
+ 'segmentation_id',
+ )
+
+ data = (
+ _network_segment.id,
+ _network_segment.network_id,
+ _network_segment.network_type,
+ _network_segment.physical_network,
+ _network_segment.segmentation_id,
+ )
+
+ def setUp(self):
+ super(TestShowNetworkSegment, self).setUp()
+
+ self.network.find_segment = mock.Mock(
+ return_value=self._network_segment
+ )
+
+ # Get the command object to test
+ self.cmd = network_segment.ShowNetworkSegment(self.app, self.namespace)
+
+ def test_show_no_options(self):
+ # Missing required args should bail here
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, [], [])
+
+ def test_show_no_beta_commands(self):
+ arglist = [
+ self._network_segment.id,
+ ]
+ verifylist = [
+ ('network_segment', self._network_segment.id),
+ ]
+ self.app.options.os_beta_command = False
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ self.assertRaises(exceptions.CommandError, self.cmd.take_action,
+ parsed_args)
+
+ def test_show_all_options(self):
+ arglist = [
+ self._network_segment.id,
+ ]
+ verifylist = [
+ ('network_segment', self._network_segment.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.find_segment.assert_called_once_with(
+ self._network_segment.id,
+ ignore_missing=False
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
diff --git a/openstackclient/tests/network/v2/test_port.py b/openstackclient/tests/network/v2/test_port.py
index f2aa26c..dd98a63 100644
--- a/openstackclient/tests/network/v2/test_port.py
+++ b/openstackclient/tests/network/v2/test_port.py
@@ -13,6 +13,8 @@
import mock
+from mock import call
+from openstackclient.common import exceptions
from openstackclient.common import utils
from openstackclient.network.v2 import port
from openstackclient.tests.network.v2 import fakes as network_fakes
@@ -174,30 +176,82 @@ class TestCreatePort(TestPort):
class TestDeletePort(TestPort):
- # The port to delete.
- _port = network_fakes.FakePort.create_one_port()
+ # Ports to delete.
+ _ports = network_fakes.FakePort.create_ports(count=2)
def setUp(self):
super(TestDeletePort, self).setUp()
self.network.delete_port = mock.Mock(return_value=None)
- self.network.find_port = mock.Mock(return_value=self._port)
+ self.network.find_port = network_fakes.FakePort.get_ports(
+ ports=self._ports)
# Get the command object to test
self.cmd = port.DeletePort(self.app, self.namespace)
- def test_delete(self):
+ def test_port_delete(self):
arglist = [
- self._port.name,
+ self._ports[0].name,
]
verifylist = [
- ('port', [self._port.name]),
+ ('port', [self._ports[0].name]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+ self.network.find_port.assert_called_once_with(
+ self._ports[0].name, ignore_missing=False)
+ self.network.delete_port.assert_called_once_with(self._ports[0])
+ self.assertIsNone(result)
+
+ def test_multi_ports_delete(self):
+ arglist = []
+ verifylist = []
+
+ for p in self._ports:
+ arglist.append(p.name)
+ verifylist = [
+ ('port', arglist),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- self.network.delete_port.assert_called_once_with(self._port)
+
+ calls = []
+ for p in self._ports:
+ calls.append(call(p))
+ self.network.delete_port.assert_has_calls(calls)
self.assertIsNone(result)
+ def test_multi_ports_delete_with_exception(self):
+ arglist = [
+ self._ports[0].name,
+ 'unexist_port',
+ ]
+ verifylist = [
+ ('port',
+ [self._ports[0].name, 'unexist_port']),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [self._ports[0], exceptions.CommandError]
+ self.network.find_port = (
+ mock.MagicMock(side_effect=find_mock_result)
+ )
+
+ try:
+ self.cmd.take_action(parsed_args)
+ self.fail('CommandError should be raised.')
+ except exceptions.CommandError as e:
+ self.assertEqual('1 of 2 ports failed to delete.', str(e))
+
+ self.network.find_port.assert_any_call(
+ self._ports[0].name, ignore_missing=False)
+ self.network.find_port.assert_any_call(
+ 'unexist_port', ignore_missing=False)
+ self.network.delete_port.assert_called_once_with(
+ self._ports[0]
+ )
+
class TestListPort(TestPort):
@@ -283,6 +337,7 @@ class TestSetPort(TestPort):
]
verifylist = [
('fixed_ip', [{'ip-address': '10.0.0.11'}]),
+ ('port', self._port.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -304,6 +359,7 @@ class TestSetPort(TestPort):
]
verifylist = [
('fixed_ip', [{'ip-address': '10.0.0.12'}]),
+ ('port', _testport.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
@@ -325,6 +381,7 @@ class TestSetPort(TestPort):
('disable', True),
('no_binding_profile', True),
('no_fixed_ip', True),
+ ('port', self._port.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -352,7 +409,8 @@ class TestSetPort(TestPort):
('vnic_type', 'macvtap'),
('binding_profile', {'foo': 'bar'}),
('host', 'binding-host-id-xxxx'),
- ('name', 'newName')
+ ('name', 'newName'),
+ ('port', self._port.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/tests/utils.py b/openstackclient/tests/utils.py
index 319c1c1..8dead71 100644
--- a/openstackclient/tests/utils.py
+++ b/openstackclient/tests/utils.py
@@ -60,6 +60,7 @@ class TestCommand(TestCase):
self.fake_log = fakes.FakeLog()
self.app = fakes.FakeApp(self.fake_stdout, self.fake_log)
self.app.client_manager = fakes.FakeClientManager()
+ self.app.options = fakes.FakeOptions()
def check_parser(self, cmd, args, verify_args):
cmd_parser = cmd.get_parser('check_parser')
diff --git a/openstackclient/tests/volume/v1/fakes.py b/openstackclient/tests/volume/v1/fakes.py
index d6c4643..6c34986 100644
--- a/openstackclient/tests/volume/v1/fakes.py
+++ b/openstackclient/tests/volume/v1/fakes.py
@@ -129,6 +129,57 @@ QOS_WITH_ASSOCIATIONS = {
}
+class FakeTransferClient(object):
+
+ def __init__(self, **kwargs):
+
+ self.transfers = mock.Mock()
+ self.transfers.resource_class = fakes.FakeResource(None, {})
+
+
+class TestTransfer(utils.TestCommand):
+
+ def setUp(self):
+ super(TestTransfer, self).setUp()
+
+ self.app.client_manager.volume = FakeTransferClient(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN
+ )
+
+
+class FakeTransfer(object):
+ """Fake one or more Transfer."""
+
+ @staticmethod
+ def create_one_transfer(attrs=None):
+ """Create a fake transfer.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes of Transfer Request
+ :retrun:
+ A FakeResource object with volume_id, name, id.
+ """
+ # Set default attribute
+ transfer_info = {
+ 'volume_id': 'ce26708d-a7f8-4b4b-9861-4a80256615a7',
+ 'name': 'fake_transfer_name',
+ 'id': '731a7f53-aa92-4fbd-9de3-6f7d729c926b'
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ attrs = attrs or {}
+
+ transfer_info.update(attrs)
+
+ transfer = fakes.FakeResource(
+ None,
+ transfer_info,
+ loaded=True)
+
+ return transfer
+
+
class FakeServiceClient(object):
def __init__(self, **kwargs):
@@ -171,8 +222,8 @@ class FakeService(object):
}
# Overwrite default attributes if there are some attributes set
- if attrs is None:
- attrs = {}
+ attrs = attrs or {}
+
service_info.update(attrs)
service = fakes.FakeResource(
diff --git a/openstackclient/tests/volume/v1/test_transfer_request.py b/openstackclient/tests/volume/v1/test_transfer_request.py
new file mode 100644
index 0000000..94e02d6
--- /dev/null
+++ b/openstackclient/tests/volume/v1/test_transfer_request.py
@@ -0,0 +1,114 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+
+from openstackclient.tests.volume.v1 import fakes as transfer_fakes
+from openstackclient.volume.v1 import volume_transfer_request
+
+
+class TestTransfer(transfer_fakes.TestTransfer):
+
+ def setUp(self):
+ super(TestTransfer, self).setUp()
+
+ # Get a shortcut to the TransferManager Mock
+ self.transfer_mock = self.app.client_manager.volume.transfers
+ self.transfer_mock.reset_mock()
+
+
+class TestTransferList(TestTransfer):
+
+ # The Transfers to be listed
+ volume_transfers = transfer_fakes.FakeTransfer.create_one_transfer()
+
+ def setUp(self):
+ super(TestTransferList, self).setUp()
+
+ self.transfer_mock.list.return_value = [self.volume_transfers]
+
+ # Get the command object to test
+ self.cmd = volume_transfer_request.ListTransferRequests(self.app, None)
+
+ def test_transfer_list_without_argument(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ expected_columns = [
+ 'ID',
+ 'Volume',
+ 'Name',
+ ]
+
+ # confirming if all expected columns are present in the result.
+ self.assertEqual(expected_columns, columns)
+
+ datalist = ((
+ self.volume_transfers.id,
+ self.volume_transfers.volume_id,
+ self.volume_transfers.name,
+ ), )
+
+ # confirming if all expected values are present in the result.
+ self.assertEqual(datalist, tuple(data))
+
+ # checking if proper call was made to list volume_transfers
+ self.transfer_mock.list.assert_called_with(
+ detailed=True,
+ search_opts={'all_tenants': 0}
+ )
+
+ def test_transfer_list_with_argument(self):
+ arglist = [
+ "--all-projects"
+ ]
+ verifylist = [
+ ("all_projects", True)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ expected_columns = [
+ 'ID',
+ 'Volume',
+ 'Name',
+ ]
+
+ # confirming if all expected columns are present in the result.
+ self.assertEqual(expected_columns, columns)
+
+ datalist = ((
+ self.volume_transfers.id,
+ self.volume_transfers.volume_id,
+ self.volume_transfers.name,
+ ), )
+
+ # confirming if all expected values are present in the result.
+ self.assertEqual(datalist, tuple(data))
+
+ # checking if proper call was made to list volume_transfers
+ self.transfer_mock.list.assert_called_with(
+ detailed=True,
+ search_opts={'all_tenants': 1}
+ )
diff --git a/openstackclient/tests/volume/v1/test_volume.py b/openstackclient/tests/volume/v1/test_volume.py
index e0fd1c0..e4f51bb 100644
--- a/openstackclient/tests/volume/v1/test_volume.py
+++ b/openstackclient/tests/volume/v1/test_volume.py
@@ -578,9 +578,6 @@ class TestVolumeSet(TestVolume):
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
-
- self.assertEqual("No changes requested\n",
- self.app.log.messages.get('error'))
self.assertIsNone(result)
def test_volume_set_name(self):
diff --git a/openstackclient/tests/volume/v2/fakes.py b/openstackclient/tests/volume/v2/fakes.py
index 181552d..e61fe8a 100644
--- a/openstackclient/tests/volume/v2/fakes.py
+++ b/openstackclient/tests/volume/v2/fakes.py
@@ -232,6 +232,57 @@ EXTENSION = {
}
+class FakeTransferClient(object):
+
+ def __init__(self, **kwargs):
+
+ self.transfers = mock.Mock()
+ self.transfers.resource_class = fakes.FakeResource(None, {})
+
+
+class TestTransfer(utils.TestCommand):
+
+ def setUp(self):
+ super(TestTransfer, self).setUp()
+
+ self.app.client_manager.volume = FakeTransferClient(
+ endpoint=fakes.AUTH_URL,
+ token=fakes.AUTH_TOKEN
+ )
+
+
+class FakeTransfer(object):
+ """Fake one or more Transfer."""
+
+ @staticmethod
+ def create_one_transfer(attrs=None):
+ """Create a fake transfer.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes of Transfer Request
+ :retrun:
+ A FakeResource object with volume_id, name, id.
+ """
+ # Set default attribute
+ transfer_info = {
+ 'volume_id': 'ce26708d-a7f8-4b4b-9861-4a80256615a7',
+ 'name': 'fake_transfer_name',
+ 'id': '731a7f53-aa92-4fbd-9de3-6f7d729c926b'
+ }
+
+ # Overwrite default attributes if there are some attributes set
+ attrs = attrs or {}
+
+ transfer_info.update(attrs)
+
+ transfer = fakes.FakeResource(
+ None,
+ transfer_info,
+ loaded=True)
+
+ return transfer
+
+
class FakeServiceClient(object):
def __init__(self, **kwargs):
@@ -274,8 +325,8 @@ class FakeService(object):
}
# Overwrite default attributes if there are some attributes set
- if attrs is None:
- attrs = {}
+ attrs = attrs or {}
+
service_info.update(attrs)
service = fakes.FakeResource(
@@ -592,6 +643,81 @@ class FakeBackup(object):
return backups
+class FakeQos(object):
+ """Fake one or more Qos specification."""
+
+ @staticmethod
+ def create_one_qos(attrs=None):
+ """Create a fake Qos specification.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with id, name, consumer, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ qos_info = {
+ "id": 'qos-id-' + uuid.uuid4().hex,
+ "name": 'qos-name-' + uuid.uuid4().hex,
+ "consumer": 'front-end',
+ "specs": {"foo": "bar", "iops": "9001"},
+ }
+
+ # Overwrite default attributes.
+ qos_info.update(attrs)
+
+ qos = fakes.FakeResource(
+ info=copy.deepcopy(qos_info),
+ loaded=True)
+ return qos
+
+ @staticmethod
+ def create_one_qos_association(attrs=None):
+ """Create a fake Qos specification association.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :return:
+ A FakeResource object with id, name, association_type, etc.
+ """
+ attrs = attrs or {}
+
+ # Set default attributes.
+ qos_association_info = {
+ "id": 'type-id-' + uuid.uuid4().hex,
+ "name": 'type-name-' + uuid.uuid4().hex,
+ "association_type": 'volume_type',
+ }
+
+ # Overwrite default attributes.
+ qos_association_info.update(attrs)
+
+ qos_association = fakes.FakeResource(
+ info=copy.deepcopy(qos_association_info),
+ loaded=True)
+ return qos_association
+
+ @staticmethod
+ def create_qoses(attrs=None, count=2):
+ """Create multiple fake Qos specifications.
+
+ :param Dictionary attrs:
+ A dictionary with all attributes
+ :param int count:
+ The number of Qos specifications to fake
+ :return:
+ A list of FakeResource objects faking the Qos specifications
+ """
+ qoses = []
+ for i in range(0, count):
+ qos = FakeQos.create_one_qos(attrs)
+ qoses.append(qos)
+
+ return qoses
+
+
class FakeSnapshot(object):
"""Fake one or more snapshot."""
diff --git a/openstackclient/tests/volume/v2/test_qos_specs.py b/openstackclient/tests/volume/v2/test_qos_specs.py
index 5232285..741f4e7 100644
--- a/openstackclient/tests/volume/v2/test_qos_specs.py
+++ b/openstackclient/tests/volume/v2/test_qos_specs.py
@@ -13,10 +13,7 @@
# under the License.
#
-import copy
-
from openstackclient.common import utils
-from openstackclient.tests import fakes
from openstackclient.tests.volume.v2 import fakes as volume_fakes
from openstackclient.volume.v2 import qos_specs
@@ -35,275 +32,228 @@ class TestQos(volume_fakes.TestVolume):
class TestQosAssociate(TestQos):
+ volume_type = volume_fakes.FakeType.create_one_type()
+ qos_spec = volume_fakes.FakeQos.create_one_qos()
+
def setUp(self):
super(TestQosAssociate, self).setUp()
+ self.qos_mock.get.return_value = self.qos_spec
+ self.types_mock.get.return_value = self.volume_type
# Get the command object to test
self.cmd = qos_specs.AssociateQos(self.app, None)
def test_qos_associate(self):
- self.qos_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.QOS),
- loaded=True
- )
- self.types_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.TYPE),
- loaded=True
- )
arglist = [
- volume_fakes.qos_id,
- volume_fakes.type_id
+ self.qos_spec.id,
+ self.volume_type.id
]
verifylist = [
- ('qos_spec', volume_fakes.qos_id),
- ('volume_type', volume_fakes.type_id)
+ ('qos_spec', self.qos_spec.id),
+ ('volume_type', self.volume_type.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.qos_mock.associate.assert_called_with(
- volume_fakes.qos_id,
- volume_fakes.type_id
+ self.qos_spec.id,
+ self.volume_type.id
)
self.assertIsNone(result)
class TestQosCreate(TestQos):
+ new_qos_spec = volume_fakes.FakeQos.create_one_qos()
columns = (
'consumer',
'id',
- 'name'
+ 'name',
+ 'specs'
)
- datalist = (
- volume_fakes.qos_consumer,
- volume_fakes.qos_id,
- volume_fakes.qos_name
+ data = (
+ new_qos_spec.consumer,
+ new_qos_spec.id,
+ new_qos_spec.name,
+ new_qos_spec.specs
)
def setUp(self):
super(TestQosCreate, self).setUp()
+ self.qos_mock.create.return_value = self.new_qos_spec
# Get the command object to test
self.cmd = qos_specs.CreateQos(self.app, None)
def test_qos_create_without_properties(self):
- self.qos_mock.create.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.QOS_DEFAULT_CONSUMER),
- loaded=True
- )
-
arglist = [
- volume_fakes.qos_name,
+ self.new_qos_spec.name,
]
verifylist = [
- ('name', volume_fakes.qos_name),
+ ('name', self.new_qos_spec.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.qos_mock.create.assert_called_with(
- volume_fakes.qos_name,
- {'consumer': volume_fakes.qos_default_consumer}
+ self.new_qos_spec.name,
+ {'consumer': 'both'}
)
self.assertEqual(self.columns, columns)
- datalist = (
- volume_fakes.qos_default_consumer,
- volume_fakes.qos_id,
- volume_fakes.qos_name
- )
- self.assertEqual(datalist, data)
+ self.assertEqual(self.data, data)
def test_qos_create_with_consumer(self):
- self.qos_mock.create.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.QOS),
- loaded=True
- )
-
arglist = [
- volume_fakes.qos_name,
- '--consumer', volume_fakes.qos_consumer
+ '--consumer', self.new_qos_spec.consumer,
+ self.new_qos_spec.name,
]
verifylist = [
- ('name', volume_fakes.qos_name),
- ('consumer', volume_fakes.qos_consumer)
+ ('consumer', self.new_qos_spec.consumer),
+ ('name', self.new_qos_spec.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.qos_mock.create.assert_called_with(
- volume_fakes.qos_name,
- {'consumer': volume_fakes.qos_consumer}
+ self.new_qos_spec.name,
+ {'consumer': self.new_qos_spec.consumer}
)
self.assertEqual(self.columns, columns)
- self.assertEqual(self.datalist, data)
+ self.assertEqual(self.data, data)
def test_qos_create_with_properties(self):
- self.qos_mock.create.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.QOS_WITH_SPECS),
- loaded=True
- )
-
arglist = [
- volume_fakes.qos_name,
- '--consumer', volume_fakes.qos_consumer,
+ '--consumer', self.new_qos_spec.consumer,
'--property', 'foo=bar',
- '--property', 'iops=9001'
+ '--property', 'iops=9001',
+ self.new_qos_spec.name,
]
verifylist = [
- ('name', volume_fakes.qos_name),
- ('consumer', volume_fakes.qos_consumer),
- ('property', volume_fakes.qos_specs)
+ ('consumer', self.new_qos_spec.consumer),
+ ('property', self.new_qos_spec.specs),
+ ('name', self.new_qos_spec.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
- specs = volume_fakes.qos_specs.copy()
- specs.update({'consumer': volume_fakes.qos_consumer})
+ self.new_qos_spec.specs.update(
+ {'consumer': self.new_qos_spec.consumer})
self.qos_mock.create.assert_called_with(
- volume_fakes.qos_name,
- specs
+ self.new_qos_spec.name,
+ self.new_qos_spec.specs
)
- columns = self.columns + (
- 'specs',
- )
- self.assertEqual(columns, columns)
- datalist = self.datalist + (
- volume_fakes.qos_specs,
- )
- self.assertEqual(datalist, data)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, data)
class TestQosDelete(TestQos):
+ qos_spec = volume_fakes.FakeQos.create_one_qos()
+
def setUp(self):
super(TestQosDelete, self).setUp()
- self.qos_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.QOS),
- loaded=True,
- )
-
+ self.qos_mock.get.return_value = self.qos_spec
# Get the command object to test
self.cmd = qos_specs.DeleteQos(self.app, None)
- def test_qos_delete_with_id(self):
- arglist = [
- volume_fakes.qos_id
- ]
- verifylist = [
- ('qos_specs', [volume_fakes.qos_id])
- ]
- parsed_args = self.check_parser(self.cmd, arglist, verifylist)
-
- result = self.cmd.take_action(parsed_args)
-
- self.qos_mock.delete.assert_called_with(volume_fakes.qos_id)
- self.assertIsNone(result)
-
- def test_qos_delete_with_name(self):
+ def test_qos_delete(self):
arglist = [
- volume_fakes.qos_name
+ self.qos_spec.id
]
verifylist = [
- ('qos_specs', [volume_fakes.qos_name])
+ ('qos_specs', [self.qos_spec.id])
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- self.qos_mock.delete.assert_called_with(volume_fakes.qos_id)
+ self.qos_mock.delete.assert_called_with(self.qos_spec.id)
self.assertIsNone(result)
class TestQosDisassociate(TestQos):
+ volume_type = volume_fakes.FakeType.create_one_type()
+ qos_spec = volume_fakes.FakeQos.create_one_qos()
+
def setUp(self):
super(TestQosDisassociate, self).setUp()
+ self.qos_mock.get.return_value = self.qos_spec
+ self.types_mock.get.return_value = self.volume_type
# Get the command object to test
self.cmd = qos_specs.DisassociateQos(self.app, None)
def test_qos_disassociate_with_volume_type(self):
- self.qos_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.QOS),
- loaded=True
- )
- self.types_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.TYPE),
- loaded=True
- )
arglist = [
- volume_fakes.qos_id,
- '--volume-type', volume_fakes.type_id
+ '--volume-type', self.volume_type.id,
+ self.qos_spec.id,
]
verifylist = [
- ('qos_spec', volume_fakes.qos_id),
- ('volume_type', volume_fakes.type_id)
+ ('volume_type', self.volume_type.id),
+ ('qos_spec', self.qos_spec.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.qos_mock.disassociate.assert_called_with(
- volume_fakes.qos_id,
- volume_fakes.type_id
+ self.qos_spec.id,
+ self.volume_type.id
)
self.assertIsNone(result)
def test_qos_disassociate_with_all_volume_types(self):
- self.qos_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.QOS),
- loaded=True
- )
-
arglist = [
- volume_fakes.qos_id,
- '--all'
+ '--all',
+ self.qos_spec.id,
]
verifylist = [
- ('qos_spec', volume_fakes.qos_id)
+ ('qos_spec', self.qos_spec.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- self.qos_mock.disassociate_all.assert_called_with(volume_fakes.qos_id)
+ self.qos_mock.disassociate_all.assert_called_with(self.qos_spec.id)
self.assertIsNone(result)
class TestQosList(TestQos):
+ qos_specs = volume_fakes.FakeQos.create_qoses(count=2)
+ qos_association = volume_fakes.FakeQos.create_one_qos_association()
+
+ columns = (
+ 'ID',
+ 'Name',
+ 'Consumer',
+ 'Associations',
+ 'Specs',
+ )
+ data = []
+ for q in qos_specs:
+ data.append((
+ q.id,
+ q.name,
+ q.consumer,
+ qos_association.name,
+ utils.format_dict(q.specs),
+ ))
+
def setUp(self):
super(TestQosList, self).setUp()
- self.qos_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.QOS_WITH_ASSOCIATIONS),
- loaded=True,
- )
- self.qos_mock.list.return_value = [self.qos_mock.get.return_value]
- self.qos_mock.get_associations.return_value = [fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.qos_association),
- loaded=True,
- )]
+ self.qos_mock.list.return_value = self.qos_specs
+ self.qos_mock.get_associations.return_value = [self.qos_association]
# Get the command object to test
self.cmd = qos_specs.ListQos(self.app, None)
@@ -317,139 +267,117 @@ class TestQosList(TestQos):
columns, data = self.cmd.take_action(parsed_args)
self.qos_mock.list.assert_called_with()
- collist = (
- 'ID',
- 'Name',
- 'Consumer',
- 'Associations',
- 'Specs',
- )
- self.assertEqual(collist, columns)
- datalist = ((
- volume_fakes.qos_id,
- volume_fakes.qos_name,
- volume_fakes.qos_consumer,
- volume_fakes.type_name,
- utils.format_dict(volume_fakes.qos_specs),
- ), )
- self.assertEqual(datalist, tuple(data))
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
class TestQosSet(TestQos):
+ qos_spec = volume_fakes.FakeQos.create_one_qos()
+
def setUp(self):
super(TestQosSet, self).setUp()
+ self.qos_mock.get.return_value = self.qos_spec
# Get the command object to test
self.cmd = qos_specs.SetQos(self.app, None)
def test_qos_set_with_properties_with_id(self):
- self.qos_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.QOS_WITH_SPECS),
- loaded=True
- )
arglist = [
- volume_fakes.qos_id,
'--property', 'foo=bar',
- '--property', 'iops=9001'
+ '--property', 'iops=9001',
+ self.qos_spec.id,
]
verifylist = [
- ('qos_spec', volume_fakes.qos_id),
- ('property', volume_fakes.qos_specs)
+ ('property', self.qos_spec.specs),
+ ('qos_spec', self.qos_spec.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.qos_mock.set_keys.assert_called_with(
- volume_fakes.qos_id,
- volume_fakes.qos_specs
+ self.qos_spec.id,
+ self.qos_spec.specs
)
self.assertIsNone(result)
class TestQosShow(TestQos):
+ qos_spec = volume_fakes.FakeQos.create_one_qos()
+ qos_association = volume_fakes.FakeQos.create_one_qos_association()
+
+ columns = (
+ 'associations',
+ 'consumer',
+ 'id',
+ 'name',
+ 'specs'
+ )
+ data = (
+ qos_association.name,
+ qos_spec.consumer,
+ qos_spec.id,
+ qos_spec.name,
+ utils.format_dict(qos_spec.specs),
+ )
+
def setUp(self):
super(TestQosShow, self).setUp()
- self.qos_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.QOS_WITH_ASSOCIATIONS),
- loaded=True,
- )
- self.qos_mock.get_associations.return_value = [fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.qos_association),
- loaded=True,
- )]
+ self.qos_mock.get.return_value = self.qos_spec
+ self.qos_mock.get_associations.return_value = [self.qos_association]
# Get the command object to test
self.cmd = qos_specs.ShowQos(self.app, None)
def test_qos_show(self):
arglist = [
- volume_fakes.qos_id
+ self.qos_spec.id
]
verifylist = [
- ('qos_spec', volume_fakes.qos_id)
+ ('qos_spec', self.qos_spec.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.qos_mock.get.assert_called_with(
- volume_fakes.qos_id
+ self.qos_spec.id
)
- collist = (
- 'associations',
- 'consumer',
- 'id',
- 'name',
- 'specs'
- )
- self.assertEqual(collist, columns)
- datalist = (
- volume_fakes.type_name,
- volume_fakes.qos_consumer,
- volume_fakes.qos_id,
- volume_fakes.qos_name,
- utils.format_dict(volume_fakes.qos_specs),
- )
- self.assertEqual(datalist, tuple(data))
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, tuple(data))
class TestQosUnset(TestQos):
+ qos_spec = volume_fakes.FakeQos.create_one_qos()
+
def setUp(self):
super(TestQosUnset, self).setUp()
+ self.qos_mock.get.return_value = self.qos_spec
# Get the command object to test
self.cmd = qos_specs.UnsetQos(self.app, None)
def test_qos_unset_with_properties(self):
- self.qos_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.QOS),
- loaded=True
- )
arglist = [
- volume_fakes.qos_id,
'--property', 'iops',
- '--property', 'foo'
+ '--property', 'foo',
+ self.qos_spec.id,
]
verifylist = [
- ('qos_spec', volume_fakes.qos_id),
- ('property', ['iops', 'foo'])
+ ('property', ['iops', 'foo']),
+ ('qos_spec', self.qos_spec.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.qos_mock.unset_keys.assert_called_with(
- volume_fakes.qos_id,
+ self.qos_spec.id,
['iops', 'foo']
)
self.assertIsNone(result)
diff --git a/openstackclient/tests/volume/v2/test_transfer_request.py b/openstackclient/tests/volume/v2/test_transfer_request.py
new file mode 100644
index 0000000..945833c
--- /dev/null
+++ b/openstackclient/tests/volume/v2/test_transfer_request.py
@@ -0,0 +1,114 @@
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+
+from openstackclient.tests.volume.v2 import fakes as transfer_fakes
+from openstackclient.volume.v2 import volume_transfer_request
+
+
+class TestTransfer(transfer_fakes.TestTransfer):
+
+ def setUp(self):
+ super(TestTransfer, self).setUp()
+
+ # Get a shortcut to the TransferManager Mock
+ self.transfer_mock = self.app.client_manager.volume.transfers
+ self.transfer_mock.reset_mock()
+
+
+class TestTransferList(TestTransfer):
+
+ # The Transfers to be listed
+ volume_transfers = transfer_fakes.FakeTransfer.create_one_transfer()
+
+ def setUp(self):
+ super(TestTransferList, self).setUp()
+
+ self.transfer_mock.list.return_value = [self.volume_transfers]
+
+ # Get the command object to test
+ self.cmd = volume_transfer_request.ListTransferRequests(self.app, None)
+
+ def test_transfer_list_without_argument(self):
+ arglist = []
+ verifylist = []
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ expected_columns = [
+ 'ID',
+ 'Volume',
+ 'Name',
+ ]
+
+ # confirming if all expected columns are present in the result.
+ self.assertEqual(expected_columns, columns)
+
+ datalist = ((
+ self.volume_transfers.id,
+ self.volume_transfers.volume_id,
+ self.volume_transfers.name,
+ ), )
+
+ # confirming if all expected values are present in the result.
+ self.assertEqual(datalist, tuple(data))
+
+ # checking if proper call was made to list volume_transfers
+ self.transfer_mock.list.assert_called_with(
+ detailed=True,
+ search_opts={'all_tenants': 0}
+ )
+
+ def test_transfer_list_with_argument(self):
+ arglist = [
+ "--all-projects"
+ ]
+ verifylist = [
+ ("all_projects", True)
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # In base command class Lister in cliff, abstract method take_action()
+ # returns a tuple containing the column names and an iterable
+ # containing the data to be listed.
+ columns, data = self.cmd.take_action(parsed_args)
+
+ expected_columns = [
+ 'ID',
+ 'Volume',
+ 'Name',
+ ]
+
+ # confirming if all expected columns are present in the result.
+ self.assertEqual(expected_columns, columns)
+
+ datalist = ((
+ self.volume_transfers.id,
+ self.volume_transfers.volume_id,
+ self.volume_transfers.name,
+ ), )
+
+ # confirming if all expected values are present in the result.
+ self.assertEqual(datalist, tuple(data))
+
+ # checking if proper call was made to list volume_transfers
+ self.transfer_mock.list.assert_called_with(
+ detailed=True,
+ search_opts={'all_tenants': 1}
+ )
diff --git a/openstackclient/tests/volume/v2/test_type.py b/openstackclient/tests/volume/v2/test_type.py
index 872b4ae..10c3861 100644
--- a/openstackclient/tests/volume/v2/test_type.py
+++ b/openstackclient/tests/volume/v2/test_type.py
@@ -397,17 +397,19 @@ class TestTypeUnset(TestType):
def test_type_unset(self):
arglist = [
'--property', 'property',
+ '--property', 'multi_property',
self.volume_type.id,
]
verifylist = [
- ('property', 'property'),
+ ('property', ['property', 'multi_property']),
('volume_type', self.volume_type.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
- self.volume_type.unset_keys.assert_called_once_with('property')
+ self.volume_type.unset_keys.assert_called_once_with(
+ ['property', 'multi_property'])
self.assertIsNone(result)
def test_type_unset_project_access(self):
diff --git a/openstackclient/tests/volume/v2/test_volume.py b/openstackclient/tests/volume/v2/test_volume.py
index 85ff614..fb48d8a 100644
--- a/openstackclient/tests/volume/v2/test_volume.py
+++ b/openstackclient/tests/volume/v2/test_volume.py
@@ -14,12 +14,12 @@
import copy
-import mock
from mock import call
from openstackclient.common import utils
from openstackclient.tests import fakes
from openstackclient.tests.identity.v3 import fakes as identity_fakes
+from openstackclient.tests.image.v2 import fakes as image_fakes
from openstackclient.tests.volume.v2 import fakes as volume_fakes
from openstackclient.volume.v2 import volume
@@ -301,19 +301,16 @@ class TestVolumeCreate(TestVolume):
self.assertEqual(self.datalist, data)
def test_volume_create_image_id(self):
- self.images_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.IMAGE),
- loaded=True,
- )
+ image = image_fakes.FakeImage.create_one_image()
+ self.images_mock.get.return_value = image
arglist = [
- '--image', volume_fakes.image_id,
+ '--image', image.id,
'--size', str(self.new_volume.size),
self.new_volume.name,
]
verifylist = [
- ('image', volume_fakes.image_id),
+ ('image', image.id),
('size', self.new_volume.size),
('name', self.new_volume.name),
]
@@ -334,7 +331,7 @@ class TestVolumeCreate(TestVolume):
project_id=None,
availability_zone=None,
metadata=None,
- imageRef=volume_fakes.image_id,
+ imageRef=image.id,
source_volid=None,
)
@@ -342,19 +339,16 @@ class TestVolumeCreate(TestVolume):
self.assertEqual(self.datalist, data)
def test_volume_create_image_name(self):
- self.images_mock.get.return_value = fakes.FakeResource(
- None,
- copy.deepcopy(volume_fakes.IMAGE),
- loaded=True,
- )
+ image = image_fakes.FakeImage.create_one_image()
+ self.images_mock.get.return_value = image
arglist = [
- '--image', volume_fakes.image_name,
+ '--image', image.name,
'--size', str(self.new_volume.size),
self.new_volume.name,
]
verifylist = [
- ('image', volume_fakes.image_name),
+ ('image', image.name),
('size', self.new_volume.size),
('name', self.new_volume.name),
]
@@ -375,7 +369,7 @@ class TestVolumeCreate(TestVolume):
project_id=None,
availability_zone=None,
metadata=None,
- imageRef=volume_fakes.image_id,
+ imageRef=image.id,
source_volid=None
)
@@ -383,21 +377,21 @@ class TestVolumeCreate(TestVolume):
self.assertEqual(self.datalist, data)
def test_volume_create_with_snapshot(self):
+ snapshot = volume_fakes.FakeSnapshot.create_one_snapshot()
+ self.new_volume.snapshot_id = snapshot.id
arglist = [
'--size', str(self.new_volume.size),
- '--snapshot', volume_fakes.snapshot_id,
+ '--snapshot', self.new_volume.snapshot_id,
self.new_volume.name,
]
verifylist = [
('size', self.new_volume.size),
- ('snapshot', volume_fakes.snapshot_id),
+ ('snapshot', self.new_volume.snapshot_id),
('name', self.new_volume.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- fake_snapshot = mock.Mock()
- fake_snapshot.id = volume_fakes.snapshot_id
- self.snapshots_mock.get.return_value = fake_snapshot
+ self.snapshots_mock.get.return_value = snapshot
# In base command class ShowOne in cliff, abstract method take_action()
# returns a two-part tuple with a tuple of column names and a tuple of
@@ -406,7 +400,7 @@ class TestVolumeCreate(TestVolume):
self.volumes_mock.create.assert_called_once_with(
size=self.new_volume.size,
- snapshot_id=fake_snapshot.id,
+ snapshot_id=snapshot.id,
name=self.new_volume.name,
description=None,
volume_type=None,
@@ -642,12 +636,12 @@ class TestVolumeList(TestVolume):
def test_volume_list_name(self):
arglist = [
- '--name', volume_fakes.volume_name,
+ '--name', self.mock_volume.name,
]
verifylist = [
('long', False),
('all_projects', False),
- ('name', volume_fakes.volume_name),
+ ('name', self.mock_volume.name),
('status', None),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -670,13 +664,13 @@ class TestVolumeList(TestVolume):
def test_volume_list_status(self):
arglist = [
- '--status', volume_fakes.volume_status,
+ '--status', self.mock_volume.status,
]
verifylist = [
('long', False),
('all_projects', False),
('name', None),
- ('status', volume_fakes.volume_status),
+ ('status', self.mock_volume.status),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
diff --git a/openstackclient/volume/v1/qos_specs.py b/openstackclient/volume/v1/qos_specs.py
index b9eb875..c49477a 100644
--- a/openstackclient/volume/v1/qos_specs.py
+++ b/openstackclient/volume/v1/qos_specs.py
@@ -202,8 +202,6 @@ class SetQos(command.Command):
if parsed_args.property:
volume_client.qos_specs.set_keys(qos_spec.id,
parsed_args.property)
- else:
- self.app.log.error(_("No changes requested\n"))
class ShowQos(command.ShowOne):
@@ -263,5 +261,3 @@ class UnsetQos(command.Command):
if parsed_args.property:
volume_client.qos_specs.unset_keys(qos_spec.id,
parsed_args.property)
- else:
- self.app.log.error(_("No changes requested\n"))
diff --git a/openstackclient/volume/v1/snapshot.py b/openstackclient/volume/v1/snapshot.py
index bf5bf26..5132d71 100644
--- a/openstackclient/volume/v1/snapshot.py
+++ b/openstackclient/volume/v1/snapshot.py
@@ -208,10 +208,6 @@ class SetSnapshot(command.Command):
if parsed_args.description:
kwargs['display_description'] = parsed_args.description
- if not kwargs and not parsed_args.property:
- self.app.log.error(_("No changes requested\n"))
- return
-
snapshot.update(**kwargs)
@@ -270,5 +266,3 @@ class UnsetSnapshot(command.Command):
snapshot.id,
parsed_args.property,
)
- else:
- self.app.log.error(_("No changes requested\n"))
diff --git a/openstackclient/volume/v1/volume.py b/openstackclient/volume/v1/volume.py
index 11e42f8..ffec180 100644
--- a/openstackclient/volume/v1/volume.py
+++ b/openstackclient/volume/v1/volume.py
@@ -363,9 +363,6 @@ class SetVolume(command.Command):
if kwargs:
volume_client.volumes.update(volume.id, **kwargs)
- if not kwargs and not parsed_args.property and not parsed_args.size:
- self.app.log.error(_("No changes requested\n"))
-
class ShowVolume(command.ShowOne):
"""Show volume details"""
@@ -428,5 +425,3 @@ class UnsetVolume(command.Command):
volume.id,
parsed_args.property,
)
- else:
- self.app.log.error(_("No changes requested\n"))
diff --git a/openstackclient/volume/v1/volume_transfer_request.py b/openstackclient/volume/v1/volume_transfer_request.py
new file mode 100644
index 0000000..98689e7
--- /dev/null
+++ b/openstackclient/volume/v1/volume_transfer_request.py
@@ -0,0 +1,51 @@
+#
+# 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.
+#
+
+"""Volume v2 transfer action implementations"""
+
+
+from openstackclient.common import command
+from openstackclient.common import utils
+from openstackclient.i18n import _
+
+
+class ListTransferRequests(command.Lister):
+ """Lists all volume transfer requests."""
+
+ def get_parser(self, prog_name):
+ parser = super(ListTransferRequests, self).get_parser(prog_name)
+ parser.add_argument(
+ '--all-projects',
+ dest='all_projects',
+ action="store_true",
+ default=False,
+ help=_('Shows detail for all projects. Admin only. '
+ '(defaults to False)')
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ columns = ['ID', 'Volume ID', 'Name']
+ column_headers = ['ID', 'Volume', 'Name']
+
+ volume_client = self.app.client_manager.volume
+
+ volume_transfer_result = volume_client.transfers.list(
+ detailed=True,
+ search_opts={'all_tenants': parsed_args.all_projects}
+ )
+
+ return (column_headers, (
+ utils.get_item_properties(s, columns)
+ for s in volume_transfer_result))
diff --git a/openstackclient/volume/v1/volume_type.py b/openstackclient/volume/v1/volume_type.py
index 7392702..4e9b192 100644
--- a/openstackclient/volume/v1/volume_type.py
+++ b/openstackclient/volume/v1/volume_type.py
@@ -181,5 +181,3 @@ class UnsetVolumeType(command.Command):
if parsed_args.property:
volume_type.unset_keys(parsed_args.property)
- else:
- self.app.log.error(_("No changes requested\n"))
diff --git a/openstackclient/volume/v2/qos_specs.py b/openstackclient/volume/v2/qos_specs.py
index aa2059d..90e11c7 100644
--- a/openstackclient/volume/v2/qos_specs.py
+++ b/openstackclient/volume/v2/qos_specs.py
@@ -202,8 +202,6 @@ class SetQos(command.Command):
if parsed_args.property:
volume_client.qos_specs.set_keys(qos_spec.id,
parsed_args.property)
- else:
- self.app.log.error(_("No changes requested\n"))
class ShowQos(command.ShowOne):
@@ -250,8 +248,8 @@ class UnsetQos(command.Command):
metavar='<key>',
action='append',
default=[],
- help=('Property to remove from the QoS specification. '
- '(repeat option to unset multiple properties)'),
+ help=_('Property to remove from the QoS specification. '
+ '(repeat option to unset multiple properties)'),
)
return parser
@@ -263,5 +261,3 @@ class UnsetQos(command.Command):
if parsed_args.property:
volume_client.qos_specs.unset_keys(qos_spec.id,
parsed_args.property)
- else:
- self.app.log.error(_("No changes requested\n"))
diff --git a/openstackclient/volume/v2/snapshot.py b/openstackclient/volume/v2/snapshot.py
index db4ce6c..d901708 100644
--- a/openstackclient/volume/v2/snapshot.py
+++ b/openstackclient/volume/v2/snapshot.py
@@ -37,7 +37,7 @@ class CreateSnapshot(command.ShowOne):
parser.add_argument(
"--name",
metavar="<name>",
- help=("Name of the snapshot")
+ help=_("Name of the snapshot")
)
parser.add_argument(
"--description",
@@ -205,11 +205,6 @@ class SetSnapshot(command.Command):
if parsed_args.description:
kwargs['description'] = parsed_args.description
- if (not kwargs and not parsed_args.property and not
- parsed_args.state):
- self.app.log.error(_("No changes requested\n"))
- return
-
if parsed_args.property:
volume_client.volume_snapshots.set_metadata(snapshot.id,
parsed_args.property)
@@ -271,5 +266,3 @@ class UnsetSnapshot(command.Command):
snapshot.id,
parsed_args.property,
)
- else:
- self.app.log.error(_("No changes requested\n"))
diff --git a/openstackclient/volume/v2/volume.py b/openstackclient/volume/v2/volume.py
index 0e07aa7..18473da 100644
--- a/openstackclient/volume/v2/volume.py
+++ b/openstackclient/volume/v2/volume.py
@@ -385,10 +385,6 @@ class SetVolume(command.Command):
if kwargs:
volume_client.volumes.update(volume.id, **kwargs)
- if (not kwargs and not parsed_args.property
- and not parsed_args.image_property and not parsed_args.size):
- self.app.log.error(_("No changes requested\n"))
-
class ShowVolume(command.ShowOne):
"""Display volume details"""
diff --git a/openstackclient/volume/v2/volume_transfer_request.py b/openstackclient/volume/v2/volume_transfer_request.py
new file mode 100644
index 0000000..98689e7
--- /dev/null
+++ b/openstackclient/volume/v2/volume_transfer_request.py
@@ -0,0 +1,51 @@
+#
+# 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.
+#
+
+"""Volume v2 transfer action implementations"""
+
+
+from openstackclient.common import command
+from openstackclient.common import utils
+from openstackclient.i18n import _
+
+
+class ListTransferRequests(command.Lister):
+ """Lists all volume transfer requests."""
+
+ def get_parser(self, prog_name):
+ parser = super(ListTransferRequests, self).get_parser(prog_name)
+ parser.add_argument(
+ '--all-projects',
+ dest='all_projects',
+ action="store_true",
+ default=False,
+ help=_('Shows detail for all projects. Admin only. '
+ '(defaults to False)')
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ columns = ['ID', 'Volume ID', 'Name']
+ column_headers = ['ID', 'Volume', 'Name']
+
+ volume_client = self.app.client_manager.volume
+
+ volume_transfer_result = volume_client.transfers.list(
+ detailed=True,
+ search_opts={'all_tenants': parsed_args.all_projects}
+ )
+
+ return (column_headers, (
+ utils.get_item_properties(s, columns)
+ for s in volume_transfer_result))
diff --git a/openstackclient/volume/v2/volume_type.py b/openstackclient/volume/v2/volume_type.py
index adaccb0..9aed17b 100644
--- a/openstackclient/volume/v2/volume_type.py
+++ b/openstackclient/volume/v2/volume_type.py
@@ -176,13 +176,6 @@ class SetVolumeType(command.Command):
volume_type = utils.find_resource(
volume_client.volume_types, parsed_args.volume_type)
- if (not parsed_args.name
- and not parsed_args.description
- and not parsed_args.property
- and not parsed_args.project):
- self.app.log.error(_("No changes requested\n"))
- return
-
result = 0
kwargs = {}
if parsed_args.name:
@@ -205,8 +198,8 @@ class SetVolumeType(command.Command):
try:
volume_type.set_keys(parsed_args.property)
except Exception as e:
- self.app.log.error(_("Failed to set volume type property: ") +
- str(e))
+ self.app.log.error(_("Failed to set volume type"
+ " property: %s") % str(e))
result += 1
if parsed_args.project:
@@ -225,8 +218,8 @@ class SetVolumeType(command.Command):
result += 1
if result > 0:
- raise exceptions.CommandError("Command Failed: One or more of the"
- " operations failed")
+ raise exceptions.CommandError(_("Command Failed: One or more of"
+ " the operations failed"))
class ShowVolumeType(command.ShowOne):
@@ -263,6 +256,7 @@ class UnsetVolumeType(command.Command):
parser.add_argument(
'--property',
metavar='<key>',
+ action='append',
help=_('Remove a property from this volume type '
'(repeat option to remove multiple properties)'),
)
@@ -285,11 +279,6 @@ class UnsetVolumeType(command.Command):
parsed_args.volume_type,
)
- if (not parsed_args.property
- and not parsed_args.project):
- self.app.log.error(_("No changes requested\n"))
- return
-
result = 0
if parsed_args.property:
try:
@@ -311,9 +300,9 @@ class UnsetVolumeType(command.Command):
volume_type.id, project_info.id)
except Exception as e:
self.app.log.error(_("Failed to remove volume type access from"
- " project: ") + str(e))
+ " project: %s") % str(e))
result += 1
if result > 0:
- raise exceptions.CommandError("Command Failed: One or more of the"
- " operations failed")
+ raise exceptions.CommandError(_("Command Failed: One or more of"
+ " the operations failed"))
diff --git a/releasenotes/notes/add-server-backup-e63feaebb6140f83.yaml b/releasenotes/notes/add-server-backup-e63feaebb6140f83.yaml
new file mode 100644
index 0000000..670f506
--- /dev/null
+++ b/releasenotes/notes/add-server-backup-e63feaebb6140f83.yaml
@@ -0,0 +1,3 @@
+---
+features:
+ - Add ``server backup create`` command
diff --git a/releasenotes/notes/address-scope-delete-multi-31c3af73feb31265.yaml b/releasenotes/notes/address-scope-delete-multi-31c3af73feb31265.yaml
new file mode 100644
index 0000000..91bce23
--- /dev/null
+++ b/releasenotes/notes/address-scope-delete-multi-31c3af73feb31265.yaml
@@ -0,0 +1,5 @@
+---
+upgrade:
+ - |
+ ``address scope delete`` command now accepts multiple address scopes
+ in a single command
diff --git a/releasenotes/notes/bp-routed-networks-3eea4978c93aa126.yaml b/releasenotes/notes/bp-routed-networks-3eea4978c93aa126.yaml
new file mode 100644
index 0000000..9157958
--- /dev/null
+++ b/releasenotes/notes/bp-routed-networks-3eea4978c93aa126.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - Add ``network segment list`` and ``network segment show`` commands.
+ These are beta commands and subject to change. Use global option
+ ``--os-beta-command`` to enable these commands.
+ [Blueprint `routed-networks <https://blueprints.launchpad.net/neutron/+spec/routed-networks>`_]
diff --git a/releasenotes/notes/bug-1554886-8e5249a655e7e7b6.yaml b/releasenotes/notes/bug-1554886-8e5249a655e7e7b6.yaml
new file mode 100644
index 0000000..bafb87d
--- /dev/null
+++ b/releasenotes/notes/bug-1554886-8e5249a655e7e7b6.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Add ``volume transfer request list`` command
+ [:lpbug:`1554886`]
diff --git a/releasenotes/notes/bug-1575461-4d7d90e792132064.yaml b/releasenotes/notes/bug-1575461-4d7d90e792132064.yaml
new file mode 100644
index 0000000..3ae0075
--- /dev/null
+++ b/releasenotes/notes/bug-1575461-4d7d90e792132064.yaml
@@ -0,0 +1,10 @@
+---
+features:
+ - |
+ Add ``--project`` option to ``flavor set`` command to set project access
+ to a flavor
+ [:lpbug:`1575461`]
+ - |
+ Add ``--project`` option to ``flavor unset`` command to remove project access
+ to a flavor
+ [:lpbug:`1575461`]
diff --git a/releasenotes/notes/bug-1582968-4d44912a033b242c.yaml b/releasenotes/notes/bug-1582968-4d44912a033b242c.yaml
new file mode 100644
index 0000000..9fd50c1
--- /dev/null
+++ b/releasenotes/notes/bug-1582968-4d44912a033b242c.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - Add ``image unset`` command
+ [:lpbug:`1582968`]
diff --git a/releasenotes/notes/bug-1588384-eb6976fcfb90cb4c.yaml b/releasenotes/notes/bug-1588384-eb6976fcfb90cb4c.yaml
new file mode 100644
index 0000000..797d673
--- /dev/null
+++ b/releasenotes/notes/bug-1588384-eb6976fcfb90cb4c.yaml
@@ -0,0 +1,7 @@
+---
+fixes:
+ - Fix the ``--enable`` option on all commands by changing the
+ ``--enable-beta-commands`` global option to ``--os-beta-command``.
+ There are no upgrade impacts for the global option rename since
+ the old name isn't used.
+ [Bug `1588384 <https://bugs.launchpad.net/python-openstackclient/+bug/1588384>`_]
diff --git a/releasenotes/notes/compute-agent-deff48988e81b30e.yaml b/releasenotes/notes/compute-agent-deff48988e81b30e.yaml
new file mode 100644
index 0000000..219ef96
--- /dev/null
+++ b/releasenotes/notes/compute-agent-deff48988e81b30e.yaml
@@ -0,0 +1,5 @@
+---
+upgrade:
+ - |
+ ``compute agent delete`` command now supports deleting multiple agents
+ in a single command
diff --git a/releasenotes/notes/ip-availability-ca1cf440f6c70afc.yaml b/releasenotes/notes/ip-availability-ca1cf440f6c70afc.yaml
new file mode 100644
index 0000000..2c78388
--- /dev/null
+++ b/releasenotes/notes/ip-availability-ca1cf440f6c70afc.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Add ``ip availability list`` and ``ip availability show`` commands
+ [Blueprint :oscbp:`neutron-ip-capacity`]
diff --git a/releasenotes/notes/server-set-state-214b12ec2161de4d.yaml b/releasenotes/notes/server-set-state-214b12ec2161de4d.yaml
new file mode 100644
index 0000000..a48384a
--- /dev/null
+++ b/releasenotes/notes/server-set-state-214b12ec2161de4d.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Add ``--state`` option to ``server set`` command to set the server to
+ active or error state.
+ [Blueprint `server-reset-state <https://blueprints.launchpad.net/python-openstackclient/+spec/server-reset-state>`_]
diff --git a/releasenotes/notes/service-set-option-61772a8940ad0778.yaml b/releasenotes/notes/service-set-option-61772a8940ad0778.yaml
new file mode 100644
index 0000000..02c7fcb
--- /dev/null
+++ b/releasenotes/notes/service-set-option-61772a8940ad0778.yaml
@@ -0,0 +1,6 @@
+---
+upgrade:
+ - An exception is not raised by command ``service set`` when nothing
+ specified. Instead, the service is not enabled by default. And if
+ ``--disable-resion`` is specified but not ``--disable``, an
+ exception will be raised.
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
index 1b6929e..12ed68d 100644
--- a/releasenotes/source/conf.py
+++ b/releasenotes/source/conf.py
@@ -40,8 +40,28 @@
extensions = [
'oslosphinx',
'reno.sphinxext',
+ 'sphinx.ext.extlinks',
]
+# Set aliases for extlinks
+# * lpbug - generic Launchpad bug :lpbug:`123456`
+# * oscbp - OSC blueprints :oscbp:`Blue Print <bp-name>`
+# * oscdoc - OSC Docs :oscdoc:`Comamnd List <command-list>`
+extlinks = {
+ 'lpbug': (
+ 'https://bugs.launchpad.net/bugs/%s',
+ 'Bug ',
+ ),
+ 'oscbp': (
+ 'https://blueprints.launchpad.net/python-openstackclient/+spec/%s',
+ '',
+ ),
+ 'oscdoc': (
+ 'http://docs.openstack.org/developer/python-openstackclient/%s.html',
+ '',
+ ),
+}
+
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index e3af0e6..e0477df 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -7,3 +7,4 @@ OpenStackClient Release Notes
unreleased
mitaka
+ pre_20_releases
diff --git a/releasenotes/source/mitaka.rst b/releasenotes/source/mitaka.rst
index e545609..05ed3e4 100644
--- a/releasenotes/source/mitaka.rst
+++ b/releasenotes/source/mitaka.rst
@@ -1,6 +1,6 @@
-===================================
- Mitaka Series Release Notes
-===================================
+===========================
+Mitaka Series Release Notes
+===========================
.. release-notes::
:branch: origin/stable/mitaka
diff --git a/doc/source/releases.rst b/releasenotes/source/pre_20_releases.rst
index 063066a..a2af7a9 100644
--- a/doc/source/releases.rst
+++ b/releasenotes/source/pre_20_releases.rst
@@ -1,16 +1,12 @@
-=============
-Release Notes
-=============
-
-As of release 2.0 the release notes can be found on the OpenStack `Release Notes site`_.
-
-.. _`Release Notes site`: http://docs.openstack.org/releasenotes/python-openstackclient
+================
+Pre-2.0 Releases
+================
1.9.0 (17 Nov 2015)
===================
* Several updates to `openstack server`
- Blueprint `servers <https://blueprints.launchpad.net/python-openstackclient/+spec/cmd-with-multi-servers>`_
+ Blueprint :oscbp:`servers <cmd-with-multi-servers>`
* `openstack server start`
* `openstack server stop`
@@ -365,17 +361,17 @@ As of release 2.0 the release notes can be found on the OpenStack `Release Notes
Bug `1446751 <https://bugs.launchpad.net/bugs/1446751>`_
* Document the backward-compatibility-breaking changes in
- :doc:`backwards-incompatible`.
- Bug `1406470 <https://bugs.launchpad.net/bugs/1406470>`_
+ :oscdoc:`Backwards Incompatible Changes <backwards-incompatible>`.
+ :lpbug:`1406470`
-* Add `--parent`` option to `projct create` command.
+* Add ``--parent`` option to ``project create`` command
1.1.0 (21 Apr 2015)
===================
* Add global ``--os-cloud`` option to select from a list of cloud configurations.
- See :doc:`configuration` for more details.
+ See :oscdoc:`Configuration <configuration>` for more details.
* Fix global ``--timing`` option operation.
Bug `1402577 <https://bugs.launchpad.net/bugs/1402577>`_
@@ -463,8 +459,9 @@ As of release 2.0 the release notes can be found on the OpenStack `Release Notes
===================
* 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.
+ the OSC source repo. This includes the :oscdoc:`Command Structure <commands>`,
+ :oscdoc:`Command List <command-list>` and
+ :oscdoc:`Human Interface Guide <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
diff --git a/requirements.txt b/requirements.txt
index 62bcfe3..5d8c844 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,12 +9,12 @@ cliff!=1.16.0,!=1.17.0,>=1.15.0 # Apache-2.0
keystoneauth1>=2.1.0 # Apache-2.0
openstacksdk>=0.8.6 # Apache-2.0
os-client-config>=1.13.1 # Apache-2.0
-oslo.config>=3.9.0 # Apache-2.0
+oslo.config>=3.10.0 # Apache-2.0
oslo.i18n>=2.1.0 # Apache-2.0
-oslo.utils>=3.5.0 # Apache-2.0
+oslo.utils>=3.11.0 # Apache-2.0
python-glanceclient>=2.0.0 # Apache-2.0
python-keystoneclient!=1.8.0,!=2.1.0,>=1.7.0 # Apache-2.0
python-novaclient!=2.33.0,>=2.29.0 # Apache-2.0
-python-cinderclient!=1.7.0,>=1.6.0 # Apache-2.0
+python-cinderclient!=1.7.0,!=1.7.1,>=1.6.0 # Apache-2.0
requests>=2.10.0 # Apache-2.0
stevedore>=1.10.0 # Apache-2.0
diff --git a/setup.cfg b/setup.cfg
index a62f5d2..2bff76b 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -131,6 +131,8 @@ openstack.compute.v2 =
server_unset = openstackclient.compute.v2.server:UnsetServer
server_unshelve = openstackclient.compute.v2.server:UnshelveServer
+ server_backup_create = openstackclient.compute.v2.server_backup:CreateServerBackup
+
server_group_create = openstackclient.compute.v2.server_group:CreateServerGroup
server_group_delete = openstackclient.compute.v2.server_group:DeleteServerGroup
server_group_list = openstackclient.compute.v2.server_group:ListServerGroup
@@ -322,6 +324,7 @@ openstack.image.v2 =
image_save = openstackclient.image.v2.image:SaveImage
image_show = openstackclient.image.v2.image:ShowImage
image_set = openstackclient.image.v2.image:SetImage
+ image_unset = openstackclient.image.v2.image:UnsetImage
openstack.network.v2 =
address_scope_create = openstackclient.network.v2.address_scope:CreateAddressScope
@@ -330,6 +333,9 @@ openstack.network.v2 =
address_scope_set = openstackclient.network.v2.address_scope:SetAddressScope
address_scope_show = openstackclient.network.v2.address_scope:ShowAddressScope
+ ip_availability_list = openstackclient.network.v2.ip_availability:ListIPAvailability
+ ip_availability_show = openstackclient.network.v2.ip_availability:ShowIPAvailability
+
ip_floating_create = openstackclient.network.v2.floating_ip:CreateFloatingIP
ip_floating_delete = openstackclient.network.v2.floating_ip:DeleteFloatingIP
ip_floating_list = openstackclient.network.v2.floating_ip:ListFloatingIP
@@ -341,6 +347,9 @@ openstack.network.v2 =
network_set = openstackclient.network.v2.network:SetNetwork
network_show = openstackclient.network.v2.network:ShowNetwork
+ network_segment_list = openstackclient.network.v2.network_segment:ListNetworkSegment
+ network_segment_show = openstackclient.network.v2.network_segment:ShowNetworkSegment
+
port_create = openstackclient.network.v2.port:CreatePort
port_delete = openstackclient.network.v2.port:DeletePort
port_list = openstackclient.network.v2.port:ListPort
@@ -438,6 +447,8 @@ openstack.volume.v1 =
volume_service_list = openstackclient.volume.v1.service:ListService
+ volume_transfer_request_list = openstackclient.volume.v1.volume_transfer_request:ListTransferRequests
+
openstack.volume.v2 =
backup_create = openstackclient.volume.v2.backup:CreateBackup
backup_delete = openstackclient.volume.v2.backup:DeleteBackup
@@ -477,6 +488,8 @@ openstack.volume.v2 =
volume_service_list = openstackclient.volume.v2.service:ListService
+ volume_transfer_request_list = openstackclient.volume.v2.volume_transfer_request:ListTransferRequests
+
[build_sphinx]
source-dir = doc/source
build-dir = doc/build
diff --git a/test-requirements.txt b/test-requirements.txt
index ffc8326..a8d6aa4 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -5,14 +5,14 @@ hacking<0.11,>=0.10.0
coverage>=3.6 # Apache-2.0
discover # BSD
-fixtures<2.0,>=1.3.1 # Apache-2.0/BSD
-mock>=1.2 # BSD
+fixtures>=3.0.0 # Apache-2.0/BSD
+mock>=2.0 # BSD
oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
oslotest>=1.10.0 # Apache-2.0
reno>=1.6.2 # Apache2
requests-mock>=0.7.0 # Apache-2.0
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD
-os-testr>=0.4.1 # Apache-2.0
+os-testr>=0.7.0 # Apache-2.0
testrepository>=0.0.18 # Apache-2.0/BSD
testtools>=1.4.0 # MIT
tempest>=11.0.0 # Apache-2.0