diff --git a/neutron/agent/securitygroups_rpc.py b/neutron/agent/securitygroups_rpc.py index 3c73e1557b3..8109123fff7 100644 --- a/neutron/agent/securitygroups_rpc.py +++ b/neutron/agent/securitygroups_rpc.py @@ -248,13 +248,17 @@ class SecurityGroupAgentRpc(object): def address_group_updated(self, address_group_id): LOG.info("Address group updated %r", address_group_id) - # TODO(mlavalle) A follow up patch in the address groups implementation - # series will add more code here + security_group_ids = ( + self.plugin_rpc.get_secgroup_ids_for_address_group( + address_group_id)) + self.security_groups_rule_updated(security_group_ids) def address_group_deleted(self, address_group_id): LOG.info("Address group deleted %r", address_group_id) - # TODO(mlavalle) A follow up patch in the address groups implementation - # series will add more code here + security_group_ids = ( + self.plugin_rpc.get_secgroup_ids_for_address_group( + address_group_id)) + self.security_groups_rule_updated(security_group_ids) def remove_devices_filter(self, device_ids): if not device_ids: diff --git a/neutron/api/rpc/handlers/securitygroups_rpc.py b/neutron/api/rpc/handlers/securitygroups_rpc.py index b1864723df4..f3a16cb346d 100644 --- a/neutron/api/rpc/handlers/securitygroups_rpc.py +++ b/neutron/api/rpc/handlers/securitygroups_rpc.py @@ -246,13 +246,10 @@ class SecurityGroupServerAPIShim(sg_rpc_base.SecurityGroupInfoAPIMixin): # error. raise NotImplementedError() - def get_address_group_details(self, address_group_id): - ag_obj = self.rcache.get_resource_by_id(resources.ADDRESSGROUP, - address_group_id) - if not ag_obj: - LOG.debug("Address group %s does not exist in cache.", - address_group_id) - return ag_obj + def get_secgroup_ids_for_address_group(self, address_group_id): + filters = {'remote_address_group_id': (address_group_id, )} + return set([rule.security_group_id for rule in + self.rcache.get_resources('SecurityGroupRule', filters)]) def _add_child_sg_rules(self, rtype, event, trigger, context, updated, **kwargs): diff --git a/neutron/db/address_group_db.py b/neutron/db/address_group_db.py index 93b2a84290e..738a219ec01 100644 --- a/neutron/db/address_group_db.py +++ b/neutron/db/address_group_db.py @@ -108,6 +108,12 @@ class AddressGroupDbMixin(ag_ext.AddressGroupPluginBase): addr_assoc = ag_obj.AddressAssociation(context, **args) addr_assoc.create() ag.update() # reload synthetic fields + # TODO(hangyang) this notification should be updated to publish when + # the callback handler handle_event, class _ObjectChangeHandler in + # neutron.plugins.ml2.ovo_rpc is updated to receive notifications with + # new style payload objects as argument. + registry.notify(ADDRESS_GROUP, events.AFTER_UPDATE, self, + context=context, address_group_id=ag.id) return {'address_group': self._make_address_group_dict(ag)} def remove_addresses(self, context, address_group_id, addresses): @@ -121,6 +127,12 @@ class AddressGroupDbMixin(ag_ext.AddressGroupPluginBase): ag_obj.AddressAssociation.delete_objects( context, address_group_id=address_group_id, address=addr) ag.update() # reload synthetic fields + # TODO(hangyang) this notification should be updated to publish when + # the callback handler handle_event, class _ObjectChangeHandler in + # neutron.plugins.ml2.ovo_rpc is updated to receive notifications with + # new style payload objects as argument. + registry.notify(ADDRESS_GROUP, events.AFTER_UPDATE, self, + context=context, address_group_id=ag.id) return {'address_group': self._make_address_group_dict(ag)} def create_address_group(self, context, address_group): @@ -132,15 +144,15 @@ class AddressGroupDbMixin(ag_ext.AddressGroupPluginBase): 'description': fields['description']} ag = ag_obj.AddressGroup(context, **args) ag.create() - if fields.get('addresses') is not constants.ATTR_NOT_SPECIFIED: - self.add_addresses(context, ag.id, fields) - ag.update() # reload synthetic fields # TODO(mlavalle) this notification should be updated to publish when # the callback handler handle_event, class _ObjectChangeHandler in # neutron.plugins.ml2.ovo_rpc is updated to receive notifications with # new style payload objects as argument. registry.notify(ADDRESS_GROUP, events.AFTER_CREATE, self, context=context, address_group_id=ag.id) + if fields.get('addresses') is not constants.ATTR_NOT_SPECIFIED: + self.add_addresses(context, ag.id, fields) + ag.update() # reload synthetic fields return self._make_address_group_dict(ag) def update_address_group(self, context, id, address_group): diff --git a/neutron/tests/unit/api/rpc/handlers/test_securitygroups_rpc.py b/neutron/tests/unit/api/rpc/handlers/test_securitygroups_rpc.py index 6cf5908d466..ba0666cb9bb 100644 --- a/neutron/tests/unit/api/rpc/handlers/test_securitygroups_rpc.py +++ b/neutron/tests/unit/api/rpc/handlers/test_securitygroups_rpc.py @@ -126,6 +126,8 @@ class SecurityGroupServerAPIShimTestCase(base.BaseTestCase): port_range_min=400, remote_group_id=attrs['id'], revision_number=1, + remote_address_group_id=kwargs.get('remote_address_group_id', + None), ) attrs['rules'] = [sg_rule] attrs.update(**kwargs) @@ -194,16 +196,15 @@ class SecurityGroupServerAPIShimTestCase(base.BaseTestCase): self.sg_agent.security_groups_member_updated.assert_called_with( {s1.id}) - def test_get_address_group_details(self): + def test_get_secgroup_ids_for_address_group(self): ag = self._make_address_group_ovo() - retrieved_ag = self.shim.get_address_group_details(ag.id) - self.assertEqual(ag.id, retrieved_ag.id) - self.assertEqual(ag.name, retrieved_ag.name) - self.assertEqual(ag.description, retrieved_ag.description) - self.assertEqual(ag.addresses[0].address, - retrieved_ag.addresses[0].address) - self.assertEqual(ag.addresses[1].address, - retrieved_ag.addresses[1].address) + sg1 = self._make_security_group_ovo(remote_address_group_id=ag.id) + sg2 = self._make_security_group_ovo(remote_address_group_id=ag.id) + sg3 = self._make_security_group_ovo() + sec_group_ids = self.shim.get_secgroup_ids_for_address_group(ag.id) + self.assertEqual(set([sg1.id, sg2.id]), set(sec_group_ids)) + self.assertEqual(2, len(sec_group_ids)) + self.assertNotIn(sg3.id, sec_group_ids) def test_address_group_update_events(self): ag = self._make_address_group_ovo() diff --git a/neutron/tests/unit/plugins/ml2/test_ovo_rpc.py b/neutron/tests/unit/plugins/ml2/test_ovo_rpc.py index 3373d334e4f..b984e61a1ac 100644 --- a/neutron/tests/unit/plugins/ml2/test_ovo_rpc.py +++ b/neutron/tests/unit/plugins/ml2/test_ovo_rpc.py @@ -39,14 +39,24 @@ class OVOServerRpcInterfaceTestCase(test_plugin.Ml2PluginV2TestCase): self.ovo_push_interface_p.stop() self.plugin.ovo_notifier = ovo_rpc.OVOServerRpcInterface() - def _assert_object_received(self, ovotype, oid=None, event=None): + def _assert_object_received(self, ovotype, oid=None, event=None, + count=1): self.plugin.ovo_notifier.wait() + match = 0 for obj, evt in self.received: if isinstance(obj, ovotype): if (obj.id == oid or not oid) and (not event or event == evt): - return obj - self.fail("Could not find OVO %s with ID %s in %s" % - (ovotype, oid, self.received)) + match += 1 + if count == 1: + return obj + if count > 1: + self.assertEqual( + match, count, + "Could not find match %s for OVO %s with ID %s in %s" % + (match, ovotype, oid, self.received)) + return + self.fail("Could not find OVO %s with ID %s or event %s in %s" % + (ovotype, oid, event, self.received)) def test_network_lifecycle(self): with self.network() as n: @@ -112,11 +122,19 @@ class OVOServerRpcInterfaceTestCase(test_plugin.Ml2PluginV2TestCase): 'addresses': ['10.0.0.1/32', '2001:db8::/32']}}) self._assert_object_received( - address_group.AddressGroup, ag['id'], 'updated') + address_group.AddressGroup, ag['id'], 'updated', 2) self.plugin.update_address_group(self.ctx, ag['id'], {'address_group': {'name': 'an-address-group-other-name'}}) self._assert_object_received( - address_group.AddressGroup, ag['id'], 'updated') + address_group.AddressGroup, ag['id'], 'updated', 3) + self.plugin.add_addresses(self.ctx, ag['id'], + {'addresses': ['10.0.0.2/32']}) + self._assert_object_received( + address_group.AddressGroup, ag['id'], 'updated', 4) + self.plugin.remove_addresses(self.ctx, ag['id'], + {'addresses': ['10.0.0.1/32']}) + self._assert_object_received( + address_group.AddressGroup, ag['id'], 'updated', 5) self.plugin.delete_address_group(self.ctx, ag['id']) self._assert_object_received( address_group.AddressGroup, ag['id'], 'deleted')