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
|
||||
|
||||
|
||||
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
|
||||
|
||||
_ephemeral = re.compile('^ephemeral(\d|[1-9]\d+)$')
|
||||
|
@ -1158,17 +1158,12 @@ class InstanceEngineNeutron(object):
|
||||
network_interface, multiple_instances):
|
||||
# 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,
|
||||
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,
|
||||
multiple_instances)
|
||||
|
||||
@ -1191,21 +1186,6 @@ class InstanceEngineNeutron(object):
|
||||
|
||||
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):
|
||||
if 'ec2_classic_nics' in launch_context:
|
||||
nics = launch_context['ec2_classic_nics']
|
||||
@ -1255,39 +1235,39 @@ class InstanceEngineNeutron(object):
|
||||
return ec2_network_interfaces
|
||||
|
||||
def merge_network_interface_parameters(self,
|
||||
context,
|
||||
security_group_names,
|
||||
subnet_id,
|
||||
private_ip_address,
|
||||
security_group_ids,
|
||||
network_interfaces):
|
||||
network_interfaces = network_interfaces or []
|
||||
|
||||
if ((subnet_id or private_ip_address or security_group_ids or
|
||||
security_group_names) and
|
||||
(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))):
|
||||
security_group_names) and network_interfaces):
|
||||
msg = _(' Network interfaces and an instance-level subnet ID or '
|
||||
'private IP address or security groups may not be '
|
||||
'specified on the same request')
|
||||
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:
|
||||
msg = _('The parameter groupName cannot be used with '
|
||||
'the parameter subnet')
|
||||
@ -1298,7 +1278,25 @@ class InstanceEngineNeutron(object):
|
||||
param['private_ip_address'] = private_ip_address
|
||||
if 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:
|
||||
msg = _('Specifying an IP address is only valid for VPC instances '
|
||||
'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')
|
||||
raise exception.InvalidParameterCombination(msg)
|
||||
else:
|
||||
# NOTE(ft): only one of this variables is not empty
|
||||
return network_interfaces
|
||||
return security_group_names, []
|
||||
|
||||
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):
|
||||
# NOTE(ft): we ignore associate_public_ip_address
|
||||
|
@ -20,7 +20,6 @@ import random
|
||||
|
||||
import mock
|
||||
from novaclient import exceptions as nova_exception
|
||||
from oslotest import base as test_base
|
||||
import six
|
||||
|
||||
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,
|
||||
|
||||
class InstancePrivateTestCase(test_base.BaseTestCase):
|
||||
class InstancePrivateTestCase(base.BaseTestCase):
|
||||
|
||||
def test_merge_network_interface_parameters(self):
|
||||
fake_context = base.create_context()
|
||||
engine = instance_api.InstanceEngineNeutron()
|
||||
|
||||
self.assertRaises(
|
||||
exception.InvalidParameterCombination,
|
||||
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'}])
|
||||
self.assertRaises(
|
||||
exception.InvalidParameterCombination,
|
||||
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'}])
|
||||
self.assertRaises(
|
||||
exception.InvalidParameterCombination,
|
||||
engine.merge_network_interface_parameters,
|
||||
['default'], None, None, None,
|
||||
fake_context, ['default'], None, None, None,
|
||||
[{'device_index': 0, 'subnet_id': 'subnet-1'}])
|
||||
self.assertRaises(
|
||||
exception.InvalidParameterCombination,
|
||||
engine.merge_network_interface_parameters,
|
||||
None, None, None, ['sg-1'],
|
||||
fake_context, None, None, None, ['sg-1'],
|
||||
[{'device_index': 0, 'subnet_id': 'subnet-1'}])
|
||||
self.assertRaises(
|
||||
exception.InvalidParameterCombination,
|
||||
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}])
|
||||
self.assertRaises(
|
||||
exception.InvalidParameterCombination,
|
||||
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': 1, 'subnet_id': 'subnet-2'}])
|
||||
self.assertRaises(
|
||||
exception.InvalidParameterCombination,
|
||||
engine.merge_network_interface_parameters,
|
||||
None, 'subnet-1', None, None,
|
||||
fake_context, None, 'subnet-1', None, None,
|
||||
[{'device_index': 0}])
|
||||
|
||||
self.assertRaises(
|
||||
exception.InvalidParameterCombination,
|
||||
engine.merge_network_interface_parameters,
|
||||
['default'], 'subnet-1', None, None, None)
|
||||
fake_context, ['default'], 'subnet-1', None, None, None)
|
||||
self.assertRaises(
|
||||
exception.InvalidParameterCombination,
|
||||
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(
|
||||
exception.InvalidParameterCombination,
|
||||
engine.merge_network_interface_parameters,
|
||||
None, None, None, ['sg-1'], None)
|
||||
fake_context, None, None, None, ['sg-1'], None)
|
||||
|
||||
self.assertEqual(
|
||||
([{'device_index': 0,
|
||||
(None, [{'device_index': 0,
|
||||
'subnet_id': 'subnet-1'}]),
|
||||
engine.merge_network_interface_parameters(
|
||||
None, 'subnet-1', None, None, None))
|
||||
fake_context, None, 'subnet-1', None, None, None))
|
||||
self.assertEqual(
|
||||
([{'device_index': 0,
|
||||
(None, [{'device_index': 0,
|
||||
'subnet_id': 'subnet-1',
|
||||
'private_ip_address': '10.10.10.10'}]),
|
||||
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(
|
||||
([{'device_index': 0,
|
||||
(None, [{'device_index': 0,
|
||||
'subnet_id': 'subnet-1',
|
||||
'private_ip_address': '10.10.10.10',
|
||||
'security_group_id': ['sg-1']}]),
|
||||
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(
|
||||
([{'device_index': 0,
|
||||
(None, [{'device_index': 0,
|
||||
'subnet_id': 'subnet-1',
|
||||
'security_group_id': ['sg-1']}]),
|
||||
engine.merge_network_interface_parameters(
|
||||
None, 'subnet-1', None, ['sg-1'], None))
|
||||
fake_context, None, 'subnet-1', None, ['sg-1'], None))
|
||||
|
||||
self.assertEqual(
|
||||
([{'device_index': 0,
|
||||
(None, [{'device_index': 0,
|
||||
'subnet_id': 'subnet-1'}]),
|
||||
engine.merge_network_interface_parameters(
|
||||
None, None, None, None,
|
||||
fake_context, None, None, None, None,
|
||||
[{'device_index': 0, 'subnet_id': 'subnet-1'}]))
|
||||
self.assertEqual([],
|
||||
self.assertEqual((['default'], []),
|
||||
engine.merge_network_interface_parameters(
|
||||
['default'], None, None, None, None))
|
||||
self.assertEqual([],
|
||||
fake_context, ['default'], None, None, None,
|
||||
None))
|
||||
self.assertEqual((None, []),
|
||||
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):
|
||||
engine = instance_api.InstanceEngineNeutron()
|
||||
|
Loading…
Reference in New Issue
Block a user