diff options
Diffstat (limited to 'openstackclient')
| -rw-r--r-- | openstackclient/common/quota.py | 33 | ||||
| -rw-r--r-- | openstackclient/compute/v2/server.py | 14 | ||||
| -rw-r--r-- | openstackclient/network/v2/port.py | 6 | ||||
| -rw-r--r-- | openstackclient/tests/functional/common/test_quota.py | 3 | ||||
| -rw-r--r-- | openstackclient/tests/functional/compute/v2/test_aggregate.py | 46 | ||||
| -rw-r--r-- | openstackclient/tests/functional/network/v2/test_floating_ip.py | 39 | ||||
| -rw-r--r-- | openstackclient/tests/functional/volume/v2/test_qos.py | 4 | ||||
| -rw-r--r-- | openstackclient/tests/functional/volume/v2/test_snapshot.py | 239 | ||||
| -rw-r--r-- | openstackclient/tests/functional/volume/v2/test_volume.py | 305 | ||||
| -rw-r--r-- | openstackclient/tests/unit/common/test_quota.py | 72 | ||||
| -rw-r--r-- | openstackclient/tests/unit/volume/v2/test_qos_specs.py | 28 | ||||
| -rw-r--r-- | openstackclient/volume/v2/qos_specs.py | 11 |
12 files changed, 588 insertions, 212 deletions
diff --git a/openstackclient/common/quota.py b/openstackclient/common/quota.py index fa6c5765..d86aec58 100644 --- a/openstackclient/common/quota.py +++ b/openstackclient/common/quota.py @@ -182,9 +182,36 @@ class SetQuota(command.Command): project, **volume_kwargs) if network_kwargs: - network_client.update_quota( - project, - **network_kwargs) + if hasattr(_quota.Quota, 'allow_get'): + # TODO(huanxuan): Remove this block once the fixed + # SDK Quota class is the minimum required version. + # This is expected to be SDK release 0.9.13 + res = network_client._get_resource( + _quota.Quota, project, **network_kwargs) + if any([res._body.dirty, res._header.dirty]): + request = res._prepare_request(prepend_key=True) + # remove the id in the body + if 'id' in request.body[res.resource_key]: + del request.body[res.resource_key]['id'] + if res.patch_update: + response = network_client.session.patch( + request.uri, + endpoint_filter=res.service, + json=request.body, + headers=request.headers + ) + else: + response = network_client.session.put( + request.uri, + endpoint_filter=res.service, + json=request.body, + headers=request.headers + ) + res._translate_response(response, has_body=True) + else: + network_client.update_quota( + project, + **network_kwargs) class ShowQuota(command.ShowOne): diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index d9221873..798d3d3f 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -144,6 +144,20 @@ def _prep_server_detail(compute_client, server): except Exception: info['flavor'] = flavor_id + if 'os-extended-volumes:volumes_attached' in info: + info.update( + { + 'volumes_attached': utils.format_list_of_dicts( + info.pop('os-extended-volumes:volumes_attached')) + } + ) + if 'security_groups' in info: + info.update( + { + 'security_groups': utils.format_list_of_dicts( + info.pop('security_groups')) + } + ) # NOTE(dtroyer): novaclient splits these into separate entries... # Format addresses in a useful way info['addresses'] = _format_servers_list_networks(server.networks) diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py index 4525da18..20f3ad75 100644 --- a/openstackclient/network/v2/port.py +++ b/openstackclient/network/v2/port.py @@ -35,6 +35,10 @@ def _format_admin_state(state): return 'UP' if state else 'DOWN' +def _format_dns_assignment(dns_assignment): + return utils.format_list_of_dicts(dns_assignment) \ + if dns_assignment else None + _formatters = { 'admin_state_up': _format_admin_state, 'is_admin_state_up': _format_admin_state, @@ -43,7 +47,7 @@ _formatters = { 'binding_vif_details': utils.format_dict, 'binding:profile': utils.format_dict, 'binding:vif_details': utils.format_dict, - 'dns_assignment': utils.format_list_of_dicts, + 'dns_assignment': _format_dns_assignment, 'extra_dhcp_opts': utils.format_list_of_dicts, 'fixed_ips': utils.format_list_of_dicts, 'security_group_ids': utils.format_list, diff --git a/openstackclient/tests/functional/common/test_quota.py b/openstackclient/tests/functional/common/test_quota.py index b2b198af..c1de9aa9 100644 --- a/openstackclient/tests/functional/common/test_quota.py +++ b/openstackclient/tests/functional/common/test_quota.py @@ -10,8 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -import testtools - from openstackclient.tests.functional import base @@ -27,7 +25,6 @@ class QuotaTests(base.TestCase): cls.PROJECT_NAME =\ cls.get_openstack_configuration_value('auth.project_name') - @testtools.skip('broken SDK testing') def test_quota_set(self): self.openstack('quota set --instances 11 --volumes 11 --networks 11 ' + self.PROJECT_NAME) diff --git a/openstackclient/tests/functional/compute/v2/test_aggregate.py b/openstackclient/tests/functional/compute/v2/test_aggregate.py index 2bc88e7b..38368103 100644 --- a/openstackclient/tests/functional/compute/v2/test_aggregate.py +++ b/openstackclient/tests/functional/compute/v2/test_aggregate.py @@ -48,7 +48,7 @@ class AggregateTests(base.TestCase): self.assertEqual(self.NAME + "\n", raw_output) def test_aggregate_properties(self): - opts = self.get_opts(['properties']) + opts = self.get_opts(['name', 'properties']) raw_output = self.openstack( 'aggregate set --property a=b --property c=d ' + self.NAME @@ -56,7 +56,7 @@ class AggregateTests(base.TestCase): self.assertEqual('', raw_output) raw_output = self.openstack('aggregate show ' + self.NAME + opts) - self.assertIn("a='b', c='d'\n", raw_output) + self.assertIn(self.NAME + "\na='b', c='d'\n", raw_output) raw_output = self.openstack( 'aggregate unset --property a ' + self.NAME @@ -64,4 +64,44 @@ class AggregateTests(base.TestCase): self.assertEqual('', raw_output) raw_output = self.openstack('aggregate show ' + self.NAME + opts) - self.assertIn("c='d'\n", raw_output) + self.assertIn(self.NAME + "\nc='d'\n", raw_output) + + raw_output = self.openstack( + 'aggregate set --property a=b --property c=d ' + self.NAME + ) + self.assertEqual('', raw_output) + + raw_output = self.openstack( + 'aggregate set --no-property ' + self.NAME + ) + self.assertEqual('', raw_output) + + raw_output = self.openstack('aggregate show ' + self.NAME + opts) + self.assertNotIn("a='b', c='d'", raw_output) + + def test_aggregate_set(self): + opts = self.get_opts(["name", "availability_zone"]) + + raw_output = self.openstack( + 'aggregate set --zone Zone_1 ' + self.NAME) + self.assertEqual("", raw_output) + + raw_output = self.openstack('aggregate show ' + self.NAME + opts) + self.assertEqual("Zone_1\n" + self.NAME + "\n", raw_output) + + def test_aggregate_add_and_remove_host(self): + opts = self.get_opts(["hosts", "name"]) + + raw_output = self.openstack('host list -f value -c "Host Name"') + host_name = raw_output.split()[0] + + self.openstack( + 'aggregate add host ' + self.NAME + ' ' + host_name) + raw_output = self.openstack('aggregate show ' + self.NAME + opts) + self.assertEqual("[u'" + host_name + "']" + "\n" + self.NAME + "\n", + raw_output) + + self.openstack( + 'aggregate remove host ' + self.NAME + ' ' + host_name) + raw_output = self.openstack('aggregate show ' + self.NAME + opts) + self.assertEqual("[]\n" + self.NAME + "\n", raw_output) diff --git a/openstackclient/tests/functional/network/v2/test_floating_ip.py b/openstackclient/tests/functional/network/v2/test_floating_ip.py index fa9607a0..8fbec3d5 100644 --- a/openstackclient/tests/functional/network/v2/test_floating_ip.py +++ b/openstackclient/tests/functional/network/v2/test_floating_ip.py @@ -31,25 +31,38 @@ class FloatingIpTests(base.TestCase): cls.re_description = re.compile("description\s+\|\s+([^|]+?)\s+\|") cls.re_network_id = re.compile("floating_network_id\s+\|\s+(\S+)") - # Make a random subnet - cls.subnet = ".".join(map( - str, - (random.randint(0, 223) for _ in range(3)) - )) + ".0/26" - # Create a network for the floating ip raw_output = cls.openstack( 'network create --external ' + cls.NETWORK_NAME ) cls.network_id = re.search(cls.re_id, raw_output).group(1) - # Create a subnet for the network - raw_output = cls.openstack( - 'subnet create ' + - '--network ' + cls.NETWORK_NAME + ' ' + - '--subnet-range ' + cls.subnet + ' ' + - cls.SUBNET_NAME - ) + # Try random subnet range for subnet creating + # Because we can not determine ahead of time what subnets are already + # in use, possibly by another test running in parallel, try 4 times + for i in range(4): + # Make a random subnet + cls.subnet = ".".join(map( + str, + (random.randint(0, 223) for _ in range(3)) + )) + ".0/26" + try: + # Create a subnet for the network + raw_output = cls.openstack( + 'subnet create ' + + '--network ' + cls.NETWORK_NAME + ' ' + + '--subnet-range ' + cls.subnet + ' ' + + cls.SUBNET_NAME + ) + except Exception: + if (i == 3): + # raise the exception at the last time + raise + pass + else: + # break and no longer retry if create sucessfully + break + cls.subnet_id = re.search(cls.re_id, raw_output).group(1) @classmethod diff --git a/openstackclient/tests/functional/volume/v2/test_qos.py b/openstackclient/tests/functional/volume/v2/test_qos.py index a54acbfd..1558c216 100644 --- a/openstackclient/tests/functional/volume/v2/test_qos.py +++ b/openstackclient/tests/functional/volume/v2/test_qos.py @@ -50,13 +50,13 @@ class QosTests(common.BaseVolumeTests): raw_output = self.openstack( 'volume qos set --property a=b --property c=d ' + self.ID) self.assertEqual("", raw_output) - opts = self.get_opts(['name', 'specs']) + opts = self.get_opts(['name', 'properties']) raw_output = self.openstack('volume qos show ' + self.ID + opts) self.assertEqual(self.NAME + "\na='b', c='d'\n", raw_output) raw_output = self.openstack( 'volume qos unset --property a ' + self.ID) self.assertEqual("", raw_output) - opts = self.get_opts(['name', 'specs']) + opts = self.get_opts(['name', 'properties']) raw_output = self.openstack('volume qos show ' + self.ID + opts) self.assertEqual(self.NAME + "\nc='d'\n", raw_output) diff --git a/openstackclient/tests/functional/volume/v2/test_snapshot.py b/openstackclient/tests/functional/volume/v2/test_snapshot.py index 4eb69e9d..c83e79f8 100644 --- a/openstackclient/tests/functional/volume/v2/test_snapshot.py +++ b/openstackclient/tests/functional/volume/v2/test_snapshot.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import json import time import uuid @@ -20,9 +21,6 @@ class VolumeSnapshotTests(common.BaseVolumeTests): """Functional tests for volume snapshot. """ VOLLY = uuid.uuid4().hex - NAME = uuid.uuid4().hex - OTHER_NAME = uuid.uuid4().hex - HEADERS = ['"Name"'] @classmethod def wait_for_status(cls, command, status, tries): @@ -37,52 +35,211 @@ class VolumeSnapshotTests(common.BaseVolumeTests): @classmethod def setUpClass(cls): super(VolumeSnapshotTests, cls).setUpClass() - cls.openstack('volume create --size 1 ' + cls.VOLLY) - cls.wait_for_status('volume show ' + cls.VOLLY, 'available\n', 3) - opts = cls.get_opts(['status']) - raw_output = cls.openstack('volume snapshot create --volume ' + - cls.VOLLY + ' ' + cls.NAME + opts) - cls.assertOutput('creating\n', raw_output) - cls.wait_for_status( - 'volume snapshot show ' + cls.NAME, 'available\n', 3) + # create a volume for all tests to create snapshot + cmd_output = json.loads(cls.openstack( + 'volume create -f json ' + + '--size 1 ' + + cls.VOLLY + )) + cls.wait_for_status('volume show ' + cls.VOLLY, 'available\n', 6) + cls.VOLUME_ID = cmd_output['id'] @classmethod def tearDownClass(cls): - # Rename test - raw_output = cls.openstack( - 'volume snapshot set --name ' + cls.OTHER_NAME + ' ' + cls.NAME) - cls.assertOutput('', raw_output) - # Delete test - raw_output_snapshot = cls.openstack( - 'volume snapshot delete ' + cls.OTHER_NAME) cls.wait_for_status('volume show ' + cls.VOLLY, 'available\n', 6) - raw_output_volume = cls.openstack('volume delete --force ' + cls.VOLLY) - cls.assertOutput('', raw_output_snapshot) - cls.assertOutput('', raw_output_volume) + raw_output = cls.openstack('volume delete --force ' + cls.VOLLY) + cls.assertOutput('', raw_output) - def test_snapshot_list(self): - opts = self.get_opts(self.HEADERS) - raw_output = self.openstack('volume snapshot list' + opts) - self.assertIn(self.NAME, raw_output) + def test_volume_snapshot__delete(self): + """Test create, delete multiple""" + name1 = uuid.uuid4().hex + cmd_output = json.loads(self.openstack( + 'volume snapshot create -f json ' + + name1 + + ' --volume ' + self.VOLLY + )) + self.assertEqual( + name1, + cmd_output["name"], + ) - def test_snapshot_properties(self): - raw_output = self.openstack( - 'volume snapshot set --property a=b --property c=d ' + self.NAME) - self.assertEqual("", raw_output) - opts = self.get_opts(["properties"]) - raw_output = self.openstack('volume snapshot show ' + self.NAME + opts) - self.assertEqual("a='b', c='d'\n", raw_output) + name2 = uuid.uuid4().hex + cmd_output = json.loads(self.openstack( + 'volume snapshot create -f json ' + + name2 + + ' --volume ' + self.VOLLY + )) + self.assertEqual( + name2, + cmd_output["name"], + ) + + self.wait_for_status( + 'volume snapshot show ' + name1, 'available\n', 6) + self.wait_for_status( + 'volume snapshot show ' + name2, 'available\n', 6) + + del_output = self.openstack( + 'volume snapshot delete ' + name1 + ' ' + name2) + self.assertOutput('', del_output) + + def test_volume_snapshot_list(self): + """Test create, list filter""" + name1 = uuid.uuid4().hex + cmd_output = json.loads(self.openstack( + 'volume snapshot create -f json ' + + name1 + + ' --volume ' + self.VOLLY + )) + self.addCleanup(self.openstack, 'volume snapshot delete ' + name1) + self.assertEqual( + name1, + cmd_output["name"], + ) + self.assertEqual( + self.VOLUME_ID, + cmd_output["volume_id"], + ) + self.assertEqual( + 1, + cmd_output["size"], + ) + self.wait_for_status( + 'volume snapshot show ' + name1, 'available\n', 6) + name2 = uuid.uuid4().hex + cmd_output = json.loads(self.openstack( + 'volume snapshot create -f json ' + + name2 + + ' --volume ' + self.VOLLY + )) + self.addCleanup(self.openstack, 'volume snapshot delete ' + name2) + self.assertEqual( + name2, + cmd_output["name"], + ) + self.assertEqual( + self.VOLUME_ID, + cmd_output["volume_id"], + ) + self.assertEqual( + 1, + cmd_output["size"], + ) + self.wait_for_status( + 'volume snapshot show ' + name2, 'available\n', 6) raw_output = self.openstack( - 'volume snapshot unset --property a ' + self.NAME) - self.assertEqual("", raw_output) - raw_output = self.openstack('volume snapshot show ' + self.NAME + opts) - self.assertEqual("c='d'\n", raw_output) + 'volume snapshot set ' + + '--state error ' + + name2 + ) + self.assertOutput('', raw_output) + + # Test list --long, --status + cmd_output = json.loads(self.openstack( + 'volume snapshot list -f json ' + + '--long ' + + '--status error' + )) + names = [x["Name"] for x in cmd_output] + self.assertNotIn(name1, names) + self.assertIn(name2, names) + + # Test list --volume + cmd_output = json.loads(self.openstack( + 'volume snapshot list -f json ' + + '--volume ' + self.VOLLY + )) + names = [x["Name"] for x in cmd_output] + self.assertIn(name1, names) + self.assertIn(name2, names) + + # Test list --name + cmd_output = json.loads(self.openstack( + 'volume snapshot list -f json ' + + '--name ' + name1 + )) + names = [x["Name"] for x in cmd_output] + self.assertIn(name1, names) + self.assertNotIn(name2, names) def test_snapshot_set(self): + """Test create, set, unset, show, delete volume snapshot""" + name = uuid.uuid4().hex + new_name = name + "_" + cmd_output = json.loads(self.openstack( + 'volume snapshot create -f json ' + + '--volume ' + self.VOLLY + + ' --description aaaa ' + + '--property Alpha=a ' + + name + )) + self.addCleanup(self.openstack, 'volume snapshot delete ' + new_name) + self.assertEqual( + name, + cmd_output["name"], + ) + self.assertEqual( + 1, + cmd_output["size"], + ) + self.assertEqual( + 'aaaa', + cmd_output["description"], + ) + self.assertEqual( + "Alpha='a'", + cmd_output["properties"], + ) + self.wait_for_status( + 'volume snapshot show ' + name, 'available\n', 6) + + # Test volume snapshot set raw_output = self.openstack( - 'volume snapshot set --description backup ' + self.NAME) - self.assertEqual("", raw_output) - opts = self.get_opts(["description", "name"]) - raw_output = self.openstack('volume snapshot show ' + self.NAME + opts) - self.assertEqual("backup\n" + self.NAME + "\n", raw_output) + 'volume snapshot set ' + + '--name ' + new_name + + ' --description bbbb ' + + '--property Alpha=c ' + + '--property Beta=b ' + + name, + ) + self.assertOutput('', raw_output) + + # Show snapshot set result + cmd_output = json.loads(self.openstack( + 'volume snapshot show -f json ' + + new_name + )) + self.assertEqual( + new_name, + cmd_output["name"], + ) + self.assertEqual( + 1, + cmd_output["size"], + ) + self.assertEqual( + 'bbbb', + cmd_output["description"], + ) + self.assertEqual( + "Alpha='c', Beta='b'", + cmd_output["properties"], + ) + + # Test volume unset + raw_output = self.openstack( + 'volume snapshot unset ' + + '--property Alpha ' + + new_name, + ) + self.assertOutput('', raw_output) + + cmd_output = json.loads(self.openstack( + 'volume snapshot show -f json ' + + new_name + )) + self.assertEqual( + "Beta='b'", + cmd_output["properties"], + ) diff --git a/openstackclient/tests/functional/volume/v2/test_volume.py b/openstackclient/tests/functional/volume/v2/test_volume.py index ea891cba..203ca819 100644 --- a/openstackclient/tests/functional/volume/v2/test_volume.py +++ b/openstackclient/tests/functional/volume/v2/test_volume.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +import json import time import uuid @@ -19,118 +20,220 @@ from openstackclient.tests.functional.volume.v2 import common class VolumeTests(common.BaseVolumeTests): """Functional tests for volume. """ - NAME = uuid.uuid4().hex - SNAPSHOT_NAME = uuid.uuid4().hex - VOLUME_FROM_SNAPSHOT_NAME = uuid.uuid4().hex - OTHER_NAME = uuid.uuid4().hex - HEADERS = ['"Display Name"'] - FIELDS = ['name'] - - @classmethod - def setUpClass(cls): - super(VolumeTests, cls).setUpClass() - opts = cls.get_opts(cls.FIELDS) - - # Create test volume - raw_output = cls.openstack('volume create --size 1 ' + cls.NAME + opts) - expected = cls.NAME + '\n' - cls.assertOutput(expected, raw_output) - - @classmethod - def tearDownClass(cls): - # Rename test volume - raw_output = cls.openstack( - 'volume set --name ' + cls.OTHER_NAME + ' ' + cls.NAME) - cls.assertOutput('', raw_output) - - # Set volume state - cls.openstack('volume set --state error ' + cls.OTHER_NAME) - opts = cls.get_opts(["status"]) - raw_output_status = cls.openstack( - 'volume show ' + cls.OTHER_NAME + opts) - - # Delete test volume - raw_output = cls.openstack('volume delete ' + cls.OTHER_NAME) - cls.assertOutput('', raw_output) - cls.assertOutput('error\n', raw_output_status) + def test_volume_delete(self): + """Test create, delete multiple""" + name1 = uuid.uuid4().hex + cmd_output = json.loads(self.openstack( + 'volume create -f json ' + + '--size 1 ' + + name1 + )) + self.assertEqual( + 1, + cmd_output["size"], + ) + + name2 = uuid.uuid4().hex + cmd_output = json.loads(self.openstack( + 'volume create -f json ' + + '--size 2 ' + + name2 + )) + self.assertEqual( + 2, + cmd_output["size"], + ) + + self.wait_for("volume", name1, "available") + self.wait_for("volume", name2, "available") + del_output = self.openstack('volume delete ' + name1 + ' ' + name2) + self.assertOutput('', del_output) def test_volume_list(self): - opts = self.get_opts(self.HEADERS) - raw_output = self.openstack('volume list' + opts) - self.assertIn(self.NAME, raw_output) - - def test_volume_show(self): - opts = self.get_opts(self.FIELDS) - raw_output = self.openstack('volume show ' + self.NAME + opts) - self.assertEqual(self.NAME + "\n", raw_output) - - def test_volume_properties(self): + """Test create, list filter""" + name1 = uuid.uuid4().hex + cmd_output = json.loads(self.openstack( + 'volume create -f json ' + + '--size 1 ' + + name1 + )) + self.addCleanup(self.openstack, 'volume delete ' + name1) + self.assertEqual( + 1, + cmd_output["size"], + ) + self.wait_for("volume", name1, "available") + + name2 = uuid.uuid4().hex + cmd_output = json.loads(self.openstack( + 'volume create -f json ' + + '--size 2 ' + + name2 + )) + self.addCleanup(self.openstack, 'volume delete ' + name2) + self.assertEqual( + 2, + cmd_output["size"], + ) + self.wait_for("volume", name2, "available") raw_output = self.openstack( - 'volume set --property a=b --property c=d ' + self.NAME) - self.assertEqual("", raw_output) - opts = self.get_opts(["properties"]) - raw_output = self.openstack('volume show ' + self.NAME + opts) - self.assertEqual("a='b', c='d'\n", raw_output) + 'volume set ' + + '--state error ' + + name2 + ) + self.assertOutput('', raw_output) - raw_output = self.openstack('volume unset --property a ' + self.NAME) - self.assertEqual("", raw_output) - raw_output = self.openstack('volume show ' + self.NAME + opts) - self.assertEqual("c='d'\n", raw_output) + # Test list --long + cmd_output = json.loads(self.openstack( + 'volume list -f json ' + + '--long' + )) + names = [x["Display Name"] for x in cmd_output] + self.assertIn(name1, names) + self.assertIn(name2, names) + + # Test list --status + cmd_output = json.loads(self.openstack( + 'volume list -f json ' + + '--status error' + )) + names = [x["Display Name"] for x in cmd_output] + self.assertNotIn(name1, names) + self.assertIn(name2, names) + + # TODO(qiangjiahui): Add project option to filter tests when we can + # specify volume with project def test_volume_set(self): - discription = uuid.uuid4().hex - self.openstack('volume set --description ' + discription + ' ' + - self.NAME) - opts = self.get_opts(["description", "name"]) - raw_output = self.openstack('volume show ' + self.NAME + opts) - self.assertEqual(discription + "\n" + self.NAME + "\n", raw_output) - - def test_volume_set_size(self): - self.openstack('volume set --size 2 ' + self.NAME) - opts = self.get_opts(["name", "size"]) - raw_output = self.openstack('volume show ' + self.NAME + opts) - self.assertEqual(self.NAME + "\n2\n", raw_output) - - def test_volume_set_bootable(self): - self.openstack('volume set --bootable ' + self.NAME) - opts = self.get_opts(["bootable"]) - raw_output = self.openstack('volume show ' + self.NAME + opts) - self.assertEqual("true\n", raw_output) - - self.openstack('volume set --non-bootable ' + self.NAME) - opts = self.get_opts(["bootable"]) - raw_output = self.openstack('volume show ' + self.NAME + opts) - self.assertEqual("false\n", raw_output) + """Tests create volume, set, unset, show, delete""" + name = uuid.uuid4().hex + new_name = name + "_" + cmd_output = json.loads(self.openstack( + 'volume create -f json ' + + '--size 1 ' + + '--description aaaa ' + + '--property Alpha=a ' + + name + )) + self.addCleanup(self.openstack, 'volume delete ' + new_name) + self.assertEqual( + name, + cmd_output["name"], + ) + self.assertEqual( + 1, + cmd_output["size"], + ) + self.assertEqual( + 'aaaa', + cmd_output["description"], + ) + self.assertEqual( + "Alpha='a'", + cmd_output["properties"], + ) + self.assertEqual( + 'false', + cmd_output["bootable"], + ) + self.wait_for("volume", name, "available") + + # Test volume set + raw_output = self.openstack( + 'volume set ' + + '--name ' + new_name + + ' --size 2 ' + + '--description bbbb ' + + '--property Alpha=c ' + + '--property Beta=b ' + + '--bootable ' + + name, + ) + self.assertOutput('', raw_output) - def test_volume_snapshot(self): - opts = self.get_opts(self.FIELDS) - - # Create snapshot from test volume - raw_output = self.openstack('volume snapshot create ' + - self.SNAPSHOT_NAME + - ' --volume ' + self.NAME + opts) - expected = self.SNAPSHOT_NAME + '\n' - self.assertOutput(expected, raw_output) - self.wait_for("volume snapshot", self.SNAPSHOT_NAME, "available") - - # Create volume from snapshot - raw_output = self.openstack('volume create --size 2 --snapshot ' + - self.SNAPSHOT_NAME + ' ' + - self.VOLUME_FROM_SNAPSHOT_NAME + opts) - expected = self.VOLUME_FROM_SNAPSHOT_NAME + '\n' - self.assertOutput(expected, raw_output) - self.wait_for("volume", self.VOLUME_FROM_SNAPSHOT_NAME, "available") - - # Delete volume that create from snapshot - raw_output = self.openstack('volume delete ' + - self.VOLUME_FROM_SNAPSHOT_NAME) + cmd_output = json.loads(self.openstack( + 'volume show -f json ' + + new_name + )) + self.assertEqual( + new_name, + cmd_output["name"], + ) + self.assertEqual( + 2, + cmd_output["size"], + ) + self.assertEqual( + 'bbbb', + cmd_output["description"], + ) + self.assertEqual( + "Alpha='c', Beta='b'", + cmd_output["properties"], + ) + self.assertEqual( + 'true', + cmd_output["bootable"], + ) + + # Test volume unset + raw_output = self.openstack( + 'volume unset ' + + '--property Alpha ' + + new_name, + ) self.assertOutput('', raw_output) - # Delete test snapshot + cmd_output = json.loads(self.openstack( + 'volume show -f json ' + + new_name + )) + self.assertEqual( + "Beta='b'", + cmd_output["properties"], + ) + + def test_volume_snapshot(self): + """Tests volume create from snapshot""" + + volume_name = uuid.uuid4().hex + snapshot_name = uuid.uuid4().hex + # Make a snapshot + cmd_output = json.loads(self.openstack( + 'volume create -f json ' + + '--size 1 ' + + volume_name + )) + self.wait_for("volume", volume_name, "available") + self.assertEqual( + volume_name, + cmd_output["name"], + ) + cmd_output = json.loads(self.openstack( + 'volume snapshot create -f json ' + + snapshot_name + + ' --volume ' + volume_name + )) + self.wait_for("volume snapshot", snapshot_name, "available") + + name = uuid.uuid4().hex + cmd_output = json.loads(self.openstack( + 'volume create -f json ' + + '--snapshot ' + snapshot_name + + ' ' + name + )) + self.addCleanup(self.openstack, 'volume delete ' + name) + self.addCleanup(self.openstack, 'volume delete ' + volume_name) + self.assertEqual( + name, + cmd_output["name"], + ) + self.wait_for("volume", name, "available") + + # Delete snapshot raw_output = self.openstack( - 'volume snapshot delete ' + self.SNAPSHOT_NAME) + 'volume snapshot delete ' + snapshot_name) self.assertOutput('', raw_output) - self.wait_for("volume", self.NAME, "available") def wait_for(self, check_type, check_name, desired_status, wait=120, interval=5, failures=['ERROR']): diff --git a/openstackclient/tests/unit/common/test_quota.py b/openstackclient/tests/unit/common/test_quota.py index 7dd23373..244d74d2 100644 --- a/openstackclient/tests/unit/common/test_quota.py +++ b/openstackclient/tests/unit/common/test_quota.py @@ -13,6 +13,8 @@ import copy import mock +from openstack.network.v2 import quota as _quota + from openstackclient.common import quota from openstackclient.tests.unit.compute.v2 import fakes as compute_fakes from openstackclient.tests.unit import fakes @@ -282,27 +284,32 @@ class TestQuotaSet(TestQuota): ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) - result = self.cmd.take_action(parsed_args) - kwargs = { - 'subnet': network_fakes.QUOTA['subnet'], - 'network': network_fakes.QUOTA['network'], - 'floatingip': network_fakes.QUOTA['floatingip'], - 'subnetpool': network_fakes.QUOTA['subnetpool'], - 'security_group_rule': - network_fakes.QUOTA['security_group_rule'], - 'security_group': network_fakes.QUOTA['security_group'], - 'router': network_fakes.QUOTA['router'], - 'rbac_policy': network_fakes.QUOTA['rbac_policy'], - 'port': network_fakes.QUOTA['port'], - 'vip': network_fakes.QUOTA['vip'], - 'healthmonitor': network_fakes.QUOTA['healthmonitor'], - 'l7policy': network_fakes.QUOTA['l7policy'], - } - self.network_mock.update_quota.assert_called_once_with( - identity_fakes.project_id, - **kwargs - ) - self.assertIsNone(result) + # TODO(huanxuan): Remove this if condition once the fixed + # SDK Quota class is the minimum required version. + # This is expected to be SDK release 0.9.13 + if not hasattr(_quota.Quota, 'allow_get'): + # Just run this when sdk <= 0.9.10 + result = self.cmd.take_action(parsed_args) + kwargs = { + 'subnet': network_fakes.QUOTA['subnet'], + 'network': network_fakes.QUOTA['network'], + 'floatingip': network_fakes.QUOTA['floatingip'], + 'subnetpool': network_fakes.QUOTA['subnetpool'], + 'security_group_rule': + network_fakes.QUOTA['security_group_rule'], + 'security_group': network_fakes.QUOTA['security_group'], + 'router': network_fakes.QUOTA['router'], + 'rbac_policy': network_fakes.QUOTA['rbac_policy'], + 'port': network_fakes.QUOTA['port'], + 'vip': network_fakes.QUOTA['vip'], + 'healthmonitor': network_fakes.QUOTA['healthmonitor'], + 'l7policy': network_fakes.QUOTA['l7policy'], + } + self.network_mock.update_quota.assert_called_once_with( + identity_fakes.project_id, + **kwargs + ) + self.assertIsNone(result) def test_quota_set_with_class(self): arglist = [ @@ -476,15 +483,20 @@ class TestQuotaShow(TestQuota): parsed_args = self.check_parser(self.cmd, arglist, verifylist) - self.cmd.take_action(parsed_args) - - self.quotas_mock.defaults.assert_called_once_with( - identity_fakes.project_id) - self.volume_quotas_mock.defaults.assert_called_once_with( - identity_fakes.project_id) - self.network.get_quota_default.assert_called_once_with( - identity_fakes.project_id) - self.assertNotCalled(self.network.get_quota) + # TODO(huanxuan): Remove this if condition once the fixed + # SDK QuotaDefault class is the minimum required version. + # This is expected to be SDK release 0.9.13 + if not hasattr(_quota.QuotaDefault, 'project'): + # Just run this when sdk <= 0.9.10 + self.cmd.take_action(parsed_args) + + self.quotas_mock.defaults.assert_called_once_with( + identity_fakes.project_id) + self.volume_quotas_mock.defaults.assert_called_once_with( + identity_fakes.project_id) + self.network.get_quota_default.assert_called_once_with( + identity_fakes.project_id) + self.assertNotCalled(self.network.get_quota) def test_quota_show_with_class(self): arglist = [ diff --git a/openstackclient/tests/unit/volume/v2/test_qos_specs.py b/openstackclient/tests/unit/volume/v2/test_qos_specs.py index 7597e852..35d9a345 100644 --- a/openstackclient/tests/unit/volume/v2/test_qos_specs.py +++ b/openstackclient/tests/unit/volume/v2/test_qos_specs.py @@ -70,24 +70,26 @@ class TestQosAssociate(TestQos): class TestQosCreate(TestQos): - new_qos_spec = volume_fakes.FakeQos.create_one_qos() columns = ( 'consumer', 'id', 'name', - 'specs' - ) - data = ( - new_qos_spec.consumer, - new_qos_spec.id, - new_qos_spec.name, - new_qos_spec.specs + 'properties' ) def setUp(self): super(TestQosCreate, self).setUp() + self.new_qos_spec = volume_fakes.FakeQos.create_one_qos() self.qos_mock.create.return_value = self.new_qos_spec + + self.data = ( + self.new_qos_spec.consumer, + self.new_qos_spec.id, + self.new_qos_spec.name, + utils.format_dict(self.new_qos_spec.specs) + ) + # Get the command object to test self.cmd = qos_specs.CreateQos(self.app, None) @@ -147,11 +149,11 @@ class TestQosCreate(TestQos): columns, data = self.cmd.take_action(parsed_args) - self.new_qos_spec.specs.update( - {'consumer': self.new_qos_spec.consumer}) self.qos_mock.create.assert_called_with( self.new_qos_spec.name, - self.new_qos_spec.specs + {'consumer': self.new_qos_spec.consumer, + 'foo': 'bar', + 'iops': '9001'} ) self.assertEqual(self.columns, columns) @@ -307,7 +309,7 @@ class TestQosList(TestQos): 'Name', 'Consumer', 'Associations', - 'Specs', + 'Properties', ) data = [] for q in qos_specs: @@ -383,7 +385,7 @@ class TestQosShow(TestQos): 'consumer', 'id', 'name', - 'specs' + 'properties' ) data = ( qos_association.name, diff --git a/openstackclient/volume/v2/qos_specs.py b/openstackclient/volume/v2/qos_specs.py index b7f49eca..8e1d67b5 100644 --- a/openstackclient/volume/v2/qos_specs.py +++ b/openstackclient/volume/v2/qos_specs.py @@ -95,6 +95,9 @@ class CreateQos(command.ShowOne): qos_spec = volume_client.qos_specs.create(parsed_args.name, specs) + qos_spec._info.update( + {'properties': utils.format_dict(qos_spec._info.pop('specs'))} + ) return zip(*sorted(six.iteritems(qos_spec._info))) @@ -190,8 +193,11 @@ class ListQos(command.Lister): for association in qos_associations] qos._info.update({'associations': associations}) + display_columns = ( + 'ID', 'Name', 'Consumer', 'Associations', 'Properties') + columns = ('ID', 'Name', 'Consumer', 'Associations', 'Specs') - return (columns, + return (display_columns, (utils.get_dict_properties( s._info, columns, formatters={ @@ -254,7 +260,8 @@ class ShowQos(command.ShowOne): qos_spec._info.update({ 'associations': utils.format_list(associations) }) - qos_spec._info.update({'specs': utils.format_dict(qos_spec.specs)}) + qos_spec._info.update( + {'properties': utils.format_dict(qos_spec._info.pop('specs'))}) return zip(*sorted(six.iteritems(qos_spec._info))) |
