From 2afbbab23a9d845cde511baa1e574fdcf5ab5171 Mon Sep 17 00:00:00 2001 From: David McNally Date: Wed, 1 Aug 2012 15:51:29 +0100 Subject: Making security group refresh more specific Fixes bug 1029495 The trigger_members_refresh method in compute.api.py specifies a group id in the call to refresh_security_group_members. This is just the last group id seen and ignores the fact that a refresh may impact members of multiple groups. This is masked by the fact that on the host the group id is ignored and all instances have their security rules refreshed regardless of if they are part of the changed group or not. This change modifies the logic surrounding refreshes so we send a refresh request for each instance which is affected by a security group change, this ensures we aren't spending time refreshing unaffected instances and also removes the possibility of refreshing an instance multiple times if it is a member of more than one group. Also changed to be instance-centric is the refresh carried out when a rule is added/removed to a security group. Change-Id: Iec98e9aed818fdc4ecc88c8dcdd4ee5fa9386e00 --- nova/compute/api.py | 26 ++++++++------------------ nova/compute/manager.py | 12 +++++++++++- nova/compute/rpcapi.py | 10 ++++++++++ 3 files changed, 29 insertions(+), 19 deletions(-) (limited to 'nova/compute') diff --git a/nova/compute/api.py b/nova/compute/api.py index b7aa99d45..93e62cb55 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -2164,20 +2164,16 @@ class SecurityGroupAPI(base.Base): security_group = self.db.security_group_get(context, id) - hosts = set() for instance in security_group['instances']: if instance['host'] is not None: - hosts.add(instance['host']) - - for host in hosts: - self.security_group_rpcapi.refresh_security_group_rules(context, - security_group.id, host=host) + self.security_group_rpcapi.refresh_instance_security_rules( + context, instance['host'], instance) 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 whom this is - relevant. + Sends an update request to each compute node for each instance for + which this is relevant. """ # First, we get the security group rules that reference these groups as # the grantee.. @@ -2188,7 +2184,7 @@ class SecurityGroupAPI(base.Base): context, group_id)) - # ..then we distill the security groups to which they belong.. + # ..then we distill the rules into the groups to which they belong.. security_groups = set() for rule in security_group_rules: security_group = self.db.security_group_get( @@ -2202,17 +2198,11 @@ class SecurityGroupAPI(base.Base): for instance in security_group['instances']: instances.add(instance) - # ...then we find the hosts where they live... - hosts = set() + # ..then we send a request to refresh the rules for each instance. for instance in instances: if instance['host']: - hosts.add(instance['host']) - - # ...and finally we tell these nodes to refresh their view of this - # particular security group. - for host in hosts: - self.security_group_rpcapi.refresh_security_group_members(context, - group_id, host=host) + self.security_group_rpcapi.refresh_instance_security_rules( + context, instance['host'], instance) def parse_cidr(self, cidr): if cidr: diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 9971be012..eb1e4cda7 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -221,7 +221,7 @@ def _get_image_meta(context, image_ref): class ComputeManager(manager.SchedulerDependentManager): """Manages the running instances from creation to destruction.""" - RPC_API_VERSION = '1.40' + RPC_API_VERSION = '1.41' def __init__(self, compute_driver=None, *args, **kwargs): """Load configuration options and connect to the hypervisor.""" @@ -355,6 +355,16 @@ class ComputeManager(manager.SchedulerDependentManager): """ return self.driver.refresh_security_group_members(security_group_id) + @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) + def refresh_instance_security_rules(self, context, instance): + """Tell the virtualization driver to refresh security rules for + an instance. + + Passes straight through to the virtualization driver. + + """ + return self.driver.refresh_instance_security_rules(instance) + @exception.wrap_exception(notifier=notifier, publisher_id=publisher_id()) def refresh_provider_fw_rules(self, context, **kwargs): """This call passes straight through to the virtualization driver.""" diff --git a/nova/compute/rpcapi.py b/nova/compute/rpcapi.py index 9b98f2ef5..9cee4f28d 100644 --- a/nova/compute/rpcapi.py +++ b/nova/compute/rpcapi.py @@ -119,6 +119,7 @@ class ComputeAPI(nova.openstack.common.rpc.proxy.RpcProxy): - remove topic, it was unused 1.39 - Remove instance_uuid, add instance argument to run_instance() 1.40 - Remove instance_id, add instance argument to live_migration() + 1.41 - Adds refresh_instance_security_rules() ''' BASE_RPC_API_VERSION = '1.0' @@ -521,6 +522,7 @@ class SecurityGroupAPI(nova.openstack.common.rpc.proxy.RpcProxy): API version history: 1.0 - Initial version. + 1.41 - Adds refresh_instance_security_rules() ''' BASE_RPC_API_VERSION = '1.0' @@ -540,3 +542,11 @@ class SecurityGroupAPI(nova.openstack.common.rpc.proxy.RpcProxy): self.cast(ctxt, self.make_msg('refresh_security_group_members', security_group_id=security_group_id), topic=_compute_topic(self.topic, ctxt, host, None)) + + def refresh_instance_security_rules(self, ctxt, host, instance): + instance_p = jsonutils.to_primitive(instance) + self.cast(ctxt, self.make_msg('refresh_instance_security_rules', + instance=instance_p), + topic=_compute_topic(self.topic, ctxt, instance['host'], + instance), + version='1.41') -- cgit