)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"2329d765c96815c7f18f8d96cf0f463c695d7d82","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"9fde9715_2cd71560","updated":"2026-06-08 20:35:40.000000000","message":"A lot of comments, but most of them are along the same lines (e.g. put things in precommits).","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"70bea5e80fd644656cb6be7963f1b620ba6e3801","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"635f14b5_551716c7","updated":"2026-06-09 16:39:49.000000000","message":"recheck","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"3ab27754b53c03845ce4897b2cabc664528b2f37","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":11,"id":"34900b73_fc93b2cf","updated":"2026-06-17 12:03:05.000000000","message":"Getting closer - a few more changes.","commit_id":"752ba06b8c49cb81d1880fb30f7328614612a652"}],"gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/distributed_snat_helper.py":[{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"2329d765c96815c7f18f8d96cf0f463c695d7d82","unresolved":true,"context_lines":[{"line_number":28,"context_line":""},{"line_number":29,"context_line":"LOG \u003d logging.getLogger(__name__)"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":"COMMON_TENANT_NAME \u003d \u0027common\u0027"},{"line_number":32,"context_line":"UNROUTED_VRF_NAME \u003d \u0027UnroutedVRF\u0027"},{"line_number":33,"context_line":""},{"line_number":34,"context_line":""},{"line_number":35,"context_line":"class DistributedSnatHelper(object):"}],"source_content_type":"text/x-python","patch_set":1,"id":"65450564_4527edc8","line":32,"range":{"start_line":31,"start_character":0,"end_line":32,"end_character":33},"updated":"2026-06-08 20:35:40.000000000","message":"These are also defined in gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py. You may want to consider moving them to a common file.","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":28,"context_line":""},{"line_number":29,"context_line":"LOG \u003d logging.getLogger(__name__)"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":"COMMON_TENANT_NAME \u003d \u0027common\u0027"},{"line_number":32,"context_line":"UNROUTED_VRF_NAME \u003d \u0027UnroutedVRF\u0027"},{"line_number":33,"context_line":""},{"line_number":34,"context_line":""},{"line_number":35,"context_line":"class DistributedSnatHelper(object):"}],"source_content_type":"text/x-python","patch_set":1,"id":"2f8c18f7_9fc857aa","line":32,"range":{"start_line":31,"start_character":0,"end_line":32,"end_character":33},"in_reply_to":"65450564_4527edc8","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"2329d765c96815c7f18f8d96cf0f463c695d7d82","unresolved":true,"context_lines":[{"line_number":91,"context_line":"            network: Neutron network dict"},{"line_number":92,"context_line":"            tenant_name: Project tenant name"},{"line_number":93,"context_line":"        \"\"\""},{"line_number":94,"context_line":"        try:"},{"line_number":95,"context_line":"            net_id \u003d network[\u0027id\u0027]"},{"line_number":96,"context_line":"            bd_name \u003d self._service_network_bd_name(net_id)"},{"line_number":97,"context_line":"            vrf_name \u003d self._get_unrouted_vrf_name()"}],"source_content_type":"text/x-python","patch_set":1,"id":"619a4d22_75034faa","line":94,"range":{"start_line":94,"start_character":0,"end_line":94,"end_character":12},"updated":"2026-06-08 20:35:40.000000000","message":"For this and all other lifecycle methods, we shouldn\u0027t catch the exception, and instead let it bubble up to the top. That\u0027s the workflow that we use with the APIs.","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":91,"context_line":"            network: Neutron network dict"},{"line_number":92,"context_line":"            tenant_name: Project tenant name"},{"line_number":93,"context_line":"        \"\"\""},{"line_number":94,"context_line":"        try:"},{"line_number":95,"context_line":"            net_id \u003d network[\u0027id\u0027]"},{"line_number":96,"context_line":"            bd_name \u003d self._service_network_bd_name(net_id)"},{"line_number":97,"context_line":"            vrf_name \u003d self._get_unrouted_vrf_name()"}],"source_content_type":"text/x-python","patch_set":1,"id":"14134fe6_ce7145db","line":94,"range":{"start_line":94,"start_character":0,"end_line":94,"end_character":12},"in_reply_to":"619a4d22_75034faa","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"2329d765c96815c7f18f8d96cf0f463c695d7d82","unresolved":true,"context_lines":[{"line_number":94,"context_line":"        try:"},{"line_number":95,"context_line":"            net_id \u003d network[\u0027id\u0027]"},{"line_number":96,"context_line":"            bd_name \u003d self._service_network_bd_name(net_id)"},{"line_number":97,"context_line":"            vrf_name \u003d self._get_unrouted_vrf_name()"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"            # Create VRF if it doesn\u0027t exist"},{"line_number":100,"context_line":"            vrf \u003d aim_resource.VRF("},{"line_number":101,"context_line":"                tenant_name\u003dCOMMON_TENANT_NAME,"},{"line_number":102,"context_line":"                name\u003dvrf_name,"},{"line_number":103,"context_line":"                display_name\u003d\u0027SNAT VRF\u0027)"},{"line_number":104,"context_line":"            self.aim.create(aim_ctx, vrf, overwrite\u003dTrue)"},{"line_number":105,"context_line":""},{"line_number":106,"context_line":"            # Create BD in common tenant, associated with UnroutedVRF"},{"line_number":107,"context_line":"            bd \u003d aim_resource.BridgeDomain("}],"source_content_type":"text/x-python","patch_set":1,"id":"96438af8_40979a76","line":104,"range":{"start_line":97,"start_character":0,"end_line":104,"end_character":57},"updated":"2026-06-08 20:35:40.000000000","message":"The UnroutedVRF should already exist in the common tenant:\nhttps://opendev.org/x/group-based-policy/src/branch/master/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py#L468. No need to recreate it.","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":94,"context_line":"        try:"},{"line_number":95,"context_line":"            net_id \u003d network[\u0027id\u0027]"},{"line_number":96,"context_line":"            bd_name \u003d self._service_network_bd_name(net_id)"},{"line_number":97,"context_line":"            vrf_name \u003d self._get_unrouted_vrf_name()"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"            # Create VRF if it doesn\u0027t exist"},{"line_number":100,"context_line":"            vrf \u003d aim_resource.VRF("},{"line_number":101,"context_line":"                tenant_name\u003dCOMMON_TENANT_NAME,"},{"line_number":102,"context_line":"                name\u003dvrf_name,"},{"line_number":103,"context_line":"                display_name\u003d\u0027SNAT VRF\u0027)"},{"line_number":104,"context_line":"            self.aim.create(aim_ctx, vrf, overwrite\u003dTrue)"},{"line_number":105,"context_line":""},{"line_number":106,"context_line":"            # Create BD in common tenant, associated with UnroutedVRF"},{"line_number":107,"context_line":"            bd \u003d aim_resource.BridgeDomain("}],"source_content_type":"text/x-python","patch_set":1,"id":"ebb7493b_7f2b37f1","line":104,"range":{"start_line":97,"start_character":0,"end_line":104,"end_character":57},"in_reply_to":"96438af8_40979a76","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"2329d765c96815c7f18f8d96cf0f463c695d7d82","unresolved":true,"context_lines":[{"line_number":107,"context_line":"            bd \u003d aim_resource.BridgeDomain("},{"line_number":108,"context_line":"                tenant_name\u003dCOMMON_TENANT_NAME,"},{"line_number":109,"context_line":"                name\u003dbd_name,"},{"line_number":110,"context_line":"                display_name\u003df\u0027Service Network BD for {net_id}\u0027,"},{"line_number":111,"context_line":"                vrf_name\u003dvrf_name,"},{"line_number":112,"context_line":"                enable_routing\u003dFalse,"},{"line_number":113,"context_line":"                enable_arp_flood\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":1,"id":"eb936db8_2ce63d76","line":110,"range":{"start_line":110,"start_character":29,"end_line":110,"end_character":64},"updated":"2026-06-08 20:35:40.000000000","message":"This should come from the description in the OpenStack/Neutron network resource.","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":107,"context_line":"            bd \u003d aim_resource.BridgeDomain("},{"line_number":108,"context_line":"                tenant_name\u003dCOMMON_TENANT_NAME,"},{"line_number":109,"context_line":"                name\u003dbd_name,"},{"line_number":110,"context_line":"                display_name\u003df\u0027Service Network BD for {net_id}\u0027,"},{"line_number":111,"context_line":"                vrf_name\u003dvrf_name,"},{"line_number":112,"context_line":"                enable_routing\u003dFalse,"},{"line_number":113,"context_line":"                enable_arp_flood\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":1,"id":"0ea8be08_27810979","line":110,"range":{"start_line":110,"start_character":29,"end_line":110,"end_character":64},"in_reply_to":"eb936db8_2ce63d76","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"2329d765c96815c7f18f8d96cf0f463c695d7d82","unresolved":true,"context_lines":[{"line_number":138,"context_line":"                tenant_name\u003dbd.tenant_name,"},{"line_number":139,"context_line":"                bd_name\u003dbd.name,"},{"line_number":140,"context_line":"                gw_ip_mask\u003dcidr,"},{"line_number":141,"context_line":"                display_name\u003df\u0027Service Subnet {subnet_id}\u0027,"},{"line_number":142,"context_line":"                scope\u003d\u0027private\u0027,  # Do not advertise externally"},{"line_number":143,"context_line":"                monitored\u003dFalse)"},{"line_number":144,"context_line":"            self.aim.create(aim_ctx, bd_subnet, overwrite\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":1,"id":"9067feda_c7e52abe","line":141,"range":{"start_line":141,"start_character":29,"end_line":141,"end_character":59},"updated":"2026-06-08 20:35:40.000000000","message":"This should come from the name of the subnet resource in OpenStack.","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":138,"context_line":"                tenant_name\u003dbd.tenant_name,"},{"line_number":139,"context_line":"                bd_name\u003dbd.name,"},{"line_number":140,"context_line":"                gw_ip_mask\u003dcidr,"},{"line_number":141,"context_line":"                display_name\u003df\u0027Service Subnet {subnet_id}\u0027,"},{"line_number":142,"context_line":"                scope\u003d\u0027private\u0027,  # Do not advertise externally"},{"line_number":143,"context_line":"                monitored\u003dFalse)"},{"line_number":144,"context_line":"            self.aim.create(aim_ctx, bd_subnet, overwrite\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":1,"id":"9ee515b2_3b33d0a8","line":141,"range":{"start_line":141,"start_character":29,"end_line":141,"end_character":59},"in_reply_to":"9067feda_c7e52abe","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"2329d765c96815c7f18f8d96cf0f463c695d7d82","unresolved":true,"context_lines":[{"line_number":174,"context_line":"            epg_name \u003d \u0027snat_epg_\u0027 + self._generate_snat_resource_name("},{"line_number":175,"context_line":"                subnet_id)"},{"line_number":176,"context_line":""},{"line_number":177,"context_line":"            epg \u003d aim_resource.EndpointGroup("},{"line_number":178,"context_line":"                tenant_name\u003dtenant_name,"},{"line_number":179,"context_line":"                app_profile_name\u003dapplication_profile.name,"},{"line_number":180,"context_line":"                name\u003depg_name,"},{"line_number":181,"context_line":"                display_name\u003df\u0027SNAT EPG for subnet {subnet_id}\u0027,"},{"line_number":182,"context_line":"                openstack_vmexport\u003dTrue,"},{"line_number":183,"context_line":"                monitored\u003dFalse)"},{"line_number":184,"context_line":"            self.aim.create(aim_ctx, epg, overwrite\u003dTrue)"},{"line_number":185,"context_line":""},{"line_number":186,"context_line":"            LOG.debug(f\"Created SNAT EPG: {epg_name} in tenant {tenant_name}\")"},{"line_number":187,"context_line":"            return epg"}],"source_content_type":"text/x-python","patch_set":1,"id":"40cb38a4_25144c3b","line":184,"range":{"start_line":177,"start_character":0,"end_line":184,"end_character":57},"updated":"2026-06-08 20:35:40.000000000","message":"Here we want to create an ExternalNetwork resource in AIM, not an EPG. In fact, we should use the aim_lib\u0027s nat strategy to do this, similar to what\u0027s done in the rest of the mechanism driver (for example, see https://opendev.org/x/group-based-policy/src/branch/master/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py#L847)","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":174,"context_line":"            epg_name \u003d \u0027snat_epg_\u0027 + self._generate_snat_resource_name("},{"line_number":175,"context_line":"                subnet_id)"},{"line_number":176,"context_line":""},{"line_number":177,"context_line":"            epg \u003d aim_resource.EndpointGroup("},{"line_number":178,"context_line":"                tenant_name\u003dtenant_name,"},{"line_number":179,"context_line":"                app_profile_name\u003dapplication_profile.name,"},{"line_number":180,"context_line":"                name\u003depg_name,"},{"line_number":181,"context_line":"                display_name\u003df\u0027SNAT EPG for subnet {subnet_id}\u0027,"},{"line_number":182,"context_line":"                openstack_vmexport\u003dTrue,"},{"line_number":183,"context_line":"                monitored\u003dFalse)"},{"line_number":184,"context_line":"            self.aim.create(aim_ctx, epg, overwrite\u003dTrue)"},{"line_number":185,"context_line":""},{"line_number":186,"context_line":"            LOG.debug(f\"Created SNAT EPG: {epg_name} in tenant {tenant_name}\")"},{"line_number":187,"context_line":"            return epg"}],"source_content_type":"text/x-python","patch_set":1,"id":"4dd214e9_34b9a842","line":184,"range":{"start_line":177,"start_character":0,"end_line":184,"end_character":57},"in_reply_to":"40cb38a4_25144c3b","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"2329d765c96815c7f18f8d96cf0f463c695d7d82","unresolved":true,"context_lines":[{"line_number":208,"context_line":"            start_port \u003d subnet.get(cisco_apic.DIST_SNAT_START_PORT)"},{"line_number":209,"context_line":"            end_port \u003d subnet.get(cisco_apic.DIST_SNAT_END_PORT)"},{"line_number":210,"context_line":"            start_port \u003d start_port if start_port is not None else 0"},{"line_number":211,"context_line":"            end_port \u003d end_port if end_port is not None else 65535"},{"line_number":212,"context_line":""},{"line_number":213,"context_line":"            filters \u003d {}"},{"line_number":214,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"c674f6f9_68a6dd1c","line":211,"range":{"start_line":211,"start_character":61,"end_line":211,"end_character":66},"updated":"2026-06-08 20:35:40.000000000","message":"nit: this should be defined as a constant somewhere and used throughout (e.g. other uses of this constant below).","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":208,"context_line":"            start_port \u003d subnet.get(cisco_apic.DIST_SNAT_START_PORT)"},{"line_number":209,"context_line":"            end_port \u003d subnet.get(cisco_apic.DIST_SNAT_END_PORT)"},{"line_number":210,"context_line":"            start_port \u003d start_port if start_port is not None else 0"},{"line_number":211,"context_line":"            end_port \u003d end_port if end_port is not None else 65535"},{"line_number":212,"context_line":""},{"line_number":213,"context_line":"            filters \u003d {}"},{"line_number":214,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"e5b5a3bb_11cb2ef4","line":211,"range":{"start_line":211,"start_character":61,"end_line":211,"end_character":66},"in_reply_to":"c674f6f9_68a6dd1c","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"2329d765c96815c7f18f8d96cf0f463c695d7d82","unresolved":true,"context_lines":[{"line_number":218,"context_line":"                tenant_name\u003dtenant_name,"},{"line_number":219,"context_line":"                name\u003dtcp_filter_name,"},{"line_number":220,"context_line":"                display_name\u003df\u0027SNAT TCP filter {subnet_id}\u0027,"},{"line_number":221,"context_line":"                monitored\u003dFalse)"},{"line_number":222,"context_line":"            self.aim.create(aim_ctx, tcp_filter, overwrite\u003dTrue)"},{"line_number":223,"context_line":""},{"line_number":224,"context_line":"            # Add TCP port range entry"}],"source_content_type":"text/x-python","patch_set":1,"id":"c3e7479e_99d66250","line":221,"range":{"start_line":221,"start_character":16,"end_line":221,"end_character":31},"updated":"2026-06-08 20:35:40.000000000","message":"This is a nit, but the default for monitored is always False for AIM resources, and doesn\u0027t need to be specified when creating instances of the resources.","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":218,"context_line":"                tenant_name\u003dtenant_name,"},{"line_number":219,"context_line":"                name\u003dtcp_filter_name,"},{"line_number":220,"context_line":"                display_name\u003df\u0027SNAT TCP filter {subnet_id}\u0027,"},{"line_number":221,"context_line":"                monitored\u003dFalse)"},{"line_number":222,"context_line":"            self.aim.create(aim_ctx, tcp_filter, overwrite\u003dTrue)"},{"line_number":223,"context_line":""},{"line_number":224,"context_line":"            # Add TCP port range entry"}],"source_content_type":"text/x-python","patch_set":1,"id":"dd2c6abe_c3f8bc1f","line":221,"range":{"start_line":221,"start_character":16,"end_line":221,"end_character":31},"in_reply_to":"c3e7479e_99d66250","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"2329d765c96815c7f18f8d96cf0f463c695d7d82","unresolved":true,"context_lines":[{"line_number":558,"context_line":"            LOG.exception(f\"Failed to create device cluster interface: {e}\")"},{"line_number":559,"context_line":"            raise"},{"line_number":560,"context_line":""},{"line_number":561,"context_line":"    def _create_device_cluster_context(self, aim_ctx, tenant_name,"},{"line_number":562,"context_line":"                                      contract_name, service_graph_name,"},{"line_number":563,"context_line":"                                      node_name, device_cluster,"},{"line_number":564,"context_line":"                                      pbr_policies, bridge_domain\u003dNone):"},{"line_number":565,"context_line":"        \"\"\"Create device cluster context linking service graph to device."},{"line_number":566,"context_line":""},{"line_number":567,"context_line":"        Args:"},{"line_number":568,"context_line":"            aim_ctx: AimContext for AIM operations"},{"line_number":569,"context_line":"            tenant_name: Project tenant name"},{"line_number":570,"context_line":"            contract_name: Contract associated with context"},{"line_number":571,"context_line":"            service_graph_name: Service graph name"},{"line_number":572,"context_line":"            node_name: Node name in service graph"},{"line_number":573,"context_line":"            device_cluster: AIM DeviceCluster object"},{"line_number":574,"context_line":"            pbr_policies: Dict with \u0027provider\u0027 and \u0027consumer\u0027 PBR policies"},{"line_number":575,"context_line":"            bridge_domain: AIM BridgeDomain for the service network (optional)"},{"line_number":576,"context_line":""},{"line_number":577,"context_line":"        Returns:"},{"line_number":578,"context_line":"            aim_resource.DeviceClusterContext: Created context"},{"line_number":579,"context_line":"        \"\"\""},{"line_number":580,"context_line":"        try:"},{"line_number":581,"context_line":"            dcc \u003d aim_service_graph.DeviceClusterContext("},{"line_number":582,"context_line":"                tenant_name\u003dtenant_name,"},{"line_number":583,"context_line":"                contract_name\u003dcontract_name,"},{"line_number":584,"context_line":"                service_graph_name\u003dservice_graph_name,"},{"line_number":585,"context_line":"                node_name\u003dnode_name,"},{"line_number":586,"context_line":"                display_name\u003df\u0027Device cluster context for {node_name}\u0027,"},{"line_number":587,"context_line":"                device_cluster_name\u003ddevice_cluster.name,"},{"line_number":588,"context_line":"                device_cluster_tenant_name\u003ddevice_cluster.tenant_name,"},{"line_number":589,"context_line":"                service_redirect_policy_name\u003dpbr_policies[\u0027provider\u0027].name,"},{"line_number":590,"context_line":"                service_redirect_policy_tenant_name\u003dpbr_policies["},{"line_number":591,"context_line":"                    \u0027provider\u0027].tenant_name,"},{"line_number":592,"context_line":"                bridge_domain_name\u003dbridge_domain.name if bridge_domain else \u0027\u0027,"},{"line_number":593,"context_line":"                bridge_domain_tenant_name\u003d("},{"line_number":594,"context_line":"                    bridge_domain.tenant_name if bridge_domain else \u0027\u0027),"},{"line_number":595,"context_line":"                monitored\u003dFalse)"},{"line_number":596,"context_line":"            self.aim.create(aim_ctx, dcc, overwrite\u003dTrue)"},{"line_number":597,"context_line":""},{"line_number":598,"context_line":"            LOG.debug(f\"Created device cluster context for contract \""},{"line_number":599,"context_line":"                     f\"{contract_name}\")"},{"line_number":600,"context_line":"            return dcc"},{"line_number":601,"context_line":"        except Exception as e:"},{"line_number":602,"context_line":"            LOG.exception(f\"Failed to create device cluster context: {e}\")"},{"line_number":603,"context_line":"            raise"},{"line_number":604,"context_line":""},{"line_number":605,"context_line":"    def _create_provider_pbr(self, aim_ctx, subnet, tenant_name,"},{"line_number":606,"context_line":"                            service_ports):"},{"line_number":607,"context_line":"        \"\"\"Create provider-side Policy-Based Redirect."}],"source_content_type":"text/x-python","patch_set":1,"id":"89c2ba0f_a9590398","line":604,"range":{"start_line":561,"start_character":1,"end_line":604,"end_character":0},"updated":"2026-06-08 20:35:40.000000000","message":"I think some of these aren\u0027t useful - they\u0027re just creating the AIM resource and calling create. I don\u0027t think that each of these needs their own methods. If there are additional steps being done that are needed for multiple callers, or if multiple resources are created as part of some logical step, then a separate function is useful.","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":558,"context_line":"            LOG.exception(f\"Failed to create device cluster interface: {e}\")"},{"line_number":559,"context_line":"            raise"},{"line_number":560,"context_line":""},{"line_number":561,"context_line":"    def _create_device_cluster_context(self, aim_ctx, tenant_name,"},{"line_number":562,"context_line":"                                      contract_name, service_graph_name,"},{"line_number":563,"context_line":"                                      node_name, device_cluster,"},{"line_number":564,"context_line":"                                      pbr_policies, bridge_domain\u003dNone):"},{"line_number":565,"context_line":"        \"\"\"Create device cluster context linking service graph to device."},{"line_number":566,"context_line":""},{"line_number":567,"context_line":"        Args:"},{"line_number":568,"context_line":"            aim_ctx: AimContext for AIM operations"},{"line_number":569,"context_line":"            tenant_name: Project tenant name"},{"line_number":570,"context_line":"            contract_name: Contract associated with context"},{"line_number":571,"context_line":"            service_graph_name: Service graph name"},{"line_number":572,"context_line":"            node_name: Node name in service graph"},{"line_number":573,"context_line":"            device_cluster: AIM DeviceCluster object"},{"line_number":574,"context_line":"            pbr_policies: Dict with \u0027provider\u0027 and \u0027consumer\u0027 PBR policies"},{"line_number":575,"context_line":"            bridge_domain: AIM BridgeDomain for the service network (optional)"},{"line_number":576,"context_line":""},{"line_number":577,"context_line":"        Returns:"},{"line_number":578,"context_line":"            aim_resource.DeviceClusterContext: Created context"},{"line_number":579,"context_line":"        \"\"\""},{"line_number":580,"context_line":"        try:"},{"line_number":581,"context_line":"            dcc \u003d aim_service_graph.DeviceClusterContext("},{"line_number":582,"context_line":"                tenant_name\u003dtenant_name,"},{"line_number":583,"context_line":"                contract_name\u003dcontract_name,"},{"line_number":584,"context_line":"                service_graph_name\u003dservice_graph_name,"},{"line_number":585,"context_line":"                node_name\u003dnode_name,"},{"line_number":586,"context_line":"                display_name\u003df\u0027Device cluster context for {node_name}\u0027,"},{"line_number":587,"context_line":"                device_cluster_name\u003ddevice_cluster.name,"},{"line_number":588,"context_line":"                device_cluster_tenant_name\u003ddevice_cluster.tenant_name,"},{"line_number":589,"context_line":"                service_redirect_policy_name\u003dpbr_policies[\u0027provider\u0027].name,"},{"line_number":590,"context_line":"                service_redirect_policy_tenant_name\u003dpbr_policies["},{"line_number":591,"context_line":"                    \u0027provider\u0027].tenant_name,"},{"line_number":592,"context_line":"                bridge_domain_name\u003dbridge_domain.name if bridge_domain else \u0027\u0027,"},{"line_number":593,"context_line":"                bridge_domain_tenant_name\u003d("},{"line_number":594,"context_line":"                    bridge_domain.tenant_name if bridge_domain else \u0027\u0027),"},{"line_number":595,"context_line":"                monitored\u003dFalse)"},{"line_number":596,"context_line":"            self.aim.create(aim_ctx, dcc, overwrite\u003dTrue)"},{"line_number":597,"context_line":""},{"line_number":598,"context_line":"            LOG.debug(f\"Created device cluster context for contract \""},{"line_number":599,"context_line":"                     f\"{contract_name}\")"},{"line_number":600,"context_line":"            return dcc"},{"line_number":601,"context_line":"        except Exception as e:"},{"line_number":602,"context_line":"            LOG.exception(f\"Failed to create device cluster context: {e}\")"},{"line_number":603,"context_line":"            raise"},{"line_number":604,"context_line":""},{"line_number":605,"context_line":"    def _create_provider_pbr(self, aim_ctx, subnet, tenant_name,"},{"line_number":606,"context_line":"                            service_ports):"},{"line_number":607,"context_line":"        \"\"\"Create provider-side Policy-Based Redirect."}],"source_content_type":"text/x-python","patch_set":1,"id":"9af1d771_d042bf64","line":604,"range":{"start_line":561,"start_character":1,"end_line":604,"end_character":0},"in_reply_to":"89c2ba0f_a9590398","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"77611d407be905efa9b898186327e31baa8a161c","unresolved":true,"context_lines":[{"line_number":184,"context_line":""},{"line_number":185,"context_line":"        filters \u003d {}"},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"        # Create TCP filter"},{"line_number":188,"context_line":"        tcp_filter_name \u003d f\u0027snat_tcp_{filter_hash}\u0027"},{"line_number":189,"context_line":"        tcp_filter \u003d aim_resource.Filter("},{"line_number":190,"context_line":"            tenant_name\u003dtenant_name,"},{"line_number":191,"context_line":"            name\u003dtcp_filter_name,"},{"line_number":192,"context_line":"            display_name\u003df\u0027SNAT TCP filter {subnet_id}\u0027)"},{"line_number":193,"context_line":"        self.aim.create(aim_ctx, tcp_filter, overwrite\u003dTrue)"},{"line_number":194,"context_line":""},{"line_number":195,"context_line":"        # Add TCP port range entry"},{"line_number":196,"context_line":"        tcp_entry_name \u003d \u0027tcp_port_range\u0027"}],"source_content_type":"text/x-python","patch_set":3,"id":"cd55d219_9bd84b1b","line":193,"range":{"start_line":187,"start_character":0,"end_line":193,"end_character":60},"updated":"2026-06-09 11:58:12.000000000","message":"We will need to create 2 filters - one for the provider and one for the consumer - each with their own 2 filter entries. The consumer filter will use filter entries on source ports, and the provider filter will use filter entries on destination ports.","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":184,"context_line":""},{"line_number":185,"context_line":"        filters \u003d {}"},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"        # Create TCP filter"},{"line_number":188,"context_line":"        tcp_filter_name \u003d f\u0027snat_tcp_{filter_hash}\u0027"},{"line_number":189,"context_line":"        tcp_filter \u003d aim_resource.Filter("},{"line_number":190,"context_line":"            tenant_name\u003dtenant_name,"},{"line_number":191,"context_line":"            name\u003dtcp_filter_name,"},{"line_number":192,"context_line":"            display_name\u003df\u0027SNAT TCP filter {subnet_id}\u0027)"},{"line_number":193,"context_line":"        self.aim.create(aim_ctx, tcp_filter, overwrite\u003dTrue)"},{"line_number":194,"context_line":""},{"line_number":195,"context_line":"        # Add TCP port range entry"},{"line_number":196,"context_line":"        tcp_entry_name \u003d \u0027tcp_port_range\u0027"}],"source_content_type":"text/x-python","patch_set":3,"id":"8d87d342_d02ba114","line":193,"range":{"start_line":187,"start_character":0,"end_line":193,"end_character":60},"in_reply_to":"cd55d219_9bd84b1b","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":254,"context_line":"            tenant_name\u003dtenant_name,"},{"line_number":255,"context_line":"            name\u003dcontract_name,"},{"line_number":256,"context_line":"            display_name\u003df\u0027SNAT contract for subnet {subnet_id}\u0027"},{"line_number":257,"context_line":"            )"},{"line_number":258,"context_line":"        self.aim.create(aim_ctx, contract, overwrite\u003dTrue)"},{"line_number":259,"context_line":""},{"line_number":260,"context_line":"        # Create contract subject, binding both TCP and UDP filters."}],"source_content_type":"text/x-python","patch_set":3,"id":"73f80818_e9f535ae","line":257,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"77611d407be905efa9b898186327e31baa8a161c","unresolved":true,"context_lines":[{"line_number":260,"context_line":"        # Create contract subject, binding both TCP and UDP filters."},{"line_number":261,"context_line":"        # bi_filters links pre-created port-range filters to subject."},{"line_number":262,"context_line":"        subject_name \u003d \u0027snat_subj\u0027"},{"line_number":263,"context_line":"        subject \u003d aim_resource.ContractSubject("},{"line_number":264,"context_line":"            tenant_name\u003dtenant_name,"},{"line_number":265,"context_line":"            contract_name\u003dcontract_name,"},{"line_number":266,"context_line":"            name\u003dsubject_name,"}],"source_content_type":"text/x-python","patch_set":3,"id":"91ff9560_eb7dbfca","line":263,"range":{"start_line":263,"start_character":0,"end_line":263,"end_character":47},"updated":"2026-06-09 11:58:12.000000000","message":"You\u0027ll need to set the service_graph_names (see https://github.com/noironetworks/aci-integration-module/blob/master/aim/api/resource.py#L723-L724)","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":260,"context_line":"        # Create contract subject, binding both TCP and UDP filters."},{"line_number":261,"context_line":"        # bi_filters links pre-created port-range filters to subject."},{"line_number":262,"context_line":"        subject_name \u003d \u0027snat_subj\u0027"},{"line_number":263,"context_line":"        subject \u003d aim_resource.ContractSubject("},{"line_number":264,"context_line":"            tenant_name\u003dtenant_name,"},{"line_number":265,"context_line":"            contract_name\u003dcontract_name,"},{"line_number":266,"context_line":"            name\u003dsubject_name,"}],"source_content_type":"text/x-python","patch_set":3,"id":"e5ed10cf_8c8b5e5d","line":263,"range":{"start_line":263,"start_character":0,"end_line":263,"end_character":47},"in_reply_to":"91ff9560_eb7dbfca","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"77611d407be905efa9b898186327e31baa8a161c","unresolved":true,"context_lines":[{"line_number":265,"context_line":"            contract_name\u003dcontract_name,"},{"line_number":266,"context_line":"            name\u003dsubject_name,"},{"line_number":267,"context_line":"            display_name\u003df\u0027SNAT subject for subnet {subnet_id}\u0027,"},{"line_number":268,"context_line":"            bi_filters\u003d[filters[\u0027tcp_filter\u0027].name,"},{"line_number":269,"context_line":"                        filters[\u0027udp_filter\u0027].name]"},{"line_number":270,"context_line":"            )"},{"line_number":271,"context_line":"        self.aim.create(aim_ctx, subject, overwrite\u003dTrue)"},{"line_number":272,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"e91caad5_28b44e00","line":269,"range":{"start_line":268,"start_character":0,"end_line":269,"end_character":51},"updated":"2026-06-09 11:58:12.000000000","message":"These should be the new \"consumer\" or \"provider\" filters, and the filters will reference their respsective consumer or provider TCP/UDP filter entries.","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":265,"context_line":"            contract_name\u003dcontract_name,"},{"line_number":266,"context_line":"            name\u003dsubject_name,"},{"line_number":267,"context_line":"            display_name\u003df\u0027SNAT subject for subnet {subnet_id}\u0027,"},{"line_number":268,"context_line":"            bi_filters\u003d[filters[\u0027tcp_filter\u0027].name,"},{"line_number":269,"context_line":"                        filters[\u0027udp_filter\u0027].name]"},{"line_number":270,"context_line":"            )"},{"line_number":271,"context_line":"        self.aim.create(aim_ctx, subject, overwrite\u003dTrue)"},{"line_number":272,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"850e15f2_3369807c","line":269,"range":{"start_line":268,"start_character":0,"end_line":269,"end_character":51},"in_reply_to":"e91caad5_28b44e00","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":267,"context_line":"            display_name\u003df\u0027SNAT subject for subnet {subnet_id}\u0027,"},{"line_number":268,"context_line":"            bi_filters\u003d[filters[\u0027tcp_filter\u0027].name,"},{"line_number":269,"context_line":"                        filters[\u0027udp_filter\u0027].name]"},{"line_number":270,"context_line":"            )"},{"line_number":271,"context_line":"        self.aim.create(aim_ctx, subject, overwrite\u003dTrue)"},{"line_number":272,"context_line":""},{"line_number":273,"context_line":"        LOG.debug(f\"Created SNAT contract: {contract_name} in tenant \""}],"source_content_type":"text/x-python","patch_set":3,"id":"75164dd9_1f8dfd60","line":270,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":303,"context_line":"            connector_direction\u003d\u0027provider\u0027,"},{"line_number":304,"context_line":"            connector_type\u003d\u0027external\u0027,"},{"line_number":305,"context_line":"            adjacency_type\u003d\u0027L3\u0027"},{"line_number":306,"context_line":"            )"},{"line_number":307,"context_line":"        self.aim.create(aim_ctx, provider_conn, overwrite\u003dTrue)"},{"line_number":308,"context_line":""},{"line_number":309,"context_line":"        consumer_conn \u003d aim_service_graph.ServiceGraphConnection("}],"source_content_type":"text/x-python","patch_set":3,"id":"d8c5c33f_cac8eca8","line":306,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":313,"context_line":"            connector_direction\u003d\u0027consumer\u0027,"},{"line_number":314,"context_line":"            connector_type\u003d\u0027external\u0027,"},{"line_number":315,"context_line":"            adjacency_type\u003d\u0027L3\u0027"},{"line_number":316,"context_line":"            )"},{"line_number":317,"context_line":"        self.aim.create(aim_ctx, consumer_conn, overwrite\u003dTrue)"},{"line_number":318,"context_line":""},{"line_number":319,"context_line":"        LOG.debug(f\"Created service graph: {sg_name} in tenant \""}],"source_content_type":"text/x-python","patch_set":3,"id":"47ee4fd3_126ca8f3","line":316,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"77611d407be905efa9b898186327e31baa8a161c","unresolved":true,"context_lines":[{"line_number":343,"context_line":"            service_graph_name\u003dservice_graph.name,"},{"line_number":344,"context_line":"            name\u003dnode_name,"},{"line_number":345,"context_line":"            display_name\u003d\u0027SNAT loadbalancer node\u0027,"},{"line_number":346,"context_line":"            function_type\u003d\u0027GoThrough\u0027,  # Type for traffic steering"},{"line_number":347,"context_line":"            routing_mode\u003d\u0027Redirect\u0027,    # Enable PBR redirect"},{"line_number":348,"context_line":"            managed\u003dTrue,"},{"line_number":349,"context_line":"            connectors\u003d[\u0027provider\u0027, \u0027consumer\u0027],"}],"source_content_type":"text/x-python","patch_set":3,"id":"201a082c_08a9dae2","line":346,"range":{"start_line":346,"start_character":27,"end_line":346,"end_character":37},"updated":"2026-06-09 11:58:12.000000000","message":"We want this to be \u0027GoTo\u0027","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":343,"context_line":"            service_graph_name\u003dservice_graph.name,"},{"line_number":344,"context_line":"            name\u003dnode_name,"},{"line_number":345,"context_line":"            display_name\u003d\u0027SNAT loadbalancer node\u0027,"},{"line_number":346,"context_line":"            function_type\u003d\u0027GoThrough\u0027,  # Type for traffic steering"},{"line_number":347,"context_line":"            routing_mode\u003d\u0027Redirect\u0027,    # Enable PBR redirect"},{"line_number":348,"context_line":"            managed\u003dTrue,"},{"line_number":349,"context_line":"            connectors\u003d[\u0027provider\u0027, \u0027consumer\u0027],"}],"source_content_type":"text/x-python","patch_set":3,"id":"ca8e0e17_97f7edc8","line":346,"range":{"start_line":346,"start_character":27,"end_line":346,"end_character":37},"in_reply_to":"201a082c_08a9dae2","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"77611d407be905efa9b898186327e31baa8a161c","unresolved":true,"context_lines":[{"line_number":345,"context_line":"            display_name\u003d\u0027SNAT loadbalancer node\u0027,"},{"line_number":346,"context_line":"            function_type\u003d\u0027GoThrough\u0027,  # Type for traffic steering"},{"line_number":347,"context_line":"            routing_mode\u003d\u0027Redirect\u0027,    # Enable PBR redirect"},{"line_number":348,"context_line":"            managed\u003dTrue,"},{"line_number":349,"context_line":"            connectors\u003d[\u0027provider\u0027, \u0027consumer\u0027],"},{"line_number":350,"context_line":"            device_cluster_name\u003d(device_cluster.name if device_cluster"},{"line_number":351,"context_line":"                                 else \u0027\u0027),"}],"source_content_type":"text/x-python","patch_set":3,"id":"f2d11edc_5d0d4936","line":348,"range":{"start_line":348,"start_character":20,"end_line":348,"end_character":24},"updated":"2026-06-09 11:58:12.000000000","message":"This should be set to False","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":345,"context_line":"            display_name\u003d\u0027SNAT loadbalancer node\u0027,"},{"line_number":346,"context_line":"            function_type\u003d\u0027GoThrough\u0027,  # Type for traffic steering"},{"line_number":347,"context_line":"            routing_mode\u003d\u0027Redirect\u0027,    # Enable PBR redirect"},{"line_number":348,"context_line":"            managed\u003dTrue,"},{"line_number":349,"context_line":"            connectors\u003d[\u0027provider\u0027, \u0027consumer\u0027],"},{"line_number":350,"context_line":"            device_cluster_name\u003d(device_cluster.name if device_cluster"},{"line_number":351,"context_line":"                                 else \u0027\u0027),"}],"source_content_type":"text/x-python","patch_set":3,"id":"7fc05f41_513da092","line":348,"range":{"start_line":348,"start_character":20,"end_line":348,"end_character":24},"in_reply_to":"f2d11edc_5d0d4936","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":352,"context_line":"            device_cluster_tenant_name\u003d("},{"line_number":353,"context_line":"                device_cluster.tenant_name if device_cluster else \u0027\u0027),"},{"line_number":354,"context_line":"            sequence_number\u003d\u00270\u0027"},{"line_number":355,"context_line":"            )"},{"line_number":356,"context_line":"        self.aim.create(aim_ctx, node, overwrite\u003dTrue)"},{"line_number":357,"context_line":""},{"line_number":358,"context_line":"        # Update the service graph to include this node in linear_chain"}],"source_content_type":"text/x-python","patch_set":3,"id":"65f08dd2_c5292988","line":355,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"77611d407be905efa9b898186327e31baa8a161c","unresolved":true,"context_lines":[{"line_number":353,"context_line":"                device_cluster.tenant_name if device_cluster else \u0027\u0027),"},{"line_number":354,"context_line":"            sequence_number\u003d\u00270\u0027"},{"line_number":355,"context_line":"            )"},{"line_number":356,"context_line":"        self.aim.create(aim_ctx, node, overwrite\u003dTrue)"},{"line_number":357,"context_line":""},{"line_number":358,"context_line":"        # Update the service graph to include this node in linear_chain"},{"line_number":359,"context_line":"        service_graph.linear_chain_nodes \u003d [{"}],"source_content_type":"text/x-python","patch_set":3,"id":"9ebaf14b_b5f56e84","line":356,"range":{"start_line":356,"start_character":39,"end_line":356,"end_character":53},"updated":"2026-06-09 11:58:12.000000000","message":"We should only use this if it\u0027s possible we might be doing updates.","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":353,"context_line":"                device_cluster.tenant_name if device_cluster else \u0027\u0027),"},{"line_number":354,"context_line":"            sequence_number\u003d\u00270\u0027"},{"line_number":355,"context_line":"            )"},{"line_number":356,"context_line":"        self.aim.create(aim_ctx, node, overwrite\u003dTrue)"},{"line_number":357,"context_line":""},{"line_number":358,"context_line":"        # Update the service graph to include this node in linear_chain"},{"line_number":359,"context_line":"        service_graph.linear_chain_nodes \u003d [{"}],"source_content_type":"text/x-python","patch_set":3,"id":"0ba6b7ec_551fd767","line":356,"range":{"start_line":356,"start_character":39,"end_line":356,"end_character":53},"in_reply_to":"9ebaf14b_b5f56e84","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"77611d407be905efa9b898186327e31baa8a161c","unresolved":true,"context_lines":[{"line_number":393,"context_line":"            name\u003dcluster_name,"},{"line_number":394,"context_line":"            display_name\u003df\u0027SNAT device cluster for domain {physdom_name}\u0027,"},{"line_number":395,"context_line":"            device_type\u003d\u0027PHYSICAL\u0027,"},{"line_number":396,"context_line":"            service_type\u003d\u0027ADC\u0027,  # Application Delivery Controller"},{"line_number":397,"context_line":"            context_aware\u003d\u0027multi-Context\u0027,"},{"line_number":398,"context_line":"            physical_domain_name\u003dphysdom_name,"},{"line_number":399,"context_line":"            managed\u003dTrue,"}],"source_content_type":"text/x-python","patch_set":3,"id":"84f9a665_93afa47d","line":396,"range":{"start_line":396,"start_character":26,"end_line":396,"end_character":29},"updated":"2026-06-09 11:58:12.000000000","message":"Use \u0027OTHERS\u0027","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":393,"context_line":"            name\u003dcluster_name,"},{"line_number":394,"context_line":"            display_name\u003df\u0027SNAT device cluster for domain {physdom_name}\u0027,"},{"line_number":395,"context_line":"            device_type\u003d\u0027PHYSICAL\u0027,"},{"line_number":396,"context_line":"            service_type\u003d\u0027ADC\u0027,  # Application Delivery Controller"},{"line_number":397,"context_line":"            context_aware\u003d\u0027multi-Context\u0027,"},{"line_number":398,"context_line":"            physical_domain_name\u003dphysdom_name,"},{"line_number":399,"context_line":"            managed\u003dTrue,"}],"source_content_type":"text/x-python","patch_set":3,"id":"5b4bccdf_9c60e67f","line":396,"range":{"start_line":396,"start_character":26,"end_line":396,"end_character":29},"in_reply_to":"84f9a665_93afa47d","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"77611d407be905efa9b898186327e31baa8a161c","unresolved":true,"context_lines":[{"line_number":394,"context_line":"            display_name\u003df\u0027SNAT device cluster for domain {physdom_name}\u0027,"},{"line_number":395,"context_line":"            device_type\u003d\u0027PHYSICAL\u0027,"},{"line_number":396,"context_line":"            service_type\u003d\u0027ADC\u0027,  # Application Delivery Controller"},{"line_number":397,"context_line":"            context_aware\u003d\u0027multi-Context\u0027,"},{"line_number":398,"context_line":"            physical_domain_name\u003dphysdom_name,"},{"line_number":399,"context_line":"            managed\u003dTrue,"},{"line_number":400,"context_line":"            devices\u003d[])  # Will be populated as hosts are added"}],"source_content_type":"text/x-python","patch_set":3,"id":"63015cf0_8c79da08","line":397,"range":{"start_line":397,"start_character":27,"end_line":397,"end_character":40},"updated":"2026-06-09 11:58:12.000000000","message":"use \u0027Single-Context\u0027","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":394,"context_line":"            display_name\u003df\u0027SNAT device cluster for domain {physdom_name}\u0027,"},{"line_number":395,"context_line":"            device_type\u003d\u0027PHYSICAL\u0027,"},{"line_number":396,"context_line":"            service_type\u003d\u0027ADC\u0027,  # Application Delivery Controller"},{"line_number":397,"context_line":"            context_aware\u003d\u0027multi-Context\u0027,"},{"line_number":398,"context_line":"            physical_domain_name\u003dphysdom_name,"},{"line_number":399,"context_line":"            managed\u003dTrue,"},{"line_number":400,"context_line":"            devices\u003d[])  # Will be populated as hosts are added"}],"source_content_type":"text/x-python","patch_set":3,"id":"d43bea72_7678874f","line":397,"range":{"start_line":397,"start_character":27,"end_line":397,"end_character":40},"in_reply_to":"63015cf0_8c79da08","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"77611d407be905efa9b898186327e31baa8a161c","unresolved":true,"context_lines":[{"line_number":396,"context_line":"            service_type\u003d\u0027ADC\u0027,  # Application Delivery Controller"},{"line_number":397,"context_line":"            context_aware\u003d\u0027multi-Context\u0027,"},{"line_number":398,"context_line":"            physical_domain_name\u003dphysdom_name,"},{"line_number":399,"context_line":"            managed\u003dTrue,"},{"line_number":400,"context_line":"            devices\u003d[])  # Will be populated as hosts are added"},{"line_number":401,"context_line":"        self.aim.create(aim_ctx, cluster, overwrite\u003dTrue)"},{"line_number":402,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"4649ff61_19983c3a","line":399,"range":{"start_line":399,"start_character":20,"end_line":399,"end_character":24},"updated":"2026-06-09 11:58:12.000000000","message":"Set to False","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":396,"context_line":"            service_type\u003d\u0027ADC\u0027,  # Application Delivery Controller"},{"line_number":397,"context_line":"            context_aware\u003d\u0027multi-Context\u0027,"},{"line_number":398,"context_line":"            physical_domain_name\u003dphysdom_name,"},{"line_number":399,"context_line":"            managed\u003dTrue,"},{"line_number":400,"context_line":"            devices\u003d[])  # Will be populated as hosts are added"},{"line_number":401,"context_line":"        self.aim.create(aim_ctx, cluster, overwrite\u003dTrue)"},{"line_number":402,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"c4f08b02_6270674c","line":399,"range":{"start_line":399,"start_character":20,"end_line":399,"end_character":24},"in_reply_to":"4649ff61_19983c3a","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":425,"context_line":"            device_cluster_name\u003ddevice_cluster.name,"},{"line_number":426,"context_line":"            name\u003dhost_name,"},{"line_number":427,"context_line":"            display_name\u003df\u0027Concrete device for host {host_name}\u0027"},{"line_number":428,"context_line":"            )"},{"line_number":429,"context_line":"        self.aim.create(aim_ctx, device, overwrite\u003dTrue)"},{"line_number":430,"context_line":""},{"line_number":431,"context_line":"        LOG.debug(f\"Created concrete device: {host_name} in cluster \""}],"source_content_type":"text/x-python","patch_set":3,"id":"16e9a2c0_53d9d9de","line":428,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":454,"context_line":"            display_name\u003df\u0027Interface for {host}\u0027,"},{"line_number":455,"context_line":"            path\u003dpath,"},{"line_number":456,"context_line":"            host\u003dhost"},{"line_number":457,"context_line":"            )"},{"line_number":458,"context_line":"        self.aim.create(aim_ctx, interface, overwrite\u003dTrue)"},{"line_number":459,"context_line":""},{"line_number":460,"context_line":"        LOG.debug(f\"Created concrete interface: {interface_name} for \""}],"source_content_type":"text/x-python","patch_set":3,"id":"0f88079f_69a7709a","line":457,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":486,"context_line":"            display_name\u003df\u0027Logical interface {interface_name}\u0027,"},{"line_number":487,"context_line":"            encap\u003dencap,"},{"line_number":488,"context_line":"            concrete_interfaces\u003dconcrete_interfaces"},{"line_number":489,"context_line":"            )"},{"line_number":490,"context_line":"        self.aim.create(aim_ctx, dci, overwrite\u003dTrue)"},{"line_number":491,"context_line":""},{"line_number":492,"context_line":"        LOG.debug(f\"Created device cluster interface: {interface_name} \""}],"source_content_type":"text/x-python","patch_set":3,"id":"1e6a3f1c_471b75ec","line":489,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":526,"context_line":"            bridge_domain_name\u003dbridge_domain.name if bridge_domain else \u0027\u0027,"},{"line_number":527,"context_line":"            bridge_domain_tenant_name\u003d("},{"line_number":528,"context_line":"                bridge_domain.tenant_name if bridge_domain else \u0027\u0027)"},{"line_number":529,"context_line":"            )"},{"line_number":530,"context_line":"        self.aim.create(aim_ctx, dcc, overwrite\u003dTrue)"},{"line_number":531,"context_line":""},{"line_number":532,"context_line":"        LOG.debug(f\"Created device cluster context for contract \""}],"source_content_type":"text/x-python","patch_set":3,"id":"906f0bc0_03075c6f","line":529,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":565,"context_line":"            name\u003dpbr_name,"},{"line_number":566,"context_line":"            display_name\u003df\u0027Provider PBR for subnet {subnet_id}\u0027,"},{"line_number":567,"context_line":"            destinations\u003ddestinations"},{"line_number":568,"context_line":"            )"},{"line_number":569,"context_line":"        self.aim.create(aim_ctx, pbr, overwrite\u003dTrue)"},{"line_number":570,"context_line":""},{"line_number":571,"context_line":"        LOG.debug(f\"Created provider PBR: {pbr_name} with \""}],"source_content_type":"text/x-python","patch_set":3,"id":"ae406114_0a99f909","line":568,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":604,"context_line":"            name\u003dpbr_name,"},{"line_number":605,"context_line":"            display_name\u003df\u0027Consumer PBR for subnet {subnet_id}\u0027,"},{"line_number":606,"context_line":"            destinations\u003ddestinations"},{"line_number":607,"context_line":"            )"},{"line_number":608,"context_line":"        self.aim.create(aim_ctx, pbr, overwrite\u003dTrue)"},{"line_number":609,"context_line":""},{"line_number":610,"context_line":"        LOG.debug(f\"Created consumer PBR: {pbr_name} with \""}],"source_content_type":"text/x-python","patch_set":3,"id":"4c5c3005_ad119a0f","line":607,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":641,"context_line":"            name\u003dext_subnet_name,"},{"line_number":642,"context_line":"            cidr\u003df\u0027{gateway_ip}/32\u0027,"},{"line_number":643,"context_line":"            display_name\u003df\u0027Gateway IP for port {port_id}\u0027"},{"line_number":644,"context_line":"            )"},{"line_number":645,"context_line":"        self.aim.create(aim_ctx, ext_subnet, overwrite\u003dTrue)"},{"line_number":646,"context_line":""},{"line_number":647,"context_line":"        LOG.debug(f\"Added gateway IP {gateway_ip}/32 as external subnet \""}],"source_content_type":"text/x-python","patch_set":3,"id":"645b4d1a_9bc802f2","line":644,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":672,"context_line":"            external_network_name\u003dext_net.name,"},{"line_number":673,"context_line":"            name\u003dext_subnet_name,"},{"line_number":674,"context_line":"            cidr\u003df\u0027{gateway_ip}/32\u0027"},{"line_number":675,"context_line":"            )"},{"line_number":676,"context_line":"        self.aim.delete(aim_ctx, ext_subnet)"},{"line_number":677,"context_line":""},{"line_number":678,"context_line":"        LOG.debug(f\"Removed gateway IP {gateway_ip}/32 external subnet \""}],"source_content_type":"text/x-python","patch_set":3,"id":"6a826456_7c2504d7","line":675,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":703,"context_line":"            sg \u003d aim_service_graph.ServiceGraph("},{"line_number":704,"context_line":"                tenant_name\u003dtenant_name,"},{"line_number":705,"context_line":"                name\u003dsg_name"},{"line_number":706,"context_line":"                )"},{"line_number":707,"context_line":"            self.aim.delete(aim_ctx, sg)"},{"line_number":708,"context_line":""},{"line_number":709,"context_line":"        # Delete contract"}],"source_content_type":"text/x-python","patch_set":3,"id":"62ce37a4_f3d50d99","line":706,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":711,"context_line":"        contract \u003d aim_resource.Contract("},{"line_number":712,"context_line":"            tenant_name\u003dtenant_name,"},{"line_number":713,"context_line":"            name\u003dcontract_name"},{"line_number":714,"context_line":"            )"},{"line_number":715,"context_line":"        self.aim.delete(aim_ctx, contract)"},{"line_number":716,"context_line":""},{"line_number":717,"context_line":"        # Delete filters"}],"source_content_type":"text/x-python","patch_set":3,"id":"3a5d3202_0c64a0cf","line":714,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":719,"context_line":"        tcp_filter \u003d aim_resource.Filter("},{"line_number":720,"context_line":"            tenant_name\u003dtenant_name,"},{"line_number":721,"context_line":"            name\u003dtcp_filter_name"},{"line_number":722,"context_line":"            )"},{"line_number":723,"context_line":"        self.aim.delete(aim_ctx, tcp_filter)"},{"line_number":724,"context_line":""},{"line_number":725,"context_line":"        udp_filter_name \u003d f\u0027snat_udp_{subnet_hash}\u0027"}],"source_content_type":"text/x-python","patch_set":3,"id":"45b7c8f0_aabf6591","line":722,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":726,"context_line":"        udp_filter \u003d aim_resource.Filter("},{"line_number":727,"context_line":"            tenant_name\u003dtenant_name,"},{"line_number":728,"context_line":"            name\u003dudp_filter_name"},{"line_number":729,"context_line":"            )"},{"line_number":730,"context_line":"        self.aim.delete(aim_ctx, udp_filter)"},{"line_number":731,"context_line":""},{"line_number":732,"context_line":"        # Delete SNAT ExternalNetwork through nat strategy."}],"source_content_type":"text/x-python","patch_set":3,"id":"0442fb27_33fc3d5c","line":729,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":760,"context_line":"        bd \u003d aim_resource.BridgeDomain("},{"line_number":761,"context_line":"            tenant_name\u003dCOMMON_TENANT_NAME,"},{"line_number":762,"context_line":"            name\u003dbd_name"},{"line_number":763,"context_line":"            )"},{"line_number":764,"context_line":"        self.aim.delete(aim_ctx, bd)"},{"line_number":765,"context_line":""},{"line_number":766,"context_line":"        LOG.debug(f\"Deleted service network BD: {bd_name}\")"}],"source_content_type":"text/x-python","patch_set":3,"id":"4d0504b8_0e4c5299","line":763,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ab35c4e9788428c46f6f47430e48d4d3f44c0d5f","unresolved":false,"context_lines":[{"line_number":803,"context_line":"        cluster \u003d aim_service_graph.DeviceCluster("},{"line_number":804,"context_line":"            tenant_name\u003dtenant_name,"},{"line_number":805,"context_line":"            name\u003dcluster_name"},{"line_number":806,"context_line":"            )"},{"line_number":807,"context_line":"        self.aim.delete(aim_ctx, cluster)"},{"line_number":808,"context_line":""},{"line_number":809,"context_line":"        LOG.debug(f\"Deleted device cluster: {cluster_name} for domain \""}],"source_content_type":"text/x-python","patch_set":3,"id":"3f9ecff5_5216ca35","line":806,"updated":"2026-06-09 10:51:44.000000000","message":"pep8: E123 closing bracket does not match indentation of opening bracket\u0027s line","commit_id":"2efe3b931e1238d46f157a3af51dbf919f401588"}],"gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py":[{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"2329d765c96815c7f18f8d96cf0f463c695d7d82","unresolved":true,"context_lines":[{"line_number":825,"context_line":""},{"line_number":826,"context_line":"        if current.get(cisco_apic.SERVICE_NETWORK_ENABLE):"},{"line_number":827,"context_line":"            self._validate_service_network_network(current)"},{"line_number":828,"context_line":"            # Create service network BD in common tenant / UnroutedVRF"},{"line_number":829,"context_line":"            self._create_service_network_bd(aim_ctx, current,"},{"line_number":830,"context_line":"                                            COMMON_TENANT_NAME)"},{"line_number":831,"context_line":""},{"line_number":832,"context_line":"        if ((current[cisco_apic.EXTRA_PROVIDED_CONTRACTS] or"},{"line_number":833,"context_line":"             current[cisco_apic.EXTRA_CONSUMED_CONTRACTS]) and"}],"source_content_type":"text/x-python","patch_set":1,"id":"b3e23516_bb2bdac5","line":830,"range":{"start_line":828,"start_character":0,"end_line":830,"end_character":63},"updated":"2026-06-08 20:35:40.000000000","message":"The code here will have to do a bit more. In this case, we want to prevent the subsequent code from creating an EPG.","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":825,"context_line":""},{"line_number":826,"context_line":"        if current.get(cisco_apic.SERVICE_NETWORK_ENABLE):"},{"line_number":827,"context_line":"            self._validate_service_network_network(current)"},{"line_number":828,"context_line":"            # Create service network BD in common tenant / UnroutedVRF"},{"line_number":829,"context_line":"            self._create_service_network_bd(aim_ctx, current,"},{"line_number":830,"context_line":"                                            COMMON_TENANT_NAME)"},{"line_number":831,"context_line":""},{"line_number":832,"context_line":"        if ((current[cisco_apic.EXTRA_PROVIDED_CONTRACTS] or"},{"line_number":833,"context_line":"             current[cisco_apic.EXTRA_CONSUMED_CONTRACTS]) and"}],"source_content_type":"text/x-python","patch_set":1,"id":"b0c5e929_4b7f95a2","line":830,"range":{"start_line":828,"start_character":0,"end_line":830,"end_character":63},"in_reply_to":"b3e23516_bb2bdac5","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"2329d765c96815c7f18f8d96cf0f463c695d7d82","unresolved":true,"context_lines":[{"line_number":1536,"context_line":"        self.extend_network_dict_bulk(session, [(result, network_db)],"},{"line_number":1537,"context_line":"                                      single\u003dTrue)"},{"line_number":1538,"context_line":""},{"line_number":1539,"context_line":"    def create_subnet_precommit(self, context):"},{"line_number":1540,"context_line":"        current \u003d context.current"},{"line_number":1541,"context_line":"        LOG.debug(\"APIC AIM MD creating subnet: %s\", current)"},{"line_number":1542,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"a82d0122_69c9401e","line":1539,"range":{"start_line":1539,"start_character":0,"end_line":1539,"end_character":47},"updated":"2026-06-08 20:35:40.000000000","message":"This is where the handling of the extensions (e.g. distribute SNAT subnet) should be managed.","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":1536,"context_line":"        self.extend_network_dict_bulk(session, [(result, network_db)],"},{"line_number":1537,"context_line":"                                      single\u003dTrue)"},{"line_number":1538,"context_line":""},{"line_number":1539,"context_line":"    def create_subnet_precommit(self, context):"},{"line_number":1540,"context_line":"        current \u003d context.current"},{"line_number":1541,"context_line":"        LOG.debug(\"APIC AIM MD creating subnet: %s\", current)"},{"line_number":1542,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"d1a99b99_6d2d228c","line":1539,"range":{"start_line":1539,"start_character":0,"end_line":1539,"end_character":47},"in_reply_to":"a82d0122_69c9401e","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"2329d765c96815c7f18f8d96cf0f463c695d7d82","unresolved":true,"context_lines":[{"line_number":1669,"context_line":"            self._create_service_graph_node(aim_ctx, sg, None, tenant_name)"},{"line_number":1670,"context_line":""},{"line_number":1671,"context_line":"        # Program BD subnet for service network subnets"},{"line_number":1672,"context_line":"        if current.get(\u0027network_id\u0027):"},{"line_number":1673,"context_line":"            net \u003d self.plugin.get_network("},{"line_number":1674,"context_line":"                plugin_context, current[\u0027network_id\u0027])"},{"line_number":1675,"context_line":"            if net.get(cisco_apic.SERVICE_NETWORK_ENABLE):"}],"source_content_type":"text/x-python","patch_set":1,"id":"0f50086e_4f919680","line":1672,"range":{"start_line":1672,"start_character":8,"end_line":1672,"end_character":37},"updated":"2026-06-08 20:35:40.000000000","message":"You won\u0027t need to check for this - the subnet DB resource has a foreign key into the network resource, so it will always have a network ID. This code can just be kept under the if condition above (and you can get rid of the if check below). Also, since all of this is DB related, it all should be done in the precommit method. That way, if there is a problem at the DB layer, everything gets rolled back atomically on failure (no need for user or admin to clean up leftover resources).","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":1669,"context_line":"            self._create_service_graph_node(aim_ctx, sg, None, tenant_name)"},{"line_number":1670,"context_line":""},{"line_number":1671,"context_line":"        # Program BD subnet for service network subnets"},{"line_number":1672,"context_line":"        if current.get(\u0027network_id\u0027):"},{"line_number":1673,"context_line":"            net \u003d self.plugin.get_network("},{"line_number":1674,"context_line":"                plugin_context, current[\u0027network_id\u0027])"},{"line_number":1675,"context_line":"            if net.get(cisco_apic.SERVICE_NETWORK_ENABLE):"}],"source_content_type":"text/x-python","patch_set":1,"id":"83384e24_11f24a5f","line":1672,"range":{"start_line":1672,"start_character":8,"end_line":1672,"end_character":37},"in_reply_to":"0f50086e_4f919680","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"2329d765c96815c7f18f8d96cf0f463c695d7d82","unresolved":true,"context_lines":[{"line_number":3321,"context_line":"            plugin_context \u003d context._plugin_context"},{"line_number":3322,"context_line":"            session \u003d plugin_context.session"},{"line_number":3323,"context_line":"            aim_ctx \u003d aim_context.AimContext(session)"},{"line_number":3324,"context_line":"            self._handle_dist_snat_first_host_use("},{"line_number":3325,"context_line":"                plugin_context, aim_ctx, port)"},{"line_number":3326,"context_line":"        self._send_postcommit_notifications(context._plugin_context)"},{"line_number":3327,"context_line":""},{"line_number":3328,"context_line":"    def _insert_provisioning_block(self, context):"}],"source_content_type":"text/x-python","patch_set":1,"id":"5b9107e7_873549de","line":3325,"range":{"start_line":3324,"start_character":12,"end_line":3325,"end_character":46},"updated":"2026-06-08 20:35:40.000000000","message":"As this is a DB level operation, it should go in the precommit method.","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":3321,"context_line":"            plugin_context \u003d context._plugin_context"},{"line_number":3322,"context_line":"            session \u003d plugin_context.session"},{"line_number":3323,"context_line":"            aim_ctx \u003d aim_context.AimContext(session)"},{"line_number":3324,"context_line":"            self._handle_dist_snat_first_host_use("},{"line_number":3325,"context_line":"                plugin_context, aim_ctx, port)"},{"line_number":3326,"context_line":"        self._send_postcommit_notifications(context._plugin_context)"},{"line_number":3327,"context_line":""},{"line_number":3328,"context_line":"    def _insert_provisioning_block(self, context):"}],"source_content_type":"text/x-python","patch_set":1,"id":"f15a7ed8_77c91c38","line":3325,"range":{"start_line":3324,"start_character":12,"end_line":3325,"end_character":46},"in_reply_to":"5b9107e7_873549de","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"2329d765c96815c7f18f8d96cf0f463c695d7d82","unresolved":true,"context_lines":[{"line_number":3803,"context_line":"        LOG.debug(\"Provisioned distributed SNAT device cluster for \""},{"line_number":3804,"context_line":"                  \"host %s on physdoms %s\", host, physdoms)"},{"line_number":3805,"context_line":""},{"line_number":3806,"context_line":"    def _handle_dist_snat_host_vm_removal(self, plugin_context, aim_ctx,"},{"line_number":3807,"context_line":"                                          port):"},{"line_number":3808,"context_line":"        \"\"\"Remove ConcreteDevice or entire cluster on last VM departure."},{"line_number":3809,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"c9f813d0_f0c6a304","line":3806,"range":{"start_line":3806,"start_character":0,"end_line":3806,"end_character":72},"updated":"2026-06-08 20:35:40.000000000","message":"I think this method should be changed in order to minimize the number of round trips to the DB. The code as it is makes DB queries in loops. The goal is to see if some joined queries can be made to reduce this. \n\nI would first start by finding out what networks are bound to this host. You can find that out with a query like this:\n\n        networks \u003d session.query(seg_db.NetworkSegment.network_id).outerjoin(\n                seg_db.SegmentHostMapping,\n                seg_db.SegmentHostMapping.segment_id \u003d\u003d  \n                seg_db.NetworkSegment.id).filter(\n                        seg_db.SegmentHostMapping.host \u003d\u003d host).distinct()\n\nYou then want to find out which of these networks have connections to routers that have gateway ports with IPs on distribute SNAT subnets, and of those subnets, which ones are referencing the same service network. If there aren\u0027t any more, only then can the AIM resources be removed. You can use these methods as a reference:\nhttps://opendev.org/x/group-based-policy/src/branch/master/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py#L6824\nhttps://opendev.org/x/group-based-policy/src/branch/master/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py#L6839","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"fe9cc4497a74f6ba826ad8d2d1d58a89885e1fc0","unresolved":false,"context_lines":[{"line_number":3803,"context_line":"        LOG.debug(\"Provisioned distributed SNAT device cluster for \""},{"line_number":3804,"context_line":"                  \"host %s on physdoms %s\", host, physdoms)"},{"line_number":3805,"context_line":""},{"line_number":3806,"context_line":"    def _handle_dist_snat_host_vm_removal(self, plugin_context, aim_ctx,"},{"line_number":3807,"context_line":"                                          port):"},{"line_number":3808,"context_line":"        \"\"\"Remove ConcreteDevice or entire cluster on last VM departure."},{"line_number":3809,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"34716c2b_e687dc16","line":3806,"range":{"start_line":3806,"start_character":0,"end_line":3806,"end_character":72},"in_reply_to":"c9f813d0_f0c6a304","updated":"2026-06-09 14:22:07.000000000","message":"Done","commit_id":"d27e87083bf8da7ab7fa49c95933cd7919ce8976"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"42e2efd67b172e9edd94d630ba997fcdd170bcc8","unresolved":true,"context_lines":[{"line_number":830,"context_line":"                                            COMMON_TENANT_NAME)"},{"line_number":831,"context_line":"            # Service networks terminate here; do not create the normal"},{"line_number":832,"context_line":"            # external-network AIM objects for this network."},{"line_number":833,"context_line":"            return"},{"line_number":834,"context_line":""},{"line_number":835,"context_line":"        if ((current[cisco_apic.EXTRA_PROVIDED_CONTRACTS] or"},{"line_number":836,"context_line":"             current[cisco_apic.EXTRA_CONSUMED_CONTRACTS]) and"}],"source_content_type":"text/x-python","patch_set":7,"id":"48457892_06e709dc","line":833,"range":{"start_line":833,"start_character":12,"end_line":833,"end_character":18},"updated":"2026-06-14 16:10:27.000000000","message":"I just realized - since users would create this without the external network DN, there is already a return statement on line 853 below, so we we can remove this (and apologies for asking to add it before).","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"0c743fc6cd44637ead5d1233db186e89546adcb2","unresolved":false,"context_lines":[{"line_number":830,"context_line":"                                            COMMON_TENANT_NAME)"},{"line_number":831,"context_line":"            # Service networks terminate here; do not create the normal"},{"line_number":832,"context_line":"            # external-network AIM objects for this network."},{"line_number":833,"context_line":"            return"},{"line_number":834,"context_line":""},{"line_number":835,"context_line":"        if ((current[cisco_apic.EXTRA_PROVIDED_CONTRACTS] or"},{"line_number":836,"context_line":"             current[cisco_apic.EXTRA_CONSUMED_CONTRACTS]) and"}],"source_content_type":"text/x-python","patch_set":7,"id":"902802d0_a1586baf","line":833,"range":{"start_line":833,"start_character":12,"end_line":833,"end_character":18},"in_reply_to":"48457892_06e709dc","updated":"2026-06-15 06:15:33.000000000","message":"Done","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"42e2efd67b172e9edd94d630ba997fcdd170bcc8","unresolved":true,"context_lines":[{"line_number":1549,"context_line":"        network_id \u003d current[\u0027network_id\u0027]"},{"line_number":1550,"context_line":"        network_db \u003d self.plugin._get_network(context._plugin_context,"},{"line_number":1551,"context_line":"                                              network_id)"},{"line_number":1552,"context_line":"        network \u003d self.plugin.get_network(context._plugin_context,"},{"line_number":1553,"context_line":"                                          network_id)"},{"line_number":1554,"context_line":"        self._validate_subnet_snat_mode("},{"line_number":1555,"context_line":"            context._plugin_context, current,"},{"line_number":1556,"context_line":"            snat_pool\u003dcurrent.get(cisco_apic.SNAT_HOST_POOL, False),"}],"source_content_type":"text/x-python","patch_set":7,"id":"ee4787c2_aea4b5e5","line":1553,"range":{"start_line":1552,"start_character":0,"end_line":1553,"end_character":53},"updated":"2026-06-14 16:10:27.000000000","message":"No need to do this - the plugin already has the network in the context (see https://opendev.org/openstack/neutron/src/branch/master/neutron/plugins/ml2/plugin.py#L1480-L1481).","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"0c743fc6cd44637ead5d1233db186e89546adcb2","unresolved":false,"context_lines":[{"line_number":1549,"context_line":"        network_id \u003d current[\u0027network_id\u0027]"},{"line_number":1550,"context_line":"        network_db \u003d self.plugin._get_network(context._plugin_context,"},{"line_number":1551,"context_line":"                                              network_id)"},{"line_number":1552,"context_line":"        network \u003d self.plugin.get_network(context._plugin_context,"},{"line_number":1553,"context_line":"                                          network_id)"},{"line_number":1554,"context_line":"        self._validate_subnet_snat_mode("},{"line_number":1555,"context_line":"            context._plugin_context, current,"},{"line_number":1556,"context_line":"            snat_pool\u003dcurrent.get(cisco_apic.SNAT_HOST_POOL, False),"}],"source_content_type":"text/x-python","patch_set":7,"id":"50052e88_6586a985","line":1553,"range":{"start_line":1552,"start_character":0,"end_line":1553,"end_character":53},"in_reply_to":"ee4787c2_aea4b5e5","updated":"2026-06-15 06:15:33.000000000","message":"Done","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"42e2efd67b172e9edd94d630ba997fcdd170bcc8","unresolved":true,"context_lines":[{"line_number":1565,"context_line":"            current.get(cisco_apic.SHARED_BETWEEN_VRFS, False))"},{"line_number":1566,"context_line":""},{"line_number":1567,"context_line":"        # Program AIM policy for distributed SNAT subnets."},{"line_number":1568,"context_line":"        if current.get(cisco_apic.SERVICE_NETWORK):"},{"line_number":1569,"context_line":"            tenant_name \u003d self.name_mapper.project("},{"line_number":1570,"context_line":"                session, current[\u0027tenant_id\u0027])"},{"line_number":1571,"context_line":"            self._create_snat_external_network("},{"line_number":1572,"context_line":"                aim_ctx, current, network, tenant_name)"},{"line_number":1573,"context_line":"            filters \u003d self._create_snat_filters(aim_ctx, current, tenant_name)"},{"line_number":1574,"context_line":"            self._create_snat_contract("},{"line_number":1575,"context_line":"                aim_ctx, current, network, tenant_name, filters)"},{"line_number":1576,"context_line":"            sg \u003d self._create_service_graph(aim_ctx, network, tenant_name)"},{"line_number":1577,"context_line":"            self._create_service_graph_node(aim_ctx, sg, None, tenant_name)"},{"line_number":1578,"context_line":""},{"line_number":1579,"context_line":"        # Program BD subnet for service network subnets."},{"line_number":1580,"context_line":"        if network.get(cisco_apic.SERVICE_NETWORK_ENABLE):"}],"source_content_type":"text/x-python","patch_set":7,"id":"404ed751_3977c472","line":1577,"range":{"start_line":1568,"start_character":0,"end_line":1577,"end_character":75},"updated":"2026-06-14 16:10:27.000000000","message":"We need to add code to handle reassignment of the service network BD. Initially the service network BD reports to the UnroutedVRF in the common tenant. Once there is a distributed SNAT subnet that references the service network, the service network should be re-parented to the VRF used by the L3 Out for the OpenStack external network that owns this distributed SNAT subnet (and we\u0027ll also need the reverse logic that checks whenever a distributed SNAT subnet is deleted that references a service network, and re-parents it back to the UnroutedVRF if there are no other subnets that reference it).","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"0c743fc6cd44637ead5d1233db186e89546adcb2","unresolved":false,"context_lines":[{"line_number":1565,"context_line":"            current.get(cisco_apic.SHARED_BETWEEN_VRFS, False))"},{"line_number":1566,"context_line":""},{"line_number":1567,"context_line":"        # Program AIM policy for distributed SNAT subnets."},{"line_number":1568,"context_line":"        if current.get(cisco_apic.SERVICE_NETWORK):"},{"line_number":1569,"context_line":"            tenant_name \u003d self.name_mapper.project("},{"line_number":1570,"context_line":"                session, current[\u0027tenant_id\u0027])"},{"line_number":1571,"context_line":"            self._create_snat_external_network("},{"line_number":1572,"context_line":"                aim_ctx, current, network, tenant_name)"},{"line_number":1573,"context_line":"            filters \u003d self._create_snat_filters(aim_ctx, current, tenant_name)"},{"line_number":1574,"context_line":"            self._create_snat_contract("},{"line_number":1575,"context_line":"                aim_ctx, current, network, tenant_name, filters)"},{"line_number":1576,"context_line":"            sg \u003d self._create_service_graph(aim_ctx, network, tenant_name)"},{"line_number":1577,"context_line":"            self._create_service_graph_node(aim_ctx, sg, None, tenant_name)"},{"line_number":1578,"context_line":""},{"line_number":1579,"context_line":"        # Program BD subnet for service network subnets."},{"line_number":1580,"context_line":"        if network.get(cisco_apic.SERVICE_NETWORK_ENABLE):"}],"source_content_type":"text/x-python","patch_set":7,"id":"5c9df063_12635fff","line":1577,"range":{"start_line":1568,"start_character":0,"end_line":1577,"end_character":75},"in_reply_to":"404ed751_3977c472","updated":"2026-06-15 06:15:33.000000000","message":"Done","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"42e2efd67b172e9edd94d630ba997fcdd170bcc8","unresolved":true,"context_lines":[{"line_number":3300,"context_line":"            self._handle_dist_snat_gateway_ports("},{"line_number":3301,"context_line":"                context._plugin_context, aim_ctx, port, adding\u003dTrue)"},{"line_number":3302,"context_line":""},{"line_number":3303,"context_line":"        # On compute port binding, provision distributed-SNAT resources for"},{"line_number":3304,"context_line":"        # the first VM that lands on a host."},{"line_number":3305,"context_line":"        if (port[\u0027device_owner\u0027].startswith(\u0027compute:\u0027) and"},{"line_number":3306,"context_line":"            port.get(\u0027binding:host_id\u0027) and self._is_port_bound(port)):"},{"line_number":3307,"context_line":"            self._handle_dist_snat_first_host_use("},{"line_number":3308,"context_line":"                context._plugin_context, aim_ctx, port)"},{"line_number":3309,"context_line":""},{"line_number":3310,"context_line":"        # Handle router interface port creation."},{"line_number":3311,"context_line":"        if self._is_port_router_interface(port):"}],"source_content_type":"text/x-python","patch_set":7,"id":"74e7f41e_34c42e52","line":3308,"range":{"start_line":3303,"start_character":0,"end_line":3308,"end_character":55},"updated":"2026-06-14 16:10:27.000000000","message":"I think we will defer this to the agent RPC call (see https://review.opendev.org/c/x/group-based-policy/+/992625).","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"42e2efd67b172e9edd94d630ba997fcdd170bcc8","unresolved":true,"context_lines":[{"line_number":3300,"context_line":"            self._handle_dist_snat_gateway_ports("},{"line_number":3301,"context_line":"                context._plugin_context, aim_ctx, port, adding\u003dTrue)"},{"line_number":3302,"context_line":""},{"line_number":3303,"context_line":"        # On compute port binding, provision distributed-SNAT resources for"},{"line_number":3304,"context_line":"        # the first VM that lands on a host."},{"line_number":3305,"context_line":"        if (port[\u0027device_owner\u0027].startswith(\u0027compute:\u0027) and"},{"line_number":3306,"context_line":"            port.get(\u0027binding:host_id\u0027) and self._is_port_bound(port)):"},{"line_number":3307,"context_line":"            self._handle_dist_snat_first_host_use("},{"line_number":3308,"context_line":"                context._plugin_context, aim_ctx, port)"},{"line_number":3309,"context_line":""},{"line_number":3310,"context_line":"        # Handle router interface port creation."},{"line_number":3311,"context_line":"        if self._is_port_router_interface(port):"}],"source_content_type":"text/x-python","patch_set":7,"id":"717c7f6f_5ba56475","line":3308,"range":{"start_line":3303,"start_character":0,"end_line":3308,"end_character":55},"updated":"2026-06-14 16:10:27.000000000","message":"Instead of having this happen on port create, I think we should have this as part of the RPCs. A lot of the same queries are made there, so having it happen on both port create and for the RPC seems un-necessary.","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"0c743fc6cd44637ead5d1233db186e89546adcb2","unresolved":false,"context_lines":[{"line_number":3300,"context_line":"            self._handle_dist_snat_gateway_ports("},{"line_number":3301,"context_line":"                context._plugin_context, aim_ctx, port, adding\u003dTrue)"},{"line_number":3302,"context_line":""},{"line_number":3303,"context_line":"        # On compute port binding, provision distributed-SNAT resources for"},{"line_number":3304,"context_line":"        # the first VM that lands on a host."},{"line_number":3305,"context_line":"        if (port[\u0027device_owner\u0027].startswith(\u0027compute:\u0027) and"},{"line_number":3306,"context_line":"            port.get(\u0027binding:host_id\u0027) and self._is_port_bound(port)):"},{"line_number":3307,"context_line":"            self._handle_dist_snat_first_host_use("},{"line_number":3308,"context_line":"                context._plugin_context, aim_ctx, port)"},{"line_number":3309,"context_line":""},{"line_number":3310,"context_line":"        # Handle router interface port creation."},{"line_number":3311,"context_line":"        if self._is_port_router_interface(port):"}],"source_content_type":"text/x-python","patch_set":7,"id":"097cc341_f010e291","line":3308,"range":{"start_line":3303,"start_character":0,"end_line":3308,"end_character":55},"in_reply_to":"717c7f6f_5ba56475","updated":"2026-06-15 06:15:33.000000000","message":"Done","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"0c743fc6cd44637ead5d1233db186e89546adcb2","unresolved":false,"context_lines":[{"line_number":3300,"context_line":"            self._handle_dist_snat_gateway_ports("},{"line_number":3301,"context_line":"                context._plugin_context, aim_ctx, port, adding\u003dTrue)"},{"line_number":3302,"context_line":""},{"line_number":3303,"context_line":"        # On compute port binding, provision distributed-SNAT resources for"},{"line_number":3304,"context_line":"        # the first VM that lands on a host."},{"line_number":3305,"context_line":"        if (port[\u0027device_owner\u0027].startswith(\u0027compute:\u0027) and"},{"line_number":3306,"context_line":"            port.get(\u0027binding:host_id\u0027) and self._is_port_bound(port)):"},{"line_number":3307,"context_line":"            self._handle_dist_snat_first_host_use("},{"line_number":3308,"context_line":"                context._plugin_context, aim_ctx, port)"},{"line_number":3309,"context_line":""},{"line_number":3310,"context_line":"        # Handle router interface port creation."},{"line_number":3311,"context_line":"        if self._is_port_router_interface(port):"}],"source_content_type":"text/x-python","patch_set":7,"id":"fa3698c9_fc76cb95","line":3308,"range":{"start_line":3303,"start_character":0,"end_line":3308,"end_character":55},"in_reply_to":"74e7f41e_34c42e52","updated":"2026-06-15 06:15:33.000000000","message":"Done","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"42e2efd67b172e9edd94d630ba997fcdd170bcc8","unresolved":true,"context_lines":[{"line_number":3703,"context_line":"        \"\"\""},{"line_number":3704,"context_line":"        session \u003d plugin_context.session"},{"line_number":3705,"context_line":"        network_id \u003d port[\u0027network_id\u0027]"},{"line_number":3706,"context_line":"        network_db \u003d self.plugin._get_network(plugin_context, network_id)"},{"line_number":3707,"context_line":"        _, ext_net, _ \u003d self._get_aim_nat_strategy_db(session, network_db)"},{"line_number":3708,"context_line":"        if not ext_net:"},{"line_number":3709,"context_line":"            return"}],"source_content_type":"text/x-python","patch_set":7,"id":"3ac876c8_02804562","line":3706,"range":{"start_line":3706,"start_character":0,"end_line":3706,"end_character":73},"updated":"2026-06-14 16:10:27.000000000","message":"I think this is already available in the (port) context (see https://opendev.org/openstack/neutron/src/branch/master/neutron/plugins/ml2/plugin.py#L1646-L1649)","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"0c743fc6cd44637ead5d1233db186e89546adcb2","unresolved":false,"context_lines":[{"line_number":3703,"context_line":"        \"\"\""},{"line_number":3704,"context_line":"        session \u003d plugin_context.session"},{"line_number":3705,"context_line":"        network_id \u003d port[\u0027network_id\u0027]"},{"line_number":3706,"context_line":"        network_db \u003d self.plugin._get_network(plugin_context, network_id)"},{"line_number":3707,"context_line":"        _, ext_net, _ \u003d self._get_aim_nat_strategy_db(session, network_db)"},{"line_number":3708,"context_line":"        if not ext_net:"},{"line_number":3709,"context_line":"            return"}],"source_content_type":"text/x-python","patch_set":7,"id":"e552a5ed_9582ac8c","line":3706,"range":{"start_line":3706,"start_character":0,"end_line":3706,"end_character":73},"in_reply_to":"3ac876c8_02804562","updated":"2026-06-15 06:15:33.000000000","message":"Done","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"42e2efd67b172e9edd94d630ba997fcdd170bcc8","unresolved":true,"context_lines":[{"line_number":3815,"context_line":""},{"line_number":3816,"context_line":"        session \u003d plugin_context.session"},{"line_number":3817,"context_line":""},{"line_number":3818,"context_line":"        # Step 1: find networks currently bound to this host via a single"},{"line_number":3819,"context_line":"        # joined query on NetworkSegment / PortBindingLevel - no get_ports."},{"line_number":3820,"context_line":"        network_ids \u003d ["},{"line_number":3821,"context_line":"            r[0] for r in session.query("},{"line_number":3822,"context_line":"                segments_model.NetworkSegment.network_id"},{"line_number":3823,"context_line":"            ).join("},{"line_number":3824,"context_line":"                models.PortBindingLevel,"},{"line_number":3825,"context_line":"                models.PortBindingLevel.segment_id \u003d\u003d"},{"line_number":3826,"context_line":"                segments_model.NetworkSegment.id"},{"line_number":3827,"context_line":"            ).filter("},{"line_number":3828,"context_line":"                models.PortBindingLevel.host \u003d\u003d host"},{"line_number":3829,"context_line":"            ).distinct()"},{"line_number":3830,"context_line":"        ]"},{"line_number":3831,"context_line":"        if not network_ids:"},{"line_number":3832,"context_line":"            return"},{"line_number":3833,"context_line":""},{"line_number":3834,"context_line":"        # Step 2: get dist-SNAT subnet references for these networks using a"},{"line_number":3835,"context_line":"        # single DB query; map by service-network for later checks."},{"line_number":3836,"context_line":"        dist_snat_refs \u003d self._get_dist_snat_references_for_networks("},{"line_number":3837,"context_line":"            session, network_ids)"},{"line_number":3838,"context_line":"        if not dist_snat_refs:"},{"line_number":3839,"context_line":"            return"},{"line_number":3840,"context_line":"        service_network_ids \u003d {r[\u0027service_network_id\u0027] for r in dist_snat_refs}"}],"source_content_type":"text/x-python","patch_set":7,"id":"a5d95469_e1cc92bb","line":3837,"range":{"start_line":3818,"start_character":0,"end_line":3837,"end_character":33},"updated":"2026-06-14 16:10:27.000000000","message":"I don\u0027t think this query is correct. The ports bound to the host are going to be ports from the tenant/private network. The query to get distributed SNAT networks is for external networks. What is needed instead is a query that figures out which private networks have reachability to public networks via router interfaces and gateways, and which of the external networks for those public networks still reference service networks. Once you have that, you know whether or not there needs to be ports from the service network(s) allocated to this host (and if not, call the cleanup methods).","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"0c743fc6cd44637ead5d1233db186e89546adcb2","unresolved":false,"context_lines":[{"line_number":3815,"context_line":""},{"line_number":3816,"context_line":"        session \u003d plugin_context.session"},{"line_number":3817,"context_line":""},{"line_number":3818,"context_line":"        # Step 1: find networks currently bound to this host via a single"},{"line_number":3819,"context_line":"        # joined query on NetworkSegment / PortBindingLevel - no get_ports."},{"line_number":3820,"context_line":"        network_ids \u003d ["},{"line_number":3821,"context_line":"            r[0] for r in session.query("},{"line_number":3822,"context_line":"                segments_model.NetworkSegment.network_id"},{"line_number":3823,"context_line":"            ).join("},{"line_number":3824,"context_line":"                models.PortBindingLevel,"},{"line_number":3825,"context_line":"                models.PortBindingLevel.segment_id \u003d\u003d"},{"line_number":3826,"context_line":"                segments_model.NetworkSegment.id"},{"line_number":3827,"context_line":"            ).filter("},{"line_number":3828,"context_line":"                models.PortBindingLevel.host \u003d\u003d host"},{"line_number":3829,"context_line":"            ).distinct()"},{"line_number":3830,"context_line":"        ]"},{"line_number":3831,"context_line":"        if not network_ids:"},{"line_number":3832,"context_line":"            return"},{"line_number":3833,"context_line":""},{"line_number":3834,"context_line":"        # Step 2: get dist-SNAT subnet references for these networks using a"},{"line_number":3835,"context_line":"        # single DB query; map by service-network for later checks."},{"line_number":3836,"context_line":"        dist_snat_refs \u003d self._get_dist_snat_references_for_networks("},{"line_number":3837,"context_line":"            session, network_ids)"},{"line_number":3838,"context_line":"        if not dist_snat_refs:"},{"line_number":3839,"context_line":"            return"},{"line_number":3840,"context_line":"        service_network_ids \u003d {r[\u0027service_network_id\u0027] for r in dist_snat_refs}"}],"source_content_type":"text/x-python","patch_set":7,"id":"081e5a1b_f6908bf0","line":3837,"range":{"start_line":3818,"start_character":0,"end_line":3837,"end_character":33},"in_reply_to":"a5d95469_e1cc92bb","updated":"2026-06-15 06:15:33.000000000","message":"Done","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"42e2efd67b172e9edd94d630ba997fcdd170bcc8","unresolved":true,"context_lines":[{"line_number":3910,"context_line":"        return None"},{"line_number":3911,"context_line":""},{"line_number":3912,"context_line":"    def _get_dist_snat_subnets(self, plugin_context):"},{"line_number":3913,"context_line":"        \"\"\"Return all subnets that have apic:service_network set.\"\"\""},{"line_number":3914,"context_line":"        return [s for s in self.plugin.get_subnets(plugin_context)"},{"line_number":3915,"context_line":"                if s.get(cisco_apic.SERVICE_NETWORK)]"},{"line_number":3916,"context_line":""},{"line_number":3917,"context_line":"    def _get_dist_snat_subnets_for_networks(self, plugin_context, network_ids):"},{"line_number":3918,"context_line":"        \"\"\"Return dist-SNAT subnets whose network is in network_ids.\"\"\""}],"source_content_type":"text/x-python","patch_set":7,"id":"a1c3dcb2_b317aa6f","line":3915,"range":{"start_line":3913,"start_character":0,"end_line":3915,"end_character":53},"updated":"2026-06-14 16:10:27.000000000","message":"This seems bad, as it\u0027s doing a DB query for all subnets in OpenStack. You could do a joined query for SubnetExtensionDb with subnets, filtering on the service network (similar to what\u0027s done in _get_dist_snat_references_for_networks below).","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"0c743fc6cd44637ead5d1233db186e89546adcb2","unresolved":false,"context_lines":[{"line_number":3910,"context_line":"        return None"},{"line_number":3911,"context_line":""},{"line_number":3912,"context_line":"    def _get_dist_snat_subnets(self, plugin_context):"},{"line_number":3913,"context_line":"        \"\"\"Return all subnets that have apic:service_network set.\"\"\""},{"line_number":3914,"context_line":"        return [s for s in self.plugin.get_subnets(plugin_context)"},{"line_number":3915,"context_line":"                if s.get(cisco_apic.SERVICE_NETWORK)]"},{"line_number":3916,"context_line":""},{"line_number":3917,"context_line":"    def _get_dist_snat_subnets_for_networks(self, plugin_context, network_ids):"},{"line_number":3918,"context_line":"        \"\"\"Return dist-SNAT subnets whose network is in network_ids.\"\"\""}],"source_content_type":"text/x-python","patch_set":7,"id":"4f6a5ec3_00bbec70","line":3915,"range":{"start_line":3913,"start_character":0,"end_line":3915,"end_character":53},"in_reply_to":"a1c3dcb2_b317aa6f","updated":"2026-06-15 06:15:33.000000000","message":"Done","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"42e2efd67b172e9edd94d630ba997fcdd170bcc8","unresolved":true,"context_lines":[{"line_number":3918,"context_line":"        \"\"\"Return dist-SNAT subnets whose network is in network_ids.\"\"\""},{"line_number":3919,"context_line":"        if not network_ids:"},{"line_number":3920,"context_line":"            return []"},{"line_number":3921,"context_line":"        return [s for s in self.plugin.get_subnets("},{"line_number":3922,"context_line":"            plugin_context, filters\u003d{\u0027network_id\u0027: list(network_ids)})"},{"line_number":3923,"context_line":"            if s.get(cisco_apic.SERVICE_NETWORK)]"},{"line_number":3924,"context_line":""},{"line_number":3925,"context_line":"    def _get_dist_snat_references_for_networks(self, session, network_ids):"},{"line_number":3926,"context_line":"        \"\"\"Return dist-SNAT subnet/service-network refs for given networks.\"\"\""}],"source_content_type":"text/x-python","patch_set":7,"id":"a296b46d_d0c1960e","line":3923,"range":{"start_line":3921,"start_character":0,"end_line":3923,"end_character":49},"updated":"2026-06-14 16:10:27.000000000","message":"Same comment as above.","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"0c743fc6cd44637ead5d1233db186e89546adcb2","unresolved":false,"context_lines":[{"line_number":3918,"context_line":"        \"\"\"Return dist-SNAT subnets whose network is in network_ids.\"\"\""},{"line_number":3919,"context_line":"        if not network_ids:"},{"line_number":3920,"context_line":"            return []"},{"line_number":3921,"context_line":"        return [s for s in self.plugin.get_subnets("},{"line_number":3922,"context_line":"            plugin_context, filters\u003d{\u0027network_id\u0027: list(network_ids)})"},{"line_number":3923,"context_line":"            if s.get(cisco_apic.SERVICE_NETWORK)]"},{"line_number":3924,"context_line":""},{"line_number":3925,"context_line":"    def _get_dist_snat_references_for_networks(self, session, network_ids):"},{"line_number":3926,"context_line":"        \"\"\"Return dist-SNAT subnet/service-network refs for given networks.\"\"\""}],"source_content_type":"text/x-python","patch_set":7,"id":"842b00ef_846755c3","line":3923,"range":{"start_line":3921,"start_character":0,"end_line":3923,"end_character":49},"in_reply_to":"a296b46d_d0c1960e","updated":"2026-06-15 06:15:33.000000000","message":"Done","commit_id":"3bef58d26a1f8bbd30a6ff1e7ed0393dc395f52c"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"3ab27754b53c03845ce4897b2cabc664528b2f37","unresolved":true,"context_lines":[{"line_number":3712,"context_line":"        delegates to the helper for the actual AIM resource work."},{"line_number":3713,"context_line":"        \"\"\""},{"line_number":3714,"context_line":"        session \u003d plugin_context.session"},{"line_number":3715,"context_line":"        network_id \u003d port[\u0027network_id\u0027]"},{"line_number":3716,"context_line":"        if network is None:"},{"line_number":3717,"context_line":"            network \u003d self.plugin.get_network(plugin_context, network_id)"},{"line_number":3718,"context_line":"        _, ext_net, _ \u003d self._get_aim_nat_strategy(network)"},{"line_number":3719,"context_line":"        if not ext_net:"},{"line_number":3720,"context_line":"            return"}],"source_content_type":"text/x-python","patch_set":11,"id":"2c5d1b51_902a85e9","line":3717,"range":{"start_line":3715,"start_character":0,"end_line":3717,"end_character":73},"updated":"2026-06-17 12:03:05.000000000","message":"I think you can pass in the context from the create_/delete_port_precommit calls, as this should have the network. This avoids another round trip to the DB.","commit_id":"752ba06b8c49cb81d1880fb30f7328614612a652"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"3ab27754b53c03845ce4897b2cabc664528b2f37","unresolved":true,"context_lines":[{"line_number":3722,"context_line":"            plugin_context,"},{"line_number":3723,"context_line":"            filters\u003d{\u0027network_id\u0027: [network_id]})"},{"line_number":3724,"context_line":"        for subnet in subnets:"},{"line_number":3725,"context_line":"            if not subnet.get(cisco_apic.SERVICE_NETWORK):"},{"line_number":3726,"context_line":"                continue"},{"line_number":3727,"context_line":"            tenant_name \u003d self.name_mapper.project("},{"line_number":3728,"context_line":"                session, subnet[\u0027tenant_id\u0027])"},{"line_number":3729,"context_line":"            if adding:"}],"source_content_type":"text/x-python","patch_set":11,"id":"17bbfab3_e8e2821d","line":3726,"range":{"start_line":3725,"start_character":0,"end_line":3726,"end_character":24},"updated":"2026-06-17 12:03:05.000000000","message":"This does bring up an interesting question - what if there are multiple distributed SNAT subnets on the external network. One reason for supporting this is if the CIDRs available don\u0027t support many IPs (which translate to tenants - b/c the router gateway from the tenant consumes an SNAT IP). We may want to put a constraint here that all distributed SNAT subnets on an external network should reference the same service network, in order to simplify resource management.","commit_id":"752ba06b8c49cb81d1880fb30f7328614612a652"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"3ab27754b53c03845ce4897b2cabc664528b2f37","unresolved":true,"context_lines":[{"line_number":3826,"context_line":""},{"line_number":3827,"context_line":"        session \u003d plugin_context.session"},{"line_number":3828,"context_line":""},{"line_number":3829,"context_line":"        # Step 1: find private/tenant networks currently bound to this host"},{"line_number":3830,"context_line":"        # via a joined query on NetworkSegment / PortBindingLevel."},{"line_number":3831,"context_line":"        private_network_ids \u003d ["},{"line_number":3832,"context_line":"            r[0] for r in session.query("},{"line_number":3833,"context_line":"                segments_model.NetworkSegment.network_id"},{"line_number":3834,"context_line":"            ).join("},{"line_number":3835,"context_line":"                models.PortBindingLevel,"},{"line_number":3836,"context_line":"                models.PortBindingLevel.segment_id \u003d\u003d"},{"line_number":3837,"context_line":"                segments_model.NetworkSegment.id"},{"line_number":3838,"context_line":"            ).filter("},{"line_number":3839,"context_line":"                models.PortBindingLevel.host \u003d\u003d host"},{"line_number":3840,"context_line":"            ).distinct()"},{"line_number":3841,"context_line":"        ]"},{"line_number":3842,"context_line":"        if not private_network_ids:"},{"line_number":3843,"context_line":"            return"},{"line_number":3844,"context_line":""},{"line_number":3845,"context_line":"        # Step 2: derive external networks reachable from these private"},{"line_number":3846,"context_line":"        # networks through router interfaces + router gateways."},{"line_number":3847,"context_line":"        external_network_ids \u003d self._get_reachable_external_network_ids("},{"line_number":3848,"context_line":"            session, private_network_ids)"},{"line_number":3849,"context_line":"        if not external_network_ids:"},{"line_number":3850,"context_line":"            return"},{"line_number":3851,"context_line":""},{"line_number":3852,"context_line":"        # Step 3: among those reachable external networks, find dist-SNAT"},{"line_number":3853,"context_line":"        # subnet references and service networks to evaluate."},{"line_number":3854,"context_line":"        dist_snat_refs \u003d self._get_dist_snat_references_for_networks("},{"line_number":3855,"context_line":"            session, external_network_ids)"},{"line_number":3856,"context_line":"        if not dist_snat_refs:"},{"line_number":3857,"context_line":"            return"},{"line_number":3858,"context_line":"        service_network_ids \u003d {r[\u0027service_network_id\u0027] for r in dist_snat_refs}"},{"line_number":3859,"context_line":""},{"line_number":3860,"context_line":"        # Step 4: keep resources while any affected dist-SNAT service-network"},{"line_number":3861,"context_line":"        # is still referenced by router gateway IPs on reachable external"},{"line_number":3862,"context_line":"        # networks."},{"line_number":3863,"context_line":"        active_service_nets \u003d self._get_active_dist_snat_service_networks("},{"line_number":3864,"context_line":"            session, external_network_ids, service_network_ids)"},{"line_number":3865,"context_line":"        if active_service_nets:"},{"line_number":3866,"context_line":"            return"},{"line_number":3867,"context_line":""},{"line_number":3868,"context_line":"        # Step 5: are there remaining compute ports on this host on those"},{"line_number":3869,"context_line":"        # private networks (excluding the port being deleted)?"},{"line_number":3870,"context_line":"        remaining \u003d session.query(models_v2.Port.id).join("},{"line_number":3871,"context_line":"            models.PortBindingLevel,"},{"line_number":3872,"context_line":"            models.PortBindingLevel.port_id \u003d\u003d models_v2.Port.id"},{"line_number":3873,"context_line":"        ).filter("},{"line_number":3874,"context_line":"            models.PortBindingLevel.host \u003d\u003d host,"},{"line_number":3875,"context_line":"            models_v2.Port.device_owner.like(\u0027compute:%\u0027),"},{"line_number":3876,"context_line":"            models_v2.Port.network_id.in_(private_network_ids),"},{"line_number":3877,"context_line":"            models_v2.Port.id !\u003d port[\u0027id\u0027]"},{"line_number":3878,"context_line":"        ).limit(1).count()"},{"line_number":3879,"context_line":"        if remaining \u003e 0:"},{"line_number":3880,"context_line":"            return"},{"line_number":3881,"context_line":""},{"line_number":3882,"context_line":"        # Step 6: get physdoms for the departing host from AIM HostLinks."},{"line_number":3883,"context_line":"        host_links \u003d self.aim.find(aim_ctx, aim_infra.HostLink,"}],"source_content_type":"text/x-python","patch_set":11,"id":"48189ee8_6b64fd2d","line":3880,"range":{"start_line":3829,"start_character":1,"end_line":3880,"end_character":18},"updated":"2026-06-17 12:03:05.000000000","message":"Can you investigate whether we can turn these separate queries into fewer joined queries? The separate queries helps explain the associations being made, but it will have an impact on scalability (given that this is a per-port call). There may be some pieces in https://review.opendev.org/c/x/group-based-policy/+/992625 that you can leverage.","commit_id":"752ba06b8c49cb81d1880fb30f7328614612a652"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"3ab27754b53c03845ce4897b2cabc664528b2f37","unresolved":true,"context_lines":[{"line_number":3922,"context_line":"                self._cleanup_device_cluster_for_last_host("},{"line_number":3923,"context_line":"                    aim_ctx, physdom, host, COMMON_TENANT_NAME)"},{"line_number":3924,"context_line":""},{"line_number":3925,"context_line":"    def _get_physdom_from_host_link(self, aim_ctx, host_link):"},{"line_number":3926,"context_line":"        \"\"\"Extract physical domain name from an AIM HostLink.\"\"\""},{"line_number":3927,"context_line":"        if hasattr(host_link, \u0027domain_name\u0027) and host_link.domain_name:"},{"line_number":3928,"context_line":"            return host_link.domain_name"},{"line_number":3929,"context_line":"        return None"},{"line_number":3930,"context_line":""},{"line_number":3931,"context_line":"    def _get_dist_snat_subnets(self, plugin_context):"},{"line_number":3932,"context_line":"        \"\"\"Return all subnets that have apic:service_network set.\"\"\""}],"source_content_type":"text/x-python","patch_set":11,"id":"93d6598c_742fd137","line":3929,"range":{"start_line":3925,"start_character":0,"end_line":3929,"end_character":19},"updated":"2026-06-17 12:03:05.000000000","message":"Unfortunately, the LLMs are hallucinating again - there isn\u0027t a domain property in the host link resource (https://github.com/noironetworks/aci-integration-module/blob/master/aim/api/infra.py#L28-L50). We instead need to consult the HostDomainMappingV2 resources, to see if there is a host-specific mapping (see https://github.com/noironetworks/aci-integration-module/blob/master/aim/api/infra.py#L98-L111 and https://opendev.org/x/group-based-policy/src/branch/master/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py#L6573-L6575)","commit_id":"752ba06b8c49cb81d1880fb30f7328614612a652"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"3ab27754b53c03845ce4897b2cabc664528b2f37","unresolved":true,"context_lines":[{"line_number":3945,"context_line":"        return self.plugin.get_subnets("},{"line_number":3946,"context_line":"            plugin_context, filters\u003d{\u0027id\u0027: subnet_ids})"},{"line_number":3947,"context_line":""},{"line_number":3948,"context_line":"    def _get_dist_snat_subnets_for_networks(self, plugin_context, network_ids):"},{"line_number":3949,"context_line":"        \"\"\"Return dist-SNAT subnets whose network is in network_ids.\"\"\""},{"line_number":3950,"context_line":"        if not network_ids:"},{"line_number":3951,"context_line":"            return []"},{"line_number":3952,"context_line":"        session \u003d plugin_context.session"},{"line_number":3953,"context_line":"        extn_db_sn \u003d extension_db.SubnetExtensionDb"},{"line_number":3954,"context_line":"        query \u003d BAKERY(lambda s: s.query(models_v2.Subnet.id))"},{"line_number":3955,"context_line":"        query +\u003d lambda q: q.join("},{"line_number":3956,"context_line":"            extn_db_sn,"},{"line_number":3957,"context_line":"            extn_db_sn.subnet_id \u003d\u003d models_v2.Subnet.id)"},{"line_number":3958,"context_line":"        query +\u003d lambda q: q.filter("},{"line_number":3959,"context_line":"            models_v2.Subnet.network_id.in_(sa.bindparam("},{"line_number":3960,"context_line":"                \u0027network_ids\u0027, expanding\u003dTrue)))"},{"line_number":3961,"context_line":"        query +\u003d lambda q: q.filter("},{"line_number":3962,"context_line":"            extn_db_sn.service_network_id.isnot(None),"},{"line_number":3963,"context_line":"            extn_db_sn.service_network_id !\u003d \u0027\u0027)"},{"line_number":3964,"context_line":"        subnet_ids \u003d [r[0] for r in query(session).params("},{"line_number":3965,"context_line":"            network_ids\u003dlist(network_ids)).all()]"},{"line_number":3966,"context_line":"        if not subnet_ids:"},{"line_number":3967,"context_line":"            return []"},{"line_number":3968,"context_line":"        return self.plugin.get_subnets("},{"line_number":3969,"context_line":"            plugin_context, filters\u003d{\u0027id\u0027: subnet_ids})"},{"line_number":3970,"context_line":""},{"line_number":3971,"context_line":"    def _get_reachable_external_network_ids(self, session,"},{"line_number":3972,"context_line":"                                            private_network_ids):"}],"source_content_type":"text/x-python","patch_set":11,"id":"c67c82d6_c8363a82","line":3969,"range":{"start_line":3948,"start_character":0,"end_line":3969,"end_character":55},"updated":"2026-06-17 12:03:05.000000000","message":"Is this used? I didn\u0027t see any callers.","commit_id":"752ba06b8c49cb81d1880fb30f7328614612a652"},{"author":{"_account_id":35928,"name":"Mohd Nisar Khan","email":"nisarkhancsengg@gmail.com","username":"nisarkhan"},"change_message_id":"9c1a14811cd41a41a1311083a903cce81aca0ce6","unresolved":true,"context_lines":[{"line_number":3945,"context_line":"        return self.plugin.get_subnets("},{"line_number":3946,"context_line":"            plugin_context, filters\u003d{\u0027id\u0027: subnet_ids})"},{"line_number":3947,"context_line":""},{"line_number":3948,"context_line":"    def _get_dist_snat_subnets_for_networks(self, plugin_context, network_ids):"},{"line_number":3949,"context_line":"        \"\"\"Return dist-SNAT subnets whose network is in network_ids.\"\"\""},{"line_number":3950,"context_line":"        if not network_ids:"},{"line_number":3951,"context_line":"            return []"},{"line_number":3952,"context_line":"        session \u003d plugin_context.session"},{"line_number":3953,"context_line":"        extn_db_sn \u003d extension_db.SubnetExtensionDb"},{"line_number":3954,"context_line":"        query \u003d BAKERY(lambda s: s.query(models_v2.Subnet.id))"},{"line_number":3955,"context_line":"        query +\u003d lambda q: q.join("},{"line_number":3956,"context_line":"            extn_db_sn,"},{"line_number":3957,"context_line":"            extn_db_sn.subnet_id \u003d\u003d models_v2.Subnet.id)"},{"line_number":3958,"context_line":"        query +\u003d lambda q: q.filter("},{"line_number":3959,"context_line":"            models_v2.Subnet.network_id.in_(sa.bindparam("},{"line_number":3960,"context_line":"                \u0027network_ids\u0027, expanding\u003dTrue)))"},{"line_number":3961,"context_line":"        query +\u003d lambda q: q.filter("},{"line_number":3962,"context_line":"            extn_db_sn.service_network_id.isnot(None),"},{"line_number":3963,"context_line":"            extn_db_sn.service_network_id !\u003d \u0027\u0027)"},{"line_number":3964,"context_line":"        subnet_ids \u003d [r[0] for r in query(session).params("},{"line_number":3965,"context_line":"            network_ids\u003dlist(network_ids)).all()]"},{"line_number":3966,"context_line":"        if not subnet_ids:"},{"line_number":3967,"context_line":"            return []"},{"line_number":3968,"context_line":"        return self.plugin.get_subnets("},{"line_number":3969,"context_line":"            plugin_context, filters\u003d{\u0027id\u0027: subnet_ids})"},{"line_number":3970,"context_line":""},{"line_number":3971,"context_line":"    def _get_reachable_external_network_ids(self, session,"},{"line_number":3972,"context_line":"                                            private_network_ids):"}],"source_content_type":"text/x-python","patch_set":11,"id":"9b01ca7a_223c1510","line":3969,"range":{"start_line":3948,"start_character":0,"end_line":3969,"end_character":55},"in_reply_to":"c67c82d6_c8363a82","updated":"2026-06-17 13:26:27.000000000","message":"It became dead because of the later refactor. sorry, forgot to remove","commit_id":"752ba06b8c49cb81d1880fb30f7328614612a652"},{"author":{"_account_id":18031,"name":"Thomas Bachman","email":"tbachman@yahoo.com","username":"bachmantech"},"change_message_id":"3ab27754b53c03845ce4897b2cabc664528b2f37","unresolved":true,"context_lines":[{"line_number":4051,"context_line":"            service_network_ids\u003dlist(service_network_ids)).distinct().all()"},{"line_number":4052,"context_line":"        return {r[0] for r in refs}"},{"line_number":4053,"context_line":""},{"line_number":4054,"context_line":"    def _get_physdoms_by_hosts(self, aim_ctx, hosts):"},{"line_number":4055,"context_line":"        \"\"\"Return mapping host -\u003e set of physdoms resolved from HostLinks.\"\"\""},{"line_number":4056,"context_line":"        result \u003d {host: set() for host in hosts}"},{"line_number":4057,"context_line":"        if not hosts:"},{"line_number":4058,"context_line":"            return result"},{"line_number":4059,"context_line":""},{"line_number":4060,"context_line":"        host_links \u003d self.aim.find("},{"line_number":4061,"context_line":"            aim_ctx, aim_infra.HostLink,"},{"line_number":4062,"context_line":"            in_\u003d{\u0027host_name\u0027: list(hosts)})"},{"line_number":4063,"context_line":"        for hl in host_links:"},{"line_number":4064,"context_line":"            if not hl.path:"},{"line_number":4065,"context_line":"                continue"},{"line_number":4066,"context_line":"            physdom \u003d self._get_physdom_from_host_link(aim_ctx, hl)"},{"line_number":4067,"context_line":"            if physdom and hl.host_name in result:"},{"line_number":4068,"context_line":"                result[hl.host_name].add(physdom)"},{"line_number":4069,"context_line":"        return result"},{"line_number":4070,"context_line":""},{"line_number":4071,"context_line":"    def _get_service_network_ports_for_host(self, plugin_context,"},{"line_number":4072,"context_line":"                                            service_net_id, host):"}],"source_content_type":"text/x-python","patch_set":11,"id":"f445b786_c00a5e71","line":4069,"range":{"start_line":4054,"start_character":0,"end_line":4069,"end_character":21},"updated":"2026-06-17 12:03:05.000000000","message":"See earlier comment about physdoms.","commit_id":"752ba06b8c49cb81d1880fb30f7328614612a652"}]}
