diff options
Diffstat (limited to 'openstackclient')
| -rw-r--r-- | openstackclient/compute/v2/host.py | 2 | ||||
| -rw-r--r-- | openstackclient/compute/v2/server.py | 6 | ||||
| -rw-r--r-- | openstackclient/image/v2/image.py | 10 | ||||
| -rw-r--r-- | openstackclient/network/client.py | 52 | ||||
| -rw-r--r-- | openstackclient/network/v2/floating_ip.py | 11 | ||||
| -rw-r--r-- | openstackclient/network/v2/port.py | 11 | ||||
| -rw-r--r-- | openstackclient/tests/functional/compute/v2/test_aggregate.py | 18 | ||||
| -rw-r--r-- | openstackclient/tests/functional/compute/v2/test_server.py | 40 | ||||
| -rw-r--r-- | openstackclient/tests/functional/image/v2/test_image.py | 29 | ||||
| -rw-r--r-- | openstackclient/tests/unit/compute/v2/test_host.py | 7 | ||||
| -rw-r--r-- | openstackclient/tests/unit/compute/v2/test_server.py | 19 | ||||
| -rw-r--r-- | openstackclient/tests/unit/fakes.py | 1 | ||||
| -rw-r--r-- | openstackclient/tests/unit/image/v2/test_image.py | 17 | ||||
| -rw-r--r-- | openstackclient/tests/unit/network/v2/test_floating_ip_network.py | 57 | ||||
| -rw-r--r-- | openstackclient/tests/unit/network/v2/test_port.py | 18 | ||||
| -rw-r--r-- | openstackclient/tests/unit/volume/v2/test_volume.py | 2 | ||||
| -rw-r--r-- | openstackclient/volume/v2/volume.py | 16 |
17 files changed, 236 insertions, 80 deletions
diff --git a/openstackclient/compute/v2/host.py b/openstackclient/compute/v2/host.py index 9fdfd927..07c92a8c 100644 --- a/openstackclient/compute/v2/host.py +++ b/openstackclient/compute/v2/host.py @@ -97,7 +97,7 @@ class SetHost(command.Command): compute_client.api.host_set( parsed_args.host, - kwargs + **kwargs ) diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index a7b99306..777f7744 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -1226,7 +1226,7 @@ class ListServer(command.Lister): # Create a dict that maps image_id to image object. # Needed so that we can display the "Image Name" column. # "Image Name" is not crucial, so we swallow any exceptions. - if not parsed_args.no_name_lookup: + if data and not parsed_args.no_name_lookup: try: images_list = self.app.client_manager.image.images.list() for i in images_list: @@ -1238,9 +1238,9 @@ class ListServer(command.Lister): # Create a dict that maps flavor_id to flavor object. # Needed so that we can display the "Flavor Name" column. # "Flavor Name" is not crucial, so we swallow any exceptions. - if not parsed_args.no_name_lookup: + if data and not parsed_args.no_name_lookup: try: - flavors_list = compute_client.flavors.list() + flavors_list = compute_client.flavors.list(is_public=None) for i in flavors_list: flavors[i.id] = i except Exception: diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py index 4a51062f..5c7d32d4 100644 --- a/openstackclient/image/v2/image.py +++ b/openstackclient/image/v2/image.py @@ -465,6 +465,12 @@ class ListImage(command.Lister): help=_("Filter images based on status.") ) parser.add_argument( + '--tag', + metavar='<tag>', + default=None, + help=_('Filter images based on tag.'), + ) + parser.add_argument( '--long', action='store_true', default=False, @@ -521,6 +527,8 @@ class ListImage(command.Lister): kwargs['name'] = parsed_args.name if parsed_args.status: kwargs['status'] = parsed_args.status + if parsed_args.tag: + kwargs['tag'] = parsed_args.tag if parsed_args.long: columns = ( 'ID', @@ -577,7 +585,7 @@ class ListImage(command.Lister): property_field='properties', ) - data = utils.sort_items(data, parsed_args.sort) + data = utils.sort_items(data, parsed_args.sort, str) return ( column_headers, diff --git a/openstackclient/network/client.py b/openstackclient/network/client.py index 5183cbda..39936fde 100644 --- a/openstackclient/network/client.py +++ b/openstackclient/network/client.py @@ -13,16 +13,6 @@ import logging -from openstack import connection - - -# NOTE(dtroyer): Attempt an import to detect if the SDK installed is new -# enough to not use Profile. If so, use that. -try: - from openstack.config import loader as config # noqa - profile = None -except ImportError: - from openstack import profile from osc_lib import utils from openstackclient.i18n import _ @@ -41,37 +31,17 @@ API_VERSIONS = { def make_client(instance): """Returns a network proxy""" - if getattr(instance, "sdk_connection", None) is None: - if profile is None: - # If the installed OpenStackSDK is new enough to not require a - # Profile obejct and osc-lib is not new enough to have created - # it for us, make an SDK Connection. - # NOTE(dtroyer): This can be removed when this bit is in the - # released osc-lib in requirements.txt. - conn = connection.Connection( - config=instance._cli_options, - session=instance.session, - ) - else: - # Fall back to the original Connection creation - prof = profile.Profile() - prof.set_region(API_NAME, instance.region_name) - prof.set_version(API_NAME, instance._api_version[API_NAME]) - prof.set_interface(API_NAME, instance.interface) - conn = connection.Connection( - authenticator=instance.session.auth, - verify=instance.session.verify, - cert=instance.session.cert, - profile=prof, - ) - - instance.sdk_connection = conn - - conn = instance.sdk_connection - LOG.debug('Connection: %s', conn) - LOG.debug('Network client initialized using OpenStack SDK: %s', - conn.network) - return conn.network + # NOTE(dtroyer): As of osc-lib 1.8.0 and OpenStackSDK 0.10.0 the + # old Profile interface and separate client creation + # for each API that uses the SDK is unnecessary. This + # callback remains as a remnant of the original plugin + # interface and to avoid the code churn of changing all + # of the existing references. + LOG.debug( + 'Network client initialized using OpenStack SDK: %s', + instance.sdk_connection.network, + ) + return instance.sdk_connection.network def build_option_parser(parser): diff --git a/openstackclient/network/v2/floating_ip.py b/openstackclient/network/v2/floating_ip.py index 1bb2c069..958480a5 100644 --- a/openstackclient/network/v2/floating_ip.py +++ b/openstackclient/network/v2/floating_ip.py @@ -347,11 +347,10 @@ class SetFloatingIP(command.Command): parser.add_argument( 'floating_ip', metavar='<floating-ip>', - help=_("Floating IP to associate (IP address or ID)")) + help=_("Floating IP to modify (IP address or ID)")) parser.add_argument( '--port', metavar='<port>', - required=True, help=_("Associate the floating IP with port (name or ID)")), parser.add_argument( '--fixed-ip-address', @@ -383,9 +382,11 @@ class SetFloatingIP(command.Command): parsed_args.floating_ip, ignore_missing=False, ) - port = client.find_port(parsed_args.port, - ignore_missing=False) - attrs['port_id'] = port.id + if parsed_args.port: + port = client.find_port(parsed_args.port, + ignore_missing=False) + attrs['port_id'] = port.id + if parsed_args.fixed_ip_address: attrs['fixed_ip_address'] = parsed_args.fixed_ip_address diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py index f13ee7b9..af6efa9d 100644 --- a/openstackclient/network/v2/port.py +++ b/openstackclient/network/v2/port.py @@ -215,6 +215,9 @@ def _prepare_filter_fixed_ips(client_manager, parsed_args): if 'ip-address' in ip_spec: ips.append('ip_address=%s' % ip_spec['ip-address']) + + if 'ip-substring' in ip_spec: + ips.append('ip_address_substr=%s' % ip_spec['ip-substring']) return ips @@ -531,11 +534,13 @@ class ListPort(command.Lister): identity_common.add_project_domain_option_to_parser(parser) parser.add_argument( '--fixed-ip', - metavar='subnet=<subnet>,ip-address=<ip-address>', + metavar=('subnet=<subnet>,ip-address=<ip-address>,' + 'ip-substring=<ip-substring>'), action=parseractions.MultiKeyValueAction, - optional_keys=['subnet', 'ip-address'], + optional_keys=['subnet', 'ip-address', 'ip-substring'], help=_("Desired IP and/or subnet for filtering ports " - "(name or ID): subnet=<subnet>,ip-address=<ip-address> " + "(name or ID): subnet=<subnet>,ip-address=<ip-address>," + "ip-substring=<ip-substring> " "(repeat option to set multiple fixed IP addresses)"), ) _tag.add_tag_filtering_option_to_parser(parser, _('ports')) diff --git a/openstackclient/tests/functional/compute/v2/test_aggregate.py b/openstackclient/tests/functional/compute/v2/test_aggregate.py index cf9d2bc0..71026757 100644 --- a/openstackclient/tests/functional/compute/v2/test_aggregate.py +++ b/openstackclient/tests/functional/compute/v2/test_aggregate.py @@ -11,6 +11,7 @@ # under the License. import json +import time import uuid from openstackclient.tests.functional import base @@ -51,6 +52,23 @@ class AggregateTests(base.TestCase): cmd_output['availability_zone'] ) + # Loop a few times since this is timing-sensitive + # Just hard-code it for now, since there is no pause and it is + # racy we shouldn't have to wait too long, a minute seems reasonable + wait_time = 0 + while wait_time < 60: + cmd_output = json.loads(self.openstack( + 'aggregate show -f json ' + + name2 + )) + if cmd_output['name'] != name2: + # Hang out for a bit and try again + print('retrying aggregate check') + wait_time += 10 + time.sleep(10) + else: + break + del_output = self.openstack( 'aggregate delete ' + name1 + ' ' + diff --git a/openstackclient/tests/functional/compute/v2/test_server.py b/openstackclient/tests/functional/compute/v2/test_server.py index 0b29fe5f..bba16f62 100644 --- a/openstackclient/tests/functional/compute/v2/test_server.py +++ b/openstackclient/tests/functional/compute/v2/test_server.py @@ -11,6 +11,7 @@ # under the License. import json +import time import uuid from tempest.lib import exceptions @@ -255,10 +256,24 @@ class ServerTests(common.ComputeTestCase): floating_ip ) self.assertEqual("", raw_output) - cmd_output = json.loads(self.openstack( - 'server show -f json ' + - name - )) + + # Loop a few times since this is timing-sensitive + # Just hard-code it for now, since there is no pause and it is + # racy we shouldn't have to wait too long, a minute seems reasonable + wait_time = 0 + while wait_time < 60: + cmd_output = json.loads(self.openstack( + 'server show -f json ' + + name + )) + if floating_ip not in cmd_output['addresses']: + # Hang out for a bit and try again + print('retrying floating IP check') + wait_time += 10 + time.sleep(10) + else: + break + self.assertIn( floating_ip, cmd_output['addresses'], @@ -272,6 +287,23 @@ class ServerTests(common.ComputeTestCase): ) self.assertEqual("", raw_output) + # Loop a few times since this is timing-sensitive + # Just hard-code it for now, since there is no pause and it is + # racy we shouldn't have to wait too long, a minute seems reasonable + wait_time = 0 + while wait_time < 60: + cmd_output = json.loads(self.openstack( + 'server show -f json ' + + name + )) + if floating_ip in cmd_output['addresses']: + # Hang out for a bit and try again + print('retrying floating IP check') + wait_time += 10 + time.sleep(10) + else: + break + cmd_output = json.loads(self.openstack( 'server show -f json ' + name diff --git a/openstackclient/tests/functional/image/v2/test_image.py b/openstackclient/tests/functional/image/v2/test_image.py index 278ba5b9..3037b903 100644 --- a/openstackclient/tests/functional/image/v2/test_image.py +++ b/openstackclient/tests/functional/image/v2/test_image.py @@ -28,10 +28,11 @@ class ImageTests(base.TestCase): @classmethod def setUpClass(cls): super(ImageTests, cls).setUpClass() + cls.image_tag = 'my_tag' json_output = json.loads(cls.openstack( '--os-image-api-version 2 ' - 'image create -f json ' + - cls.NAME + 'image create -f json --tag {tag} {name}'.format( + tag=cls.image_tag, name=cls.NAME) )) cls.image_id = json_output["id"] cls.assertOutput(cls.NAME, json_output['name']) @@ -81,6 +82,16 @@ class ImageTests(base.TestCase): [img['Status'] for img in json_output] ) + def test_image_list_with_tag_filter(self): + json_output = json.loads(self.openstack( + 'image list --tag ' + self.image_tag + ' --long -f json' + )) + for taglist in [img['Tags'].split(', ') for img in json_output]: + self.assertIn( + self.image_tag, + taglist + ) + def test_image_attributes(self): """Test set, unset, show on attributes, tags and properties""" @@ -142,6 +153,10 @@ class ImageTests(base.TestCase): ) # Test tags + self.assertNotIn( + '01', + json_output["tags"].split(', ') + ) self.openstack( 'image set ' + '--tag 01 ' + @@ -151,9 +166,9 @@ class ImageTests(base.TestCase): 'image show -f json ' + self.NAME )) - self.assertEqual( + self.assertIn( '01', - json_output["tags"], + json_output["tags"].split(', ') ) self.openstack( @@ -165,9 +180,9 @@ class ImageTests(base.TestCase): 'image show -f json ' + self.NAME )) - self.assertEqual( - '', - json_output["tags"], + self.assertNotIn( + '01', + json_output["tags"].split(', ') ) def test_image_set_rename(self): diff --git a/openstackclient/tests/unit/compute/v2/test_host.py b/openstackclient/tests/unit/compute/v2/test_host.py index 329095de..244da413 100644 --- a/openstackclient/tests/unit/compute/v2/test_host.py +++ b/openstackclient/tests/unit/compute/v2/test_host.py @@ -111,8 +111,7 @@ class TestHostSet(TestHost): result = self.cmd.take_action(parsed_args) self.assertIsNone(result) - body = {} - h_mock.assert_called_with(self.host['host'], body) + h_mock.assert_called_with(self.host['host']) def test_host_set(self, h_mock): h_mock.return_value = self.host @@ -133,8 +132,8 @@ class TestHostSet(TestHost): result = self.cmd.take_action(parsed_args) self.assertIsNone(result) - body = {'status': 'enable', 'maintenance_mode': 'disable'} - h_mock.assert_called_with(self.host['host'], body) + h_mock.assert_called_with(self.host['host'], status='enable', + maintenance_mode='disable') @mock.patch( diff --git a/openstackclient/tests/unit/compute/v2/test_server.py b/openstackclient/tests/unit/compute/v2/test_server.py index a53c6c81..46d4c241 100644 --- a/openstackclient/tests/unit/compute/v2/test_server.py +++ b/openstackclient/tests/unit/compute/v2/test_server.py @@ -1947,6 +1947,25 @@ class TestServerList(TestServer): self.assertEqual(self.columns, columns) self.assertEqual(tuple(self.data), tuple(data)) + def test_server_list_no_servers(self): + arglist = [] + verifylist = [ + ('all_projects', False), + ('long', False), + ('deleted', False), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + self.servers_mock.list.return_value = [] + self.data = () + + columns, data = self.cmd.take_action(parsed_args) + + self.servers_mock.list.assert_called_with(**self.kwargs) + self.assertEqual(0, self.images_mock.list.call_count) + self.assertEqual(0, self.flavors_mock.list.call_count) + self.assertEqual(self.columns, columns) + self.assertEqual(tuple(self.data), tuple(data)) + def test_server_list_long_option(self): arglist = [ '--long', diff --git a/openstackclient/tests/unit/fakes.py b/openstackclient/tests/unit/fakes.py index 954973ef..bca457e4 100644 --- a/openstackclient/tests/unit/fakes.py +++ b/openstackclient/tests/unit/fakes.py @@ -106,6 +106,7 @@ class FakeApp(object): def __init__(self, _stdout, _log): self.stdout = _stdout self.client_manager = None + self.api_version = {} self.stdin = sys.stdin self.stdout = _stdout or sys.stdout self.stderr = sys.stderr diff --git a/openstackclient/tests/unit/image/v2/test_image.py b/openstackclient/tests/unit/image/v2/test_image.py index 301cd037..e7cd34c3 100644 --- a/openstackclient/tests/unit/image/v2/test_image.py +++ b/openstackclient/tests/unit/image/v2/test_image.py @@ -708,7 +708,8 @@ class TestImageList(TestImage): ) si_mock.assert_called_with( [self._image], - 'name:asc' + 'name:asc', + str, ) self.assertEqual(self.columns, columns) self.assertEqual(self.datalist, tuple(data)) @@ -779,6 +780,20 @@ class TestImageList(TestImage): status='active', marker=self._image.id ) + def test_image_list_tag_option(self): + arglist = [ + '--tag', 'abc', + ] + verifylist = [ + ('tag', 'abc'), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + self.api_mock.image_list.assert_called_with( + tag='abc', marker=self._image.id + ) + class TestListImageProjects(TestImage): diff --git a/openstackclient/tests/unit/network/v2/test_floating_ip_network.py b/openstackclient/tests/unit/network/v2/test_floating_ip_network.py index 65d87377..822d3ae8 100644 --- a/openstackclient/tests/unit/network/v2/test_floating_ip_network.py +++ b/openstackclient/tests/unit/network/v2/test_floating_ip_network.py @@ -747,6 +747,31 @@ class TestSetFloatingIP(TestFloatingIPNetwork): self.network.update_ip.assert_called_once_with( self.floating_ip, **attrs) + def test_qos_policy_option(self): + qos_policy = network_fakes.FakeNetworkQosPolicy.create_one_qos_policy() + self.network.find_qos_policy = mock.Mock(return_value=qos_policy) + arglist = [ + "--qos-policy", qos_policy.id, + self.floating_ip.id, + ] + verifylist = [ + ('qos_policy', qos_policy.id), + ('floating_ip', self.floating_ip.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + + attrs = { + 'qos_policy_id': qos_policy.id, + } + self.network.find_ip.assert_called_once_with( + self.floating_ip.id, + ignore_missing=False, + ) + self.network.update_ip.assert_called_once_with( + self.floating_ip, **attrs) + def test_port_and_qos_policy_option(self): qos_policy = network_fakes.FakeNetworkQosPolicy.create_one_qos_policy() self.network.find_qos_policy = mock.Mock(return_value=qos_policy) @@ -775,6 +800,29 @@ class TestSetFloatingIP(TestFloatingIPNetwork): self.network.update_ip.assert_called_once_with( self.floating_ip, **attrs) + def test_no_qos_policy_option(self): + arglist = [ + "--no-qos-policy", + self.floating_ip.id, + ] + verifylist = [ + ('no_qos_policy', True), + ('floating_ip', self.floating_ip.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.cmd.take_action(parsed_args) + + attrs = { + 'qos_policy_id': None, + } + self.network.find_ip.assert_called_once_with( + self.floating_ip.id, + ignore_missing=False, + ) + self.network.update_ip.assert_called_once_with( + self.floating_ip, **attrs) + def test_port_and_no_qos_policy_option(self): arglist = [ "--no-qos-policy", @@ -810,16 +858,13 @@ class TestSetFloatingIP(TestFloatingIPNetwork): arglist = ['--no-tag'] verifylist = [('no_tag', True)] expected_args = [] - arglist.extend(['--port', self.floating_ip.port_id, - self.floating_ip.id]) - verifylist.extend([ - ('port', self.floating_ip.port_id), - ('floating_ip', self.floating_ip.id)]) + arglist.extend([self.floating_ip.id]) + verifylist.extend([('floating_ip', self.floating_ip.id)]) parsed_args = self.check_parser(self.cmd, arglist, verifylist) result = self.cmd.take_action(parsed_args) - self.assertTrue(self.network.update_ip.called) + self.assertFalse(self.network.update_ip.called) self.network.set_tags.assert_called_once_with( self.floating_ip, tests_utils.CompareBySet(expected_args)) diff --git a/openstackclient/tests/unit/network/v2/test_port.py b/openstackclient/tests/unit/network/v2/test_port.py index 03e1d841..78d7fd6c 100644 --- a/openstackclient/tests/unit/network/v2/test_port.py +++ b/openstackclient/tests/unit/network/v2/test_port.py @@ -867,6 +867,24 @@ class TestListPort(TestPort): self.assertEqual(self.columns, columns) self.assertEqual(self.data, list(data)) + def test_port_list_fixed_ip_opt_ip_address_substr(self): + ip_address_ss = self._ports[0].fixed_ips[0]['ip_address'][:-1] + arglist = [ + '--fixed-ip', "ip-substring=%s" % ip_address_ss, + ] + verifylist = [ + ('fixed_ip', [{'ip-substring': ip_address_ss}]) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.network.ports.assert_called_once_with(**{ + 'fixed_ips': ['ip_address_substr=%s' % ip_address_ss]}) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + def test_port_list_fixed_ip_opt_subnet_id(self): subnet_id = self._ports[0].fixed_ips[0]['subnet_id'] arglist = [ diff --git a/openstackclient/tests/unit/volume/v2/test_volume.py b/openstackclient/tests/unit/volume/v2/test_volume.py index 2fa924b8..304aa91c 100644 --- a/openstackclient/tests/unit/volume/v2/test_volume.py +++ b/openstackclient/tests/unit/volume/v2/test_volume.py @@ -430,7 +430,7 @@ class TestVolumeCreate(TestVolume): columns, data = self.cmd.take_action(parsed_args) self.volumes_mock.create.assert_called_once_with( - size=None, + size=snapshot.size, snapshot_id=snapshot.id, name=self.new_volume.name, description=None, diff --git a/openstackclient/volume/v2/volume.py b/openstackclient/volume/v2/volume.py index 61f846b0..ee3d2f20 100644 --- a/openstackclient/volume/v2/volume.py +++ b/openstackclient/volume/v2/volume.py @@ -186,11 +186,21 @@ class CreateVolume(command.ShowOne): image_client.images, parsed_args.image).id + size = parsed_args.size + snapshot = None if parsed_args.snapshot: - snapshot = utils.find_resource( + snapshot_obj = utils.find_resource( volume_client.volume_snapshots, - parsed_args.snapshot).id + parsed_args.snapshot) + snapshot = snapshot_obj.id + # Cinder requires a value for size when creating a volume + # even if creating from a snapshot. Cinder will create the + # volume with at least the same size as the snapshot anyway, + # so since we have the object here, just override the size + # value if it's either not given or is smaller than the + # snapshot size. + size = max(size or 0, snapshot_obj.size) project = None if parsed_args.project: @@ -205,7 +215,7 @@ class CreateVolume(command.ShowOne): parsed_args.user).id volume = volume_client.volumes.create( - size=parsed_args.size, + size=size, snapshot_id=snapshot, name=parsed_args.name, description=parsed_args.description, |
