Determine ip version during subnet create.
Currently, the default IP version for a subnet-create is IPv4. This behavior is wrong when we use a IPv6 subnetpool and do not specify the ip version explicitly during the subnet create operation. This fix proposes to make the neutron client code for subnet creation become aware of the subnetpool version. This ensures that the proper IP version is sent down to the neutron server if the subnet create is requested with a subnetpool. Co-Authored-By: Akihiro Motoki <amotoki@gmail.com> Change-Id: I13da0f204e8ce335a2082c7d829bee28ac567c3f Closes-bug: 1444146
This commit is contained in:
parent
52721a8e93
commit
043656c8f8
|
@ -46,8 +46,8 @@ def _get_resource_plural(resource, client):
|
|||
return resource + 's'
|
||||
|
||||
|
||||
def find_resourceid_by_id(client, resource, resource_id, cmd_resource=None,
|
||||
parent_id=None):
|
||||
def find_resource_by_id(client, resource, resource_id, cmd_resource=None,
|
||||
parent_id=None, fields=None):
|
||||
if not cmd_resource:
|
||||
cmd_resource = resource
|
||||
cmd_resource_plural = _get_resource_plural(cmd_resource, client)
|
||||
|
@ -57,12 +57,15 @@ def find_resourceid_by_id(client, resource, resource_id, cmd_resource=None,
|
|||
match = re.match(UUID_PATTERN, resource_id)
|
||||
collection = resource_plural
|
||||
if match:
|
||||
params = {'id': resource_id}
|
||||
if fields:
|
||||
params['fields'] = fields
|
||||
if parent_id:
|
||||
data = obj_lister(parent_id, id=resource_id, fields='id')
|
||||
data = obj_lister(parent_id, **params)
|
||||
else:
|
||||
data = obj_lister(id=resource_id, fields='id')
|
||||
data = obj_lister(**params)
|
||||
if data and data[collection]:
|
||||
return data[collection][0]['id']
|
||||
return data[collection][0]
|
||||
not_found_message = (_("Unable to find %(resource)s with id "
|
||||
"'%(id)s'") %
|
||||
{'resource': resource, 'id': resource_id})
|
||||
|
@ -71,14 +74,23 @@ def find_resourceid_by_id(client, resource, resource_id, cmd_resource=None,
|
|||
message=not_found_message, status_code=404)
|
||||
|
||||
|
||||
def _find_resourceid_by_name(client, resource, name, project_id=None,
|
||||
cmd_resource=None, parent_id=None):
|
||||
def find_resourceid_by_id(client, resource, resource_id, cmd_resource=None,
|
||||
parent_id=None):
|
||||
info = find_resource_by_id(client, resource, resource_id, cmd_resource,
|
||||
parent_id, fields='id')
|
||||
return info['id']
|
||||
|
||||
|
||||
def _find_resource_by_name(client, resource, name, project_id=None,
|
||||
cmd_resource=None, parent_id=None, fields=None):
|
||||
if not cmd_resource:
|
||||
cmd_resource = resource
|
||||
cmd_resource_plural = _get_resource_plural(cmd_resource, client)
|
||||
resource_plural = _get_resource_plural(resource, client)
|
||||
obj_lister = getattr(client, "list_%s" % cmd_resource_plural)
|
||||
params = {'name': name, 'fields': 'id'}
|
||||
params = {'name': name}
|
||||
if fields:
|
||||
params['fields'] = fields
|
||||
if project_id:
|
||||
params['tenant_id'] = project_id
|
||||
if parent_id:
|
||||
|
@ -98,18 +110,27 @@ def _find_resourceid_by_name(client, resource, name, project_id=None,
|
|||
raise exceptions.NeutronClientException(
|
||||
message=not_found_message, status_code=404)
|
||||
else:
|
||||
return info[0]['id']
|
||||
return info[0]
|
||||
|
||||
|
||||
def find_resource_by_name_or_id(client, resource, name_or_id,
|
||||
project_id=None, cmd_resource=None,
|
||||
parent_id=None, fields=None):
|
||||
try:
|
||||
return find_resource_by_id(client, resource, name_or_id,
|
||||
cmd_resource, parent_id, fields)
|
||||
except exceptions.NeutronClientException:
|
||||
return _find_resource_by_name(client, resource, name_or_id,
|
||||
project_id, cmd_resource, parent_id,
|
||||
fields)
|
||||
|
||||
|
||||
def find_resourceid_by_name_or_id(client, resource, name_or_id,
|
||||
project_id=None, cmd_resource=None,
|
||||
parent_id=None):
|
||||
try:
|
||||
return find_resourceid_by_id(client, resource, name_or_id,
|
||||
cmd_resource, parent_id)
|
||||
except exceptions.NeutronClientException:
|
||||
return _find_resourceid_by_name(client, resource, name_or_id,
|
||||
project_id, cmd_resource, parent_id)
|
||||
return find_resource_by_name_or_id(client, resource, name_or_id,
|
||||
project_id, cmd_resource,
|
||||
parent_id, fields='id')['id']
|
||||
|
||||
|
||||
def add_show_list_common_argument(parser):
|
||||
|
|
|
@ -165,7 +165,10 @@ class CreateSubnet(neutronV20.CreateCommand):
|
|||
'--ip-version',
|
||||
type=int,
|
||||
default=4, choices=[4, 6],
|
||||
help=_('IP version to use, default is 4.'))
|
||||
help=_('IP version to use, default is 4. '
|
||||
'Note that when subnetpool is specified, '
|
||||
'IP version is determined from the subnetpool '
|
||||
'and this option is ignored.'))
|
||||
parser.add_argument(
|
||||
'--ip_version',
|
||||
type=int,
|
||||
|
@ -196,8 +199,25 @@ class CreateSubnet(neutronV20.CreateCommand):
|
|||
def args2body(self, parsed_args):
|
||||
_network_id = neutronV20.find_resourceid_by_name_or_id(
|
||||
self.get_client(), 'network', parsed_args.network_id)
|
||||
body = {'subnet': {'network_id': _network_id,
|
||||
'ip_version': parsed_args.ip_version, }, }
|
||||
body = {'subnet': {'network_id': _network_id}}
|
||||
|
||||
if parsed_args.prefixlen:
|
||||
body['subnet'].update({'prefixlen': parsed_args.prefixlen})
|
||||
if parsed_args.subnetpool:
|
||||
if parsed_args.subnetpool == 'None':
|
||||
_subnetpool_id = None
|
||||
else:
|
||||
_subnetpool = neutronV20.find_resource_by_name_or_id(
|
||||
self.get_client(), 'subnetpool', parsed_args.subnetpool)
|
||||
_subnetpool_id = _subnetpool['id']
|
||||
# Now that we have the pool_id - let's just have a check on the
|
||||
# ip version used in the pool
|
||||
parsed_args.ip_version = _subnetpool['ip_version']
|
||||
body['subnet'].update({'subnetpool_id': _subnetpool_id})
|
||||
|
||||
# IP version needs to be set as IP version can be
|
||||
# determined by subnetpool.
|
||||
body['subnet']['ip_version'] = parsed_args.ip_version
|
||||
|
||||
if parsed_args.cidr:
|
||||
# With subnetpool, cidr is now optional for creating subnet.
|
||||
|
@ -212,16 +232,6 @@ class CreateSubnet(neutronV20.CreateCommand):
|
|||
% {"ip": parsed_args.ip_version,
|
||||
"cidr": unusable_cidr})
|
||||
|
||||
if parsed_args.prefixlen:
|
||||
body['subnet'].update({'prefixlen': parsed_args.prefixlen})
|
||||
if parsed_args.subnetpool:
|
||||
if parsed_args.subnetpool == 'None':
|
||||
_subnetpool_id = None
|
||||
else:
|
||||
_subnetpool_id = neutronV20.find_resourceid_by_name_or_id(
|
||||
self.get_client(), 'subnetpool', parsed_args.subnetpool)
|
||||
body['subnet'].update({'subnetpool_id': _subnetpool_id})
|
||||
|
||||
updatable_args2body(parsed_args, body)
|
||||
if parsed_args.tenant_id:
|
||||
body['subnet'].update({'tenant_id': parsed_args.tenant_id})
|
||||
|
|
|
@ -19,6 +19,7 @@ import sys
|
|||
from mox3 import mox
|
||||
|
||||
from neutronclient.common import exceptions
|
||||
from neutronclient.neutron import v2_0 as neutronV20
|
||||
from neutronclient.neutron.v2_0 import subnet
|
||||
from neutronclient.tests.unit import test_cli20
|
||||
|
||||
|
@ -484,6 +485,28 @@ class CLITestV20SubnetJSON(test_cli20.CLITestV20Base):
|
|||
position_values, tenant_id='tenantid',
|
||||
no_api_call=True, expected_exception=exceptions.CommandError)
|
||||
|
||||
def test_create_subnet_with_subnetpool_ipv6_and_ip_ver_ignored(self):
|
||||
resource = 'subnet'
|
||||
cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None)
|
||||
name = 'myname'
|
||||
myid = 'myid'
|
||||
netid = 'netid'
|
||||
args = ['--tenant_id', 'tenantid',
|
||||
'--ip-version', '4',
|
||||
'--subnetpool', 'subnetpool_id',
|
||||
netid]
|
||||
position_names = ['ip_version', 'network_id', 'subnetpool_id']
|
||||
position_values = [6, netid, 'subnetpool_id']
|
||||
self.mox.StubOutWithMock(neutronV20, 'find_resource_by_name_or_id')
|
||||
neutronV20.find_resource_by_name_or_id(
|
||||
self.client,
|
||||
'subnetpool',
|
||||
'subnetpool_id').AndReturn({'id': 'subnetpool_id',
|
||||
'ip_version': 6})
|
||||
self._test_create_resource(
|
||||
resource, cmd, name, myid, args, position_names,
|
||||
position_values, tenant_id='tenantid')
|
||||
|
||||
def test_create_subnet_with_subnetpool_ipv4_with_cidr_wildcard(self):
|
||||
resource = 'subnet'
|
||||
cmd = subnet.CreateSubnet(test_cli20.MyApp(sys.stdout), None)
|
||||
|
@ -499,6 +522,12 @@ class CLITestV20SubnetJSON(test_cli20.CLITestV20Base):
|
|||
position_names = ['ip_version', 'ipv6_address_mode',
|
||||
'network_id', 'subnetpool_id', 'cidr']
|
||||
position_values = [4, None, netid, 'subnetpool_id', cidr]
|
||||
self.mox.StubOutWithMock(neutronV20, 'find_resource_by_name_or_id')
|
||||
neutronV20.find_resource_by_name_or_id(
|
||||
self.client,
|
||||
'subnetpool',
|
||||
'subnetpool_id').AndReturn({'id': 'subnetpool_id',
|
||||
'ip_version': 4})
|
||||
self._test_create_resource(
|
||||
resource, cmd, name, myid, args, position_names,
|
||||
position_values, tenant_id='tenantid',
|
||||
|
@ -519,6 +548,12 @@ class CLITestV20SubnetJSON(test_cli20.CLITestV20Base):
|
|||
position_names = ['ip_version', 'ipv6_address_mode',
|
||||
'network_id', 'subnetpool_id']
|
||||
position_values = [4, None, netid, 'subnetpool_id']
|
||||
self.mox.StubOutWithMock(neutronV20, 'find_resource_by_name_or_id')
|
||||
neutronV20.find_resource_by_name_or_id(
|
||||
self.client,
|
||||
'subnetpool',
|
||||
'subnetpool_id').AndReturn({'id': 'subnetpool_id',
|
||||
'ip_version': 4})
|
||||
self._test_create_resource(
|
||||
resource, cmd, name, myid, args, position_names,
|
||||
position_values, tenant_id='tenantid',
|
||||
|
|
Loading…
Reference in New Issue