diff options
Diffstat (limited to 'openstackclient')
23 files changed, 413 insertions, 289 deletions
diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py index d3b601b0..bf9f0985 100644 --- a/openstackclient/compute/v2/server.py +++ b/openstackclient/compute/v2/server.py @@ -293,7 +293,7 @@ class CreateServer(command.ShowOne): action='append', default=[], help=_('Security group to assign to this server (name or ID) ' - '(repeat for multiple groups)'), + '(repeat option to set multiple groups)'), ) parser.add_argument( '--key-name', @@ -305,7 +305,7 @@ class CreateServer(command.ShowOne): metavar='<key=value>', action=parseractions.KeyValueAction, help=_('Set a property on this server ' - '(repeat for multiple values)'), + '(repeat option to set multiple values)'), ) parser.add_argument( '--file', @@ -313,7 +313,7 @@ class CreateServer(command.ShowOne): action='append', default=[], help=_('File to inject into image before boot ' - '(repeat for multiple files)'), + '(repeat option to set multiple files)'), ) parser.add_argument( '--user-data', @@ -1738,7 +1738,7 @@ class UnsetServer(command.Command): action='append', default=[], help=_('Property key to remove from server ' - '(repeat to remove multiple values)'), + '(repeat option to remove multiple values)'), ) return parser diff --git a/openstackclient/identity/v3/identity_provider.py b/openstackclient/identity/v3/identity_provider.py index 37f79ed6..276a7f57 100644 --- a/openstackclient/identity/v3/identity_provider.py +++ b/openstackclient/identity/v3/identity_provider.py @@ -35,7 +35,7 @@ class CreateIdentityProvider(command.ShowOne): metavar='<remote-id>', action='append', help='Remote IDs to associate with the Identity Provider ' - '(repeat to provide multiple values)' + '(repeat option to provide multiple values)' ) identity_remote_id_provider.add_argument( '--remote-id-file', @@ -139,7 +139,7 @@ class SetIdentityProvider(command.Command): metavar='<remote-id>', action='append', help='Remote IDs to associate with the Identity Provider ' - '(repeat to provide multiple values)' + '(repeat option to provide multiple values)' ) identity_remote_id_provider.add_argument( '--remote-id-file', diff --git a/openstackclient/identity/v3/token.py b/openstackclient/identity/v3/token.py index 62a4c4a3..bdc5e95f 100644 --- a/openstackclient/identity/v3/token.py +++ b/openstackclient/identity/v3/token.py @@ -40,7 +40,7 @@ class AuthorizeRequestToken(command.ShowOne): action='append', default=[], help='Roles to authorize (name or ID) ' - '(repeat to set multiple values) (required)', + '(repeat option to set multiple values, required)', required=True ) return parser diff --git a/openstackclient/identity/v3/trust.py b/openstackclient/identity/v3/trust.py index 26fb8338..b6f5c6b4 100644 --- a/openstackclient/identity/v3/trust.py +++ b/openstackclient/identity/v3/trust.py @@ -48,7 +48,7 @@ class CreateTrust(command.ShowOne): action='append', default=[], help='Roles to authorize (name or ID) ' - '(repeat to set multiple values) (required)', + '(repeat option to set multiple values, required)', required=True ) parser.add_argument( diff --git a/openstackclient/network/client.py b/openstackclient/network/client.py index 7714c525..dca9efc4 100644 --- a/openstackclient/network/client.py +++ b/openstackclient/network/client.py @@ -31,7 +31,8 @@ API_VERSIONS = { def make_client(instance): """Returns a network proxy""" - conn = connection.Connection(authenticator=instance.session.auth) + conn = connection.Connection(authenticator=instance.session.auth, + verify=instance.session.verify) LOG.debug('Connection: %s', conn) LOG.debug('Network client initialized using OpenStack SDK: %s', conn.network) diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py index ebd5cb63..20d943ed 100644 --- a/openstackclient/network/v2/network.py +++ b/openstackclient/network/v2/network.py @@ -142,7 +142,7 @@ class CreateNetwork(common.NetworkAndComputeShowOne): metavar='<availability-zone>', help='Availability Zone in which to create this network ' '(requires the Network Availability Zone extension, ' - 'this option can be repeated).', + 'repeat option to set multiple availability zones)', ) external_router_grp = parser.add_mutually_exclusive_group() external_router_grp.add_argument( diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py index a9e80428..820f2ac2 100644 --- a/openstackclient/network/v2/port.py +++ b/openstackclient/network/v2/port.py @@ -210,13 +210,13 @@ class CreatePort(command.ShowOne): optional_keys=['subnet', 'ip-address'], help='Desired IP and/or subnet (name or ID) for this port: ' 'subnet=<subnet>,ip-address=<ip-address> ' - '(this option can be repeated)') + '(repeat option to set multiple fixed IP addresses)') parser.add_argument( '--binding-profile', metavar='<binding-profile>', action=parseractions.KeyValueAction, help='Custom data to be passed as binding:profile: <key>=<value> ' - '(this option can be repeated)') + '(repeat option to set multiple binding:profile data)') admin_group = parser.add_mutually_exclusive_group() admin_group.add_argument( '--enable', @@ -360,7 +360,7 @@ class SetPort(command.Command): optional_keys=['subnet', 'ip-address'], help='Desired IP and/or subnet (name or ID) for this port: ' 'subnet=<subnet>,ip-address=<ip-address> ' - '(this option can be repeated)') + '(repeat option to set multiple fixed IP addresses)') fixed_ip.add_argument( '--no-fixed-ip', action='store_true', @@ -371,7 +371,7 @@ class SetPort(command.Command): metavar='<binding-profile>', action=parseractions.KeyValueAction, help='Custom data to be passed as binding:profile: <key>=<value> ' - '(this option can be repeated)') + '(repeat option to set multiple binding:profile data)') binding_profile.add_argument( '--no-binding-profile', action='store_true', diff --git a/openstackclient/network/v2/router.py b/openstackclient/network/v2/router.py index 6a78be6c..2ededae8 100644 --- a/openstackclient/network/v2/router.py +++ b/openstackclient/network/v2/router.py @@ -179,7 +179,7 @@ class CreateRouter(command.ShowOne): dest='availability_zone_hints', help='Availability Zone in which to create this router ' '(requires the Router Availability Zone extension, ' - 'this option can be repeated).', + 'repeat option to set multiple availability zones)', ) identity_common.add_project_domain_option_to_parser(parser) @@ -368,10 +368,10 @@ class SetRouter(command.Command): dest='routes', default=None, required_keys=['destination', 'gateway'], - help="Routes associated with the router. " - "Repeat this option to set multiple routes. " - "destination: destination subnet (in CIDR notation). " - "gateway: nexthop IP address.", + help="Routes associated with the router " + "destination: destination subnet (in CIDR notation) " + "gateway: nexthop IP address " + "(repeat option to set multiple routes)", ) routes_group.add_argument( '--clear-routes', diff --git a/openstackclient/network/v2/subnet.py b/openstackclient/network/v2/subnet.py index eb96bb1f..3d539fea 100644 --- a/openstackclient/network/v2/subnet.py +++ b/openstackclient/network/v2/subnet.py @@ -52,15 +52,15 @@ def _get_common_parse_arguments(parser): required_keys=['start', 'end'], help='Allocation pool IP addresses for this subnet ' 'e.g.: start=192.168.199.2,end=192.168.199.254 ' - '(This option can be repeated)', + '(repeat option to add multiple IP addresses)', ) parser.add_argument( '--dns-nameserver', metavar='<dns-nameserver>', action='append', dest='dns_nameservers', - help='DNS name server for this subnet ' - '(This option can be repeated)', + help='DNS server for this subnet ' + '(repeat option to set multiple DNS servers)', ) parser.add_argument( '--host-route', @@ -72,7 +72,7 @@ def _get_common_parse_arguments(parser): 'e.g.: destination=10.10.0.0/16,gateway=192.168.71.254 ' 'destination: destination subnet (in CIDR notation) ' 'gateway: nexthop IP address ' - '(This option can be repeated)', + '(repeat option to add multiple routes)', ) @@ -365,6 +365,12 @@ class SetSubnet(command.Command): if not attrs: msg = "Nothing specified to be set" raise exceptions.CommandError(msg) + if 'dns_nameservers' in attrs: + attrs['dns_nameservers'] += obj.dns_nameservers + if 'host_routes' in attrs: + attrs['host_routes'] += obj.host_routes + if 'allocation_pools' in attrs: + attrs['allocation_pools'] += obj.allocation_pools client.update_subnet(obj, **attrs) return diff --git a/openstackclient/network/v2/subnet_pool.py b/openstackclient/network/v2/subnet_pool.py index 6b6fc090..0837f81b 100644 --- a/openstackclient/network/v2/subnet_pool.py +++ b/openstackclient/network/v2/subnet_pool.py @@ -35,6 +35,8 @@ _formatters = { def _get_attrs(client_manager, parsed_args): attrs = {} + network_client = client_manager.network + if parsed_args.name is not None: attrs['name'] = str(parsed_args.name) if parsed_args.prefixes is not None: @@ -46,6 +48,12 @@ def _get_attrs(client_manager, parsed_args): if parsed_args.max_prefix_length is not None: attrs['max_prefixlen'] = parsed_args.max_prefix_length + if parsed_args.address_scope is not None: + attrs['address_scope_id'] = network_client.find_address_scope( + parsed_args.address_scope, ignore_missing=False).id + if 'no_address_scope' in parsed_args and parsed_args.no_address_scope: + attrs['address_scope_id'] = None + # "subnet pool set" command doesn't support setting project. if 'project' in parsed_args and parsed_args.project is not None: identity_client = client_manager.identity @@ -65,8 +73,8 @@ def _add_prefix_options(parser): metavar='<pool-prefix>', dest='prefixes', action='append', - help='Set subnet pool prefixes (in CIDR notation). ' - 'Repeat this option to set multiple prefixes.', + help='Set subnet pool prefixes (in CIDR notation) ' + '(repeat option to set multiple prefixes)', ) parser.add_argument( '--default-prefix-length', @@ -105,7 +113,13 @@ class CreateSubnetPool(command.ShowOne): help="Owner's project (name or ID)", ) identity_common.add_project_domain_option_to_parser(parser) - + parser.add_argument( + '--address-scope', + metavar='<address-scope>', + help="Set address scope associated with the subnet pool " + "(name or ID). Prefixes must be unique across address " + "scopes.", + ) return parser def take_action(self, parsed_args): @@ -184,7 +198,7 @@ class ListSubnetPool(command.Lister): return (headers, (utils.get_item_properties( s, columns, - formatters={}, + formatters=_formatters, ) for s in data)) @@ -204,7 +218,19 @@ class SetSubnetPool(command.Command): help='Set subnet pool name', ) _add_prefix_options(parser) - + address_scope_group = parser.add_mutually_exclusive_group() + address_scope_group.add_argument( + '--address-scope', + metavar='<address-scope>', + help="Set address scope associated with the subnet pool " + "(name or ID). Prefixes must be unique across address " + "scopes.", + ) + address_scope_group.add_argument( + '--no-address-scope', + action='store_true', + help="Remove address scope associated with the subnet pool", + ) return parser def take_action(self, parsed_args): diff --git a/openstackclient/tests/compute/v2/fakes.py b/openstackclient/tests/compute/v2/fakes.py index 6c67c470..1cca2787 100644 --- a/openstackclient/tests/compute/v2/fakes.py +++ b/openstackclient/tests/compute/v2/fakes.py @@ -342,20 +342,16 @@ class FakeSecurityGroup(object): """Fake one or more security groups.""" @staticmethod - def create_one_security_group(attrs=None, methods=None): + def create_one_security_group(attrs=None): """Create a fake security group. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :return: A FakeResource object, with id, name, etc. """ if attrs is None: attrs = {} - if methods is None: - methods = {} # Set default attributes. security_group_attrs = { @@ -369,28 +365,17 @@ class FakeSecurityGroup(object): # Overwrite default attributes. security_group_attrs.update(attrs) - # Set default methods. - security_group_methods = { - 'keys': ['id', 'name', 'description', 'tenant_id', 'rules'], - } - - # Overwrite default methods. - security_group_methods.update(methods) - security_group = fakes.FakeResource( info=copy.deepcopy(security_group_attrs), - methods=copy.deepcopy(security_group_methods), loaded=True) return security_group @staticmethod - def create_security_groups(attrs=None, methods=None, count=2): + def create_security_groups(attrs=None, count=2): """Create multiple fake security groups. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :param int count: The number of security groups to fake :return: @@ -399,7 +384,7 @@ class FakeSecurityGroup(object): security_groups = [] for i in range(0, count): security_groups.append( - FakeSecurityGroup.create_one_security_group(attrs, methods)) + FakeSecurityGroup.create_one_security_group(attrs)) return security_groups @@ -408,20 +393,16 @@ class FakeSecurityGroupRule(object): """Fake one or more security group rules.""" @staticmethod - def create_one_security_group_rule(attrs=None, methods=None): + def create_one_security_group_rule(attrs=None): """Create a fake security group rule. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :return: A FakeResource object, with id, etc. """ if attrs is None: attrs = {} - if methods is None: - methods = {} # Set default attributes. security_group_rule_attrs = { @@ -437,26 +418,17 @@ class FakeSecurityGroupRule(object): # Overwrite default attributes. security_group_rule_attrs.update(attrs) - # Set default methods. - security_group_rule_methods = {} - - # Overwrite default methods. - security_group_rule_methods.update(methods) - security_group_rule = fakes.FakeResource( info=copy.deepcopy(security_group_rule_attrs), - methods=copy.deepcopy(security_group_rule_methods), loaded=True) return security_group_rule @staticmethod - def create_security_group_rules(attrs=None, methods=None, count=2): + def create_security_group_rules(attrs=None, count=2): """Create multiple fake security group rules. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :param int count: The number of security group rules to fake :return: @@ -465,8 +437,7 @@ class FakeSecurityGroupRule(object): security_group_rules = [] for i in range(0, count): security_group_rules.append( - FakeSecurityGroupRule.create_one_security_group_rule( - attrs, methods)) + FakeSecurityGroupRule.create_one_security_group_rule(attrs)) return security_group_rules @@ -688,13 +659,11 @@ class FakeAvailabilityZone(object): """Fake one or more compute availability zones (AZs).""" @staticmethod - def create_one_availability_zone(attrs={}, methods={}): + def create_one_availability_zone(attrs={}): """Create a fake AZ. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :return: A FakeResource object with zoneName, zoneState, etc. """ @@ -717,18 +686,15 @@ class FakeAvailabilityZone(object): availability_zone = fakes.FakeResource( info=copy.deepcopy(availability_zone), - methods=methods, loaded=True) return availability_zone @staticmethod - def create_availability_zones(attrs={}, methods={}, count=2): + def create_availability_zones(attrs={}, count=2): """Create multiple fake AZs. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :param int count: The number of AZs to fake :return: @@ -737,8 +703,7 @@ class FakeAvailabilityZone(object): availability_zones = [] for i in range(0, count): availability_zone = \ - FakeAvailabilityZone.create_one_availability_zone( - attrs, methods) + FakeAvailabilityZone.create_one_availability_zone(attrs) availability_zones.append(availability_zone) return availability_zones @@ -748,13 +713,11 @@ class FakeFloatingIP(object): """Fake one or more floating ip.""" @staticmethod - def create_one_floating_ip(attrs={}, methods={}): + def create_one_floating_ip(attrs={}): """Create a fake floating ip. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :return: A FakeResource object, with id, ip, and so on """ @@ -770,27 +733,18 @@ class FakeFloatingIP(object): # Overwrite default attributes. floating_ip_attrs.update(attrs) - # Set default methods. - floating_ip_methods = {} - - # Overwrite default methods. - floating_ip_methods.update(methods) - floating_ip = fakes.FakeResource( info=copy.deepcopy(floating_ip_attrs), - methods=copy.deepcopy(floating_ip_methods), loaded=True) return floating_ip @staticmethod - def create_floating_ips(attrs={}, methods={}, count=2): + def create_floating_ips(attrs={}, count=2): """Create multiple fake floating ips. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :param int count: The number of floating ips to fake :return: @@ -798,10 +752,7 @@ class FakeFloatingIP(object): """ floating_ips = [] for i in range(0, count): - floating_ips.append(FakeFloatingIP.create_one_floating_ip( - attrs, - methods - )) + floating_ips.append(FakeFloatingIP.create_one_floating_ip(attrs)) return floating_ips @staticmethod @@ -828,13 +779,11 @@ class FakeNetwork(object): """Fake one or more networks.""" @staticmethod - def create_one_network(attrs={}, methods={}): + def create_one_network(attrs={}): """Create a fake network. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :return: A FakeResource object, with id, label, cidr and so on """ @@ -877,28 +826,17 @@ class FakeNetwork(object): # Overwrite default attributes. network_attrs.update(attrs) - # Set default methods. - network_methods = { - 'keys': ['id', 'label', 'cidr'], - } - - # Overwrite default methods. - network_methods.update(methods) - network = fakes.FakeResource(info=copy.deepcopy(network_attrs), - methods=copy.deepcopy(network_methods), loaded=True) return network @staticmethod - def create_networks(attrs={}, methods={}, count=2): + def create_networks(attrs={}, count=2): """Create multiple fake networks. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :param int count: The number of networks to fake :return: @@ -906,7 +844,7 @@ class FakeNetwork(object): """ networks = [] for i in range(0, count): - networks.append(FakeNetwork.create_one_network(attrs, methods)) + networks.append(FakeNetwork.create_one_network(attrs)) return networks diff --git a/openstackclient/tests/fakes.py b/openstackclient/tests/fakes.py index 9fdcc7e9..f0cebb06 100644 --- a/openstackclient/tests/fakes.py +++ b/openstackclient/tests/fakes.py @@ -183,6 +183,9 @@ class FakeResource(object): info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) return "<%s %s>" % (self.__class__.__name__, info) + def keys(self): + return self._info.keys() + class FakeResponse(requests.Response): diff --git a/openstackclient/tests/network/v2/fakes.py b/openstackclient/tests/network/v2/fakes.py index 7f89ef7a..5fd7ea3b 100644 --- a/openstackclient/tests/network/v2/fakes.py +++ b/openstackclient/tests/network/v2/fakes.py @@ -71,17 +71,52 @@ class TestNetworkV2(utils.TestCommand): ) +class FakeAddressScope(object): + """Fake one or more address scopes.""" + + @staticmethod + def create_one_address_scope(attrs=None): + """Create a fake address scope. + + :param Dictionary attrs: + A dictionary with all attributes + :return: + A FakeResource object with name, id, etc. + """ + if attrs is None: + attrs = {} + + # Set default attributes. + address_scope_attrs = { + 'name': 'address-scope-name-' + uuid.uuid4().hex, + 'id': 'address-scope-id-' + uuid.uuid4().hex, + 'tenant_id': 'project-id-' + uuid.uuid4().hex, + 'shared': False, + 'ip_version': 4, + } + + # Overwrite default attributes. + address_scope_attrs.update(attrs) + + address_scope = fakes.FakeResource( + info=copy.deepcopy(address_scope_attrs), + loaded=True) + + # Set attributes with special mapping in OpenStack SDK. + address_scope.project_id = address_scope_attrs['tenant_id'] + + return address_scope + + class FakeAvailabilityZone(object): """Fake one or more network availability zones (AZs).""" @staticmethod - def create_one_availability_zone(attrs={}, methods={}): + def create_one_availability_zone(attrs={}): """Create a fake AZ. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :return: A FakeResource object with name, state, etc. """ @@ -97,18 +132,15 @@ class FakeAvailabilityZone(object): availability_zone = fakes.FakeResource( info=copy.deepcopy(availability_zone), - methods=methods, loaded=True) return availability_zone @staticmethod - def create_availability_zones(attrs={}, methods={}, count=2): + def create_availability_zones(attrs={}, count=2): """Create multiple fake AZs. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :param int count: The number of AZs to fake :return: @@ -117,8 +149,7 @@ class FakeAvailabilityZone(object): availability_zones = [] for i in range(0, count): availability_zone = \ - FakeAvailabilityZone.create_one_availability_zone( - attrs, methods) + FakeAvailabilityZone.create_one_availability_zone(attrs) availability_zones.append(availability_zone) return availability_zones @@ -128,13 +159,11 @@ class FakeNetwork(object): """Fake one or more networks.""" @staticmethod - def create_one_network(attrs={}, methods={}): + def create_one_network(attrs={}): """Create a fake network. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :return: A FakeResource object, with id, name, admin_state_up, router_external, status, subnets, tenant_id @@ -158,18 +187,7 @@ class FakeNetwork(object): # Overwrite default attributes. network_attrs.update(attrs) - # Set default methods. - network_methods = { - 'keys': ['id', 'name', 'admin_state_up', 'router_external', - 'status', 'subnets', 'tenant_id', 'availability_zones', - 'availability_zone_hints', 'is_default'], - } - - # Overwrite default methods. - network_methods.update(methods) - network = fakes.FakeResource(info=copy.deepcopy(network_attrs), - methods=copy.deepcopy(network_methods), loaded=True) # Set attributes with special mapping in OpenStack SDK. @@ -178,13 +196,11 @@ class FakeNetwork(object): return network @staticmethod - def create_networks(attrs={}, methods={}, count=2): + def create_networks(attrs={}, count=2): """Create multiple fake networks. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :param int count: The number of networks to fake :return: @@ -192,7 +208,7 @@ class FakeNetwork(object): """ networks = [] for i in range(0, count): - networks.append(FakeNetwork.create_one_network(attrs, methods)) + networks.append(FakeNetwork.create_one_network(attrs)) return networks @@ -220,7 +236,7 @@ class FakePort(object): """Fake one or more ports.""" @staticmethod - def create_one_port(attrs={}, methods={}): + def create_one_port(attrs={}): """Create a fake port. :param Dictionary attrs: @@ -258,23 +274,7 @@ class FakePort(object): # Overwrite default attributes. port_attrs.update(attrs) - # Set default methods. - port_methods = { - 'keys': ['admin_state_up', 'allowed_address_pairs', - 'binding:host_id', 'binding:profile', - 'binding:vif_details', 'binding:vif_type', - 'binding:vnic_type', 'device_id', 'device_owner', - 'dns_assignment', 'dns_name', 'extra_dhcp_opts', - 'fixed_ips', 'id', 'mac_address', 'name', - 'network_id', 'port_security_enabled', - 'security_groups', 'status', 'tenant_id'], - } - - # Overwrite default methods. - port_methods.update(methods) - port = fakes.FakeResource(info=copy.deepcopy(port_attrs), - methods=copy.deepcopy(port_methods), loaded=True) # Set attributes with special mappings in OpenStack SDK. @@ -288,13 +288,11 @@ class FakePort(object): return port @staticmethod - def create_ports(attrs={}, methods={}, count=2): + def create_ports(attrs={}, count=2): """Create multiple fake ports. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :param int count: The number of ports to fake :return: @@ -302,7 +300,7 @@ class FakePort(object): """ ports = [] for i in range(0, count): - ports.append(FakePort.create_one_port(attrs, methods)) + ports.append(FakePort.create_one_port(attrs)) return ports @@ -330,13 +328,11 @@ class FakeRouter(object): """Fake one or more routers.""" @staticmethod - def create_one_router(attrs={}, methods={}): + def create_one_router(attrs={}): """Create a fake router. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :return: A FakeResource object, with id, name, admin_state_up, status, tenant_id @@ -359,17 +355,7 @@ class FakeRouter(object): # Overwrite default attributes. router_attrs.update(attrs) - # Set default methods. - router_methods = { - 'keys': ['id', 'name', 'admin_state_up', 'distributed', 'ha', - 'tenant_id'], - } - - # Overwrite default methods. - router_methods.update(methods) - router = fakes.FakeResource(info=copy.deepcopy(router_attrs), - methods=copy.deepcopy(router_methods), loaded=True) # Set attributes with special mapping in OpenStack SDK. @@ -378,13 +364,11 @@ class FakeRouter(object): return router @staticmethod - def create_routers(attrs={}, methods={}, count=2): + def create_routers(attrs={}, count=2): """Create multiple fake routers. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :param int count: The number of routers to fake :return: @@ -392,7 +376,7 @@ class FakeRouter(object): """ routers = [] for i in range(0, count): - routers.append(FakeRouter.create_one_router(attrs, methods)) + routers.append(FakeRouter.create_one_router(attrs)) return routers @@ -420,20 +404,16 @@ class FakeSecurityGroup(object): """Fake one or more security groups.""" @staticmethod - def create_one_security_group(attrs=None, methods=None): + def create_one_security_group(attrs=None): """Create a fake security group. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :return: A FakeResource object, with id, name, etc. """ if attrs is None: attrs = {} - if methods is None: - methods = {} # Set default attributes. security_group_attrs = { @@ -447,18 +427,8 @@ class FakeSecurityGroup(object): # Overwrite default attributes. security_group_attrs.update(attrs) - # Set default methods. - security_group_methods = { - 'keys': ['id', 'name', 'description', 'tenant_id', - 'security_group_rules'], - } - - # Overwrite default methods. - security_group_methods.update(methods) - security_group = fakes.FakeResource( info=copy.deepcopy(security_group_attrs), - methods=copy.deepcopy(security_group_methods), loaded=True) # Set attributes with special mapping in OpenStack SDK. @@ -467,13 +437,11 @@ class FakeSecurityGroup(object): return security_group @staticmethod - def create_security_groups(attrs=None, methods=None, count=2): + def create_security_groups(attrs=None, count=2): """Create multiple fake security groups. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :param int count: The number of security groups to fake :return: @@ -482,7 +450,7 @@ class FakeSecurityGroup(object): security_groups = [] for i in range(0, count): security_groups.append( - FakeSecurityGroup.create_one_security_group(attrs, methods)) + FakeSecurityGroup.create_one_security_group(attrs)) return security_groups @@ -491,20 +459,16 @@ class FakeSecurityGroupRule(object): """Fake one or more security group rules.""" @staticmethod - def create_one_security_group_rule(attrs=None, methods=None): + def create_one_security_group_rule(attrs=None): """Create a fake security group rule. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :return: A FakeResource object, with id, etc. """ if attrs is None: attrs = {} - if methods is None: - methods = {} # Set default attributes. security_group_rule_attrs = { @@ -523,19 +487,8 @@ class FakeSecurityGroupRule(object): # Overwrite default attributes. security_group_rule_attrs.update(attrs) - # Set default methods. - security_group_rule_methods = { - 'keys': ['direction', 'ethertype', 'id', 'port_range_max', - 'port_range_min', 'protocol', 'remote_group_id', - 'remote_ip_prefix', 'security_group_id', 'tenant_id'], - } - - # Overwrite default methods. - security_group_rule_methods.update(methods) - security_group_rule = fakes.FakeResource( info=copy.deepcopy(security_group_rule_attrs), - methods=copy.deepcopy(security_group_rule_methods), loaded=True) # Set attributes with special mapping in OpenStack SDK. @@ -544,13 +497,11 @@ class FakeSecurityGroupRule(object): return security_group_rule @staticmethod - def create_security_group_rules(attrs=None, methods=None, count=2): + def create_security_group_rules(attrs=None, count=2): """Create multiple fake security group rules. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :param int count: The number of security group rules to fake :return: @@ -559,8 +510,7 @@ class FakeSecurityGroupRule(object): security_group_rules = [] for i in range(0, count): security_group_rules.append( - FakeSecurityGroupRule.create_one_security_group_rule( - attrs, methods)) + FakeSecurityGroupRule.create_one_security_group_rule(attrs)) return security_group_rules @@ -569,13 +519,11 @@ class FakeSubnet(object): """Fake one or more subnets.""" @staticmethod - def create_one_subnet(attrs={}, methods={}): + def create_one_subnet(attrs={}): """Create a fake subnet. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :return: A FakeResource object faking the subnet """ @@ -601,19 +549,7 @@ class FakeSubnet(object): # Overwrite default attributes. subnet_attrs.update(attrs) - # Set default methods. - subnet_methods = { - 'keys': ['id', 'name', 'network_id', 'cidr', 'enable_dhcp', - 'allocation_pools', 'dns_nameservers', 'gateway_ip', - 'host_routes', 'ip_version', 'tenant_id', - 'ipv6_address_mode', 'ipv6_ra_mode', 'subnetpool_id'] - } - - # Overwrite default methods. - subnet_methods.update(methods) - subnet = fakes.FakeResource(info=copy.deepcopy(subnet_attrs), - methods=copy.deepcopy(subnet_methods), loaded=True) # Set attributes with special mappings in OpenStack SDK. subnet.project_id = subnet_attrs['tenant_id'] @@ -621,13 +557,11 @@ class FakeSubnet(object): return subnet @staticmethod - def create_subnets(attrs={}, methods={}, count=2): + def create_subnets(attrs={}, count=2): """Create multiple fake subnets. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :param int count: The number of subnets to fake :return: @@ -635,7 +569,7 @@ class FakeSubnet(object): """ subnets = [] for i in range(0, count): - subnets.append(FakeSubnet.create_one_subnet(attrs, methods)) + subnets.append(FakeSubnet.create_one_subnet(attrs)) return subnets @@ -644,13 +578,11 @@ class FakeFloatingIP(object): """Fake one or more floating ip.""" @staticmethod - def create_one_floating_ip(attrs={}, methods={}): + def create_one_floating_ip(attrs={}): """Create a fake floating ip. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :return: A FakeResource object, with id, ip, and so on """ @@ -671,19 +603,8 @@ class FakeFloatingIP(object): # Overwrite default attributes. floating_ip_attrs.update(attrs) - # Set default methods. - floating_ip_methods = { - 'keys': ['id', 'floating_ip_address', 'fixed_ip_address', - 'dns_domain', 'dns_name', 'status', 'router_id', - 'floating_network_id', 'port_id', 'tenant_id'] - } - - # Overwrite default methods. - floating_ip_methods.update(methods) - floating_ip = fakes.FakeResource( info=copy.deepcopy(floating_ip_attrs), - methods=copy.deepcopy(floating_ip_methods), loaded=True ) @@ -693,13 +614,11 @@ class FakeFloatingIP(object): return floating_ip @staticmethod - def create_floating_ips(attrs={}, methods={}, count=2): + def create_floating_ips(attrs={}, count=2): """Create multiple fake floating ips. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :param int count: The number of floating ips to fake :return: @@ -707,10 +626,7 @@ class FakeFloatingIP(object): """ floating_ips = [] for i in range(0, count): - floating_ips.append(FakeFloatingIP.create_one_floating_ip( - attrs, - methods - )) + floating_ips.append(FakeFloatingIP.create_one_floating_ip(attrs)) return floating_ips @staticmethod @@ -737,13 +653,11 @@ class FakeSubnetPool(object): """Fake one or more subnet pools.""" @staticmethod - def create_one_subnet_pool(attrs={}, methods={}): + def create_one_subnet_pool(attrs={}): """Create a fake subnet pool. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :return: A FakeResource object faking the subnet pool """ @@ -766,20 +680,8 @@ class FakeSubnetPool(object): # Overwrite default attributes. subnet_pool_attrs.update(attrs) - # Set default methods. - subnet_pool_methods = { - 'keys': ['id', 'name', 'prefixes', 'default_prefixlen', - 'address_scope_id', 'tenant_id', 'is_default', - 'shared', 'max_prefixlen', 'min_prefixlen', - 'default_quota', 'ip_version'] - } - - # Overwrite default methods. - subnet_pool_methods.update(methods) - subnet_pool = fakes.FakeResource( info=copy.deepcopy(subnet_pool_attrs), - methods=copy.deepcopy(subnet_pool_methods), loaded=True ) @@ -789,13 +691,11 @@ class FakeSubnetPool(object): return subnet_pool @staticmethod - def create_subnet_pools(attrs={}, methods={}, count=2): + def create_subnet_pools(attrs={}, count=2): """Create multiple fake subnet pools. :param Dictionary attrs: A dictionary with all attributes - :param Dictionary methods: - A dictionary with all methods :param int count: The number of subnet pools to fake :return: @@ -804,7 +704,7 @@ class FakeSubnetPool(object): subnet_pools = [] for i in range(0, count): subnet_pools.append( - FakeSubnetPool.create_one_subnet_pool(attrs, methods) + FakeSubnetPool.create_one_subnet_pool(attrs) ) return subnet_pools diff --git a/openstackclient/tests/network/v2/test_network.py b/openstackclient/tests/network/v2/test_network.py index 0dec0e2f..8a75101b 100644 --- a/openstackclient/tests/network/v2/test_network.py +++ b/openstackclient/tests/network/v2/test_network.py @@ -54,7 +54,9 @@ class TestCreateNetworkIdentityV3(TestNetwork): 'is_default', 'name', 'project_id', + 'provider_network_type', 'router_external', + 'shared', 'status', 'subnets', ) @@ -67,7 +69,9 @@ class TestCreateNetworkIdentityV3(TestNetwork): _network.is_default, _network.name, _network.project_id, + _network.provider_network_type, network._format_router_external(_network.router_external), + _network.shared, _network.status, utils.format_list(_network.subnets), ) @@ -219,7 +223,9 @@ class TestCreateNetworkIdentityV2(TestNetwork): 'is_default', 'name', 'project_id', + 'provider_network_type', 'router_external', + 'shared', 'status', 'subnets', ) @@ -232,7 +238,9 @@ class TestCreateNetworkIdentityV2(TestNetwork): _network.is_default, _network.name, _network.project_id, + _network.provider_network_type, network._format_router_external(_network.router_external), + _network.shared, _network.status, utils.format_list(_network.subnets), ) @@ -539,7 +547,9 @@ class TestShowNetwork(TestNetwork): 'is_default', 'name', 'project_id', + 'provider_network_type', 'router_external', + 'shared', 'status', 'subnets', ) @@ -552,7 +562,9 @@ class TestShowNetwork(TestNetwork): _network.is_default, _network.name, _network.project_id, + _network.provider_network_type, network._format_router_external(_network.router_external), + _network.shared, _network.status, utils.format_list(_network.subnets), ) diff --git a/openstackclient/tests/network/v2/test_router.py b/openstackclient/tests/network/v2/test_router.py index cf94bfd0..e8041498 100644 --- a/openstackclient/tests/network/v2/test_router.py +++ b/openstackclient/tests/network/v2/test_router.py @@ -117,19 +117,29 @@ class TestCreateRouter(TestRouter): columns = ( 'admin_state_up', + 'availability_zone_hints', + 'availability_zones', 'distributed', + 'external_gateway_info', 'ha', 'id', 'name', 'project_id', + 'routes', + 'status', ) data = ( router._format_admin_state(new_router.admin_state_up), + osc_utils.format_list(new_router.availability_zone_hints), + osc_utils.format_list(new_router.availability_zones), new_router.distributed, + router._format_external_gateway_info(new_router.external_gateway_info), new_router.ha, new_router.id, new_router.name, new_router.tenant_id, + new_router.routes, + new_router.status, ) def setUp(self): @@ -541,20 +551,29 @@ class TestShowRouter(TestRouter): columns = ( 'admin_state_up', + 'availability_zone_hints', + 'availability_zones', 'distributed', + 'external_gateway_info', 'ha', 'id', 'name', 'project_id', + 'routes', + 'status', ) - data = ( router._format_admin_state(_router.admin_state_up), + osc_utils.format_list(_router.availability_zone_hints), + osc_utils.format_list(_router.availability_zones), _router.distributed, + router._format_external_gateway_info(_router.external_gateway_info), _router.ha, _router.id, _router.name, - _router.project_id, + _router.tenant_id, + _router.routes, + _router.status, ) def setUp(self): diff --git a/openstackclient/tests/network/v2/test_subnet.py b/openstackclient/tests/network/v2/test_subnet.py index 2535bbe6..ede37416 100644 --- a/openstackclient/tests/network/v2/test_subnet.py +++ b/openstackclient/tests/network/v2/test_subnet.py @@ -536,6 +536,26 @@ class TestSetSubnet(TestSubnet): self.assertRaises(exceptions.CommandError, self.cmd.take_action, parsed_args) + def test_append_options(self): + _testsubnet = network_fakes.FakeSubnet.create_one_subnet( + {'dns_nameservers': ["10.0.0.1"]}) + self.network.find_subnet = mock.Mock(return_value=_testsubnet) + arglist = [ + '--dns-nameserver', '10.0.0.2', + _testsubnet.name, + ] + verifylist = [ + ('dns_nameservers', ['10.0.0.2']), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + result = self.cmd.take_action(parsed_args) + attrs = { + 'dns_nameservers': ['10.0.0.2', '10.0.0.1'], + } + self.network.update_subnet.assert_called_once_with( + _testsubnet, **attrs) + self.assertIsNone(result) + class TestShowSubnet(TestSubnet): # The subnets to be shown diff --git a/openstackclient/tests/network/v2/test_subnet_pool.py b/openstackclient/tests/network/v2/test_subnet_pool.py index 093e26c6..cbb32fc3 100644 --- a/openstackclient/tests/network/v2/test_subnet_pool.py +++ b/openstackclient/tests/network/v2/test_subnet_pool.py @@ -38,6 +38,8 @@ class TestCreateSubnetPool(TestSubnetPool): # The new subnet pool to create. _subnet_pool = network_fakes.FakeSubnetPool.create_one_subnet_pool() + _address_scope = network_fakes.FakeAddressScope.create_one_address_scope() + columns = ( 'address_scope_id', 'default_prefixlen', @@ -76,6 +78,9 @@ class TestCreateSubnetPool(TestSubnetPool): # Get the command object to test self.cmd = subnet_pool.CreateSubnetPool(self.app, self.namespace) + self.network.find_address_scope = mock.Mock( + return_value=self._address_scope) + # Set identity client. And get a shortcut to Identity client. identity_client = identity_fakes_v3.FakeIdentityv3Client( endpoint=fakes.AUTH_URL, @@ -193,6 +198,29 @@ class TestCreateSubnetPool(TestSubnetPool): self.assertEqual(self.columns, columns) self.assertEqual(self.data, data) + def test_create_address_scope_option(self): + arglist = [ + '--pool-prefix', '10.0.10.0/24', + '--address-scope', self._address_scope.id, + self._subnet_pool.name, + ] + verifylist = [ + ('prefixes', ['10.0.10.0/24']), + ('address_scope', self._address_scope.id), + ('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(**{ + 'prefixes': ['10.0.10.0/24'], + 'address_scope_id': self._address_scope.id, + 'name': self._subnet_pool.name, + }) + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + class TestDeleteSubnetPool(TestSubnetPool): @@ -246,7 +274,7 @@ class TestListSubnetPool(TestSubnetPool): data.append(( pool.id, pool.name, - pool.prefixes, + utils.format_list(pool.prefixes), )) data_long = [] @@ -254,7 +282,7 @@ class TestListSubnetPool(TestSubnetPool): data_long.append(( pool.id, pool.name, - pool.prefixes, + utils.format_list(pool.prefixes), pool.default_prefixlen, pool.address_scope_id, )) @@ -301,6 +329,8 @@ class TestSetSubnetPool(TestSubnetPool): # The subnet_pool to set. _subnet_pool = network_fakes.FakeSubnetPool.create_one_subnet_pool() + _address_scope = network_fakes.FakeAddressScope.create_one_address_scope() + def setUp(self): super(TestSetSubnetPool, self).setUp() @@ -309,21 +339,24 @@ class TestSetSubnetPool(TestSubnetPool): self.network.find_subnet_pool = mock.Mock( return_value=self._subnet_pool) + self.network.find_address_scope = mock.Mock( + return_value=self._address_scope) + # Get the command object to test self.cmd = subnet_pool.SetSubnetPool(self.app, self.namespace) def test_set_this(self): arglist = [ - self._subnet_pool.name, '--name', 'noob', '--default-prefix-length', '8', '--min-prefix-length', '8', + self._subnet_pool.name, ] verifylist = [ - ('subnet_pool', self._subnet_pool.name), ('name', 'noob'), ('default_prefix_length', '8'), ('min_prefix_length', '8'), + ('subnet_pool', self._subnet_pool.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -340,15 +373,15 @@ class TestSetSubnetPool(TestSubnetPool): def test_set_that(self): arglist = [ - self._subnet_pool.name, '--pool-prefix', '10.0.1.0/24', '--pool-prefix', '10.0.2.0/24', '--max-prefix-length', '16', + self._subnet_pool.name, ] verifylist = [ - ('subnet_pool', self._subnet_pool.name), ('prefixes', ['10.0.1.0/24', '10.0.2.0/24']), ('max_prefix_length', '16'), + ('subnet_pool', self._subnet_pool.name), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -374,17 +407,73 @@ class TestSetSubnetPool(TestSubnetPool): def test_set_len_negative(self): arglist = [ - self._subnet_pool.name, '--max-prefix-length', '-16', + self._subnet_pool.name, ] verifylist = [ - ('subnet_pool', self._subnet_pool.name), ('max_prefix_length', '-16'), + ('subnet_pool', self._subnet_pool.name), ] self.assertRaises(argparse.ArgumentTypeError, self.check_parser, self.cmd, arglist, verifylist) + def test_set_address_scope(self): + arglist = [ + '--address-scope', self._address_scope.id, + self._subnet_pool.name, + ] + verifylist = [ + ('address_scope', self._address_scope.id), + ('subnet_pool', self._subnet_pool.name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + attrs = { + 'address_scope_id': self._address_scope.id, + } + self.network.update_subnet_pool.assert_called_once_with( + self._subnet_pool, **attrs) + self.assertIsNone(result) + + def test_set_no_address_scope(self): + arglist = [ + '--no-address-scope', + self._subnet_pool.name, + ] + verifylist = [ + ('no_address_scope', True), + ('subnet_pool', self._subnet_pool.name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + attrs = { + 'address_scope_id': None, + } + self.network.update_subnet_pool.assert_called_once_with( + self._subnet_pool, **attrs) + self.assertIsNone(result) + + def test_set_no_address_scope_conflict(self): + arglist = [ + '--address-scope', self._address_scope.id, + '--no-address-scope', + self._subnet_pool.name, + ] + verifylist = [ + ('address_scope', self._address_scope.id), + ('no_address_scope', True), + ('subnet_pool', self._subnet_pool.name), + ] + + # Exclusive arguments will conflict here. + self.assertRaises(tests_utils.ParserException, self.check_parser, + self.cmd, arglist, verifylist) + class TestShowSubnetPool(TestSubnetPool): diff --git a/openstackclient/tests/volume/v2/fakes.py b/openstackclient/tests/volume/v2/fakes.py index 97bbc59b..3c238d10 100644 --- a/openstackclient/tests/volume/v2/fakes.py +++ b/openstackclient/tests/volume/v2/fakes.py @@ -243,6 +243,8 @@ class FakeVolumeClient(object): self.backups.resource_class = fakes.FakeResource(None, {}) self.volume_types = mock.Mock() self.volume_types.resource_class = fakes.FakeResource(None, {}) + self.volume_type_access = mock.Mock() + self.volume_type_access.resource_class = fakes.FakeResource(None, {}) self.restores = mock.Mock() self.restores.resource_class = fakes.FakeResource(None, {}) self.qos_specs = mock.Mock() diff --git a/openstackclient/tests/volume/v2/test_type.py b/openstackclient/tests/volume/v2/test_type.py index b014706b..448da432 100644 --- a/openstackclient/tests/volume/v2/test_type.py +++ b/openstackclient/tests/volume/v2/test_type.py @@ -15,6 +15,8 @@ import copy from openstackclient.tests import fakes +from openstackclient.tests.identity.v3 import fakes as identity_fakes +from openstackclient.tests import utils as tests_utils from openstackclient.tests.volume.v2 import fakes as volume_fakes from openstackclient.volume.v2 import volume_type @@ -41,6 +43,13 @@ class TestType(volume_fakes.TestVolume): self.types_mock = self.app.client_manager.volume.volume_types self.types_mock.reset_mock() + self.types_access_mock = ( + self.app.client_manager.volume.volume_type_access) + self.types_access_mock.reset_mock() + + self.projects_mock = self.app.client_manager.identity.projects + self.projects_mock.reset_mock() + class TestTypeCreate(TestType): @@ -211,6 +220,13 @@ class TestTypeSet(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.SetVolumeType(self.app, None) @@ -286,6 +302,56 @@ class TestTypeSet(TestType): self.assertIn('myprop', result) self.assertEqual('myvalue', result['myprop']) + def test_type_set_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.add_project_access.called) + + def test_type_set_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) + + def test_type_set_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.add_project_access.assert_called_with( + volume_fakes.type_id, + identity_fakes.project_id, + ) + class TestTypeShow(TestType): diff --git a/openstackclient/volume/v1/snapshot.py b/openstackclient/volume/v1/snapshot.py index c54bac8a..6c6131ea 100644 --- a/openstackclient/volume/v1/snapshot.py +++ b/openstackclient/volume/v1/snapshot.py @@ -249,7 +249,7 @@ class UnsetSnapshot(command.Command): action='append', default=[], help='Property to remove from snapshot ' - '(repeat to remove multiple values)', + '(repeat option to remove multiple properties)', required=True, ) return parser diff --git a/openstackclient/volume/v2/snapshot.py b/openstackclient/volume/v2/snapshot.py index c9e50297..f124a5e2 100644 --- a/openstackclient/volume/v2/snapshot.py +++ b/openstackclient/volume/v2/snapshot.py @@ -240,7 +240,7 @@ class UnsetSnapshot(command.Command): action='append', default=[], help='Property to remove from snapshot ' - '(repeat to remove multiple values)', + '(repeat option to remove multiple properties)', ) return parser diff --git a/openstackclient/volume/v2/volume.py b/openstackclient/volume/v2/volume.py index 5b7511e8..5a739f61 100644 --- a/openstackclient/volume/v2/volume.py +++ b/openstackclient/volume/v2/volume.py @@ -110,7 +110,7 @@ class CreateVolume(command.ShowOne): snapshot = None if parsed_args.snapshot: snapshot = utils.find_resource( - volume_client.snapshots, + volume_client.volume_snapshots, parsed_args.snapshot).id project = None diff --git a/openstackclient/volume/v2/volume_type.py b/openstackclient/volume/v2/volume_type.py index 5509ac52..203974da 100644 --- a/openstackclient/volume/v2/volume_type.py +++ b/openstackclient/volume/v2/volume_type.py @@ -17,8 +17,10 @@ import six from openstackclient.common import command +from openstackclient.common import exceptions from openstackclient.common import parseractions from openstackclient.common import utils +from openstackclient.identity import common as identity_common class CreateVolumeType(command.ShowOne): @@ -55,7 +57,7 @@ class CreateVolumeType(command.ShowOne): '--property', metavar='<key=value>', action=parseractions.KeyValueAction, - help='Set a property on this volume type' + help='Set a property on this volume type ' '(repeat option to set multiple properties)', ) return parser @@ -156,19 +158,30 @@ class SetVolumeType(command.Command): help='Set a property on this volume type ' '(repeat option to set multiple properties)', ) + parser.add_argument( + '--project', + metavar='<project>', + help='Set 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) if (not parsed_args.name and not parsed_args.description - and not parsed_args.property): + and not parsed_args.property + and not parsed_args.project): self.app.log.error("No changes requested\n") return + result = 0 kwargs = {} if parsed_args.name: kwargs['name'] = parsed_args.name @@ -176,13 +189,42 @@ class SetVolumeType(command.Command): kwargs['description'] = parsed_args.description if kwargs: - volume_client.volume_types.update( - volume_type.id, - **kwargs - ) + try: + volume_client.volume_types.update( + volume_type.id, + **kwargs + ) + except Exception as e: + self.app.log.error("Failed to update volume type name or" + " description: " + str(e)) + result += 1 if parsed_args.property: - volume_type.set_keys(parsed_args.property) + try: + volume_type.set_keys(parsed_args.property) + except Exception as e: + self.app.log.error("Failed to set 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.add_project_access( + volume_type.id, project_info.id) + except Exception as e: + self.app.log.error("Failed to set volume type access to" + " project: " + str(e)) + result += 1 + + if result > 0: + raise exceptions.CommandError("Command Failed: One or more of the" + " operations failed") class ShowVolumeType(command.ShowOne): |
