Skip to content

Commit

Permalink
Fix bug 933147 Security group trigger notifications.
Browse files Browse the repository at this point in the history
Add a lightweight mechanism to allow security group trigger
notifications to be propagated to quantum security group handlers.

Add a global flag: "security_group_handler" to allow for runtime
selection of security group handler class.

Change-Id: I8a3768c26c97020071ad4e52d3a22d8898e72e9f
  • Loading branch information
davlaps committed Feb 17, 2012
1 parent 31d1a42 commit 269c0fc
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 2 deletions.
14 changes: 14 additions & 0 deletions nova/api/ec2/cloud.py
Expand Up @@ -202,6 +202,7 @@ def __init__(self):
self.volume_api = volume.API()
self.compute_api = compute.API(network_api=self.network_api,
volume_api=self.volume_api)
self.sgh = utils.import_object(FLAGS.security_group_handler)

def __str__(self):
return 'CloudController'
Expand Down Expand Up @@ -622,6 +623,7 @@ def revoke_security_group_ingress(self, context, group_name=None,
except KeyError:
prevalues.append(kwargs)
rule_id = None
rule_ids = []
for values in prevalues:
rulesvalues = self._rule_args_to_dict(context, values)
if not rulesvalues:
Expand All @@ -634,11 +636,14 @@ def revoke_security_group_ingress(self, context, group_name=None,
values_for_rule)
if rule_id:
db.security_group_rule_destroy(context, rule_id)
rule_ids.append(rule_id)
if rule_id:
# NOTE(vish): we removed a rule, so refresh
self.compute_api.trigger_security_group_rules_refresh(
context,
security_group_id=security_group['id'])
self.sgh.trigger_security_group_rule_destroy_refresh(
context, rule_ids)
return True
raise exception.EC2APIError(_("No rule for the specified parameters."))

Expand Down Expand Up @@ -685,15 +690,19 @@ def authorize_security_group_ingress(self, context, group_name=None,
raise exception.EC2APIError(_(err) % values_for_rule)
postvalues.append(values_for_rule)

rule_ids = []
for values_for_rule in postvalues:
security_group_rule = db.security_group_rule_create(
context,
values_for_rule)
rule_ids.append(security_group_rule['id'])

if postvalues:
self.compute_api.trigger_security_group_rules_refresh(
context,
security_group_id=security_group['id'])
self.sgh.trigger_security_group_rule_create_refresh(
context, rule_ids)
return True

raise exception.EC2APIError(_("No rule for the specified parameters."))
Expand Down Expand Up @@ -744,6 +753,8 @@ def create_security_group(self, context, group_name, group_description):
'description': group_description}
group_ref = db.security_group_create(context, group)

self.sgh.trigger_security_group_create_refresh(context, group)

return {'securityGroupSet': [self._format_security_group(context,
group_ref)]}

Expand All @@ -765,6 +776,9 @@ def delete_security_group(self, context, group_name=None, group_id=None,
raise notfound(security_group_id=group_id)
LOG.audit(_("Delete security group %s"), group_name, context=context)
db.security_group_destroy(context, security_group.id)

self.sgh.trigger_security_group_destroy_refresh(context,
security_group.id)
return True

def get_console_output(self, context, instance_id, **kwargs):
Expand Down
14 changes: 13 additions & 1 deletion nova/api/openstack/compute/contrib/security_groups.py
Expand Up @@ -179,6 +179,7 @@ class SecurityGroupController(object):
def __init__(self):
self.compute_api = compute.API()
super(SecurityGroupController, self).__init__()
self.sgh = utils.import_object(FLAGS.security_group_handler)

def _format_security_group_rule(self, context, rule):
sg_rule = {}
Expand Down Expand Up @@ -236,6 +237,8 @@ def delete(self, req, id):
security_group = self._get_security_group(context, id)
LOG.audit(_("Delete security group %s"), id, context=context)
db.security_group_destroy(context, security_group.id)
self.sgh.trigger_security_group_destroy_refresh(
context, security_group.id)

return webob.Response(status_int=202)

Expand Down Expand Up @@ -290,6 +293,7 @@ def create(self, req, body):
'name': group_name,
'description': group_description}
group_ref = db.security_group_create(context, group)
self.sgh.trigger_security_group_create_refresh(context, group)

return {'security_group': self._format_security_group(context,
group_ref)}
Expand Down Expand Up @@ -366,7 +370,8 @@ def create(self, req, body):
raise exc.HTTPBadRequest(explanation=msg)

security_group_rule = db.security_group_rule_create(context, values)

self.sgh.trigger_security_group_rule_create_refresh(
context, [security_group_rule['id']])
self.compute_api.trigger_security_group_rules_refresh(context,
security_group_id=security_group['id'])

Expand Down Expand Up @@ -495,6 +500,8 @@ def delete(self, req, id):
LOG.audit(msg, security_group['name'], context=context)

db.security_group_rule_destroy(context, rule['id'])
self.sgh.trigger_security_group_rule_destroy_refresh(
context, [rule['id']])
self.compute_api.trigger_security_group_rules_refresh(context,
security_group_id=security_group['id'])

Expand All @@ -505,6 +512,7 @@ class SecurityGroupActionController(wsgi.Controller):
def __init__(self, *args, **kwargs):
super(SecurityGroupActionController, self).__init__(*args, **kwargs)
self.compute_api = compute.API()
self.sgh = utils.import_object(FLAGS.security_group_handler)

@wsgi.action('addSecurityGroup')
def _addSecurityGroup(self, req, id, body):
Expand All @@ -528,6 +536,8 @@ def _addSecurityGroup(self, req, id, body):
try:
instance = self.compute_api.get(context, id)
self.compute_api.add_security_group(context, instance, group_name)
self.sgh.trigger_instance_add_security_group_refresh(
context, instance, group_name)
except exception.SecurityGroupNotFound as exp:
raise exc.HTTPNotFound(explanation=unicode(exp))
except exception.InstanceNotFound as exp:
Expand Down Expand Up @@ -560,6 +570,8 @@ def _removeSecurityGroup(self, req, id, body):
instance = self.compute_api.get(context, id)
self.compute_api.remove_security_group(context, instance,
group_name)
self.sgh.trigger_instance_remove_security_group_refresh(
context, instance, group_name)
except exception.SecurityGroupNotFound as exp:
raise exc.HTTPNotFound(explanation=unicode(exp))
except exception.InstanceNotFound as exp:
Expand Down
3 changes: 3 additions & 0 deletions nova/flags.py
Expand Up @@ -451,6 +451,9 @@ def _get_my_ip():
cfg.StrOpt('volume_api_class',
default='nova.volume.api.API',
help='The volume API class to use'),
cfg.StrOpt('security_group_handler',
default='nova.network.quantum.sg.NullSecurityGroupHandler',
help='security group handler class')
]

FLAGS.register_opts(global_opts)
5 changes: 4 additions & 1 deletion nova/network/manager.py
Expand Up @@ -685,6 +685,7 @@ def __init__(self, network_driver=None, *args, **kwargs):
self.floating_dns_manager = temp
self.network_api = network_api.API()
self.compute_api = compute_api.API()
self.sgh = utils.import_object(FLAGS.security_group_handler)

# NOTE(tr3buchet: unless manager subclassing NetworkManager has
# already imported ipam, import nova ipam here
Expand Down Expand Up @@ -761,7 +762,9 @@ def _do_trigger_security_group_members_refresh_for_instance(self,
groups = instance_ref['security_groups']
group_ids = [group['id'] for group in groups]
self.compute_api.trigger_security_group_members_refresh(admin_context,
group_ids)
group_ids)
self.sgh.trigger_security_group_members_refresh(admin_context,
group_ids)

def get_floating_ips_by_fixed_address(self, context, fixed_address):
# NOTE(jkoelker) This is just a stub function. Managers supporting
Expand Down
159 changes: 159 additions & 0 deletions nova/network/quantum/sg.py
@@ -0,0 +1,159 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2012 Nicira Networks, Inc
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

'''Implement Security Groups abstraction and API.
The nova security_group_handler flag specifies which class is to be used
to implement the security group calls.
The NullSecurityGroupHandler provides a "no-op" plugin that is loaded
by default and has no impact on current system behavior. In the future,
special purposes classes that inherit from SecurityGroupHandlerBase
will provide enhanced functionality and will be loadable via the
security_group_handler flag.
'''

from nova import log as logging


LOG = logging.getLogger('nova.network.api.quantum.sg')


class SecurityGroupHandlerBase(object):

def __init__(self):
raise NotImplementedError()

def trigger_security_group_create_refresh(self, context, group):
'''Called when a rule is added to a security_group.
:param context: the security context.
:param group: the new group added. group is a dictionary that contains
the following: user_id, project_id, name, description).'''
raise NotImplementedError()

def trigger_security_group_destroy_refresh(self, context,
security_group_id):
'''Called when a rule is added to a security_group.
:param context: the security context.
:param security_group_id: the security group identifier.'''
raise NotImplementedError()

def trigger_security_group_rule_create_refresh(self, context,
rule_ids):
'''Called when a rule is added to a security_group.
:param context: the security context.
:param rule_ids: a list of rule ids that have been affected.'''
raise NotImplementedError()

def trigger_security_group_rule_destroy_refresh(self, context,
rule_ids):
'''Called when a rule is removed from a security_group.
:param context: the security context.
:param rule_ids: a list of rule ids that have been affected.'''
raise NotImplementedError()

def trigger_instance_add_security_group_refresh(self, context, instance,
group_name):
'''Called when a security group gains a new member.
:param context: the security context.
:param instance: the instance to be associated.
:param group_name: the name of the security group to be associated.'''
raise NotImplementedError()

def trigger_instance_remove_security_group_refresh(self, context, instance,
group_name):
'''Called when a security group loses a member.
:param context: the security context.
:param instance: the instance to be associated.
:param group_name: the name of the security group to be associated.'''
raise NotImplementedError()

def trigger_security_group_members_refresh(self, context, group_ids):
'''Called when a security group gains or loses a member.
:param context: the security context.
:param group_ids: a list of security group identifiers.'''
raise NotImplementedError()


class NullSecurityGroupHandler(SecurityGroupHandlerBase):

def __init__(self):
pass

def trigger_security_group_create_refresh(self, context, group):
'''Called when a rule is added to a security_group.
:param context: the security context.
:param group: the new group added. group is a dictionary that contains
the following: user_id, project_id, name, description).'''
pass

def trigger_security_group_destroy_refresh(self, context,
security_group_id):
'''Called when a rule is added to a security_group.
:param context: the security context.
:param security_group_id: the security group identifier.'''
pass

def trigger_security_group_rule_create_refresh(self, context,
rule_ids):
'''Called when a rule is added to a security_group.
:param context: the security context.
:param rule_ids: a list of rule ids that have been affected.'''
pass

def trigger_security_group_rule_destroy_refresh(self, context,
rule_ids):
'''Called when a rule is removed from a security_group.
:param context: the security context.
:param rule_ids: a list of rule ids that have been affected.'''
pass

def trigger_instance_add_security_group_refresh(self, context, instance,
group_name):
'''Called when a security group gains a new member.
:param context: the security context.
:param instance: the instance to be associated.
:param group_name: the name of the security group to be associated.'''
pass

def trigger_instance_remove_security_group_refresh(self, context, instance,
group_name):
'''Called when a security group loses a member.
:param context: the security context.
:param instance: the instance to be associated.
:param group_name: the name of the security group to be associated.'''
pass

def trigger_security_group_members_refresh(self, context, group_ids):
'''Called when a security group gains or loses a member.
:param context: the security context.
:param group_ids: a list of security group identifiers.'''
pass

0 comments on commit 269c0fc

Please sign in to comment.