summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Lapsley <dlapsley@nicira.com>2012-02-15 18:04:23 -0500
committerDave Lapsley <dlapsley@nicira.com>2012-02-16 20:21:32 -0500
commit269c0fca4d2dd78fecdd142047c5198b41c4e7d7 (patch)
treee10be3457d207e5100134c3efd8db021e702dd70
parent31d1a423761ac2d68d227559f4e3f424487333be (diff)
downloadnova-269c0fca4d2dd78fecdd142047c5198b41c4e7d7.tar.gz
nova-269c0fca4d2dd78fecdd142047c5198b41c4e7d7.tar.xz
nova-269c0fca4d2dd78fecdd142047c5198b41c4e7d7.zip
Fix bug 933147 Security group trigger notifications.
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
-rw-r--r--nova/api/ec2/cloud.py14
-rw-r--r--nova/api/openstack/compute/contrib/security_groups.py14
-rw-r--r--nova/flags.py3
-rw-r--r--nova/network/manager.py5
-rw-r--r--nova/network/quantum/sg.py159
5 files changed, 193 insertions, 2 deletions
diff --git a/nova/api/ec2/cloud.py b/nova/api/ec2/cloud.py
index 560a2d0dd..1a574ec6f 100644
--- a/nova/api/ec2/cloud.py
+++ b/nova/api/ec2/cloud.py
@@ -202,6 +202,7 @@ class CloudController(object):
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'
@@ -622,6 +623,7 @@ class CloudController(object):
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:
@@ -634,11 +636,14 @@ class CloudController(object):
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."))
@@ -685,15 +690,19 @@ class CloudController(object):
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."))
@@ -744,6 +753,8 @@ class CloudController(object):
'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)]}
@@ -765,6 +776,9 @@ class CloudController(object):
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):
diff --git a/nova/api/openstack/compute/contrib/security_groups.py b/nova/api/openstack/compute/contrib/security_groups.py
index e1e5a47fe..d7e851468 100644
--- a/nova/api/openstack/compute/contrib/security_groups.py
+++ b/nova/api/openstack/compute/contrib/security_groups.py
@@ -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 = {}
@@ -236,6 +237,8 @@ class SecurityGroupController(object):
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)
@@ -290,6 +293,7 @@ class SecurityGroupController(object):
'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)}
@@ -366,7 +370,8 @@ class SecurityGroupRulesController(SecurityGroupController):
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'])
@@ -495,6 +500,8 @@ class SecurityGroupRulesController(SecurityGroupController):
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'])
@@ -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):
@@ -528,6 +536,8 @@ class SecurityGroupActionController(wsgi.Controller):
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:
@@ -560,6 +570,8 @@ class SecurityGroupActionController(wsgi.Controller):
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:
diff --git a/nova/flags.py b/nova/flags.py
index af490e287..4277d1eda 100644
--- a/nova/flags.py
+++ b/nova/flags.py
@@ -451,6 +451,9 @@ global_opts = [
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)
diff --git a/nova/network/manager.py b/nova/network/manager.py
index fe6cfa07a..5ad14f839 100644
--- a/nova/network/manager.py
+++ b/nova/network/manager.py
@@ -685,6 +685,7 @@ class NetworkManager(manager.SchedulerDependentManager):
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
@@ -761,7 +762,9 @@ class NetworkManager(manager.SchedulerDependentManager):
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
diff --git a/nova/network/quantum/sg.py b/nova/network/quantum/sg.py
new file mode 100644
index 000000000..93ba6be11
--- /dev/null
+++ b/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