diff --git a/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py b/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py index 00d43e5c3..32cb8f16e 100644 --- a/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py +++ b/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py @@ -3713,6 +3713,50 @@ class ApicMechanismDriver(api_plus.MechanismDriver, return tenant_id + @registry.receives(resources.ADDRESS_GROUP, [events.AFTER_UPDATE]) + def update_addresses_in_address_group(self, resource, event, + trigger, payload): + context = payload.context + with db_api.CONTEXT_WRITER.using(context): + aim_ctx = aim_context.AimContext(context.session) + + previous_state = payload.states[0] + updated_state = payload.states[1] + + if (previous_state['addresses'] != updated_state['addresses']): + ag_id = payload.states[0]['id'] + + query = BAKERY(lambda s: s.query( + sg_models.SecurityGroupRule)) + query += lambda q: q.join(ag_db.AddressGroup).filter( + sg_models.SecurityGroupRule.remote_address_group_id == + ag_db.AddressGroup.id) + sg_rules = query(context.session).params( + sg_rule=ag_id).all() + + if sg_rules: + sg_rule = sg_rules[0] + else: + return + + sg_rule_aim = aim_resource.SecurityGroupRule( + tenant_name="prj_" + payload.states[0]['tenant_id'], + security_group_name=sg_rule['security_group_id'], + security_group_subject_name='default', + name=sg_rule['id']) + aim_sg_rule = self.aim.get(aim_ctx, sg_rule_aim) + + for address in payload.states[0]['addresses']: + if address not in payload.states[1]['addresses']: + aim_sg_rule.remote_ips.remove(address) + + for address in payload.states[1]['addresses']: + if address not in payload.states[0]['addresses']: + aim_sg_rule.remote_ips.append(address) + + self.aim.update(aim_ctx, sg_rule_aim, + remote_ips=aim_sg_rule.remote_ips) + def _get_sg_tenant_id(self, session, sg_id): query = BAKERY(lambda s: s.query( sg_models.SecurityGroup.tenant_id)) @@ -3779,12 +3823,15 @@ class ApicMechanismDriver(api_plus.MechanismDriver, remote_ips = [] query = BAKERY(lambda s: s.query( - ag_db.AddressAssociation)) + ag_db.AddressAssociation)) + query += lambda q: q.join( + sg_models.SecurityGroupRule, + ag_db.AddressAssociation.address_group_id == + sg_models.SecurityGroupRule.remote_address_group_id) query += lambda q: q.filter( sg_models.SecurityGroupRule.remote_address_group_id == - ag_db.AddressGroup.id) - - addresses = query(session).params( + sa.bindparam('ag_id')) + address_group_list = query(session).params( ag_id=sg_rule['remote_address_group_id']).all() ip_version = 0 @@ -3793,10 +3840,10 @@ class ApicMechanismDriver(api_plus.MechanismDriver, elif sg_rule['ethertype'] == 'IPv6': ip_version = 6 - for addr in addresses: + for address_group in address_group_list: if ip_version == netaddr.IPAddress( - addr['address'].split('/')[0]).version: - remote_ips.append(addr['address']) + address_group['address'].split('/')[0]).version: + remote_ips.append(address_group['address']) remote_group_id = '' dn = '' diff --git a/gbpservice/neutron/tests/unit/plugins/ml2plus/test_apic_aim.py b/gbpservice/neutron/tests/unit/plugins/ml2plus/test_apic_aim.py index 1cb99478b..b5019b39f 100644 --- a/gbpservice/neutron/tests/unit/plugins/ml2plus/test_apic_aim.py +++ b/gbpservice/neutron/tests/unit/plugins/ml2plus/test_apic_aim.py @@ -12079,39 +12079,68 @@ class TestPortOnPhysicalNode(TestPortVlanNetwork): self.assertEqual(aim_sg_rule1.remote_ips, ['10.0.1.100']) def test_sg_rule_with_remote_address_group(self): + # Create network. net_resp = self._make_network(self.fmt, 'net1', True) + + # Create subnet self._make_subnet(self.fmt, net_resp, '10.0.1.1', '10.0.1.0/24')['subnet'] + + # create security group rule sg = self._make_security_group(self.fmt, 'test', 'test remote address group') sg_id = sg['security_group']['id'] - # Create Address group + # create address group ag = self._test_create_address_group(name='foo', - addresses=['10.0.1.0/24', - '192.168.0.1/32']) + addresses=['10.0.1.0/24']) ag_id = ag['address_group']['id'] + + # create security group rule rule = self._build_security_group_rule( sg_id, 'ingress', n_constants.PROTO_NAME_ICMP, '33', '2', remote_address_group_id=ag_id, ethertype=n_constants.IPv4) - - # Create security group rule with address group rule rules = {'security_group_rules': [rule['security_group_rule']]} sg_rule = self._make_security_group_rule( self.fmt, rules)['security_group_rules'][0] - tenant_aname = self.name_mapper.project(None, sg['security_group']['tenant_id']) aim_sg_rule = self._get_sg_rule( sg_rule['id'], 'default', sg_id, tenant_aname) + self.assertEqual(aim_sg_rule.remote_ips, ['10.0.1.0/24']) + # add addresses to address group + data = {'addresses': ['192.168.0.1/32']} + self._test_address_group_actions(ag['address_group']['id'], + data, 'add_addresses') + req = self.new_show_request('address-groups', + ag['address_group']['id']) + ag = self.deserialize(self.fmt, req.get_response(self.ext_api)) + aim_sg_rule = self._get_sg_rule( + sg_rule['id'], 'default', sg_id, tenant_aname) self.assertEqual(aim_sg_rule.remote_ips, - ['10.0.1.0/24', '192.168.0.1/32']) + ['10.0.1.0/24', '192.168.0.1/32']) - # Delete security group rule referenced with address group + # remove addresses to address group + data = {'addresses': ['192.168.0.1/32']} + self._test_address_group_actions(ag['address_group']['id'], + data, 'remove_addresses') + req = self.new_show_request('address-groups', + ag['address_group']['id']) + ag = self.deserialize(self.fmt, req.get_response(self.ext_api)) + aim_sg_rule = self._get_sg_rule( + sg_rule['id'], 'default', sg_id, tenant_aname) + self.assertEqual(aim_sg_rule.remote_ips, ['10.0.1.0/24']) + + # delete address group when sg rule reference present + self._delete('address-groups', ag['address_group']['id'], + expected_code=webob.exc.HTTPConflict.code) + + # delete address group with removing sg rule self._delete('security-group-rules', sg_rule['id']) - # Delete Address group self._delete('address-groups', ag['address_group']['id']) + self._show('address-groups', ag['address_group']['id'], + expected_code=webob.exc.HTTPNotFound.code) def _test_create_sg_rule_with_remote_group_set_different_tenant(self): session = db_api.get_reader_session()