nova-net: Remove nova-network security group driver
This is another self-explanatory change. We remove the driver along with related tests. Some additional API tests need to be fixed since these were using the nova-network security group driver. Change-Id: Ia05215b2e7168563c54b78263625125537b7234c Signed-off-by: Stephen Finucane <sfinucan@redhat.com>
This commit is contained in:
parent
d5c9423e40
commit
bf0d099f4b
|
@ -63,7 +63,6 @@ from nova import network
|
|||
from nova.network import model as network_model
|
||||
from nova.network.neutronv2 import constants
|
||||
from nova.network.security_group import openstack_driver
|
||||
from nova.network.security_group import security_group_base
|
||||
from nova import objects
|
||||
from nova.objects import base as obj_base
|
||||
from nova.objects import block_device as block_device_obj
|
||||
|
@ -97,8 +96,6 @@ wrap_exception = functools.partial(exception_wrapper.wrap_exception,
|
|||
binary='nova-api')
|
||||
CONF = nova.conf.CONF
|
||||
|
||||
RO_SECURITY_GROUPS = ['default']
|
||||
|
||||
AGGREGATE_ACTION_UPDATE = 'Update'
|
||||
AGGREGATE_ACTION_UPDATE_META = 'UpdateMeta'
|
||||
AGGREGATE_ACTION_DELETE = 'Delete'
|
||||
|
@ -385,13 +382,7 @@ class API(base.Base):
|
|||
raise exception.SecurityGroupNotFoundForProject(
|
||||
project_id=context.project_id, security_group_id=secgroup)
|
||||
|
||||
# Check to see if it's a nova-network or neutron type.
|
||||
if isinstance(secgroup_dict['id'], int):
|
||||
# This is nova-network so just return the requested name.
|
||||
security_groups.append(secgroup)
|
||||
else:
|
||||
# The id for neutron is a uuid, so we return the id (uuid).
|
||||
security_groups.append(secgroup_dict['id'])
|
||||
security_groups.append(secgroup_dict['id'])
|
||||
|
||||
return security_groups
|
||||
|
||||
|
@ -6132,334 +6123,3 @@ class KeypairAPI(base.Base):
|
|||
def get_key_pair(self, context, user_id, key_name):
|
||||
"""Get a keypair by name."""
|
||||
return objects.KeyPair.get_by_name(context, user_id, key_name)
|
||||
|
||||
|
||||
class SecurityGroupAPI(base.Base, security_group_base.SecurityGroupBase):
|
||||
"""Sub-set of the Compute API related to managing security groups
|
||||
and security group rules
|
||||
"""
|
||||
|
||||
# The nova security group api does not use a uuid for the id.
|
||||
id_is_uuid = False
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(SecurityGroupAPI, self).__init__(**kwargs)
|
||||
self.compute_rpcapi = compute_rpcapi.ComputeAPI()
|
||||
|
||||
def validate_property(self, value, property, allowed):
|
||||
"""Validate given security group property.
|
||||
|
||||
:param value: the value to validate, as a string or unicode
|
||||
:param property: the property, either 'name' or 'description'
|
||||
:param allowed: the range of characters allowed
|
||||
"""
|
||||
|
||||
try:
|
||||
val = value.strip()
|
||||
except AttributeError:
|
||||
msg = _("Security group %s is not a string or unicode") % property
|
||||
self.raise_invalid_property(msg)
|
||||
utils.check_string_length(val, name=property, min_length=1,
|
||||
max_length=255)
|
||||
|
||||
if allowed and not re.match(allowed, val):
|
||||
# Some validation to ensure that values match API spec.
|
||||
# - Alphanumeric characters, spaces, dashes, and underscores.
|
||||
# TODO(Daviey): LP: #813685 extend beyond group_name checking, and
|
||||
# probably create a param validator that can be used elsewhere.
|
||||
msg = (_("Value (%(value)s) for parameter Group%(property)s is "
|
||||
"invalid. Content limited to '%(allowed)s'.") %
|
||||
{'value': value, 'allowed': allowed,
|
||||
'property': property.capitalize()})
|
||||
self.raise_invalid_property(msg)
|
||||
|
||||
def ensure_default(self, context):
|
||||
"""Ensure that a context has a security group.
|
||||
|
||||
Creates a security group for the security context if it does not
|
||||
already exist.
|
||||
|
||||
:param context: the security context
|
||||
"""
|
||||
self.db.security_group_ensure_default(context)
|
||||
|
||||
def create_security_group(self, context, name, description):
|
||||
try:
|
||||
objects.Quotas.check_deltas(context, {'security_groups': 1},
|
||||
context.project_id,
|
||||
user_id=context.user_id)
|
||||
except exception.OverQuota:
|
||||
msg = _("Quota exceeded, too many security groups.")
|
||||
self.raise_over_quota(msg)
|
||||
|
||||
LOG.info("Create Security Group %s", name)
|
||||
|
||||
self.ensure_default(context)
|
||||
|
||||
group = {'user_id': context.user_id,
|
||||
'project_id': context.project_id,
|
||||
'name': name,
|
||||
'description': description}
|
||||
try:
|
||||
group_ref = self.db.security_group_create(context, group)
|
||||
except exception.SecurityGroupExists:
|
||||
msg = _('Security group %s already exists') % name
|
||||
self.raise_group_already_exists(msg)
|
||||
|
||||
# NOTE(melwitt): We recheck the quota after creating the object to
|
||||
# prevent users from allocating more resources than their allowed quota
|
||||
# in the event of a race. This is configurable because it can be
|
||||
# expensive if strict quota limits are not required in a deployment.
|
||||
if CONF.quota.recheck_quota:
|
||||
try:
|
||||
objects.Quotas.check_deltas(context, {'security_groups': 0},
|
||||
context.project_id,
|
||||
user_id=context.user_id)
|
||||
except exception.OverQuota:
|
||||
self.db.security_group_destroy(context, group_ref['id'])
|
||||
msg = _("Quota exceeded, too many security groups.")
|
||||
self.raise_over_quota(msg)
|
||||
|
||||
return group_ref
|
||||
|
||||
def update_security_group(self, context, security_group,
|
||||
name, description):
|
||||
if security_group['name'] in RO_SECURITY_GROUPS:
|
||||
msg = (_("Unable to update system group '%s'") %
|
||||
security_group['name'])
|
||||
self.raise_invalid_group(msg)
|
||||
|
||||
group = {'name': name,
|
||||
'description': description}
|
||||
|
||||
columns_to_join = ['rules.grantee_group']
|
||||
group_ref = self.db.security_group_update(context,
|
||||
security_group['id'],
|
||||
group,
|
||||
columns_to_join=columns_to_join)
|
||||
return group_ref
|
||||
|
||||
def get(self, context, name=None, id=None, map_exception=False):
|
||||
self.ensure_default(context)
|
||||
cols = ['rules']
|
||||
try:
|
||||
if name:
|
||||
return self.db.security_group_get_by_name(context,
|
||||
context.project_id,
|
||||
name,
|
||||
columns_to_join=cols)
|
||||
elif id:
|
||||
return self.db.security_group_get(context, id,
|
||||
columns_to_join=cols)
|
||||
except exception.NotFound as exp:
|
||||
if map_exception:
|
||||
msg = exp.format_message()
|
||||
self.raise_not_found(msg)
|
||||
else:
|
||||
raise
|
||||
|
||||
def list(self, context, names=None, ids=None, project=None,
|
||||
search_opts=None):
|
||||
self.ensure_default(context)
|
||||
|
||||
groups = []
|
||||
if names or ids:
|
||||
if names:
|
||||
for name in names:
|
||||
groups.append(self.db.security_group_get_by_name(context,
|
||||
project,
|
||||
name))
|
||||
if ids:
|
||||
for id in ids:
|
||||
groups.append(self.db.security_group_get(context, id))
|
||||
|
||||
elif context.is_admin:
|
||||
# TODO(eglynn): support a wider set of search options than just
|
||||
# all_tenants, at least include the standard filters defined for
|
||||
# the EC2 DescribeSecurityGroups API for the non-admin case also
|
||||
if (search_opts and 'all_tenants' in search_opts):
|
||||
groups = self.db.security_group_get_all(context)
|
||||
else:
|
||||
groups = self.db.security_group_get_by_project(context,
|
||||
project)
|
||||
|
||||
elif project:
|
||||
groups = self.db.security_group_get_by_project(context, project)
|
||||
|
||||
return groups
|
||||
|
||||
def destroy(self, context, security_group):
|
||||
if security_group['name'] in RO_SECURITY_GROUPS:
|
||||
msg = _("Unable to delete system group '%s'") % \
|
||||
security_group['name']
|
||||
self.raise_invalid_group(msg)
|
||||
|
||||
if self.db.security_group_in_use(context, security_group['id']):
|
||||
msg = _("Security group is still in use")
|
||||
self.raise_invalid_group(msg)
|
||||
|
||||
LOG.info("Delete security group %s", security_group['name'])
|
||||
self.db.security_group_destroy(context, security_group['id'])
|
||||
|
||||
def is_associated_with_server(self, security_group, instance_uuid):
|
||||
"""Check if the security group is already associated
|
||||
with the instance. If Yes, return True.
|
||||
"""
|
||||
|
||||
if not security_group:
|
||||
return False
|
||||
|
||||
instances = security_group.get('instances')
|
||||
if not instances:
|
||||
return False
|
||||
|
||||
for inst in instances:
|
||||
if (instance_uuid == inst['uuid']):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def add_to_instance(self, context, instance, security_group_name):
|
||||
"""Add security group to the instance."""
|
||||
security_group = self.db.security_group_get_by_name(context,
|
||||
context.project_id,
|
||||
security_group_name)
|
||||
|
||||
instance_uuid = instance.uuid
|
||||
|
||||
# check if the security group is associated with the server
|
||||
if self.is_associated_with_server(security_group, instance_uuid):
|
||||
raise exception.SecurityGroupExistsForInstance(
|
||||
security_group_id=security_group['id'],
|
||||
instance_id=instance_uuid)
|
||||
|
||||
self.db.instance_add_security_group(context.elevated(),
|
||||
instance_uuid,
|
||||
security_group['id'])
|
||||
if instance.host:
|
||||
self.compute_rpcapi.refresh_instance_security_rules(
|
||||
context, instance, instance.host)
|
||||
|
||||
def remove_from_instance(self, context, instance, security_group_name):
|
||||
"""Remove the security group associated with the instance."""
|
||||
security_group = self.db.security_group_get_by_name(context,
|
||||
context.project_id,
|
||||
security_group_name)
|
||||
|
||||
instance_uuid = instance.uuid
|
||||
|
||||
# check if the security group is associated with the server
|
||||
if not self.is_associated_with_server(security_group, instance_uuid):
|
||||
raise exception.SecurityGroupNotExistsForInstance(
|
||||
security_group_id=security_group['id'],
|
||||
instance_id=instance_uuid)
|
||||
|
||||
self.db.instance_remove_security_group(context.elevated(),
|
||||
instance_uuid,
|
||||
security_group['id'])
|
||||
if instance.host:
|
||||
self.compute_rpcapi.refresh_instance_security_rules(
|
||||
context, instance, instance.host)
|
||||
|
||||
def get_rule(self, context, id):
|
||||
self.ensure_default(context)
|
||||
try:
|
||||
return self.db.security_group_rule_get(context, id)
|
||||
except exception.NotFound:
|
||||
msg = _("Rule (%s) not found") % id
|
||||
self.raise_not_found(msg)
|
||||
|
||||
def add_rules(self, context, id, name, vals):
|
||||
"""Add security group rule(s) to security group.
|
||||
|
||||
Note: the Nova security group API doesn't support adding multiple
|
||||
security group rules at once but the EC2 one does. Therefore,
|
||||
this function is written to support both.
|
||||
"""
|
||||
|
||||
try:
|
||||
objects.Quotas.check_deltas(context,
|
||||
{'security_group_rules': len(vals)},
|
||||
id)
|
||||
except exception.OverQuota:
|
||||
msg = _("Quota exceeded, too many security group rules.")
|
||||
self.raise_over_quota(msg)
|
||||
|
||||
msg = ("Security group %(name)s added %(protocol)s ingress "
|
||||
"(%(from_port)s:%(to_port)s)")
|
||||
rules = []
|
||||
for v in vals:
|
||||
rule = self.db.security_group_rule_create(context, v)
|
||||
|
||||
# NOTE(melwitt): We recheck the quota after creating the object to
|
||||
# prevent users from allocating more resources than their allowed
|
||||
# quota in the event of a race. This is configurable because it can
|
||||
# be expensive if strict quota limits are not required in a
|
||||
# deployment.
|
||||
if CONF.quota.recheck_quota:
|
||||
try:
|
||||
objects.Quotas.check_deltas(context,
|
||||
{'security_group_rules': 0},
|
||||
id)
|
||||
except exception.OverQuota:
|
||||
self.db.security_group_rule_destroy(context, rule['id'])
|
||||
msg = _("Quota exceeded, too many security group rules.")
|
||||
self.raise_over_quota(msg)
|
||||
|
||||
rules.append(rule)
|
||||
LOG.info(msg, {'name': name,
|
||||
'protocol': rule.protocol,
|
||||
'from_port': rule.from_port,
|
||||
'to_port': rule.to_port})
|
||||
|
||||
self.trigger_rules_refresh(context, id=id)
|
||||
return rules
|
||||
|
||||
def remove_rules(self, context, security_group, rule_ids):
|
||||
msg = ("Security group %(name)s removed %(protocol)s ingress "
|
||||
"(%(from_port)s:%(to_port)s)")
|
||||
for rule_id in rule_ids:
|
||||
rule = self.get_rule(context, rule_id)
|
||||
LOG.info(msg, {'name': security_group['name'],
|
||||
'protocol': rule.protocol,
|
||||
'from_port': rule.from_port,
|
||||
'to_port': rule.to_port})
|
||||
|
||||
self.db.security_group_rule_destroy(context, rule_id)
|
||||
|
||||
# NOTE(vish): we removed some rules, so refresh
|
||||
self.trigger_rules_refresh(context, id=security_group['id'])
|
||||
|
||||
def validate_id(self, id):
|
||||
try:
|
||||
return int(id)
|
||||
except ValueError:
|
||||
msg = _("Security group id should be integer")
|
||||
self.raise_invalid_property(msg)
|
||||
|
||||
def _refresh_instance_security_rules(self, context, instances):
|
||||
for instance in instances:
|
||||
if instance.host is not None:
|
||||
self.compute_rpcapi.refresh_instance_security_rules(
|
||||
context, instance, instance.host)
|
||||
|
||||
def trigger_rules_refresh(self, context, id):
|
||||
"""Called when a rule is added to or removed from a security_group."""
|
||||
instances = objects.InstanceList.get_by_security_group_id(context, id)
|
||||
self._refresh_instance_security_rules(context, instances)
|
||||
|
||||
def trigger_members_refresh(self, context, group_ids):
|
||||
"""Called when a security group gains a new or loses a member.
|
||||
|
||||
Sends an update request to each compute node for each instance for
|
||||
which this is relevant.
|
||||
"""
|
||||
instances = objects.InstanceList.get_by_grantee_security_group_ids(
|
||||
context, group_ids)
|
||||
self._refresh_instance_security_rules(context, instances)
|
||||
|
||||
def get_instance_security_groups(self, context, instance, detailed=False):
|
||||
if detailed:
|
||||
return self.db.security_group_get_by_instance(context,
|
||||
instance.uuid)
|
||||
return [{'name': group.name} for group in instance.security_groups]
|
||||
|
|
|
@ -26,6 +26,7 @@ from nova.i18n import _
|
|||
from nova.objects import security_group as security_group_obj
|
||||
|
||||
|
||||
# TODO(stephenfin): Merge this into the only implementation that exists now
|
||||
class SecurityGroupBase(object):
|
||||
|
||||
def parse_cidr(self, cidr):
|
||||
|
|
|
@ -324,13 +324,6 @@ class BaseTestCase(test.TestCase):
|
|||
|
||||
return inst
|
||||
|
||||
def _create_group(self):
|
||||
values = {'name': 'testgroup',
|
||||
'description': 'testgroup',
|
||||
'user_id': self.user_id,
|
||||
'project_id': self.project_id}
|
||||
return db.security_group_create(self.context, values)
|
||||
|
||||
def _init_aggregate_with_host(self, aggr, aggr_name, zone, host):
|
||||
if not aggr:
|
||||
aggr = self.api.create_aggregate(self.context, aggr_name, zone)
|
||||
|
@ -8527,14 +8520,8 @@ class ComputeAPITestCase(BaseTestCase):
|
|||
self.useFixture(fixtures.SpawnIsSynchronousFixture())
|
||||
self.stub_out('nova.network.api.API.get_instance_nw_info',
|
||||
fake_get_nw_info)
|
||||
# NOTE(mriedem): Everything in here related to the security group API
|
||||
# is written for nova-network and using the database. Neutron-specific
|
||||
# security group API tests are covered in
|
||||
# nova.tests.unit.network.security_group.test_neutron_driver.
|
||||
self.security_group_api = compute.SecurityGroupAPI()
|
||||
|
||||
self.compute_api = compute.API(
|
||||
security_group_api=self.security_group_api)
|
||||
self.compute_api = compute.API()
|
||||
self.fake_image = {
|
||||
'id': 'f9000000-0000-0000-0000-000000000000',
|
||||
'name': 'fake_name',
|
||||
|
@ -8766,10 +8753,14 @@ class ComputeAPITestCase(BaseTestCase):
|
|||
|
||||
def test_create_instance_associates_security_groups(self):
|
||||
# Make sure create associates security groups.
|
||||
group = self._create_group()
|
||||
with mock.patch.object(self.compute_api.compute_task_api,
|
||||
'schedule_and_build_instances') as mock_sbi:
|
||||
(ref, resv_id) = self.compute_api.create(
|
||||
group = {'id': uuids.secgroup_id, 'name': 'testgroup'}
|
||||
with test.nested(
|
||||
mock.patch.object(self.compute_api.compute_task_api,
|
||||
'schedule_and_build_instances'),
|
||||
mock.patch.object(self.compute_api.security_group_api, 'get',
|
||||
return_value=group),
|
||||
) as (mock_sbi, mock_secgroups):
|
||||
self.compute_api.create(
|
||||
self.context,
|
||||
instance_type=self.default_flavor,
|
||||
image_href=uuids.image_href_id,
|
||||
|
@ -8779,18 +8770,25 @@ class ComputeAPITestCase(BaseTestCase):
|
|||
reqspec = build_call[1]['request_spec'][0]
|
||||
|
||||
self.assertEqual(1, len(reqspec.security_groups))
|
||||
self.assertEqual(group.name, reqspec.security_groups[0].name)
|
||||
self.assertEqual(group['id'], reqspec.security_groups[0].uuid)
|
||||
mock_secgroups.assert_called_once_with(mock.ANY, 'testgroup')
|
||||
|
||||
def test_create_instance_with_invalid_security_group_raises(self):
|
||||
pre_build_len = len(db.instance_get_all(self.context))
|
||||
self.assertRaises(exception.SecurityGroupNotFoundForProject,
|
||||
self.compute_api.create,
|
||||
self.context,
|
||||
instance_type=self.default_flavor,
|
||||
image_href=None,
|
||||
security_groups=['this_is_a_fake_sec_group'])
|
||||
with test.nested(
|
||||
mock.patch.object(self.compute_api.security_group_api, 'get',
|
||||
return_value=None),
|
||||
) as (mock_secgroups, ):
|
||||
self.assertRaises(exception.SecurityGroupNotFoundForProject,
|
||||
self.compute_api.create,
|
||||
self.context,
|
||||
instance_type=self.default_flavor,
|
||||
image_href=None,
|
||||
security_groups=['invalid_sec_group'])
|
||||
|
||||
self.assertEqual(pre_build_len,
|
||||
len(db.instance_get_all(self.context)))
|
||||
mock_secgroups.assert_called_once_with(mock.ANY, 'invalid_sec_group')
|
||||
|
||||
def test_create_with_malformed_user_data(self):
|
||||
# Test an instance type with malformed user data.
|
||||
|
@ -11089,21 +11087,6 @@ class ComputeAPITestCase(BaseTestCase):
|
|||
self.context, instance, CONF.host, action='unlock',
|
||||
source='nova-api')
|
||||
|
||||
def test_add_remove_security_group(self):
|
||||
instance = self._create_fake_instance_obj()
|
||||
|
||||
self.compute.build_and_run_instance(self.context,
|
||||
instance, {}, {}, {}, block_device_mapping=[])
|
||||
instance = self.compute_api.get(self.context, instance.uuid)
|
||||
security_group_name = self._create_group()['name']
|
||||
|
||||
self.security_group_api.add_to_instance(self.context,
|
||||
instance,
|
||||
security_group_name)
|
||||
self.security_group_api.remove_from_instance(self.context,
|
||||
instance,
|
||||
security_group_name)
|
||||
|
||||
@mock.patch.object(compute_rpcapi.ComputeAPI, 'get_diagnostics')
|
||||
def test_get_diagnostics(self, mock_get):
|
||||
instance = self._create_fake_instance_obj()
|
||||
|
@ -11120,51 +11103,6 @@ class ComputeAPITestCase(BaseTestCase):
|
|||
|
||||
mock_get.assert_called_once_with(self.context, instance=instance)
|
||||
|
||||
@mock.patch.object(compute_rpcapi.ComputeAPI,
|
||||
'refresh_instance_security_rules')
|
||||
def test_refresh_instance_security_rules(self, mock_refresh):
|
||||
inst1 = self._create_fake_instance_obj()
|
||||
inst2 = self._create_fake_instance_obj({'host': None})
|
||||
|
||||
self.security_group_api._refresh_instance_security_rules(
|
||||
self.context, [inst1, inst2])
|
||||
mock_refresh.assert_called_once_with(self.context, inst1, inst1.host)
|
||||
|
||||
@mock.patch.object(compute_rpcapi.ComputeAPI,
|
||||
'refresh_instance_security_rules')
|
||||
def test_refresh_instance_security_rules_empty(self, mock_refresh):
|
||||
self.security_group_api._refresh_instance_security_rules(self.context,
|
||||
[])
|
||||
self.assertFalse(mock_refresh.called)
|
||||
|
||||
@mock.patch.object(compute.SecurityGroupAPI,
|
||||
'_refresh_instance_security_rules')
|
||||
@mock.patch.object(objects.InstanceList,
|
||||
'get_by_grantee_security_group_ids')
|
||||
def test_secgroup_refresh(self, mock_get, mock_refresh):
|
||||
mock_get.return_value = mock.sentinel.instances
|
||||
|
||||
self.security_group_api.trigger_members_refresh(mock.sentinel.ctxt,
|
||||
mock.sentinel.ids)
|
||||
|
||||
mock_get.assert_called_once_with(mock.sentinel.ctxt, mock.sentinel.ids)
|
||||
mock_refresh.assert_called_once_with(mock.sentinel.ctxt,
|
||||
mock.sentinel.instances)
|
||||
|
||||
@mock.patch.object(compute.SecurityGroupAPI,
|
||||
'_refresh_instance_security_rules')
|
||||
@mock.patch.object(objects.InstanceList,
|
||||
'get_by_security_group_id')
|
||||
def test_secrule_refresh(self, mock_get, mock_refresh):
|
||||
mock_get.return_value = mock.sentinel.instances
|
||||
|
||||
self.security_group_api.trigger_rules_refresh(mock.sentinel.ctxt,
|
||||
mock.sentinel.id)
|
||||
|
||||
mock_get.assert_called_once_with(mock.sentinel.ctxt, mock.sentinel.id)
|
||||
mock_refresh.assert_called_once_with(mock.sentinel.ctxt,
|
||||
mock.sentinel.instances)
|
||||
|
||||
def _test_live_migrate(self, force=None):
|
||||
instance, instance_uuid = self._run_instance()
|
||||
|
||||
|
|
|
@ -6913,29 +6913,3 @@ class DiffDictTestCase(test.NoDBTestCase):
|
|||
diff = compute_api._diff_dict(old, new)
|
||||
|
||||
self.assertEqual(diff, dict(b=['-']))
|
||||
|
||||
|
||||
class SecurityGroupAPITest(test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
super(SecurityGroupAPITest, self).setUp()
|
||||
self.secgroup_api = compute_api.SecurityGroupAPI()
|
||||
self.user_id = 'fake'
|
||||
self.project_id = 'fake'
|
||||
self.context = context.RequestContext(self.user_id,
|
||||
self.project_id)
|
||||
|
||||
def test_get_instance_security_groups(self):
|
||||
groups = objects.SecurityGroupList()
|
||||
groups.objects = [objects.SecurityGroup(name='foo'),
|
||||
objects.SecurityGroup(name='bar')]
|
||||
instance = objects.Instance(security_groups=groups)
|
||||
names = self.secgroup_api.get_instance_security_groups(self.context,
|
||||
instance)
|
||||
self.assertEqual(sorted([{'name': 'bar'}, {'name': 'foo'}], key=str),
|
||||
sorted(names, key=str))
|
||||
|
||||
@mock.patch('nova.objects.security_group.make_secgroup_list')
|
||||
def test_populate_security_groups(self, mock_msl):
|
||||
r = self.secgroup_api.populate_security_groups([mock.sentinel.group])
|
||||
mock_msl.assert_called_once_with([mock.sentinel.group])
|
||||
self.assertEqual(r, mock_msl.return_value)
|
||||
|
|
Loading…
Reference in New Issue