diff options
Diffstat (limited to 'openstackclient')
30 files changed, 1438 insertions, 218 deletions
diff --git a/openstackclient/common/quota.py b/openstackclient/common/quota.py index ebbf7ddf..8f099cc9 100644 --- a/openstackclient/common/quota.py +++ b/openstackclient/common/quota.py @@ -154,36 +154,34 @@ class SetQuota(command.Command): if value is not None: compute_kwargs[k] = value - if parsed_args.project: - project = utils.find_resource( - identity_client.projects, - parsed_args.project, - ) - if parsed_args.quota_class: if compute_kwargs: compute_client.quota_classes.update( - project.id, + parsed_args.project, **compute_kwargs) if volume_kwargs: volume_client.quota_classes.update( - project.id, + parsed_args.project, **volume_kwargs) if network_kwargs: sys.stderr.write("Network quotas are ignored since quota class" "is not supported.") else: + project = utils.find_resource( + identity_client.projects, + parsed_args.project, + ).id if compute_kwargs: compute_client.quotas.update( - project.id, + project, **compute_kwargs) if volume_kwargs: volume_client.quotas.update( - project.id, + project, **volume_kwargs) if network_kwargs: network_client.update_quota( - project.id, + project, **network_kwargs) @@ -230,15 +228,15 @@ class ShowQuota(command.ShowOne): return project def get_compute_volume_quota(self, client, parsed_args): - project = self._get_project(parsed_args) - try: if parsed_args.quota_class: - quota = client.quota_classes.get(project) - elif parsed_args.default: - quota = client.quotas.defaults(project) + quota = client.quota_classes.get(parsed_args.project) else: - quota = client.quotas.get(project) + project = self._get_project(parsed_args) + if parsed_args.default: + quota = client.quotas.defaults(project) + else: + quota = client.quotas.get(project) except Exception as e: if type(e).__name__ == 'EndpointNotFound': return {} diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py index 6529f869..dbf1b601 100644 --- a/openstackclient/network/v2/network.py +++ b/openstackclient/network/v2/network.py @@ -78,6 +78,10 @@ def _get_attrs(client_manager, parsed_args): parsed_args.availability_zone_hints is not None: attrs['availability_zone_hints'] = parsed_args.availability_zone_hints + # set description + if parsed_args.description: + attrs['description'] = parsed_args.description + # update_external_network_options if parsed_args.internal: attrs['router:external'] = False @@ -191,6 +195,11 @@ class CreateNetwork(common.NetworkAndComputeShowOne): metavar='<project>', help=_("Owner's project (name or ID)") ) + parser.add_argument( + '--description', + metavar='<description>', + help=_("Set network description") + ) identity_common.add_project_domain_option_to_parser(parser) parser.add_argument( '--availability-zone-hint', @@ -491,6 +500,11 @@ class SetNetwork(command.Command): action='store_true', help=_("Do not share the network between projects") ) + parser.add_argument( + '--description', + metavar="<description", + help=_("Set network description") + ) port_security_group = parser.add_mutually_exclusive_group() port_security_group.add_argument( '--enable-port-security', diff --git a/openstackclient/network/v2/network_segment.py b/openstackclient/network/v2/network_segment.py index bedf15f7..34cac0e0 100644 --- a/openstackclient/network/v2/network_segment.py +++ b/openstackclient/network/v2/network_segment.py @@ -13,14 +13,129 @@ """Network segment action implementations""" -# TODO(rtheis): Add description and name properties when support is available. +import logging from osc_lib.command import command +from osc_lib import exceptions from osc_lib import utils from openstackclient.i18n import _ +LOG = logging.getLogger(__name__) + + +class CreateNetworkSegment(command.ShowOne): + """Create new network segment + + (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(CreateNetworkSegment, self).get_parser(prog_name) + parser.add_argument( + 'name', + metavar='<name>', + help=_('New network segment name') + ) + parser.add_argument( + '--description', + metavar='<description>', + help=_('Network segment description'), + ) + parser.add_argument( + '--physical-network', + metavar='<physical-network>', + help=_('Physical network name of this network segment'), + ) + parser.add_argument( + '--segment', + metavar='<segment>', + type=int, + help=_('Segment identifier for this network segment which is ' + 'based on the network type, VLAN ID for vlan network ' + 'type and tunnel ID for geneve, gre and vxlan network ' + 'types'), + ) + parser.add_argument( + '--network', + metavar='<network>', + required=True, + help=_('Network this network segment belongs to (name or ID)'), + ) + parser.add_argument( + '--network-type', + metavar='<network-type>', + choices=['flat', 'geneve', 'gre', 'local', 'vlan', 'vxlan'], + required=True, + help=_('Network type of this network segment ' + '(flat, geneve, gre, local, vlan or vxlan)'), + ) + return parser + + def take_action(self, parsed_args): + self.validate_os_beta_command_enabled() + client = self.app.client_manager.network + attrs = {} + attrs['name'] = parsed_args.name + attrs['network_id'] = client.find_network(parsed_args.network, + ignore_missing=False).id + attrs['network_type'] = parsed_args.network_type + if parsed_args.description is not None: + attrs['description'] = parsed_args.description + if parsed_args.physical_network is not None: + attrs['physical_network'] = parsed_args.physical_network + if parsed_args.segment is not None: + attrs['segmentation_id'] = parsed_args.segment + obj = client.create_segment(**attrs) + columns = tuple(sorted(obj.keys())) + data = utils.get_item_properties(obj, columns) + return (columns, data) + + +class DeleteNetworkSegment(command.Command): + """Delete network segment(s) + + (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(DeleteNetworkSegment, self).get_parser(prog_name) + parser.add_argument( + 'network_segment', + metavar='<network-segment>', + nargs='+', + help=_('Network segment(s) to delete (name or ID)'), + ) + return parser + + def take_action(self, parsed_args): + self.validate_os_beta_command_enabled() + client = self.app.client_manager.network + + result = 0 + for network_segment in parsed_args.network_segment: + try: + obj = client.find_segment(network_segment, + ignore_missing=False) + client.delete_segment(obj) + except Exception as e: + result += 1 + LOG.error(_("Failed to delete network segment with " + "ID '%(network_segment)s': %(e)s") + % {'network_segment': network_segment, 'e': e}) + + if result > 0: + total = len(parsed_args.network_segment) + msg = (_("%(result)s of %(total)s network segments failed " + "to delete.") % {'result': result, 'total': total}) + raise exceptions.CommandError(msg) + + class ListNetworkSegment(command.Lister): """List network segments @@ -61,12 +176,14 @@ class ListNetworkSegment(command.Lister): headers = ( 'ID', + 'Name', 'Network', 'Network Type', 'Segment', ) columns = ( 'id', + 'name', 'network_id', 'network_type', 'segmentation_id', @@ -86,6 +203,46 @@ class ListNetworkSegment(command.Lister): ) for s in data)) +class SetNetworkSegment(command.Command): + """Set network segment properties + + (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(SetNetworkSegment, self).get_parser(prog_name) + parser.add_argument( + 'network_segment', + metavar='<network-segment>', + help=_('Network segment to modify (name or ID)'), + ) + parser.add_argument( + '--description', + metavar='<description>', + help=_('Set network segment description'), + ) + parser.add_argument( + '--name', + metavar='<name>', + help=_('Set network segment name'), + ) + 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) + attrs = {} + if parsed_args.description is not None: + attrs['description'] = parsed_args.description + if parsed_args.name is not None: + attrs['name'] = parsed_args.name + client.update_segment(obj, **attrs) + + class ShowNetworkSegment(command.ShowOne): """Display network segment details @@ -99,7 +256,7 @@ class ShowNetworkSegment(command.ShowOne): parser.add_argument( 'network_segment', metavar='<network-segment>', - help=_('Network segment to display (ID only)'), + help=_('Network segment to display (name or ID)'), ) return parser diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py index d7268573..0df78e43 100644 --- a/openstackclient/network/v2/port.py +++ b/openstackclient/network/v2/port.py @@ -345,6 +345,10 @@ class ListPort(command.Lister): "This is the entity that uses the port (for example, " "network:dhcp).") ) + parser.add_argument( + '--network', + metavar='<network>', + help=_("List only ports connected to this network (name or ID)")) device_group = parser.add_mutually_exclusive_group() device_group.add_argument( '--router', @@ -387,6 +391,10 @@ class ListPort(command.Lister): server = utils.find_resource(compute_client.servers, parsed_args.server) filters['device_id'] = server.id + if parsed_args.network: + network = network_client.find_network(parsed_args.network, + ignore_missing=False) + filters['network_id'] = network.id data = network_client.ports(**filters) diff --git a/openstackclient/network/v2/router.py b/openstackclient/network/v2/router.py index d30197cc..03134b8c 100644 --- a/openstackclient/network/v2/router.py +++ b/openstackclient/network/v2/router.py @@ -119,7 +119,7 @@ class AddPortToRouter(command.Command): def take_action(self, parsed_args): client = self.app.client_manager.network port = client.find_port(parsed_args.port, ignore_missing=False) - client.router_add_interface(client.find_router( + client.add_interface_to_router(client.find_router( parsed_args.router, ignore_missing=False), port_id=port.id) @@ -144,7 +144,7 @@ class AddSubnetToRouter(command.Command): client = self.app.client_manager.network subnet = client.find_subnet(parsed_args.subnet, ignore_missing=False) - client.router_add_interface( + client.add_interface_to_router( client.find_router(parsed_args.router, ignore_missing=False), subnet_id=subnet.id) @@ -324,7 +324,7 @@ class RemovePortFromRouter(command.Command): def take_action(self, parsed_args): client = self.app.client_manager.network port = client.find_port(parsed_args.port, ignore_missing=False) - client.router_remove_interface(client.find_router( + client.remove_interface_from_router(client.find_router( parsed_args.router, ignore_missing=False), port_id=port.id) @@ -349,7 +349,7 @@ class RemoveSubnetFromRouter(command.Command): client = self.app.client_manager.network subnet = client.find_subnet(parsed_args.subnet, ignore_missing=False) - client.router_remove_interface( + client.remove_interface_from_router( client.find_router(parsed_args.router, ignore_missing=False), subnet_id=subnet.id) diff --git a/openstackclient/network/v2/subnet.py b/openstackclient/network/v2/subnet.py index 8a3f229a..76453487 100644 --- a/openstackclient/network/v2/subnet.py +++ b/openstackclient/network/v2/subnet.py @@ -196,6 +196,8 @@ def _get_attrs(client_manager, parsed_args, is_create=True): if ('service_types' in parsed_args and parsed_args.service_types is not None): attrs['service_types'] = parsed_args.service_types + if parsed_args.description is not None: + attrs['description'] = parsed_args.description return attrs @@ -294,6 +296,11 @@ class CreateSubnet(command.ShowOne): metavar='<network>', help=_("Network this subnet belongs to (name or ID)") ) + parser.add_argument( + '--description', + metavar='<description>', + help=_("Set subnet description") + ) _get_common_parse_arguments(parser) return parser @@ -496,6 +503,11 @@ class SetSubnet(command.Command): "'none': This subnet will not use a gateway, " "e.g.: --gateway 192.168.9.1, --gateway none.") ) + parser.add_argument( + '--description', + metavar='<description>', + help=_("Set subnet description") + ) _get_common_parse_arguments(parser) return parser diff --git a/openstackclient/network/v2/subnet_pool.py b/openstackclient/network/v2/subnet_pool.py index 6852ca27..a01d2f7b 100644 --- a/openstackclient/network/v2/subnet_pool.py +++ b/openstackclient/network/v2/subnet_pool.py @@ -81,6 +81,9 @@ def _get_attrs(client_manager, parsed_args): ).id attrs['tenant_id'] = project_id + if parsed_args.description is not None: + attrs['description'] = parsed_args.description + return attrs @@ -167,6 +170,11 @@ class CreateSubnetPool(command.ShowOne): action='store_true', help=_("Set this subnet pool as not shared"), ) + parser.add_argument( + '--description', + metavar='<description>', + help=_("Set subnet pool description") + ) return parser def take_action(self, parsed_args): @@ -340,6 +348,11 @@ class SetSubnetPool(command.Command): help=_("Remove address scope associated with the subnet pool") ) _add_default_options(parser) + parser.add_argument( + '--description', + metavar='<description>', + help=_("Set subnet pool description") + ) return parser diff --git a/openstackclient/tests/functional/base.py b/openstackclient/tests/functional/base.py index f7f0361e..298b2454 100644 --- a/openstackclient/tests/functional/base.py +++ b/openstackclient/tests/functional/base.py @@ -58,6 +58,11 @@ class TestCase(testtools.TestCase): return cls.openstack('configuration show ' + opts) @classmethod + def get_openstack_extention_names(cls): + opts = cls.get_opts(['Name']) + return cls.openstack('extension list ' + opts) + + @classmethod def get_opts(cls, fields, format='value'): return ' -f {0} {1}'.format(format, ' '.join(['-c ' + it for it in fields])) diff --git a/openstackclient/tests/functional/common/test_quota.py b/openstackclient/tests/functional/common/test_quota.py index 9687cdb0..c1de9aa9 100644 --- a/openstackclient/tests/functional/common/test_quota.py +++ b/openstackclient/tests/functional/common/test_quota.py @@ -26,8 +26,8 @@ class QuotaTests(base.TestCase): cls.get_openstack_configuration_value('auth.project_name') def test_quota_set(self): - self.openstack('quota set --instances 11 --volumes 11 --networks 11 ' - + self.PROJECT_NAME) + self.openstack('quota set --instances 11 --volumes 11 --networks 11 ' + + self.PROJECT_NAME) opts = self.get_opts(self.EXPECTED_FIELDS) raw_output = self.openstack('quota show ' + self.PROJECT_NAME + opts) self.assertEqual("11\n11\n11\n", raw_output) @@ -51,3 +51,12 @@ class QuotaTests(base.TestCase): raw_output = self.openstack('quota show --class') for expected_field in self.EXPECTED_CLASS_FIELDS: self.assertIn(expected_field, raw_output) + + def test_quota_class_set(self): + class_name = 'default' + class_expected_fields = ['instances', 'volumes'] + self.openstack('quota set --instances 11 --volumes 11 --class ' + + class_name) + opts = self.get_opts(class_expected_fields) + raw_output = self.openstack('quota show --class ' + class_name + opts) + self.assertEqual("11\n11\n", raw_output) diff --git a/openstackclient/tests/functional/network/v2/test_network_segment.py b/openstackclient/tests/functional/network/v2/test_network_segment.py index f871e88e..de5aef96 100644 --- a/openstackclient/tests/functional/network/v2/test_network_segment.py +++ b/openstackclient/tests/functional/network/v2/test_network_segment.py @@ -10,20 +10,18 @@ # License for the specific language governing permissions and limitations # under the License. -import testtools import uuid from openstackclient.tests.functional import base -# NOTE(rtheis): Routed networks is still a WIP and not enabled by default. -@testtools.skip("bp/routed-networks") class NetworkSegmentTests(base.TestCase): """Functional tests for network segment. """ NETWORK_NAME = uuid.uuid4().hex PHYSICAL_NETWORK_NAME = uuid.uuid4().hex NETWORK_SEGMENT_ID = None NETWORK_ID = None + NETWORK_SEGMENT_EXTENSION = None @classmethod def setUpClass(cls): @@ -32,29 +30,75 @@ class NetworkSegmentTests(base.TestCase): 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_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] + # NOTE(rtheis): The segment extension is not yet enabled by default. + # Skip the tests if not enabled. + extensions = cls.get_openstack_extention_names() + if 'Segment' in extensions: + cls.NETWORK_SEGMENT_EXTENSION = 'Segment' + + if cls.NETWORK_SEGMENT_EXTENSION: + # Get the segment for the network. + opts = cls.get_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_create_delete(self): + if self.NETWORK_SEGMENT_EXTENSION: + opts = self.get_opts(['id']) + raw_output = self.openstack( + '--os-beta-command' + + ' network segment create --network ' + self.NETWORK_ID + + ' --network-type geneve ' + + ' --segment 2055 test_segment ' + opts + ) + network_segment_id = raw_output.strip('\n') + raw_output = self.openstack('--os-beta-command ' + + 'network segment delete ' + + network_segment_id) + self.assertOutput('', raw_output) + else: + self.skipTest('Segment extension disabled') + def test_network_segment_list(self): - opts = self.get_opts(['ID']) - raw_output = self.openstack('--os-beta-command ' - 'network segment list' + opts) - self.assertIn(self.NETWORK_SEGMENT_ID, raw_output) + if self.NETWORK_SEGMENT_EXTENSION: + opts = self.get_opts(['ID']) + raw_output = self.openstack('--os-beta-command ' + 'network segment list' + opts) + self.assertIn(self.NETWORK_SEGMENT_ID, raw_output) + else: + self.skipTest('Segment extension disabled') + + def test_network_segment_set(self): + if self.NETWORK_SEGMENT_EXTENSION: + new_description = 'new_description' + raw_output = self.openstack('--os-beta-command ' + 'network segment set ' + + '--description ' + new_description + + ' ' + self.NETWORK_SEGMENT_ID) + self.assertOutput('', raw_output) + opts = self.get_opts(['description']) + raw_output = self.openstack('--os-beta-command ' + 'network segment show ' + + self.NETWORK_SEGMENT_ID + opts) + self.assertEqual(new_description + "\n", raw_output) + else: + self.skipTest('Segment extension disabled') def test_network_segment_show(self): - opts = self.get_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) + if self.NETWORK_SEGMENT_EXTENSION: + opts = self.get_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) + else: + self.skipTest('Segment extension disabled') diff --git a/openstackclient/tests/functional/volume/v1/test_transfer_request.py b/openstackclient/tests/functional/volume/v1/test_transfer_request.py index d8406b02..e03cd717 100644 --- a/openstackclient/tests/functional/volume/v1/test_transfer_request.py +++ b/openstackclient/tests/functional/volume/v1/test_transfer_request.py @@ -47,7 +47,45 @@ class TransferRequestTests(common.BaseVolumeTests): cls.assertOutput('', raw_output_transfer) cls.assertOutput('', raw_output_volume) + def test_volume_transfer_request_accept(self): + volume_name = uuid.uuid4().hex + name = uuid.uuid4().hex + + # create a volume + opts = self.get_opts(['display_name']) + raw_output = self.openstack( + 'volume create --size 1 ' + volume_name + opts) + self.assertEqual(volume_name + '\n', raw_output) + + # create volume transfer request for the volume + # and get the auth_key of the new transfer request + opts = self.get_opts(['auth_key']) + auth_key = self.openstack( + 'volume transfer request create ' + + volume_name + + ' --name ' + name + opts) + self.assertNotEqual('', auth_key) + + # accept the volume transfer request + opts = self.get_opts(self.FIELDS) + raw_output = self.openstack( + 'volume transfer request accept ' + name + + ' ' + auth_key + opts) + self.assertEqual(name + '\n', raw_output) + + # the volume transfer will be removed by default after accepted + # so just need to delete the volume here + raw_output = self.openstack( + 'volume delete ' + volume_name) + self.assertEqual('', raw_output) + def test_volume_transfer_request_list(self): opts = self.get_opts(self.HEADERS) raw_output = self.openstack('volume transfer request list' + opts) self.assertIn(self.NAME, raw_output) + + def test_volume_transfer_request_show(self): + opts = self.get_opts(self.FIELDS) + raw_output = self.openstack( + 'volume transfer request show ' + self.NAME + opts) + self.assertEqual(self.NAME + '\n', raw_output) diff --git a/openstackclient/tests/functional/volume/v2/test_transfer_request.py b/openstackclient/tests/functional/volume/v2/test_transfer_request.py index 4f02238b..1791f8ac 100644 --- a/openstackclient/tests/functional/volume/v2/test_transfer_request.py +++ b/openstackclient/tests/functional/volume/v2/test_transfer_request.py @@ -47,7 +47,45 @@ class TransferRequestTests(common.BaseVolumeTests): cls.assertOutput('', raw_output_transfer) cls.assertOutput('', raw_output_volume) + def test_volume_transfer_request_accept(self): + volume_name = uuid.uuid4().hex + name = uuid.uuid4().hex + + # create a volume + opts = self.get_opts(self.FIELDS) + raw_output = self.openstack( + 'volume create --size 1 ' + volume_name + opts) + self.assertEqual(volume_name + '\n', raw_output) + + # create volume transfer request for the volume + # and get the auth_key of the new transfer request + opts = self.get_opts(['auth_key']) + auth_key = self.openstack( + 'volume transfer request create ' + + volume_name + + ' --name ' + name + opts) + self.assertNotEqual('', auth_key) + + # accept the volume transfer request + opts = self.get_opts(self.FIELDS) + raw_output = self.openstack( + 'volume transfer request accept ' + name + + ' ' + auth_key + opts) + self.assertEqual(name + '\n', raw_output) + + # the volume transfer will be removed by default after accepted + # so just need to delete the volume here + raw_output = self.openstack( + 'volume delete ' + volume_name) + self.assertEqual('', raw_output) + def test_volume_transfer_request_list(self): opts = self.get_opts(self.HEADERS) raw_output = self.openstack('volume transfer request list' + opts) self.assertIn(self.NAME, raw_output) + + def test_volume_transfer_request_show(self): + opts = self.get_opts(self.FIELDS) + raw_output = self.openstack( + 'volume transfer request show ' + self.NAME + opts) + self.assertEqual(self.NAME + '\n', raw_output) diff --git a/openstackclient/tests/unit/common/test_quota.py b/openstackclient/tests/unit/common/test_quota.py index 294d772d..7dd23373 100644 --- a/openstackclient/tests/unit/common/test_quota.py +++ b/openstackclient/tests/unit/common/test_quota.py @@ -82,6 +82,18 @@ class TestQuotaSet(TestQuota): loaded=True, ) + self.quotas_class_mock.update.return_value = FakeQuotaResource( + None, + copy.deepcopy(compute_fakes.QUOTA), + loaded=True, + ) + + self.volume_quotas_class_mock.update.return_value = FakeQuotaResource( + None, + copy.deepcopy(compute_fakes.QUOTA), + loaded=True, + ) + self.network_mock = self.app.client_manager.network self.network_mock.update_quota = mock.Mock() @@ -294,27 +306,72 @@ class TestQuotaSet(TestQuota): def test_quota_set_with_class(self): arglist = [ + '--injected-files', str(compute_fakes.injected_file_num), + '--injected-file-size', str(compute_fakes.injected_file_size_num), + '--injected-path-size', str(compute_fakes.injected_path_size_num), + '--key-pairs', str(compute_fakes.key_pair_num), + '--cores', str(compute_fakes.core_num), + '--ram', str(compute_fakes.ram_num), '--instances', str(compute_fakes.instance_num), + '--properties', str(compute_fakes.property_num), + '--server-groups', str(compute_fakes.servgroup_num), + '--server-group-members', str(compute_fakes.servgroup_members_num), + '--gigabytes', str(compute_fakes.floating_ip_num), + '--snapshots', str(compute_fakes.fix_ip_num), '--volumes', str(volume_fakes.QUOTA['volumes']), '--network', str(network_fakes.QUOTA['network']), - '--class', - identity_fakes.project_name, + '--class', identity_fakes.project_name, ] verifylist = [ + ('injected_files', compute_fakes.injected_file_num), + ('injected_file_content_bytes', + compute_fakes.injected_file_size_num), + ('injected_file_path_bytes', compute_fakes.injected_path_size_num), + ('key_pairs', compute_fakes.key_pair_num), + ('cores', compute_fakes.core_num), + ('ram', compute_fakes.ram_num), ('instances', compute_fakes.instance_num), + ('metadata_items', compute_fakes.property_num), + ('server_groups', compute_fakes.servgroup_num), + ('server_group_members', compute_fakes.servgroup_members_num), + ('gigabytes', compute_fakes.floating_ip_num), + ('snapshots', compute_fakes.fix_ip_num), ('volumes', volume_fakes.QUOTA['volumes']), ('network', network_fakes.QUOTA['network']), + ('project', identity_fakes.project_name), ('quota_class', True), ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) - self.quotas_class_mock.update.assert_called_once_with( - identity_fakes.project_id, - **{'instances': compute_fakes.instance_num} + + kwargs_compute = { + 'injected_files': compute_fakes.injected_file_num, + 'injected_file_content_bytes': + compute_fakes.injected_file_size_num, + 'injected_file_path_bytes': compute_fakes.injected_path_size_num, + 'key_pairs': compute_fakes.key_pair_num, + 'cores': compute_fakes.core_num, + 'ram': compute_fakes.ram_num, + 'instances': compute_fakes.instance_num, + 'metadata_items': compute_fakes.property_num, + 'server_groups': compute_fakes.servgroup_num, + 'server_group_members': compute_fakes.servgroup_members_num, + } + kwargs_volume = { + 'gigabytes': compute_fakes.floating_ip_num, + 'snapshots': compute_fakes.fix_ip_num, + 'volumes': volume_fakes.QUOTA['volumes'], + } + + self.quotas_class_mock.update.assert_called_with( + identity_fakes.project_name, + **kwargs_compute ) - self.volume_quotas_class_mock.update.assert_called_once_with( - identity_fakes.project_id, - **{'volumes': volume_fakes.QUOTA['volumes']} + self.volume_quotas_class_mock.update.assert_called_with( + identity_fakes.project_name, + **kwargs_volume ) self.assertNotCalled(self.network_mock.update_quota) self.assertIsNone(result) @@ -444,9 +501,9 @@ class TestQuotaShow(TestQuota): self.cmd.take_action(parsed_args) self.quotas_class_mock.get.assert_called_once_with( - identity_fakes.project_id) + identity_fakes.project_name) self.volume_quotas_class_mock.get.assert_called_once_with( - identity_fakes.project_id) + identity_fakes.project_name) self.assertNotCalled(self.network.get_quota) self.assertNotCalled(self.network.get_quota_default) diff --git a/openstackclient/tests/unit/network/v2/fakes.py b/openstackclient/tests/unit/network/v2/fakes.py index 4cc3512e..91aebf9f 100644 --- a/openstackclient/tests/unit/network/v2/fakes.py +++ b/openstackclient/tests/unit/network/v2/fakes.py @@ -285,6 +285,7 @@ class FakeNetwork(object): 'id': 'network-id-' + uuid.uuid4().hex, 'name': 'network-name-' + uuid.uuid4().hex, 'status': 'ACTIVE', + 'description': 'network-description-' + uuid.uuid4().hex, 'tenant_id': 'project-id-' + uuid.uuid4().hex, 'admin_state_up': True, 'shared': False, @@ -363,11 +364,14 @@ class FakeNetworkSegment(object): attrs = attrs or {} # Set default attributes. + fake_uuid = uuid.uuid4().hex network_segment_attrs = { - 'id': 'network-segment-id-' + uuid.uuid4().hex, - 'network_id': 'network-id-' + uuid.uuid4().hex, + 'description': 'network-segment-description-' + fake_uuid, + 'id': 'network-segment-id-' + fake_uuid, + 'name': 'network-segment-name-' + fake_uuid, + 'network_id': 'network-id-' + fake_uuid, 'network_type': 'vlan', - 'physical_network': 'physical-network-name-' + uuid.uuid4().hex, + 'physical_network': 'physical-network-name-' + fake_uuid, 'segmentation_id': 1024, } @@ -892,6 +896,7 @@ class FakeSubnet(object): 'segment_id': None, 'service_types': [], 'subnetpool_id': None, + 'description': 'subnet-description-' + uuid.uuid4().hex, } # Overwrite default attributes. @@ -1047,6 +1052,7 @@ class FakeSubnetPool(object): 'min_prefixlen': '8', 'default_quota': None, 'ip_version': '4', + 'description': 'subnet-pool-description-' + uuid.uuid4().hex, } # Overwrite default attributes. diff --git a/openstackclient/tests/unit/network/v2/test_network.py b/openstackclient/tests/unit/network/v2/test_network.py index 9a375645..50a60c2d 100644 --- a/openstackclient/tests/unit/network/v2/test_network.py +++ b/openstackclient/tests/unit/network/v2/test_network.py @@ -58,6 +58,7 @@ class TestCreateNetworkIdentityV3(TestNetwork): 'admin_state_up', 'availability_zone_hints', 'availability_zones', + 'description', 'id', 'is_default', 'name', @@ -74,6 +75,7 @@ class TestCreateNetworkIdentityV3(TestNetwork): network._format_admin_state(_network.admin_state_up), utils.format_list(_network.availability_zone_hints), utils.format_list(_network.availability_zones), + _network.description, _network.id, _network.is_default, _network.name, @@ -130,6 +132,7 @@ class TestCreateNetworkIdentityV3(TestNetwork): arglist = [ "--disable", "--share", + "--description", self._network.description, "--project", self.project.name, "--project-domain", self.domain.name, "--availability-zone-hint", "nova", @@ -144,6 +147,7 @@ class TestCreateNetworkIdentityV3(TestNetwork): verifylist = [ ('disable', True), ('share', True), + ('description', self._network.description), ('project', self.project.name), ('project_domain', self.domain.name), ('availability_zone_hints', ["nova"]), @@ -165,6 +169,7 @@ class TestCreateNetworkIdentityV3(TestNetwork): 'availability_zone_hints': ["nova"], 'name': self._network.name, 'shared': True, + 'description': self._network.description, 'tenant_id': self.project.id, 'is_default': True, 'router:external': True, @@ -217,6 +222,7 @@ class TestCreateNetworkIdentityV2(TestNetwork): 'admin_state_up', 'availability_zone_hints', 'availability_zones', + 'description', 'id', 'is_default', 'name', @@ -233,6 +239,7 @@ class TestCreateNetworkIdentityV2(TestNetwork): network._format_admin_state(_network.admin_state_up), utils.format_list(_network.availability_zone_hints), utils.format_list(_network.availability_zones), + _network.description, _network.id, _network.is_default, _network.name, @@ -694,6 +701,7 @@ class TestSetNetwork(TestNetwork): '--enable', '--name', 'noob', '--share', + '--description', self._network.description, '--external', '--default', '--provider-network-type', 'vlan', @@ -705,6 +713,7 @@ class TestSetNetwork(TestNetwork): verifylist = [ ('network', self._network.name), ('enable', True), + ('description', self._network.description), ('name', 'noob'), ('share', True), ('external', True), @@ -722,6 +731,7 @@ class TestSetNetwork(TestNetwork): attrs = { 'name': 'noob', 'admin_state_up': True, + 'description': self._network.description, 'shared': True, 'router:external': True, 'is_default': True, @@ -786,6 +796,7 @@ class TestShowNetwork(TestNetwork): 'admin_state_up', 'availability_zone_hints', 'availability_zones', + 'description', 'id', 'is_default', 'name', @@ -802,6 +813,7 @@ class TestShowNetwork(TestNetwork): network._format_admin_state(_network.admin_state_up), utils.format_list(_network.availability_zone_hints), utils.format_list(_network.availability_zones), + _network.description, _network.id, _network.is_default, _network.name, diff --git a/openstackclient/tests/unit/network/v2/test_network_segment.py b/openstackclient/tests/unit/network/v2/test_network_segment.py index b9fce078..3e755e07 100644 --- a/openstackclient/tests/unit/network/v2/test_network_segment.py +++ b/openstackclient/tests/unit/network/v2/test_network_segment.py @@ -12,6 +12,7 @@ # import mock +from mock import call from osc_lib import exceptions @@ -32,6 +33,243 @@ class TestNetworkSegment(network_fakes.TestNetworkV2): self.network = self.app.client_manager.network +class TestCreateNetworkSegment(TestNetworkSegment): + + # The network segment to create along with associated network. + _network_segment = \ + network_fakes.FakeNetworkSegment.create_one_network_segment() + _network = network_fakes.FakeNetwork.create_one_network({ + 'id': _network_segment.network_id, + }) + + columns = ( + 'description', + 'id', + 'name', + 'network_id', + 'network_type', + 'physical_network', + 'segmentation_id', + ) + + data = ( + _network_segment.description, + _network_segment.id, + _network_segment.name, + _network_segment.network_id, + _network_segment.network_type, + _network_segment.physical_network, + _network_segment.segmentation_id, + ) + + def setUp(self): + super(TestCreateNetworkSegment, self).setUp() + + self.network.create_segment = mock.Mock( + return_value=self._network_segment + ) + self.network.find_network = mock.Mock(return_value=self._network) + + # Get the command object to test + self.cmd = network_segment.CreateNetworkSegment( + self.app, + self.namespace + ) + + def test_create_no_options(self): + # Missing required args should bail here + self.assertRaises(tests_utils.ParserException, self.check_parser, + self.cmd, [], []) + + def test_create_no_beta_commands(self): + arglist = [ + '--network', self._network_segment.network_id, + '--network-type', self._network_segment.network_type, + self._network_segment.name, + ] + verifylist = [ + ('network', self._network_segment.network_id), + ('network_type', self._network_segment.network_type), + ('name', self._network_segment.name), + ] + 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_create_invalid_network_type(self): + arglist = [ + '--network', self._network_segment.network_id, + '--network-type', 'foo', + self._network_segment.name, + ] + self.assertRaises(tests_utils.ParserException, self.check_parser, + self.cmd, arglist, []) + + def test_create_minimum_options(self): + arglist = [ + '--network', self._network_segment.network_id, + '--network-type', self._network_segment.network_type, + self._network_segment.name, + ] + verifylist = [ + ('network', self._network_segment.network_id), + ('network_type', self._network_segment.network_type), + ('name', self._network_segment.name), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + + self.network.find_network.assert_called_once_with( + self._network_segment.network_id, + ignore_missing=False + ) + self.network.create_segment.assert_called_once_with(**{ + 'network_id': self._network_segment.network_id, + 'network_type': self._network_segment.network_type, + 'name': self._network_segment.name, + }) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + def test_create_all_options(self): + arglist = [ + '--description', self._network_segment.description, + '--network', self._network_segment.network_id, + '--network-type', self._network_segment.network_type, + '--physical-network', self._network_segment.physical_network, + '--segment', str(self._network_segment.segmentation_id), + self._network_segment.name, + ] + verifylist = [ + ('description', self._network_segment.description), + ('network', self._network_segment.network_id), + ('network_type', self._network_segment.network_type), + ('physical_network', self._network_segment.physical_network), + ('segment', self._network_segment.segmentation_id), + ('name', self._network_segment.name), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + + self.network.find_network.assert_called_once_with( + self._network_segment.network_id, + ignore_missing=False + ) + self.network.create_segment.assert_called_once_with(**{ + 'description': self._network_segment.description, + 'network_id': self._network_segment.network_id, + 'network_type': self._network_segment.network_type, + 'physical_network': self._network_segment.physical_network, + 'segmentation_id': self._network_segment.segmentation_id, + 'name': self._network_segment.name, + }) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + +class TestDeleteNetworkSegment(TestNetworkSegment): + + # The network segments to delete. + _network_segments = \ + network_fakes.FakeNetworkSegment.create_network_segments() + + def setUp(self): + super(TestDeleteNetworkSegment, self).setUp() + + self.network.delete_segment = mock.Mock(return_value=None) + self.network.find_segment = mock.MagicMock( + side_effect=self._network_segments + ) + + # Get the command object to test + self.cmd = network_segment.DeleteNetworkSegment( + self.app, + self.namespace + ) + + def test_delete_no_beta_commands(self): + arglist = [ + self._network_segments[0].id, + ] + verifylist = [ + ('network_segment', [self._network_segments[0].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_delete(self): + arglist = [ + self._network_segments[0].id, + ] + verifylist = [ + ('network_segment', [self._network_segments[0].id]), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + self.network.delete_segment.assert_called_once_with( + self._network_segments[0] + ) + self.assertIsNone(result) + + def test_delete_multiple(self): + arglist = [] + for _network_segment in self._network_segments: + arglist.append(_network_segment.id) + verifylist = [ + ('network_segment', arglist), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + calls = [] + for _network_segment in self._network_segments: + calls.append(call(_network_segment)) + self.network.delete_segment.assert_has_calls(calls) + self.assertIsNone(result) + + def test_delete_multiple_with_exception(self): + arglist = [ + self._network_segments[0].id, + 'doesnotexist' + ] + verifylist = [ + ('network_segment', [self._network_segments[0].id, + 'doesnotexist']), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + find_mock_result = [self._network_segments[0], + exceptions.CommandError] + self.network.find_segment = ( + 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 network segments failed to delete.', + str(e)) + + self.network.find_segment.assert_any_call( + self._network_segments[0].id, ignore_missing=False) + self.network.find_segment.assert_any_call( + 'doesnotexist', ignore_missing=False) + self.network.delete_segment.assert_called_once_with( + self._network_segments[0] + ) + + class TestListNetworkSegment(TestNetworkSegment): _network = network_fakes.FakeNetwork.create_one_network() _network_segments = \ @@ -39,6 +277,7 @@ class TestListNetworkSegment(TestNetworkSegment): columns = ( 'ID', + 'Name', 'Network', 'Network Type', 'Segment', @@ -51,6 +290,7 @@ class TestListNetworkSegment(TestNetworkSegment): for _network_segment in _network_segments: data.append(( _network_segment.id, + _network_segment.name, _network_segment.network_id, _network_segment.network_type, _network_segment.segmentation_id, @@ -60,6 +300,7 @@ class TestListNetworkSegment(TestNetworkSegment): for _network_segment in _network_segments: data_long.append(( _network_segment.id, + _network_segment.name, _network_segment.network_id, _network_segment.network_type, _network_segment.segmentation_id, @@ -131,6 +372,78 @@ class TestListNetworkSegment(TestNetworkSegment): self.assertEqual(self.data, list(data)) +class TestSetNetworkSegment(TestNetworkSegment): + + # The network segment to show. + _network_segment = \ + network_fakes.FakeNetworkSegment.create_one_network_segment() + + def setUp(self): + super(TestSetNetworkSegment, self).setUp() + + self.network.find_segment = mock.Mock( + return_value=self._network_segment + ) + self.network.update_segment = mock.Mock( + return_value=self._network_segment + ) + + # Get the command object to test + self.cmd = network_segment.SetNetworkSegment(self.app, self.namespace) + + def test_set_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_set_no_options(self): + arglist = [ + self._network_segment.id, + ] + verifylist = [ + ('network_segment', self._network_segment.id), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + + self.network.update_segment.assert_called_once_with( + self._network_segment, **{} + ) + self.assertIsNone(result) + + def test_set_all_options(self): + arglist = [ + '--description', 'new description', + '--name', 'new name', + self._network_segment.id, + ] + verifylist = [ + ('description', 'new description'), + ('name', 'new name'), + ('network_segment', self._network_segment.id), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + + attrs = { + 'description': 'new description', + 'name': 'new name', + } + self.network.update_segment.assert_called_once_with( + self._network_segment, **attrs + ) + self.assertIsNone(result) + + class TestShowNetworkSegment(TestNetworkSegment): # The network segment to show. @@ -138,7 +451,9 @@ class TestShowNetworkSegment(TestNetworkSegment): network_fakes.FakeNetworkSegment.create_one_network_segment() columns = ( + 'description', 'id', + 'name', 'network_id', 'network_type', 'physical_network', @@ -146,7 +461,9 @@ class TestShowNetworkSegment(TestNetworkSegment): ) data = ( + _network_segment.description, _network_segment.id, + _network_segment.name, _network_segment.network_id, _network_segment.network_type, _network_segment.physical_network, diff --git a/openstackclient/tests/unit/network/v2/test_port.py b/openstackclient/tests/unit/network/v2/test_port.py index afa67bba..271e8160 100644 --- a/openstackclient/tests/unit/network/v2/test_port.py +++ b/openstackclient/tests/unit/network/v2/test_port.py @@ -337,7 +337,11 @@ class TestListPort(TestPort): fake_router = network_fakes.FakeRouter.create_one_router({ 'id': 'fake-router-id', }) + fake_network = network_fakes.FakeNetwork.create_one_network({ + 'id': 'fake-network-id', + }) self.network.find_router = mock.Mock(return_value=fake_router) + self.network.find_network = mock.Mock(return_value=fake_network) self.app.client_manager.compute = mock.Mock() def test_port_list_no_options(self): @@ -414,11 +418,13 @@ class TestListPort(TestPort): arglist = [ '--device-owner', self._ports[0].device_owner, '--router', 'fake-router-name', + '--network', 'fake-network-name', ] verifylist = [ ('device_owner', self._ports[0].device_owner), - ('router', 'fake-router-name') + ('router', 'fake-router-name'), + ('network', 'fake-network-name') ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -427,7 +433,8 @@ class TestListPort(TestPort): self.network.ports.assert_called_once_with(**{ 'device_owner': self._ports[0].device_owner, - 'device_id': 'fake-router-id' + 'device_id': 'fake-router-id', + 'network_id': 'fake-network-id' }) self.assertEqual(self.columns, columns) self.assertEqual(self.data, list(data)) diff --git a/openstackclient/tests/unit/network/v2/test_router.py b/openstackclient/tests/unit/network/v2/test_router.py index 6898a046..5ed969b4 100644 --- a/openstackclient/tests/unit/network/v2/test_router.py +++ b/openstackclient/tests/unit/network/v2/test_router.py @@ -40,7 +40,7 @@ class TestAddPortToRouter(TestRouter): def setUp(self): super(TestAddPortToRouter, self).setUp() - self.network.router_add_interface = mock.Mock() + self.network.add_interface_to_router = mock.Mock() self.cmd = router.AddPortToRouter(self.app, self.namespace) self.network.find_router = mock.Mock(return_value=self._router) self.network.find_port = mock.Mock(return_value=self._port) @@ -65,9 +65,8 @@ class TestAddPortToRouter(TestRouter): result = self.cmd.take_action(parsed_args) - self.network.router_add_interface.assert_called_with(self._router, **{ - 'port_id': self._router.port, - }) + self.network.add_interface_to_router.assert_called_with( + self._router, **{'port_id': self._router.port, }) self.assertIsNone(result) @@ -80,7 +79,7 @@ class TestAddSubnetToRouter(TestRouter): def setUp(self): super(TestAddSubnetToRouter, self).setUp() - self.network.router_add_interface = mock.Mock() + self.network.add_interface_to_router = mock.Mock() self.cmd = router.AddSubnetToRouter(self.app, self.namespace) self.network.find_router = mock.Mock(return_value=self._router) self.network.find_subnet = mock.Mock(return_value=self._subnet) @@ -104,7 +103,7 @@ class TestAddSubnetToRouter(TestRouter): parsed_args = self.check_parser(self.cmd, arglist, verifylist) result = self.cmd.take_action(parsed_args) - self.network.router_add_interface.assert_called_with( + self.network.add_interface_to_router.assert_called_with( self._router, **{'subnet_id': self._router.subnet}) self.assertIsNone(result) @@ -411,7 +410,7 @@ class TestRemovePortFromRouter(TestRouter): def setUp(self): super(TestRemovePortFromRouter, self).setUp() - self.network.router_remove_interface = mock.Mock() + self.network.remove_interface_from_router = mock.Mock() self.cmd = router.RemovePortFromRouter(self.app, self.namespace) self.network.find_router = mock.Mock(return_value=self._router) self.network.find_port = mock.Mock(return_value=self._port) @@ -436,7 +435,7 @@ class TestRemovePortFromRouter(TestRouter): result = self.cmd.take_action(parsed_args) - self.network.router_remove_interface.assert_called_with( + self.network.remove_interface_from_router.assert_called_with( self._router, **{'port_id': self._router.port}) self.assertIsNone(result) @@ -450,7 +449,7 @@ class TestRemoveSubnetFromRouter(TestRouter): def setUp(self): super(TestRemoveSubnetFromRouter, self).setUp() - self.network.router_remove_interface = mock.Mock() + self.network.remove_interface_from_router = mock.Mock() self.cmd = router.RemoveSubnetFromRouter(self.app, self.namespace) self.network.find_router = mock.Mock(return_value=self._router) self.network.find_subnet = mock.Mock(return_value=self._subnet) @@ -474,7 +473,7 @@ class TestRemoveSubnetFromRouter(TestRouter): parsed_args = self.check_parser(self.cmd, arglist, verifylist) result = self.cmd.take_action(parsed_args) - self.network.router_remove_interface.assert_called_with( + self.network.remove_interface_from_router.assert_called_with( self._router, **{'subnet_id': self._router.subnet}) self.assertIsNone(result) diff --git a/openstackclient/tests/unit/network/v2/test_subnet.py b/openstackclient/tests/unit/network/v2/test_subnet.py index f09fe4fa..58506391 100644 --- a/openstackclient/tests/unit/network/v2/test_subnet.py +++ b/openstackclient/tests/unit/network/v2/test_subnet.py @@ -110,6 +110,7 @@ class TestCreateSubnet(TestSubnet): columns = ( 'allocation_pools', 'cidr', + 'description', 'dns_nameservers', 'enable_dhcp', 'gateway_ip', @@ -129,6 +130,7 @@ class TestCreateSubnet(TestSubnet): data = ( subnet_v2._format_allocation_pools(_subnet.allocation_pools), _subnet.cidr, + _subnet.description, utils.format_list(_subnet.dns_nameservers), _subnet.enable_dhcp, _subnet.gateway_ip, @@ -148,6 +150,7 @@ class TestCreateSubnet(TestSubnet): data_subnet_pool = ( subnet_v2._format_allocation_pools(_subnet_from_pool.allocation_pools), _subnet_from_pool.cidr, + _subnet_from_pool.description, utils.format_list(_subnet_from_pool.dns_nameservers), _subnet_from_pool.enable_dhcp, _subnet_from_pool.gateway_ip, @@ -167,6 +170,7 @@ class TestCreateSubnet(TestSubnet): data_ipv6 = ( subnet_v2._format_allocation_pools(_subnet_ipv6.allocation_pools), _subnet_ipv6.cidr, + _subnet_ipv6.description, utils.format_list(_subnet_ipv6.dns_nameservers), _subnet_ipv6.enable_dhcp, _subnet_ipv6.gateway_ip, @@ -427,6 +431,40 @@ class TestCreateSubnet(TestSubnet): self.assertEqual(self.columns, columns) self.assertEqual(self.data, data) + def test_create_with_description(self): + # Mock SDK calls for this test. + self.network.create_subnet = mock.Mock(return_value=self._subnet) + self._network.id = self._subnet.network_id + + arglist = [ + "--subnet-range", self._subnet.cidr, + "--network", self._subnet.network_id, + "--description", self._subnet.description, + self._subnet.name, + ] + verifylist = [ + ('name', self._subnet.name), + ('description', self._subnet.description), + ('subnet_range', self._subnet.cidr), + ('network', self._subnet.network_id), + ('ip_version', self._subnet.ip_version), + ('gateway', 'auto'), + + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + columns, data = self.cmd.take_action(parsed_args) + + self.network.create_subnet.assert_called_once_with(**{ + 'cidr': self._subnet.cidr, + 'ip_version': self._subnet.ip_version, + 'name': self._subnet.name, + 'network_id': self._subnet.network_id, + 'description': self._subnet.description, + }) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + class TestDeleteSubnet(TestSubnet): @@ -876,6 +914,30 @@ class TestSetSubnet(TestSubnet): _testsubnet, **attrs) self.assertIsNone(result) + def test_set_non_append_options(self): + arglist = [ + "--description", "new_description", + "--dhcp", + "--gateway", self._subnet.gateway_ip, + self._subnet.name, + ] + verifylist = [ + ('description', "new_description"), + ('dhcp', True), + ('gateway', self._subnet.gateway_ip), + ('subnet', self._subnet.name), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + attrs = { + 'enable_dhcp': True, + 'gateway_ip': self._subnet.gateway_ip, + 'description': "new_description", + } + self.network.update_subnet.assert_called_with(self._subnet, **attrs) + self.assertIsNone(result) + class TestShowSubnet(TestSubnet): # The subnets to be shown @@ -884,6 +946,7 @@ class TestShowSubnet(TestSubnet): columns = ( 'allocation_pools', 'cidr', + 'description', 'dns_nameservers', 'enable_dhcp', 'gateway_ip', @@ -903,6 +966,7 @@ class TestShowSubnet(TestSubnet): data = ( subnet_v2._format_allocation_pools(_subnet.allocation_pools), _subnet.cidr, + _subnet.description, utils.format_list(_subnet.dns_nameservers), _subnet.enable_dhcp, _subnet.gateway_ip, diff --git a/openstackclient/tests/unit/network/v2/test_subnet_pool.py b/openstackclient/tests/unit/network/v2/test_subnet_pool.py index 251323d9..fa6ffff3 100644 --- a/openstackclient/tests/unit/network/v2/test_subnet_pool.py +++ b/openstackclient/tests/unit/network/v2/test_subnet_pool.py @@ -50,6 +50,7 @@ class TestCreateSubnetPool(TestSubnetPool): 'address_scope_id', 'default_prefixlen', 'default_quota', + 'description', 'id', 'ip_version', 'is_default', @@ -64,6 +65,7 @@ class TestCreateSubnetPool(TestSubnetPool): _subnet_pool.address_scope_id, _subnet_pool.default_prefixlen, _subnet_pool.default_quota, + _subnet_pool.description, _subnet_pool.id, _subnet_pool.ip_version, _subnet_pool.is_default, @@ -245,6 +247,29 @@ class TestCreateSubnetPool(TestSubnetPool): self.assertEqual(self.columns, columns) self.assertEqual(self.data, data) + def test_create_with_description(self): + arglist = [ + '--pool-prefix', '10.0.10.0/24', + '--description', self._subnet_pool.description, + self._subnet_pool.name, + ] + verifylist = [ + ('prefixes', ['10.0.10.0/24']), + ('description', self._subnet_pool.description), + ('name', self._subnet_pool.name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = (self.cmd.take_action(parsed_args)) + + self.network.create_subnet_pool.assert_called_once_with(**{ + 'name': self._subnet_pool.name, + 'prefixes': ['10.0.10.0/24'], + 'description': self._subnet_pool.description, + }) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + class TestDeleteSubnetPool(TestSubnetPool): @@ -749,6 +774,26 @@ class TestSetSubnetPool(TestSubnetPool): self.assertRaises(tests_utils.ParserException, self.check_parser, self.cmd, arglist, verifylist) + def test_set_description(self): + arglist = [ + '--description', 'new_description', + self._subnet_pool.name, + ] + verifylist = [ + ('description', "new_description"), + ('subnet_pool', self._subnet_pool.name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + attrs = { + 'description': "new_description", + } + self.network.update_subnet_pool.assert_called_once_with( + self._subnet_pool, **attrs) + self.assertIsNone(result) + class TestShowSubnetPool(TestSubnetPool): @@ -759,6 +804,7 @@ class TestShowSubnetPool(TestSubnetPool): 'address_scope_id', 'default_prefixlen', 'default_quota', + 'description', 'id', 'ip_version', 'is_default', @@ -774,6 +820,7 @@ class TestShowSubnetPool(TestSubnetPool): _subnet_pool.address_scope_id, _subnet_pool.default_prefixlen, _subnet_pool.default_quota, + _subnet_pool.description, _subnet_pool.id, _subnet_pool.ip_version, _subnet_pool.is_default, diff --git a/openstackclient/tests/unit/test_shell.py b/openstackclient/tests/unit/test_shell.py index 87cd7f51..3d91da9b 100644 --- a/openstackclient/tests/unit/test_shell.py +++ b/openstackclient/tests/unit/test_shell.py @@ -413,9 +413,6 @@ class TestShellCli(TestShell): class TestShellArgV(TestShell): """Test the deferred help flag""" - def setUp(self): - super(TestShellArgV, self).setUp() - def test_shell_argv(self): """Test argv decoding diff --git a/openstackclient/tests/unit/volume/v1/fakes.py b/openstackclient/tests/unit/volume/v1/fakes.py index 2a4f62c5..ef52e4b0 100644 --- a/openstackclient/tests/unit/volume/v1/fakes.py +++ b/openstackclient/tests/unit/volume/v1/fakes.py @@ -146,8 +146,6 @@ class FakeTransfer(object): """ # Set default attribute transfer_info = { - 'auth_key': 'key-' + uuid.uuid4().hex, - 'created_at': 'time-' + uuid.uuid4().hex, 'volume_id': 'volume-id-' + uuid.uuid4().hex, 'name': 'fake_transfer_name', 'id': 'id-' + uuid.uuid4().hex, @@ -363,24 +361,24 @@ class FakeVolume(object): # Set default attribute volume_info = { 'id': 'volume-id' + uuid.uuid4().hex, - 'name': 'volume-name' + uuid.uuid4().hex, - 'description': 'description' + uuid.uuid4().hex, - 'status': random.choice(['available', 'in_use']), - 'size': random.randint(1, 20), + 'display_name': 'volume-name' + uuid.uuid4().hex, + 'display_description': 'description' + uuid.uuid4().hex, + 'status': 'available', + 'size': 10, 'volume_type': random.choice(['fake_lvmdriver-1', 'fake_lvmdriver-2']), - 'bootable': - random.randint(0, 1), + 'bootable': 'true', 'metadata': { 'key' + uuid.uuid4().hex: 'val' + uuid.uuid4().hex, 'key' + uuid.uuid4().hex: 'val' + uuid.uuid4().hex, 'key' + uuid.uuid4().hex: 'val' + uuid.uuid4().hex}, - 'snapshot_id': random.randint(1, 5), + 'snapshot_id': 'snapshot-id-' + uuid.uuid4().hex, 'availability_zone': 'zone' + uuid.uuid4().hex, 'attachments': [{ 'device': '/dev/' + uuid.uuid4().hex, 'server_id': uuid.uuid4().hex, }, ], + 'created_at': 'time-' + uuid.uuid4().hex, } # Overwrite default attributes if there are some attributes set diff --git a/openstackclient/tests/unit/volume/v1/test_transfer_request.py b/openstackclient/tests/unit/volume/v1/test_transfer_request.py index e89c5056..b3788d6e 100644 --- a/openstackclient/tests/unit/volume/v1/test_transfer_request.py +++ b/openstackclient/tests/unit/volume/v1/test_transfer_request.py @@ -36,6 +36,53 @@ class TestTransfer(transfer_fakes.TestVolumev1): self.volumes_mock.reset_mock() +class TestTransferAccept(TestTransfer): + + columns = ( + 'id', + 'name', + 'volume_id', + ) + + def setUp(self): + super(TestTransferAccept, self).setUp() + + self.volume_transfer = ( + transfer_fakes.FakeTransfer.create_one_transfer()) + self.data = ( + self.volume_transfer.id, + self.volume_transfer.name, + self.volume_transfer.volume_id, + ) + + self.transfer_mock.get.return_value = self.volume_transfer + self.transfer_mock.accept.return_value = self.volume_transfer + + # Get the command object to test + self.cmd = volume_transfer_request.AcceptTransferRequest( + self.app, None) + + def test_transfer_accept(self): + arglist = [ + self.volume_transfer.id, + 'auth_key', + ] + verifylist = [ + ('transfer_request', self.volume_transfer.id), + ('auth_key', 'auth_key'), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.transfer_mock.get.assert_called_once_with( + self.volume_transfer.id) + self.transfer_mock.accept.assert_called_once_with( + self.volume_transfer.id, 'auth_key') + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + class TestTransferCreate(TestTransfer): volume = transfer_fakes.FakeVolume.create_one_volume() @@ -52,7 +99,10 @@ class TestTransferCreate(TestTransfer): super(TestTransferCreate, self).setUp() self.volume_transfer = transfer_fakes.FakeTransfer.create_one_transfer( - attrs={'volume_id': self.volume.id}) + attrs={'volume_id': self.volume.id, + 'auth_key': 'key', + 'created_at': 'time'} + ) self.data = ( self.volume_transfer.auth_key, self.volume_transfer.created_at, @@ -266,3 +316,49 @@ class TestTransferList(TestTransfer): detailed=True, search_opts={'all_tenants': 1} ) + + +class TestTransferShow(TestTransfer): + + columns = ( + 'created_at', + 'id', + 'name', + 'volume_id', + ) + + def setUp(self): + super(TestTransferShow, self).setUp() + + self.volume_transfer = ( + transfer_fakes.FakeTransfer.create_one_transfer( + attrs={'created_at': 'time'}) + ) + self.data = ( + self.volume_transfer.created_at, + self.volume_transfer.id, + self.volume_transfer.name, + self.volume_transfer.volume_id, + ) + + self.transfer_mock.get.return_value = self.volume_transfer + + # Get the command object to test + self.cmd = volume_transfer_request.ShowTransferRequest( + self.app, None) + + def test_transfer_show(self): + arglist = [ + self.volume_transfer.id, + ] + verifylist = [ + ('transfer_request', self.volume_transfer.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.transfer_mock.get.assert_called_once_with( + self.volume_transfer.id) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) diff --git a/openstackclient/tests/unit/volume/v1/test_volume.py b/openstackclient/tests/unit/volume/v1/test_volume.py index e95f42d0..895f1f87 100644 --- a/openstackclient/tests/unit/volume/v1/test_volume.py +++ b/openstackclient/tests/unit/volume/v1/test_volume.py @@ -67,48 +67,50 @@ class TestVolumeCreate(TestVolume): user = identity_fakes.FakeUser.create_one_user() columns = ( - 'attach_status', + 'attachments', 'availability_zone', + 'bootable', + 'created_at', 'display_description', 'display_name', 'id', 'properties', 'size', + 'snapshot_id', 'status', 'type', ) - datalist = ( - 'detached', - volume_fakes.volume_zone, - volume_fakes.volume_description, - volume_fakes.volume_name, - volume_fakes.volume_id, - volume_fakes.volume_metadata_str, - volume_fakes.volume_size, - volume_fakes.volume_status, - volume_fakes.volume_type, - ) def setUp(self): super(TestVolumeCreate, self).setUp() - - self.volumes_mock.create.return_value = fakes.FakeResource( - None, - copy.deepcopy(volume_fakes.VOLUME), - loaded=True, + self.new_volume = volume_fakes.FakeVolume.create_one_volume() + self.datalist = ( + self.new_volume.attachments, + self.new_volume.availability_zone, + self.new_volume.bootable, + self.new_volume.created_at, + self.new_volume.display_description, + self.new_volume.display_name, + self.new_volume.id, + utils.format_dict(self.new_volume.metadata), + self.new_volume.size, + self.new_volume.snapshot_id, + self.new_volume.status, + self.new_volume.volume_type, ) + self.volumes_mock.create.return_value = self.new_volume # Get the command object to test self.cmd = volume.CreateVolume(self.app, None) def test_volume_create_min_options(self): arglist = [ - '--size', str(volume_fakes.volume_size), - volume_fakes.volume_name, + '--size', str(self.new_volume.size), + self.new_volume.display_name, ] verifylist = [ - ('size', volume_fakes.volume_size), - ('name', volume_fakes.volume_name), + ('size', self.new_volume.size), + ('name', self.new_volume.display_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -123,10 +125,10 @@ class TestVolumeCreate(TestVolume): # project_id=, availability_zone=, # metadata=, imageRef=) self.volumes_mock.create.assert_called_with( - volume_fakes.volume_size, + self.new_volume.size, None, None, - volume_fakes.volume_name, + self.new_volume.display_name, None, None, None, @@ -140,18 +142,18 @@ class TestVolumeCreate(TestVolume): def test_volume_create_options(self): arglist = [ - '--size', str(volume_fakes.volume_size), - '--description', volume_fakes.volume_description, - '--type', volume_fakes.volume_type, - '--availability-zone', volume_fakes.volume_zone, - volume_fakes.volume_name, + '--size', str(self.new_volume.size), + '--description', self.new_volume.display_description, + '--type', self.new_volume.volume_type, + '--availability-zone', self.new_volume.availability_zone, + self.new_volume.display_name, ] verifylist = [ - ('size', volume_fakes.volume_size), - ('description', volume_fakes.volume_description), - ('type', volume_fakes.volume_type), - ('availability_zone', volume_fakes.volume_zone), - ('name', volume_fakes.volume_name), + ('size', self.new_volume.size), + ('description', self.new_volume.display_description), + ('type', self.new_volume.volume_type), + ('availability_zone', self.new_volume.availability_zone), + ('name', self.new_volume.display_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -166,15 +168,15 @@ class TestVolumeCreate(TestVolume): # project_id=, availability_zone=, # metadata=, imageRef=) self.volumes_mock.create.assert_called_with( - volume_fakes.volume_size, + self.new_volume.size, None, None, - volume_fakes.volume_name, - volume_fakes.volume_description, - volume_fakes.volume_type, + self.new_volume.display_name, + self.new_volume.display_description, + self.new_volume.volume_type, None, None, - volume_fakes.volume_zone, + self.new_volume.availability_zone, None, None, ) @@ -189,16 +191,16 @@ class TestVolumeCreate(TestVolume): self.users_mock.get.return_value = self.user arglist = [ - '--size', str(volume_fakes.volume_size), + '--size', str(self.new_volume.size), '--project', self.project.id, '--user', self.user.id, - volume_fakes.volume_name, + self.new_volume.display_name, ] verifylist = [ - ('size', volume_fakes.volume_size), + ('size', self.new_volume.size), ('project', self.project.id), ('user', self.user.id), - ('name', volume_fakes.volume_name), + ('name', self.new_volume.display_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -213,10 +215,10 @@ class TestVolumeCreate(TestVolume): # project_id=, availability_zone=, # metadata=, imageRef=) self.volumes_mock.create.assert_called_with( - volume_fakes.volume_size, + self.new_volume.size, None, None, - volume_fakes.volume_name, + self.new_volume.display_name, None, None, self.user.id, @@ -236,16 +238,16 @@ class TestVolumeCreate(TestVolume): self.users_mock.get.return_value = self.user arglist = [ - '--size', str(volume_fakes.volume_size), + '--size', str(self.new_volume.size), '--project', self.project.name, '--user', self.user.name, - volume_fakes.volume_name, + self.new_volume.display_name, ] verifylist = [ - ('size', volume_fakes.volume_size), + ('size', self.new_volume.size), ('project', self.project.name), ('user', self.user.name), - ('name', volume_fakes.volume_name), + ('name', self.new_volume.display_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -260,10 +262,10 @@ class TestVolumeCreate(TestVolume): # project_id=, availability_zone=, # metadata=, imageRef=) self.volumes_mock.create.assert_called_with( - volume_fakes.volume_size, + self.new_volume.size, None, None, - volume_fakes.volume_name, + self.new_volume.display_name, None, None, self.user.id, @@ -280,13 +282,13 @@ class TestVolumeCreate(TestVolume): arglist = [ '--property', 'Alpha=a', '--property', 'Beta=b', - '--size', str(volume_fakes.volume_size), - volume_fakes.volume_name, + '--size', str(self.new_volume.size), + self.new_volume.display_name, ] verifylist = [ ('property', {'Alpha': 'a', 'Beta': 'b'}), - ('size', volume_fakes.volume_size), - ('name', volume_fakes.volume_name), + ('size', self.new_volume.size), + ('name', self.new_volume.display_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -301,10 +303,10 @@ class TestVolumeCreate(TestVolume): # project_id=, availability_zone=, # metadata=, imageRef=) self.volumes_mock.create.assert_called_with( - volume_fakes.volume_size, + self.new_volume.size, None, None, - volume_fakes.volume_name, + self.new_volume.display_name, None, None, None, @@ -326,13 +328,13 @@ class TestVolumeCreate(TestVolume): arglist = [ '--image', volume_fakes.image_id, - '--size', str(volume_fakes.volume_size), - volume_fakes.volume_name, + '--size', str(self.new_volume.size), + self.new_volume.display_name, ] verifylist = [ ('image', volume_fakes.image_id), - ('size', volume_fakes.volume_size), - ('name', volume_fakes.volume_name), + ('size', self.new_volume.size), + ('name', self.new_volume.display_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -347,10 +349,10 @@ class TestVolumeCreate(TestVolume): # project_id=, availability_zone=, # metadata=, imageRef=) self.volumes_mock.create.assert_called_with( - volume_fakes.volume_size, + self.new_volume.size, None, None, - volume_fakes.volume_name, + self.new_volume.display_name, None, None, None, @@ -372,13 +374,13 @@ class TestVolumeCreate(TestVolume): arglist = [ '--image', volume_fakes.image_name, - '--size', str(volume_fakes.volume_size), - volume_fakes.volume_name, + '--size', str(self.new_volume.size), + self.new_volume.display_name, ] verifylist = [ ('image', volume_fakes.image_name), - ('size', volume_fakes.volume_size), - ('name', volume_fakes.volume_name), + ('size', self.new_volume.size), + ('name', self.new_volume.display_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -393,10 +395,10 @@ class TestVolumeCreate(TestVolume): # project_id=, availability_zone=, # metadata=, imageRef=) self.volumes_mock.create.assert_called_with( - volume_fakes.volume_size, + self.new_volume.size, None, None, - volume_fakes.volume_name, + self.new_volume.display_name, None, None, None, @@ -503,6 +505,7 @@ class TestVolumeDelete(TestVolume): class TestVolumeList(TestVolume): + _volume = volume_fakes.FakeVolume.create_one_volume() columns = ( 'ID', 'Display Name', @@ -510,26 +513,23 @@ class TestVolumeList(TestVolume): 'Size', 'Attached to', ) + server = _volume.attachments[0]['server_id'] + device = _volume.attachments[0]['device'] + msg = 'Attached to %s on %s ' % (server, device) datalist = ( ( - volume_fakes.volume_id, - volume_fakes.volume_name, - volume_fakes.volume_status, - volume_fakes.volume_size, - '', + _volume.id, + _volume.display_name, + _volume.status, + _volume.size, + msg, ), ) def setUp(self): super(TestVolumeList, self).setUp() - self.volumes_mock.list.return_value = [ - fakes.FakeResource( - None, - copy.deepcopy(volume_fakes.VOLUME), - loaded=True, - ), - ] + self.volumes_mock.list.return_value = [self._volume] # Get the command object to test self.cmd = volume.ListVolume(self.app, None) @@ -552,12 +552,12 @@ class TestVolumeList(TestVolume): def test_volume_list_name(self): arglist = [ - '--name', volume_fakes.volume_name, + '--name', self._volume.display_name, ] verifylist = [ ('long', False), ('all_projects', False), - ('name', volume_fakes.volume_name), + ('name', self._volume.display_name), ('status', None), ('limit', None), ] @@ -569,13 +569,13 @@ class TestVolumeList(TestVolume): def test_volume_list_status(self): arglist = [ - '--status', volume_fakes.volume_status, + '--status', self._volume.status, ] verifylist = [ ('long', False), ('all_projects', False), ('name', None), - ('status', volume_fakes.volume_status), + ('status', self._volume.status), ('limit', None), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -630,14 +630,14 @@ class TestVolumeList(TestVolume): self.assertEqual(collist, columns) datalist = (( - volume_fakes.volume_id, - volume_fakes.volume_name, - volume_fakes.volume_status, - volume_fakes.volume_size, - volume_fakes.volume_type, - '', - '', - "Alpha='a', Beta='b', Gamma='g'", + self._volume.id, + self._volume.display_name, + self._volume.status, + self._volume.size, + self._volume.volume_type, + self._volume.bootable, + self.msg, + utils.format_dict(self._volume.metadata), ), ) self.assertEqual(datalist, tuple(data)) @@ -679,33 +679,27 @@ class TestVolumeList(TestVolume): class TestVolumeSet(TestVolume): + _volume = volume_fakes.FakeVolume.create_one_volume() + def setUp(self): super(TestVolumeSet, self).setUp() - self.volumes_mock.get.return_value = fakes.FakeResource( - None, - copy.deepcopy(volume_fakes.VOLUME), - loaded=True, - ) + self.volumes_mock.get.return_value = self._volume - self.volumes_mock.update.return_value = fakes.FakeResource( - None, - copy.deepcopy(volume_fakes.VOLUME), - loaded=True, - ) + self.volumes_mock.update.return_value = self._volume # Get the command object to test self.cmd = volume.SetVolume(self.app, None) def test_volume_set_no_options(self): arglist = [ - volume_fakes.volume_name, + self._volume.display_name, ] verifylist = [ ('name', None), ('description', None), ('size', None), ('property', None), - ('volume', volume_fakes.volume_name), + ('volume', self._volume.display_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -715,14 +709,14 @@ class TestVolumeSet(TestVolume): def test_volume_set_name(self): arglist = [ '--name', 'qwerty', - volume_fakes.volume_name, + self._volume.display_name, ] verifylist = [ ('name', 'qwerty'), ('description', None), ('size', None), ('property', None), - ('volume', volume_fakes.volume_name), + ('volume', self._volume.display_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -733,7 +727,7 @@ class TestVolumeSet(TestVolume): 'display_name': 'qwerty', } self.volumes_mock.update.assert_called_with( - volume_fakes.volume_id, + self._volume.id, **kwargs ) self.assertIsNone(result) @@ -741,14 +735,14 @@ class TestVolumeSet(TestVolume): def test_volume_set_description(self): arglist = [ '--description', 'new desc', - volume_fakes.volume_name, + self._volume.display_name, ] verifylist = [ ('name', None), ('description', 'new desc'), ('size', None), ('property', None), - ('volume', volume_fakes.volume_name), + ('volume', self._volume.display_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -759,7 +753,7 @@ class TestVolumeSet(TestVolume): 'display_description': 'new desc', } self.volumes_mock.update.assert_called_with( - volume_fakes.volume_id, + self._volume.id, **kwargs ) self.assertIsNone(result) @@ -767,14 +761,14 @@ class TestVolumeSet(TestVolume): def test_volume_set_size(self): arglist = [ '--size', '130', - volume_fakes.volume_name, + self._volume.display_name, ] verifylist = [ ('name', None), ('description', None), ('size', 130), ('property', None), - ('volume', volume_fakes.volume_name), + ('volume', self._volume.display_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -783,23 +777,24 @@ class TestVolumeSet(TestVolume): # Set expected values size = 130 self.volumes_mock.extend.assert_called_with( - volume_fakes.volume_id, + self._volume.id, size ) self.assertIsNone(result) @mock.patch.object(volume.LOG, 'error') def test_volume_set_size_smaller(self, mock_log_error): + self._volume.status = 'available' arglist = [ - '--size', '100', - volume_fakes.volume_name, + '--size', '1', + self._volume.display_name, ] verifylist = [ ('name', None), ('description', None), - ('size', 100), + ('size', 1), ('property', None), - ('volume', volume_fakes.volume_name), + ('volume', self._volume.display_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -807,22 +802,22 @@ class TestVolumeSet(TestVolume): mock_log_error.assert_called_with("New size must be greater " "than %s GB", - volume_fakes.volume_size) + self._volume.size) self.assertIsNone(result) @mock.patch.object(volume.LOG, 'error') def test_volume_set_size_not_available(self, mock_log_error): - self.volumes_mock.get.return_value.status = 'error' + self._volume.status = 'error' arglist = [ '--size', '130', - volume_fakes.volume_name, + self._volume.display_name, ] verifylist = [ ('name', None), ('description', None), ('size', 130), ('property', None), - ('volume', volume_fakes.volume_name), + ('volume', self._volume.display_name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -836,14 +831,14 @@ class TestVolumeSet(TestVolume): def test_volume_set_property(self): arglist = [ '--property', 'myprop=myvalue', - volume_fakes.volume_name, + self._volume.display_name, ] verifylist = [ ('name', None), ('description', None), ('size', None), ('property', {'myprop': 'myvalue'}), - ('volume', volume_fakes.volume_name), + ('volume', self._volume.display_name), ('bootable', False), ('non_bootable', False) ] @@ -856,26 +851,26 @@ class TestVolumeSet(TestVolume): 'myprop': 'myvalue' } self.volumes_mock.set_metadata.assert_called_with( - volume_fakes.volume_id, + self._volume.id, metadata ) self.assertIsNone(result) def test_volume_set_bootable(self): arglist = [ - ['--bootable', volume_fakes.volume_id], - ['--non-bootable', volume_fakes.volume_id] + ['--bootable', self._volume.id], + ['--non-bootable', self._volume.id] ] verifylist = [ [ ('bootable', True), ('non_bootable', False), - ('volume', volume_fakes.volume_id) + ('volume', self._volume.id) ], [ ('bootable', False), ('non_bootable', True), - ('volume', volume_fakes.volume_id) + ('volume', self._volume.id) ] ] for index in range(len(arglist)): @@ -884,4 +879,103 @@ class TestVolumeSet(TestVolume): self.cmd.take_action(parsed_args) self.volumes_mock.set_bootable.assert_called_with( - volume_fakes.volume_id, verifylist[index][0][1]) + self._volume.id, verifylist[index][0][1]) + + +class TestVolumeShow(TestVolume): + + columns = ( + 'attachments', + 'availability_zone', + 'bootable', + 'created_at', + 'display_description', + 'display_name', + 'id', + 'properties', + 'size', + 'snapshot_id', + 'status', + 'type', + ) + + def setUp(self): + super(TestVolumeShow, self).setUp() + self._volume = volume_fakes.FakeVolume.create_one_volume() + self.datalist = ( + self._volume.attachments, + self._volume.availability_zone, + self._volume.bootable, + self._volume.created_at, + self._volume.display_description, + self._volume.display_name, + self._volume.id, + utils.format_dict(self._volume.metadata), + self._volume.size, + self._volume.snapshot_id, + self._volume.status, + self._volume.volume_type, + ) + self.volumes_mock.get.return_value = self._volume + # Get the command object to test + self.cmd = volume.ShowVolume(self.app, None) + + def test_volume_show(self): + arglist = [ + self._volume.id + ] + verifylist = [ + ("volume", self._volume.id) + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + self.volumes_mock.get.assert_called_with(self._volume.id) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.datalist, data) + + +class TestVolumeUnset(TestVolume): + + _volume = volume_fakes.FakeVolume.create_one_volume() + + def setUp(self): + super(TestVolumeUnset, self).setUp() + + self.volumes_mock.get.return_value = self._volume + + self.volumes_mock.delete_metadata.return_value = None + # Get the command object to test + self.cmd = volume.UnsetVolume(self.app, None) + + def test_volume_unset_no_options(self): + arglist = [ + self._volume.display_name, + ] + verifylist = [ + ('property', None), + ('volume', self._volume.display_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + self.assertIsNone(result) + + def test_volume_unset_property(self): + arglist = [ + '--property', 'myprop', + self._volume.display_name, + ] + verifylist = [ + ('property', ['myprop']), + ('volume', self._volume.display_name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + self.volumes_mock.delete_metadata.assert_called_with( + self._volume.id, ['myprop'] + ) + self.assertIsNone(result) diff --git a/openstackclient/tests/unit/volume/v2/fakes.py b/openstackclient/tests/unit/volume/v2/fakes.py index 8d7ac831..2aeea60a 100644 --- a/openstackclient/tests/unit/volume/v2/fakes.py +++ b/openstackclient/tests/unit/volume/v2/fakes.py @@ -52,8 +52,6 @@ class FakeTransfer(object): """ # Set default attribute transfer_info = { - 'auth_key': 'key-' + uuid.uuid4().hex, - 'created_at': 'time-' + uuid.uuid4().hex, 'volume_id': 'volume-id-' + uuid.uuid4().hex, 'name': 'fake_transfer_name', 'id': 'id-' + uuid.uuid4().hex, diff --git a/openstackclient/tests/unit/volume/v2/test_transfer_request.py b/openstackclient/tests/unit/volume/v2/test_transfer_request.py index b4f89089..8cd6534b 100644 --- a/openstackclient/tests/unit/volume/v2/test_transfer_request.py +++ b/openstackclient/tests/unit/volume/v2/test_transfer_request.py @@ -36,6 +36,53 @@ class TestTransfer(transfer_fakes.TestVolume): self.volumes_mock.reset_mock() +class TestTransferAccept(TestTransfer): + + columns = ( + 'id', + 'name', + 'volume_id', + ) + + def setUp(self): + super(TestTransferAccept, self).setUp() + + self.volume_transfer = ( + transfer_fakes.FakeTransfer.create_one_transfer()) + self.data = ( + self.volume_transfer.id, + self.volume_transfer.name, + self.volume_transfer.volume_id, + ) + + self.transfer_mock.get.return_value = self.volume_transfer + self.transfer_mock.accept.return_value = self.volume_transfer + + # Get the command object to test + self.cmd = volume_transfer_request.AcceptTransferRequest( + self.app, None) + + def test_transfer_accept(self): + arglist = [ + self.volume_transfer.id, + 'auth_key', + ] + verifylist = [ + ('transfer_request', self.volume_transfer.id), + ('auth_key', 'auth_key'), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.transfer_mock.get.assert_called_once_with( + self.volume_transfer.id) + self.transfer_mock.accept.assert_called_once_with( + self.volume_transfer.id, 'auth_key') + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + class TestTransferCreate(TestTransfer): volume = transfer_fakes.FakeVolume.create_one_volume() @@ -52,7 +99,10 @@ class TestTransferCreate(TestTransfer): super(TestTransferCreate, self).setUp() self.volume_transfer = transfer_fakes.FakeTransfer.create_one_transfer( - attrs={'volume_id': self.volume.id}) + attrs={'volume_id': self.volume.id, + 'auth_key': 'key', + 'created_at': 'time'} + ) self.data = ( self.volume_transfer.auth_key, self.volume_transfer.created_at, @@ -266,3 +316,49 @@ class TestTransferList(TestTransfer): detailed=True, search_opts={'all_tenants': 1} ) + + +class TestTransferShow(TestTransfer): + + columns = ( + 'created_at', + 'id', + 'name', + 'volume_id', + ) + + def setUp(self): + super(TestTransferShow, self).setUp() + + self.volume_transfer = ( + transfer_fakes.FakeTransfer.create_one_transfer( + attrs={'created_at': 'time'}) + ) + self.data = ( + self.volume_transfer.created_at, + self.volume_transfer.id, + self.volume_transfer.name, + self.volume_transfer.volume_id, + ) + + self.transfer_mock.get.return_value = self.volume_transfer + + # Get the command object to test + self.cmd = volume_transfer_request.ShowTransferRequest( + self.app, None) + + def test_transfer_show(self): + arglist = [ + self.volume_transfer.id, + ] + verifylist = [ + ('transfer_request', self.volume_transfer.id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.transfer_mock.get.assert_called_once_with( + self.volume_transfer.id) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) diff --git a/openstackclient/volume/v1/volume.py b/openstackclient/volume/v1/volume.py index 69bf3803..89fa2014 100644 --- a/openstackclient/volume/v1/volume.py +++ b/openstackclient/volume/v1/volume.py @@ -452,10 +452,8 @@ class UnsetVolume(command.Command): '--property', metavar='<key>', action='append', - default=[], help=_('Remove a property from volume ' '(repeat option to remove multiple properties)'), - required=True, ) return parser diff --git a/openstackclient/volume/v1/volume_transfer_request.py b/openstackclient/volume/v1/volume_transfer_request.py index a985f8e5..4d6f2161 100644 --- a/openstackclient/volume/v1/volume_transfer_request.py +++ b/openstackclient/volume/v1/volume_transfer_request.py @@ -27,6 +27,34 @@ from openstackclient.i18n import _ LOG = logging.getLogger(__name__) +class AcceptTransferRequest(command.ShowOne): + """Accept volume transfer request.""" + + def get_parser(self, prog_name): + parser = super(AcceptTransferRequest, self).get_parser(prog_name) + parser.add_argument( + 'transfer_request', + metavar="<transfer-request>", + help=_('Volume transfer request to accept (name or ID)'), + ) + parser.add_argument( + 'auth_key', + metavar="<auth-key>", + help=_('Authentication key of transfer request'), + ) + return parser + + def take_action(self, parsed_args): + volume_client = self.app.client_manager.volume + transfer_request_id = utils.find_resource( + volume_client.transfers, parsed_args.transfer_request).id + transfer_accept = volume_client.transfers.accept( + transfer_request_id, parsed_args.auth_key) + transfer_accept._info.pop("links", None) + + return zip(*sorted(six.iteritems(transfer_accept._info))) + + class CreateTransferRequest(command.ShowOne): """Create volume transfer request.""" @@ -120,3 +148,24 @@ class ListTransferRequest(command.Lister): return (column_headers, ( utils.get_item_properties(s, columns) for s in volume_transfer_result)) + + +class ShowTransferRequest(command.ShowOne): + """Show volume transfer request details.""" + + def get_parser(self, prog_name): + parser = super(ShowTransferRequest, self).get_parser(prog_name) + parser.add_argument( + 'transfer_request', + metavar="<transfer-request>", + help=_('Volume transfer request to display (name or ID)'), + ) + return parser + + def take_action(self, parsed_args): + volume_client = self.app.client_manager.volume + volume_transfer_request = utils.find_resource( + volume_client.transfers, parsed_args.transfer_request) + volume_transfer_request._info.pop("links", None) + + return zip(*sorted(six.iteritems(volume_transfer_request._info))) diff --git a/openstackclient/volume/v2/volume.py b/openstackclient/volume/v2/volume.py index 5089aed1..0805b2be 100644 --- a/openstackclient/volume/v2/volume.py +++ b/openstackclient/volume/v2/volume.py @@ -490,7 +490,7 @@ class ShowVolume(command.ShowOne): parser = super(ShowVolume, self).get_parser(prog_name) parser.add_argument( 'volume', - metavar="<volume-id>", + metavar="<volume>", help=_("Volume to display (name or ID)") ) return parser diff --git a/openstackclient/volume/v2/volume_transfer_request.py b/openstackclient/volume/v2/volume_transfer_request.py index 8e79807c..9008fe3c 100644 --- a/openstackclient/volume/v2/volume_transfer_request.py +++ b/openstackclient/volume/v2/volume_transfer_request.py @@ -27,6 +27,34 @@ from openstackclient.i18n import _ LOG = logging.getLogger(__name__) +class AcceptTransferRequest(command.ShowOne): + """Accept volume transfer request.""" + + def get_parser(self, prog_name): + parser = super(AcceptTransferRequest, self).get_parser(prog_name) + parser.add_argument( + 'transfer_request', + metavar="<transfer-request>", + help=_('Volume transfer request to accept (name or ID)'), + ) + parser.add_argument( + 'auth_key', + metavar="<auth-key>", + help=_('Authentication key of transfer request'), + ) + return parser + + def take_action(self, parsed_args): + volume_client = self.app.client_manager.volume + transfer_request_id = utils.find_resource( + volume_client.transfers, parsed_args.transfer_request).id + transfer_accept = volume_client.transfers.accept( + transfer_request_id, parsed_args.auth_key) + transfer_accept._info.pop("links", None) + + return zip(*sorted(six.iteritems(transfer_accept._info))) + + class CreateTransferRequest(command.ShowOne): """Create volume transfer request.""" @@ -120,3 +148,24 @@ class ListTransferRequest(command.Lister): return (column_headers, ( utils.get_item_properties(s, columns) for s in volume_transfer_result)) + + +class ShowTransferRequest(command.ShowOne): + """Show volume transfer request details.""" + + def get_parser(self, prog_name): + parser = super(ShowTransferRequest, self).get_parser(prog_name) + parser.add_argument( + 'transfer_request', + metavar="<transfer-request>", + help=_('Volume transfer request to display (name or ID)'), + ) + return parser + + def take_action(self, parsed_args): + volume_client = self.app.client_manager.volume + volume_transfer_request = utils.find_resource( + volume_client.transfers, parsed_args.transfer_request) + volume_transfer_request._info.pop("links", None) + + return zip(*sorted(six.iteritems(volume_transfer_request._info))) |
