summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/network/v2/network.py38
-rw-r--r--openstackclient/network/v2/port.py20
-rw-r--r--openstackclient/tests/network/v2/test_network.py9
-rw-r--r--openstackclient/tests/network/v2/test_port.py21
-rw-r--r--openstackclient/tests/volume/v2/test_type.py58
-rw-r--r--openstackclient/tests/volume/v2/test_volume.py43
-rw-r--r--openstackclient/volume/v2/volume_type.py46
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")