add instance in default-vpc by security-group-name
or private-ip-address add unit test Change-Id: Iff5421ca84d5d5f6c2f87c9aed636ead6aadef2f
This commit is contained in:
parent
ead353712e
commit
df67b88930
@ -494,6 +494,14 @@ def set_check_and_create_default_vpc(check_and_create_default_vpc):
|
|||||||
_check_and_create_default_vpc = check_and_create_default_vpc
|
_check_and_create_default_vpc = check_and_create_default_vpc
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_vpc(context):
|
||||||
|
check_and_create_default_vpc(context)
|
||||||
|
default_vpc = next((vpc for vpc in db_api.get_items(context, 'vpc')
|
||||||
|
if vpc.get('is_default')), None)
|
||||||
|
if not default_vpc:
|
||||||
|
raise exception.VPCIdNotSpecified()
|
||||||
|
return default_vpc
|
||||||
|
|
||||||
# NOTE(ft): following functions are copied from various parts of Nova
|
# NOTE(ft): following functions are copied from various parts of Nova
|
||||||
|
|
||||||
_ephemeral = re.compile('^ephemeral(\d|[1-9]\d+)$')
|
_ephemeral = re.compile('^ephemeral(\d|[1-9]\d+)$')
|
||||||
|
@ -1158,17 +1158,12 @@ class InstanceEngineNeutron(object):
|
|||||||
network_interface, multiple_instances):
|
network_interface, multiple_instances):
|
||||||
# TODO(ft): support auto_assign_floating_ip
|
# TODO(ft): support auto_assign_floating_ip
|
||||||
|
|
||||||
vpc_network_parameters = self.merge_network_interface_parameters(
|
(security_group,
|
||||||
security_group,
|
vpc_network_parameters) = self.merge_network_interface_parameters(
|
||||||
|
context, security_group,
|
||||||
subnet_id, private_ip_address, security_group_id,
|
subnet_id, private_ip_address, security_group_id,
|
||||||
network_interface)
|
network_interface)
|
||||||
|
|
||||||
if not vpc_network_parameters and CONF.disable_ec2_classic:
|
|
||||||
ec2utils.check_and_create_default_vpc(context)
|
|
||||||
subnet_id = self.get_default_subnet(context)
|
|
||||||
vpc_network_parameters = [{'device_index': 0,
|
|
||||||
'subnet_id': subnet_id}]
|
|
||||||
|
|
||||||
self.check_network_interface_parameters(vpc_network_parameters,
|
self.check_network_interface_parameters(vpc_network_parameters,
|
||||||
multiple_instances)
|
multiple_instances)
|
||||||
|
|
||||||
@ -1191,21 +1186,6 @@ class InstanceEngineNeutron(object):
|
|||||||
|
|
||||||
return vpc_id, launch_context
|
return vpc_id, launch_context
|
||||||
|
|
||||||
def get_default_subnet(self, context):
|
|
||||||
default_vpc = next(
|
|
||||||
(vpc for vpc in db_api.get_items(context, 'vpc')
|
|
||||||
if vpc.get('is_default')), None)
|
|
||||||
if not default_vpc:
|
|
||||||
raise exception.VPCIdNotSpecified()
|
|
||||||
subnet = next(
|
|
||||||
(subnet for subnet in db_api.get_items(context, 'subnet')
|
|
||||||
if subnet['vpc_id'] == default_vpc['id']), None)
|
|
||||||
if not subnet:
|
|
||||||
raise exception.MissingInput(
|
|
||||||
_("No subnets found for the default VPC '%s'. "
|
|
||||||
"Please specify a subnet.") % default_vpc['id'])
|
|
||||||
return subnet['id']
|
|
||||||
|
|
||||||
def get_launch_extra_parameters(self, context, cleaner, launch_context):
|
def get_launch_extra_parameters(self, context, cleaner, launch_context):
|
||||||
if 'ec2_classic_nics' in launch_context:
|
if 'ec2_classic_nics' in launch_context:
|
||||||
nics = launch_context['ec2_classic_nics']
|
nics = launch_context['ec2_classic_nics']
|
||||||
@ -1255,39 +1235,39 @@ class InstanceEngineNeutron(object):
|
|||||||
return ec2_network_interfaces
|
return ec2_network_interfaces
|
||||||
|
|
||||||
def merge_network_interface_parameters(self,
|
def merge_network_interface_parameters(self,
|
||||||
|
context,
|
||||||
security_group_names,
|
security_group_names,
|
||||||
subnet_id,
|
subnet_id,
|
||||||
private_ip_address,
|
private_ip_address,
|
||||||
security_group_ids,
|
security_group_ids,
|
||||||
network_interfaces):
|
network_interfaces):
|
||||||
network_interfaces = network_interfaces or []
|
|
||||||
|
|
||||||
if ((subnet_id or private_ip_address or security_group_ids or
|
if ((subnet_id or private_ip_address or security_group_ids or
|
||||||
security_group_names) and
|
security_group_names) and network_interfaces):
|
||||||
(len(network_interfaces) > 1 or
|
|
||||||
# NOTE(ft): the only case in AWS when simple subnet_id
|
|
||||||
# and/or private_ip_address parameters are compatible with
|
|
||||||
# network_interface parameter is default behavior change of
|
|
||||||
# public IP association for passed subnet_id by specifying
|
|
||||||
# the only element in network_interfaces:
|
|
||||||
# {"device_index": 0,
|
|
||||||
# "associate_public_ip_address": <boolean>}
|
|
||||||
# Both keys must be in the dict, and no other keys
|
|
||||||
# are allowed
|
|
||||||
# We should support such combination of parameters for
|
|
||||||
# compatibility purposes, even if we ignore
|
|
||||||
# associate_public_ip_address in all other code
|
|
||||||
len(network_interfaces) == 1 and
|
|
||||||
(len(network_interfaces[0]) != 2 or
|
|
||||||
('associate_public_ip_address' not in
|
|
||||||
network_interfaces[0]) or
|
|
||||||
network_interfaces[0].get('device_index') != 0))):
|
|
||||||
msg = _(' Network interfaces and an instance-level subnet ID or '
|
msg = _(' Network interfaces and an instance-level subnet ID or '
|
||||||
'private IP address or security groups may not be '
|
'private IP address or security groups may not be '
|
||||||
'specified on the same request')
|
'specified on the same request')
|
||||||
raise exception.InvalidParameterCombination(msg)
|
raise exception.InvalidParameterCombination(msg)
|
||||||
|
|
||||||
if subnet_id:
|
if network_interfaces:
|
||||||
|
if (CONF.disable_ec2_classic and
|
||||||
|
len(network_interfaces) == 1 and
|
||||||
|
# NOTE(tikitavi): the case in AWS CLI when security_group_ids
|
||||||
|
# and/or private_ip_address parameters are set with
|
||||||
|
# network_interface parameter having
|
||||||
|
# associate_public_ip_address setting
|
||||||
|
# private_ip_address and security_group_ids in that case
|
||||||
|
# go to network_interface parameter
|
||||||
|
'associate_public_ip_address' in network_interfaces[0] and
|
||||||
|
'device_index' in network_interfaces[0] and
|
||||||
|
network_interfaces[0]['device_index'] == 0 and
|
||||||
|
('subnet_id' not in network_interfaces[0] or
|
||||||
|
'network_interface_id' not in network_interfaces[0])):
|
||||||
|
|
||||||
|
subnet_id = self.get_default_subnet(context)['id']
|
||||||
|
network_interfaces[0]['subnet_id'] = subnet_id
|
||||||
|
return None, network_interfaces
|
||||||
|
elif subnet_id:
|
||||||
if security_group_names:
|
if security_group_names:
|
||||||
msg = _('The parameter groupName cannot be used with '
|
msg = _('The parameter groupName cannot be used with '
|
||||||
'the parameter subnet')
|
'the parameter subnet')
|
||||||
@ -1298,7 +1278,25 @@ class InstanceEngineNeutron(object):
|
|||||||
param['private_ip_address'] = private_ip_address
|
param['private_ip_address'] = private_ip_address
|
||||||
if security_group_ids:
|
if security_group_ids:
|
||||||
param['security_group_id'] = security_group_ids
|
param['security_group_id'] = security_group_ids
|
||||||
return [param]
|
return None, [param]
|
||||||
|
elif CONF.disable_ec2_classic:
|
||||||
|
subnet_id = self.get_default_subnet(context)['id']
|
||||||
|
param = {'device_index': 0,
|
||||||
|
'subnet_id': subnet_id}
|
||||||
|
if security_group_ids or security_group_names:
|
||||||
|
security_group_id = security_group_ids or []
|
||||||
|
if security_group_names:
|
||||||
|
security_groups = (
|
||||||
|
security_group_api.describe_security_groups(
|
||||||
|
context, group_name=security_group_names)
|
||||||
|
['securityGroupInfo'])
|
||||||
|
security_group_id.extend(sg['groupId']
|
||||||
|
for sg in security_groups)
|
||||||
|
|
||||||
|
param['security_group_id'] = security_group_id
|
||||||
|
if private_ip_address:
|
||||||
|
param['private_ip_address'] = private_ip_address
|
||||||
|
return None, [param]
|
||||||
elif private_ip_address:
|
elif private_ip_address:
|
||||||
msg = _('Specifying an IP address is only valid for VPC instances '
|
msg = _('Specifying an IP address is only valid for VPC instances '
|
||||||
'and thus requires a subnet in which to launch')
|
'and thus requires a subnet in which to launch')
|
||||||
@ -1307,8 +1305,18 @@ class InstanceEngineNeutron(object):
|
|||||||
msg = _('VPC security groups may not be used for a non-VPC launch')
|
msg = _('VPC security groups may not be used for a non-VPC launch')
|
||||||
raise exception.InvalidParameterCombination(msg)
|
raise exception.InvalidParameterCombination(msg)
|
||||||
else:
|
else:
|
||||||
# NOTE(ft): only one of this variables is not empty
|
return security_group_names, []
|
||||||
return network_interfaces
|
|
||||||
|
def get_default_subnet(self, context):
|
||||||
|
default_vpc = ec2utils.get_default_vpc(context)
|
||||||
|
subnet = next(
|
||||||
|
(subnet for subnet in db_api.get_items(context, 'subnet')
|
||||||
|
if subnet['vpc_id'] == default_vpc['id']), None)
|
||||||
|
if not subnet:
|
||||||
|
raise exception.MissingInput(
|
||||||
|
_("No subnets found for the default VPC '%s'. "
|
||||||
|
"Please specify a subnet.") % default_vpc['id'])
|
||||||
|
return subnet
|
||||||
|
|
||||||
def check_network_interface_parameters(self, params, multiple_instances):
|
def check_network_interface_parameters(self, params, multiple_instances):
|
||||||
# NOTE(ft): we ignore associate_public_ip_address
|
# NOTE(ft): we ignore associate_public_ip_address
|
||||||
|
@ -20,7 +20,6 @@ import random
|
|||||||
|
|
||||||
import mock
|
import mock
|
||||||
from novaclient import exceptions as nova_exception
|
from novaclient import exceptions as nova_exception
|
||||||
from oslotest import base as test_base
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from ec2api.api import instance as instance_api
|
from ec2api.api import instance as instance_api
|
||||||
@ -1169,98 +1168,138 @@ class InstanceTestCase(base.ApiTestCase):
|
|||||||
|
|
||||||
# TODO(ft): add tests for get_vpc_default_security_group_id,
|
# TODO(ft): add tests for get_vpc_default_security_group_id,
|
||||||
|
|
||||||
class InstancePrivateTestCase(test_base.BaseTestCase):
|
class InstancePrivateTestCase(base.BaseTestCase):
|
||||||
|
|
||||||
def test_merge_network_interface_parameters(self):
|
def test_merge_network_interface_parameters(self):
|
||||||
|
fake_context = base.create_context()
|
||||||
engine = instance_api.InstanceEngineNeutron()
|
engine = instance_api.InstanceEngineNeutron()
|
||||||
|
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exception.InvalidParameterCombination,
|
exception.InvalidParameterCombination,
|
||||||
engine.merge_network_interface_parameters,
|
engine.merge_network_interface_parameters,
|
||||||
None, 'subnet-1', None, None,
|
fake_context, None, 'subnet-1', None, None,
|
||||||
[{'device_index': 0, 'private_ip_address': '10.10.10.10'}])
|
[{'device_index': 0, 'private_ip_address': '10.10.10.10'}])
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exception.InvalidParameterCombination,
|
exception.InvalidParameterCombination,
|
||||||
engine.merge_network_interface_parameters,
|
engine.merge_network_interface_parameters,
|
||||||
None, None, '10.10.10.10', None,
|
fake_context, None, None, '10.10.10.10', None,
|
||||||
[{'device_index': 0, 'subnet_id': 'subnet-1'}])
|
[{'device_index': 0, 'subnet_id': 'subnet-1'}])
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exception.InvalidParameterCombination,
|
exception.InvalidParameterCombination,
|
||||||
engine.merge_network_interface_parameters,
|
engine.merge_network_interface_parameters,
|
||||||
['default'], None, None, None,
|
fake_context, ['default'], None, None, None,
|
||||||
[{'device_index': 0, 'subnet_id': 'subnet-1'}])
|
[{'device_index': 0, 'subnet_id': 'subnet-1'}])
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exception.InvalidParameterCombination,
|
exception.InvalidParameterCombination,
|
||||||
engine.merge_network_interface_parameters,
|
engine.merge_network_interface_parameters,
|
||||||
None, None, None, ['sg-1'],
|
fake_context, None, None, None, ['sg-1'],
|
||||||
[{'device_index': 0, 'subnet_id': 'subnet-1'}])
|
[{'device_index': 0, 'subnet_id': 'subnet-1'}])
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exception.InvalidParameterCombination,
|
exception.InvalidParameterCombination,
|
||||||
engine.merge_network_interface_parameters,
|
engine.merge_network_interface_parameters,
|
||||||
None, 'subnet-1', None, None,
|
fake_context, None, 'subnet-1', None, None,
|
||||||
[{'device_index': 1, 'associate_public_ip_address': True}])
|
[{'device_index': 1, 'associate_public_ip_address': True}])
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exception.InvalidParameterCombination,
|
exception.InvalidParameterCombination,
|
||||||
engine.merge_network_interface_parameters,
|
engine.merge_network_interface_parameters,
|
||||||
None, 'subnet-1', None, None,
|
fake_context, None, 'subnet-1', None, None,
|
||||||
[{'device_index': 0, 'associate_public_ip_address': True},
|
[{'device_index': 0, 'associate_public_ip_address': True},
|
||||||
{'device_index': 1, 'subnet_id': 'subnet-2'}])
|
{'device_index': 1, 'subnet_id': 'subnet-2'}])
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exception.InvalidParameterCombination,
|
exception.InvalidParameterCombination,
|
||||||
engine.merge_network_interface_parameters,
|
engine.merge_network_interface_parameters,
|
||||||
None, 'subnet-1', None, None,
|
fake_context, None, 'subnet-1', None, None,
|
||||||
[{'device_index': 0}])
|
[{'device_index': 0}])
|
||||||
|
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exception.InvalidParameterCombination,
|
exception.InvalidParameterCombination,
|
||||||
engine.merge_network_interface_parameters,
|
engine.merge_network_interface_parameters,
|
||||||
['default'], 'subnet-1', None, None, None)
|
fake_context, ['default'], 'subnet-1', None, None, None)
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exception.InvalidParameterCombination,
|
exception.InvalidParameterCombination,
|
||||||
engine.merge_network_interface_parameters,
|
engine.merge_network_interface_parameters,
|
||||||
None, None, '10.10.10.10', None, None)
|
fake_context, None, None, '10.10.10.10', None, None)
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exception.InvalidParameterCombination,
|
exception.InvalidParameterCombination,
|
||||||
engine.merge_network_interface_parameters,
|
engine.merge_network_interface_parameters,
|
||||||
None, None, None, ['sg-1'], None)
|
fake_context, None, None, None, ['sg-1'], None)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
([{'device_index': 0,
|
(None, [{'device_index': 0,
|
||||||
'subnet_id': 'subnet-1'}]),
|
'subnet_id': 'subnet-1'}]),
|
||||||
engine.merge_network_interface_parameters(
|
engine.merge_network_interface_parameters(
|
||||||
None, 'subnet-1', None, None, None))
|
fake_context, None, 'subnet-1', None, None, None))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
([{'device_index': 0,
|
(None, [{'device_index': 0,
|
||||||
'subnet_id': 'subnet-1',
|
'subnet_id': 'subnet-1',
|
||||||
'private_ip_address': '10.10.10.10'}]),
|
'private_ip_address': '10.10.10.10'}]),
|
||||||
engine.merge_network_interface_parameters(
|
engine.merge_network_interface_parameters(
|
||||||
None, 'subnet-1', '10.10.10.10', None, None))
|
fake_context, None, 'subnet-1', '10.10.10.10', None, None))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
([{'device_index': 0,
|
(None, [{'device_index': 0,
|
||||||
'subnet_id': 'subnet-1',
|
'subnet_id': 'subnet-1',
|
||||||
'private_ip_address': '10.10.10.10',
|
'private_ip_address': '10.10.10.10',
|
||||||
'security_group_id': ['sg-1']}]),
|
'security_group_id': ['sg-1']}]),
|
||||||
engine.merge_network_interface_parameters(
|
engine.merge_network_interface_parameters(
|
||||||
None, 'subnet-1', '10.10.10.10', ['sg-1'], None))
|
fake_context, None, 'subnet-1', '10.10.10.10', ['sg-1'], None))
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
([{'device_index': 0,
|
(None, [{'device_index': 0,
|
||||||
'subnet_id': 'subnet-1',
|
'subnet_id': 'subnet-1',
|
||||||
'security_group_id': ['sg-1']}]),
|
'security_group_id': ['sg-1']}]),
|
||||||
engine.merge_network_interface_parameters(
|
engine.merge_network_interface_parameters(
|
||||||
None, 'subnet-1', None, ['sg-1'], None))
|
fake_context, None, 'subnet-1', None, ['sg-1'], None))
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
([{'device_index': 0,
|
(None, [{'device_index': 0,
|
||||||
'subnet_id': 'subnet-1'}]),
|
'subnet_id': 'subnet-1'}]),
|
||||||
engine.merge_network_interface_parameters(
|
engine.merge_network_interface_parameters(
|
||||||
None, None, None, None,
|
fake_context, None, None, None, None,
|
||||||
[{'device_index': 0, 'subnet_id': 'subnet-1'}]))
|
[{'device_index': 0, 'subnet_id': 'subnet-1'}]))
|
||||||
self.assertEqual([],
|
self.assertEqual((['default'], []),
|
||||||
engine.merge_network_interface_parameters(
|
engine.merge_network_interface_parameters(
|
||||||
['default'], None, None, None, None))
|
fake_context, ['default'], None, None, None,
|
||||||
self.assertEqual([],
|
None))
|
||||||
|
self.assertEqual((None, []),
|
||||||
engine.merge_network_interface_parameters(
|
engine.merge_network_interface_parameters(
|
||||||
None, None, None, None, None))
|
fake_context, None, None, None, None, None))
|
||||||
|
|
||||||
|
self.configure(disable_ec2_classic=True)
|
||||||
|
self.db_api = self.mock_db()
|
||||||
|
self.db_api.set_mock_items(fakes.DB_VPC_DEFAULT,
|
||||||
|
fakes.DB_SUBNET_DEFAULT)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
(None, [{'device_index': 0,
|
||||||
|
'subnet_id': fakes.ID_EC2_SUBNET_DEFAULT}]),
|
||||||
|
engine.merge_network_interface_parameters(
|
||||||
|
fake_context, None, None, None, None, None))
|
||||||
|
self.assertEqual(
|
||||||
|
(None, [{'device_index': 0,
|
||||||
|
'subnet_id': fakes.ID_EC2_SUBNET_DEFAULT,
|
||||||
|
'security_group_id': ['sg-id'],
|
||||||
|
'associate_public_ip_address': True}]),
|
||||||
|
engine.merge_network_interface_parameters(
|
||||||
|
fake_context, None, None, None, None,
|
||||||
|
[{'device_index': 0,
|
||||||
|
'associate_public_ip_address': True,
|
||||||
|
'security_group_id': ['sg-id']}]))
|
||||||
|
|
||||||
|
with mock.patch('ec2api.api.security_group.describe_security_groups'
|
||||||
|
) as describe_sg:
|
||||||
|
|
||||||
|
describe_sg.return_value = {
|
||||||
|
'securityGroupInfo': [{'groupId': 'sg-named-id'}]
|
||||||
|
}
|
||||||
|
self.assertEqual((None, [{'device_index': 0,
|
||||||
|
'subnet_id': fakes.ID_EC2_SUBNET_DEFAULT,
|
||||||
|
'security_group_id': ['sg-id',
|
||||||
|
'sg-named-id'],
|
||||||
|
'private_ip_address': 'private-ip'}]),
|
||||||
|
engine.merge_network_interface_parameters(
|
||||||
|
fake_context, ['sg-name'], None,
|
||||||
|
'private-ip', ['sg-id'], None))
|
||||||
|
describe_sg.assert_called_once_with(mock.ANY,
|
||||||
|
group_name=['sg-name'])
|
||||||
|
|
||||||
def test_check_network_interface_parameters(self):
|
def test_check_network_interface_parameters(self):
|
||||||
engine = instance_api.InstanceEngineNeutron()
|
engine = instance_api.InstanceEngineNeutron()
|
||||||
|
Loading…
Reference in New Issue
Block a user