Fixes in security_groups.
Fixed exception for orphan "vpc-..."-named groups in describe. Added check for not deleting default VPC group. Added check for not deleting VPC if non-default groups exist. Added check for not allowing creation of groups with existing names. Change-Id: Ia205ff65409577d148c08b40a297d521d8a8acb1
This commit is contained in:
parent
46edb3ccd1
commit
5332325708
@ -59,6 +59,15 @@ def get_security_group_engine():
|
||||
def create_security_group(context, group_name, group_description,
|
||||
vpc_id=None):
|
||||
nova = clients.nova(context)
|
||||
if vpc_id:
|
||||
security_groups = describe_security_groups(
|
||||
context,
|
||||
filter=[{'name': 'vpc-id',
|
||||
'value': [vpc_id]},
|
||||
{'name': 'group-name',
|
||||
'value': [group_name]}])['securityGroupInfo']
|
||||
if security_groups:
|
||||
raise exception.InvalidGroupDuplicate(name=group_name)
|
||||
with common.OnCrashCleaner() as cleaner:
|
||||
try:
|
||||
# TODO(Alex): Shouldn't allow creation of groups with existing
|
||||
@ -87,10 +96,12 @@ def _create_default_security_group(context, vpc):
|
||||
'Default VPC security group', vpc['id'])
|
||||
|
||||
|
||||
def delete_security_group(context, group_name=None, group_id=None):
|
||||
def delete_security_group(context, group_name=None, group_id=None,
|
||||
delete_default=False):
|
||||
if group_name is None and group_id is None:
|
||||
raise exception.MissingParameter(param='group id or name')
|
||||
security_group_engine.delete_group(context, group_name, group_id)
|
||||
security_group_engine.delete_group(context, group_name, group_id,
|
||||
delete_default)
|
||||
return True
|
||||
|
||||
|
||||
@ -291,7 +302,7 @@ def _translate_group_name(context, os_group, db_groups):
|
||||
# in all of the subsequent handling (filtering, using in parameters...)
|
||||
if (os_group['name'].startswith('vpc-') and db_groups and
|
||||
next((g for g in db_groups
|
||||
if g['os_id'] == os_group['id']))):
|
||||
if g['os_id'] == os_group['id']), None)):
|
||||
return 'default'
|
||||
return os_group['name']
|
||||
|
||||
@ -379,7 +390,8 @@ def _format_security_group(security_group, os_security_group,
|
||||
|
||||
class SecurityGroupEngineNeutron(object):
|
||||
|
||||
def delete_group(self, context, group_name=None, group_id=None):
|
||||
def delete_group(self, context, group_name=None, group_id=None,
|
||||
delete_default=False):
|
||||
neutron = clients.neutron(context)
|
||||
if group_id is None or not group_id.startswith('sg-'):
|
||||
return SecurityGroupEngineNova().delete_group(context,
|
||||
@ -387,6 +399,13 @@ class SecurityGroupEngineNeutron(object):
|
||||
group_id)
|
||||
security_group = ec2utils.get_db_item(context, group_id)
|
||||
try:
|
||||
if not delete_default:
|
||||
os_security_group = neutron.show_security_group(
|
||||
security_group['os_id'])
|
||||
if (os_security_group and
|
||||
os_security_group['security_group']['name'] ==
|
||||
security_group['vpc_id']):
|
||||
raise exception.CannotDelete()
|
||||
neutron.delete_security_group(security_group['os_id'])
|
||||
except neutron_exception.Conflict as ex:
|
||||
# TODO(Alex): Instance ID is unknown here, report exception message
|
||||
@ -435,7 +454,8 @@ class SecurityGroupEngineNeutron(object):
|
||||
|
||||
class SecurityGroupEngineNova(object):
|
||||
|
||||
def delete_group(self, context, group_name=None, group_id=None):
|
||||
def delete_group(self, context, group_name=None, group_id=None,
|
||||
delete_default=False):
|
||||
nova = clients.nova(context)
|
||||
os_id = self.get_group_os_id(context, group_id, group_name)
|
||||
try:
|
||||
|
@ -75,7 +75,12 @@ def delete_vpc(context, vpc_id):
|
||||
route_tables = route_table_api.describe_route_tables(
|
||||
context,
|
||||
filter=[{'name': 'vpc-id', 'value': [vpc['id']]}])['routeTableSet']
|
||||
if subnets or internet_gateways or len(route_tables) > 1:
|
||||
security_groups = security_group_api.describe_security_groups(
|
||||
context,
|
||||
filter=[{'name': 'vpc-id',
|
||||
'value': [vpc['id']]}])['securityGroupInfo']
|
||||
if (subnets or internet_gateways or len(route_tables) > 1 or
|
||||
len(security_groups) > 1):
|
||||
msg = _("The vpc '%(vpc_id)s' has dependencies and "
|
||||
"cannot be deleted.")
|
||||
msg = msg % {'vpc_id': vpc['id']}
|
||||
@ -87,15 +92,10 @@ def delete_vpc(context, vpc_id):
|
||||
cleaner.addCleanup(db_api.restore_item, context, 'vpc', vpc)
|
||||
route_table_api._delete_route_table(context, vpc['route_table_id'],
|
||||
cleaner=cleaner)
|
||||
# TODO(Alex): Check that only the default security group is left
|
||||
# in this VPC, otherwise DependencyViolation.
|
||||
security_groups = security_group_api.describe_security_groups(
|
||||
context,
|
||||
filter=[{'name': 'vpc-id',
|
||||
'value': [vpc['id']]}])['securityGroupInfo']
|
||||
for security_group in security_groups:
|
||||
if len(security_groups) > 0:
|
||||
security_group_api.delete_security_group(
|
||||
context, group_id=security_group['groupId'])
|
||||
context, group_id=security_groups[0]['groupId'],
|
||||
delete_default=True)
|
||||
try:
|
||||
neutron.delete_router(vpc['os_id'])
|
||||
except neutron_exception.Conflict as ex:
|
||||
|
@ -243,6 +243,10 @@ class DependencyViolation(EC2IncorrectStateException):
|
||||
msg_fmt = _('Object %(obj1_id)s has dependent resource %(obj2_id)s')
|
||||
|
||||
|
||||
class CannotDelete(EC2IncorrectStateException):
|
||||
msg_fmt = _('Cannot delete the default VPC security group')
|
||||
|
||||
|
||||
class ResourceAlreadyAssociated(EC2IncorrectStateException):
|
||||
ec2_code = 'Resource.AlreadyAssociated'
|
||||
|
||||
@ -283,6 +287,11 @@ class InvalidPermissionDuplicate(EC2DuplicateException):
|
||||
msg_fmt = _('The specified rule already exists for that security group.')
|
||||
|
||||
|
||||
class InvalidGroupDuplicate(EC2DuplicateException):
|
||||
ec2_code = 'InvalidGroup.Duplicate'
|
||||
msg_fmt = _("Security group '%(name)s' already exists.")
|
||||
|
||||
|
||||
class RouteAlreadyExists(EC2DuplicateException):
|
||||
msg_fmt = _('The route identified by %(destination_cidr_block)s '
|
||||
'already exists.')
|
||||
|
@ -104,6 +104,14 @@ class SecurityGroupTestCase(base.ApiTestCase):
|
||||
do_check({'GroupDescription': 'description'},
|
||||
'MissingParameter')
|
||||
|
||||
self.set_mock_db_items(fakes.DB_SECURITY_GROUP_2, fakes.DB_VPC_1)
|
||||
self.neutron.list_security_groups.return_value = (
|
||||
{'security_groups': [fakes.OS_SECURITY_GROUP_2]})
|
||||
do_check({'VpcId': fakes.ID_EC2_VPC_1,
|
||||
'GroupName': fakes.OS_SECURITY_GROUP_2['name'],
|
||||
'GroupDescription': 'description'},
|
||||
'InvalidGroup.Duplicate')
|
||||
|
||||
def test_create_security_group_over_quota(self):
|
||||
security_group.security_group_engine = (
|
||||
security_group.SecurityGroupEngineNeutron())
|
||||
@ -184,10 +192,15 @@ class SecurityGroupTestCase(base.ApiTestCase):
|
||||
def test_delete_security_group_invalid(self):
|
||||
security_group.security_group_engine = (
|
||||
security_group.SecurityGroupEngineNeutron())
|
||||
self.set_mock_db_items()
|
||||
self.set_mock_db_items(fakes.DB_SECURITY_GROUP_1, fakes.DB_VPC_1)
|
||||
self.neutron.show_security_group.return_value = (
|
||||
{'security_group': fakes.OS_SECURITY_GROUP_1})
|
||||
self.assert_execution_error(
|
||||
'CannotDelete', 'DeleteSecurityGroup',
|
||||
{'GroupId': fakes.ID_EC2_SECURITY_GROUP_1})
|
||||
self.assert_execution_error(
|
||||
'InvalidGroup.NotFound', 'DeleteSecurityGroup',
|
||||
{'GroupId': fakes.ID_EC2_SECURITY_GROUP_1})
|
||||
{'GroupId': fakes.ID_EC2_SECURITY_GROUP_2})
|
||||
self.assertEqual(0, self.neutron.delete_port.call_count)
|
||||
self.assert_execution_error(
|
||||
'InvalidGroup.NotFound', 'DeleteSecurityGroup',
|
||||
|
@ -114,7 +114,8 @@ class VpcTestCase(base.ApiTestCase):
|
||||
fakes.ID_EC2_ROUTE_TABLE_1)
|
||||
|
||||
def test_delete_vpc(self):
|
||||
self.set_mock_db_items(fakes.DB_VPC_1, fakes.DB_ROUTE_TABLE_1)
|
||||
self.set_mock_db_items(fakes.DB_VPC_1, fakes.DB_ROUTE_TABLE_1,
|
||||
fakes.DB_SECURITY_GROUP_1)
|
||||
|
||||
resp = self.execute('DeleteVpc', {'VpcId': fakes.ID_EC2_VPC_1})
|
||||
|
||||
@ -127,6 +128,9 @@ class VpcTestCase(base.ApiTestCase):
|
||||
self.db_api.delete_item.assert_any_call(
|
||||
mock.ANY,
|
||||
fakes.ID_EC2_ROUTE_TABLE_1)
|
||||
self.db_api.delete_item.assert_any_call(
|
||||
mock.ANY,
|
||||
fakes.ID_EC2_SECURITY_GROUP_1)
|
||||
|
||||
def test_delete_vpc_not_found(self):
|
||||
self.set_mock_db_items()
|
||||
@ -153,6 +157,13 @@ class VpcTestCase(base.ApiTestCase):
|
||||
fakes.DB_VPC_1)
|
||||
do_check()
|
||||
|
||||
self.set_mock_db_items(fakes.DB_SECURITY_GROUP_1,
|
||||
fakes.DB_SECURITY_GROUP_2, fakes.DB_VPC_1)
|
||||
self.neutron.list_security_groups.return_value = (
|
||||
{'security_groups': [fakes.OS_SECURITY_GROUP_1,
|
||||
fakes.OS_SECURITY_GROUP_2]})
|
||||
do_check()
|
||||
|
||||
def test_delete_vpc_not_conststent_os_vpc(self):
|
||||
self.set_mock_db_items(fakes.DB_VPC_1, fakes.DB_ROUTE_TABLE_1)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user