diff options
Diffstat (limited to 'openstackclient')
| -rw-r--r-- | openstackclient/network/v2/network.py | 38 | ||||
| -rw-r--r-- | openstackclient/network/v2/port.py | 20 | ||||
| -rw-r--r-- | openstackclient/tests/network/v2/test_network.py | 9 | ||||
| -rw-r--r-- | openstackclient/tests/network/v2/test_port.py | 21 | ||||
| -rw-r--r-- | openstackclient/tests/volume/v2/test_type.py | 58 | ||||
| -rw-r--r-- | openstackclient/tests/volume/v2/test_volume.py | 43 | ||||
| -rw-r--r-- | openstackclient/volume/v2/volume_type.py | 46 |
7 files changed, 217 insertions, 18 deletions
diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py index 20d943ed..afac471a 100644 --- a/openstackclient/network/v2/network.py +++ b/openstackclient/network/v2/network.py @@ -76,6 +76,16 @@ def _get_attrs(client_manager, parsed_args): parsed_args.availability_zone_hints is not None: attrs['availability_zone_hints'] = parsed_args.availability_zone_hints + # update_external_network_options + if parsed_args.internal: + attrs['router:external'] = False + if parsed_args.external: + attrs['router:external'] = True + if parsed_args.no_default: + attrs['is_default'] = False + if parsed_args.default: + attrs['is_default'] = True + return attrs @@ -197,14 +207,6 @@ class CreateNetwork(common.NetworkAndComputeShowOne): def take_action_network(self, client, parsed_args): attrs = _get_attrs(self.app.client_manager, parsed_args) - if parsed_args.internal: - attrs['router:external'] = False - if parsed_args.external: - attrs['router:external'] = True - if parsed_args.no_default: - attrs['is_default'] = False - if parsed_args.default: - attrs['is_default'] = True if parsed_args.provider_network_type: attrs['provider:network_type'] = parsed_args.provider_network_type if parsed_args.physical_network: @@ -379,6 +381,26 @@ class SetNetwork(command.Command): action='store_true', help='Do not share the network between projects', ) + external_router_grp = parser.add_mutually_exclusive_group() + external_router_grp.add_argument( + '--external', + action='store_true', + help='Set this network as an external network. ' + 'Requires the "external-net" extension to be enabled.') + external_router_grp.add_argument( + '--internal', + action='store_true', + help='Set this network as an internal network') + default_router_grp = parser.add_mutually_exclusive_group() + default_router_grp.add_argument( + '--default', + action='store_true', + help='Specify if this network should be used as ' + 'the default external network') + default_router_grp.add_argument( + '--no-default', + action='store_true', + help='Do not use the network as the default external network.') return parser def take_action(self, parsed_args): diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py index 820f2ac2..c54cb257 100644 --- a/openstackclient/network/v2/port.py +++ b/openstackclient/network/v2/port.py @@ -30,6 +30,7 @@ LOG = logging.getLogger(__name__) def _format_admin_state(state): return 'UP' if state else 'DOWN' + _formatters = { 'admin_state_up': _format_admin_state, 'allowed_address_pairs': utils.format_list_of_dicts, @@ -383,17 +384,24 @@ class SetPort(command.Command): _prepare_fixed_ips(self.app.client_manager, parsed_args) attrs = _get_attrs(self.app.client_manager, parsed_args) - - if parsed_args.no_fixed_ip: - attrs['fixed_ips'] = [] - if parsed_args.no_binding_profile: + obj = client.find_port(parsed_args.port, ignore_missing=False) + if 'binding:profile' in attrs: + attrs['binding:profile'].update(obj.binding_profile) + elif parsed_args.no_binding_profile: attrs['binding:profile'] = {} + if 'fixed_ips' in attrs: + # When user unsets the fixed_ips, obj.fixed_ips = [{}]. + # Adding the obj.fixed_ips list to attrs['fixed_ips'] + # would therefore add an empty dictionary, while we need + # to append the attrs['fixed_ips'] iff there is some info + # in the obj.fixed_ips. Therefore I have opted for this `for` loop + attrs['fixed_ips'] += [ip for ip in obj.fixed_ips if ip] + elif parsed_args.no_fixed_ip: + attrs['fixed_ips'] = [] if attrs == {}: msg = "Nothing specified to be set" raise exceptions.CommandError(msg) - - obj = client.find_port(parsed_args.port, ignore_missing=False) client.update_port(obj, **attrs) diff --git a/openstackclient/tests/network/v2/test_network.py b/openstackclient/tests/network/v2/test_network.py index 8a75101b..7d0f8717 100644 --- a/openstackclient/tests/network/v2/test_network.py +++ b/openstackclient/tests/network/v2/test_network.py @@ -482,12 +482,16 @@ class TestSetNetwork(TestNetwork): '--enable', '--name', 'noob', '--share', + '--external', + '--default', ] verifylist = [ ('network', self._network.name), ('enable', True), ('name', 'noob'), ('share', True), + ('external', True), + ('default', True), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -497,6 +501,8 @@ class TestSetNetwork(TestNetwork): 'name': 'noob', 'admin_state_up': True, 'shared': True, + 'router:external': True, + 'is_default': True, } self.network.update_network.assert_called_once_with( self._network, **attrs) @@ -507,11 +513,13 @@ class TestSetNetwork(TestNetwork): self._network.name, '--disable', '--no-share', + '--internal', ] verifylist = [ ('network', self._network.name), ('disable', True), ('no_share', True), + ('internal', True), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -520,6 +528,7 @@ class TestSetNetwork(TestNetwork): attrs = { 'admin_state_up': False, 'shared': False, + 'router:external': False, } self.network.update_network.assert_called_once_with( self._network, **attrs) diff --git a/openstackclient/tests/network/v2/test_port.py b/openstackclient/tests/network/v2/test_port.py index 3b1a641a..f2aa26cf 100644 --- a/openstackclient/tests/network/v2/test_port.py +++ b/openstackclient/tests/network/v2/test_port.py @@ -268,7 +268,6 @@ class TestSetPort(TestPort): def setUp(self): super(TestSetPort, self).setUp() - self.fake_subnet = network_fakes.FakeSubnet.create_one_subnet() self.network.find_subnet = mock.Mock(return_value=self.fake_subnet) self.network.find_port = mock.Mock(return_value=self._port) @@ -295,6 +294,26 @@ class TestSetPort(TestPort): self.network.update_port.assert_called_once_with(self._port, **attrs) self.assertIsNone(result) + def test_append_fixed_ip(self): + _testport = network_fakes.FakePort.create_one_port( + {'fixed_ips': [{'ip_address': '0.0.0.1'}]}) + self.network.find_port = mock.Mock(return_value=_testport) + arglist = [ + '--fixed-ip', 'ip-address=10.0.0.12', + _testport.name, + ] + verifylist = [ + ('fixed_ip', [{'ip-address': '10.0.0.12'}]), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + attrs = { + 'fixed_ips': [ + {'ip_address': '10.0.0.12'}, {'ip_address': '0.0.0.1'}], + } + self.network.update_port.assert_called_once_with(_testport, **attrs) + self.assertIsNone(result) + def test_set_this(self): arglist = [ '--disable', diff --git a/openstackclient/tests/volume/v2/test_type.py b/openstackclient/tests/volume/v2/test_type.py index 448da432..f0ca9b01 100644 --- a/openstackclient/tests/volume/v2/test_type.py +++ b/openstackclient/tests/volume/v2/test_type.py @@ -394,6 +394,14 @@ class TestTypeUnset(TestType): loaded=True ) + # Return a project + self.projects_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.PROJECT), + loaded=True, + ) + + # Get the command object to test self.cmd = volume_type.UnsetVolumeType(self.app, None) def test_type_unset(self): @@ -413,3 +421,53 @@ class TestTypeUnset(TestType): result = self.types_mock.get.return_value._keys self.assertNotIn('property', result) + + def test_type_unset_project_access(self): + arglist = [ + '--project', identity_fakes.project_id, + volume_fakes.type_id, + ] + verifylist = [ + ('project', identity_fakes.project_id), + ('volume_type', volume_fakes.type_id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + self.assertIsNone(result) + + self.types_access_mock.remove_project_access.assert_called_with( + volume_fakes.type_id, + identity_fakes.project_id, + ) + + def test_type_unset_not_called_without_project_argument(self): + arglist = [ + '--project', '', + volume_fakes.type_id, + ] + verifylist = [ + ('project', ''), + ('volume_type', volume_fakes.type_id), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + self.assertIsNone(result) + + self.assertFalse(self.types_access_mock.remove_project_access.called) + + def test_type_unset_failed_with_missing_volume_type_argument(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) diff --git a/openstackclient/tests/volume/v2/test_volume.py b/openstackclient/tests/volume/v2/test_volume.py index 12253806..e4ac7c10 100644 --- a/openstackclient/tests/volume/v2/test_volume.py +++ b/openstackclient/tests/volume/v2/test_volume.py @@ -14,6 +14,7 @@ import copy +import mock from mock import call from openstackclient.common import utils @@ -40,6 +41,9 @@ class TestVolume(volume_fakes.TestVolume): self.images_mock = self.app.client_manager.image.images self.images_mock.reset_mock() + self.snapshots_mock = self.app.client_manager.volume.volume_snapshots + self.snapshots_mock.reset_mock() + def setup_volumes_mock(self, count): volumes = volume_fakes.FakeVolume.create_volumes(count=count) @@ -376,6 +380,45 @@ class TestVolumeCreate(TestVolume): self.assertEqual(self.columns, columns) self.assertEqual(self.datalist, data) + def test_volume_create_with_snapshot(self): + arglist = [ + '--size', str(self.new_volume.size), + '--snapshot', volume_fakes.snapshot_id, + self.new_volume.name, + ] + verifylist = [ + ('size', self.new_volume.size), + ('snapshot', volume_fakes.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 + + # 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) + + self.volumes_mock.create.assert_called_once_with( + size=self.new_volume.size, + snapshot_id=fake_snapshot.id, + name=self.new_volume.name, + description=None, + volume_type=None, + user_id=None, + project_id=None, + availability_zone=None, + metadata=None, + imageRef=None, + source_volid=None + ) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) + class TestVolumeDelete(TestVolume): diff --git a/openstackclient/volume/v2/volume_type.py b/openstackclient/volume/v2/volume_type.py index 203974da..30500518 100644 --- a/openstackclient/volume/v2/volume_type.py +++ b/openstackclient/volume/v2/volume_type.py @@ -261,17 +261,57 @@ class UnsetVolumeType(command.Command): parser.add_argument( '--property', metavar='<key>', - default=[], - required=True, help='Remove a property from this volume type ' '(repeat option to remove multiple properties)', ) + parser.add_argument( + '--project', + metavar='<project>', + help='Removes volume type 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): volume_client = self.app.client_manager.volume + identity_client = self.app.client_manager.identity + volume_type = utils.find_resource( volume_client.volume_types, parsed_args.volume_type, ) - volume_type.unset_keys(parsed_args.property) + + 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: + volume_type.unset_keys(parsed_args.property) + except Exception as e: + self.app.log.error("Failed to unset volume type property: " + + str(e)) + result += 1 + + if parsed_args.project: + project_info = None + try: + project_info = identity_common.find_project( + identity_client, + parsed_args.project, + parsed_args.project_domain) + + volume_client.volume_type_access.remove_project_access( + volume_type.id, project_info.id) + except Exception as e: + self.app.log.error("Failed to remove volume type access from" + " project: " + str(e)) + result += 1 + + if result > 0: + raise exceptions.CommandError("Command Failed: One or more of the" + " operations failed") |
