)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"dab4ca24070bd8bc170cef546102bc741e0551d6","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"cca322df_8672a9ca","updated":"2026-09-20 17:52:31.000000000","message":"check experimental","commit_id":"137f16d0af5686edac48dc9635af71fd7501fee9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"a73230d06e88a30cc44d18043f24a91a778a4330","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"3d09b38f_d3f25c4c","updated":"2026-09-19 22:07:24.000000000","message":"recheck docs job retry limit","commit_id":"137f16d0af5686edac48dc9635af71fd7501fee9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"efd7eb50b14456bec7e718fb485e884f2db05f45","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"d1eefd28_3c0a6d70","updated":"2026-09-22 18:08:40.000000000","message":"check experimental","commit_id":"18c3770095c0e6e0e97e150aa7b285f9336db5ef"},{"author":{"_account_id":34271,"name":"Miro Tomaska","display_name":"Miro Tomaska","email":"mtomaska@redhat.com","username":"mtomaska"},"change_message_id":"18118553489200ae6637b8f829249ce64f7210f7","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"1d081395_e5dd42c3","updated":"2026-09-22 20:52:23.000000000","message":"Good, few comments","commit_id":"46e1b76a21b2371a7578613cc1424b0797fdf514"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"d75d6148e590dfabb7f356e1e4feba9902d924ae","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"b0cbed8b_01c7e5ad","updated":"2026-09-22 18:38:33.000000000","message":"check experimental","commit_id":"46e1b76a21b2371a7578613cc1424b0797fdf514"},{"author":{"_account_id":34271,"name":"Miro Tomaska","display_name":"Miro Tomaska","email":"mtomaska@redhat.com","username":"mtomaska"},"change_message_id":"36852e97069007b1c34caa14b19b494072c617e5","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"16239438_5573b00f","updated":"2026-09-24 20:54:24.000000000","message":"With the db_sync patch, LGTM","commit_id":"42c2f410d11e3d64fd6ab6ed9d2b45e259c5c391"}],"neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/impl_idl_ovn.py":[{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"3733d44843c296683223908678301bf707753ec5","unresolved":false,"context_lines":[{"line_number":637,"context_line":"        \"\"\""},{"line_number":638,"context_line":"        primaries \u003d []"},{"line_number":639,"context_line":"        chassis_set \u003d set(chassis_names)"},{"line_number":640,"context_line":"        for hcg in self.db_list_rows("},{"line_number":641,"context_line":"                \u0027HA_Chassis_Group\u0027).execute(check_error\u003dTrue):"},{"line_number":642,"context_line":"            if not hcg.ha_chassis:"},{"line_number":643,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":2,"id":"199f2c17_4f70114b","line":640,"updated":"2026-09-22 15:33:51.000000000","message":"This seems like it could be very expensive with a very large number of gateway chassis, but I don\u0027t have any better ideas right now.","commit_id":"137f16d0af5686edac48dc9635af71fd7501fee9"},{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"3733d44843c296683223908678301bf707753ec5","unresolved":true,"context_lines":[{"line_number":1063,"context_line":""},{"line_number":1064,"context_line":"    def get_gateway_chassis_with_az_filter(self, az_hints\u003dNone):"},{"line_number":1065,"context_line":"        az_hints \u003d set(az_hints) if az_hints else set()"},{"line_number":1066,"context_line":"        gw_chassis \u003d []"},{"line_number":1067,"context_line":"        candidates \u003d []"},{"line_number":1068,"context_line":"        for ch in self.chassis_list().execute(check_error\u003dTrue):"},{"line_number":1069,"context_line":"            if not utils.is_gateway_chassis(ch):"},{"line_number":1070,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":2,"id":"a044b239_7e3b365b","line":1067,"range":{"start_line":1066,"start_character":0,"end_line":1067,"end_character":23},"updated":"2026-09-22 15:33:51.000000000","message":"nit/question: if this is not ordered data and won\u0027t contain duplicates, maybe using a set type will make matching cheaper later? I think we even convert it to a set eventually above. And if we wanted to be really fancy we could add type hints to document that we returned sets.","commit_id":"137f16d0af5686edac48dc9635af71fd7501fee9"},{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"7332341e1d225ee86f1faf29ce4a78aecd4b14f7","unresolved":true,"context_lines":[{"line_number":1063,"context_line":""},{"line_number":1064,"context_line":"    def get_gateway_chassis_with_az_filter(self, az_hints\u003dNone):"},{"line_number":1065,"context_line":"        az_hints \u003d set(az_hints) if az_hints else set()"},{"line_number":1066,"context_line":"        gw_chassis \u003d []"},{"line_number":1067,"context_line":"        candidates \u003d []"},{"line_number":1068,"context_line":"        for ch in self.chassis_list().execute(check_error\u003dTrue):"},{"line_number":1069,"context_line":"            if not utils.is_gateway_chassis(ch):"},{"line_number":1070,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":2,"id":"af3379c1_52741a0a","line":1067,"range":{"start_line":1066,"start_character":0,"end_line":1067,"end_character":23},"in_reply_to":"6c8e4c49_71f535e5","updated":"2026-09-22 20:00:43.000000000","message":"That doesn\u0027t mean they have to be a list now, and before they make it to the candidate list where they are sorted, it is converted to a set.","commit_id":"137f16d0af5686edac48dc9635af71fd7501fee9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"1182beef30a02c362cb682b4e379b8888eb2352f","unresolved":false,"context_lines":[{"line_number":1063,"context_line":""},{"line_number":1064,"context_line":"    def get_gateway_chassis_with_az_filter(self, az_hints\u003dNone):"},{"line_number":1065,"context_line":"        az_hints \u003d set(az_hints) if az_hints else set()"},{"line_number":1066,"context_line":"        gw_chassis \u003d []"},{"line_number":1067,"context_line":"        candidates \u003d []"},{"line_number":1068,"context_line":"        for ch in self.chassis_list().execute(check_error\u003dTrue):"},{"line_number":1069,"context_line":"            if not utils.is_gateway_chassis(ch):"},{"line_number":1070,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":2,"id":"6c8e4c49_71f535e5","line":1067,"range":{"start_line":1066,"start_character":0,"end_line":1067,"end_character":23},"in_reply_to":"a044b239_7e3b365b","updated":"2026-09-22 16:37:00.000000000","message":"Done\n\nThe candidates must be a list because we\u0027re going to sort it later based on the load.","commit_id":"137f16d0af5686edac48dc9635af71fd7501fee9"},{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"a1c550995cf711ffcd294bea31b02d69033843b4","unresolved":false,"context_lines":[{"line_number":1063,"context_line":""},{"line_number":1064,"context_line":"    def get_gateway_chassis_with_az_filter(self, az_hints\u003dNone):"},{"line_number":1065,"context_line":"        az_hints \u003d set(az_hints) if az_hints else set()"},{"line_number":1066,"context_line":"        gw_chassis \u003d []"},{"line_number":1067,"context_line":"        candidates \u003d []"},{"line_number":1068,"context_line":"        for ch in self.chassis_list().execute(check_error\u003dTrue):"},{"line_number":1069,"context_line":"            if not utils.is_gateway_chassis(ch):"},{"line_number":1070,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":2,"id":"fd46dbed_bfd7ac7d","line":1067,"range":{"start_line":1066,"start_character":0,"end_line":1067,"end_character":23},"in_reply_to":"af3379c1_52741a0a","updated":"2026-09-22 20:03:53.000000000","message":"nm, I got mixed up on the candidates vs chassis names.","commit_id":"137f16d0af5686edac48dc9635af71fd7501fee9"}],"neutron/services/evpn/plugin.py":[{"author":{"_account_id":34271,"name":"Miro Tomaska","display_name":"Miro Tomaska","email":"mtomaska@redhat.com","username":"mtomaska"},"change_message_id":"18118553489200ae6637b8f829249ce64f7210f7","unresolved":true,"context_lines":[{"line_number":162,"context_line":"            load_fn\u003dlambda ch: hcg_load.get(ch, 0))"},{"line_number":163,"context_line":"        ordered_chassis \u003d scheduler.select(candidates\u003dcandidates)"},{"line_number":164,"context_line":"        if not ordered_chassis:"},{"line_number":165,"context_line":"            LOG.warning(\"No gateway chassis available for EVPN router %s. \""},{"line_number":166,"context_line":"                        \"The VRF will remain unhosted until chassis \""},{"line_number":167,"context_line":"                        \"matching the requested AZ hints become available.\","},{"line_number":168,"context_line":"                        router_id)"},{"line_number":169,"context_line":""},{"line_number":170,"context_line":"        with self._nb_idl.transaction(check_error\u003dTrue) as txn:"},{"line_number":171,"context_line":"            txn.add(evpn_ovn.CreateEVPNRouterCommand("}],"source_content_type":"text/x-python","patch_set":4,"id":"acdc7c7c_03a73f5a","line":168,"range":{"start_line":165,"start_character":0,"end_line":168,"end_character":34},"updated":"2026-09-22 20:52:23.000000000","message":"Just asking, if I see this warning, what do I need to do? Set AZ hint on a router?","commit_id":"46e1b76a21b2371a7578613cc1424b0797fdf514"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"93217b98147f7bfd1a4c2ca5426df2dd227998b0","unresolved":true,"context_lines":[{"line_number":162,"context_line":"            load_fn\u003dlambda ch: hcg_load.get(ch, 0))"},{"line_number":163,"context_line":"        ordered_chassis \u003d scheduler.select(candidates\u003dcandidates)"},{"line_number":164,"context_line":"        if not ordered_chassis:"},{"line_number":165,"context_line":"            LOG.warning(\"No gateway chassis available for EVPN router %s. \""},{"line_number":166,"context_line":"                        \"The VRF will remain unhosted until chassis \""},{"line_number":167,"context_line":"                        \"matching the requested AZ hints become available.\","},{"line_number":168,"context_line":"                        router_id)"},{"line_number":169,"context_line":""},{"line_number":170,"context_line":"        with self._nb_idl.transaction(check_error\u003dTrue) as txn:"},{"line_number":171,"context_line":"            txn.add(evpn_ovn.CreateEVPNRouterCommand("}],"source_content_type":"text/x-python","patch_set":4,"id":"1af694d5_012b2404","line":168,"range":{"start_line":165,"start_character":0,"end_line":168,"end_character":34},"in_reply_to":"acdc7c7c_03a73f5a","updated":"2026-09-22 20:55:03.000000000","message":"I guess set `ovn-cms-options\u003denable-chassis-as-gw`. No AZ on a router means \"any gw chassis\".","commit_id":"46e1b76a21b2371a7578613cc1424b0797fdf514"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"fbf0dcebca40b4de37a16251982f7b5c2a920f25","unresolved":true,"context_lines":[{"line_number":153,"context_line":"        router_id \u003d payload.resource_id"},{"line_number":154,"context_line":"        vlan \u003d self._evpn_db.get_vlan_for_router(payload.context, router_id)"},{"line_number":155,"context_line":""},{"line_number":156,"context_line":"        gw_chassis, candidates \u003d ("},{"line_number":157,"context_line":"            self._sb_idl.get_gateway_chassis_with_az_filter("},{"line_number":158,"context_line":"                az_hints\u003drouter.get(\u0027availability_zone_hints\u0027, [])))"},{"line_number":159,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"043ca90f_80bdd1fa","line":156,"range":{"start_line":156,"start_character":8,"end_line":156,"end_character":30},"updated":"2026-09-25 11:20:17.000000000","message":"I would impose a hard limit of 5 (MAX_GW_CHASSIS), same as we have in the L3 OVN scheduler. If not, in environments with DVR, we can have as many GW nodes as computes.","commit_id":"42c2f410d11e3d64fd6ab6ed9d2b45e259c5c391"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"8225c576d82eebb5ec6e6b278f066bd04f558fed","unresolved":false,"context_lines":[{"line_number":153,"context_line":"        router_id \u003d payload.resource_id"},{"line_number":154,"context_line":"        vlan \u003d self._evpn_db.get_vlan_for_router(payload.context, router_id)"},{"line_number":155,"context_line":""},{"line_number":156,"context_line":"        gw_chassis, candidates \u003d ("},{"line_number":157,"context_line":"            self._sb_idl.get_gateway_chassis_with_az_filter("},{"line_number":158,"context_line":"                az_hints\u003drouter.get(\u0027availability_zone_hints\u0027, [])))"},{"line_number":159,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"a58704bb_42fb02f1","line":156,"range":{"start_line":156,"start_character":8,"end_line":156,"end_character":30},"in_reply_to":"043ca90f_80bdd1fa","updated":"2026-09-25 12:15:59.000000000","message":"Done","commit_id":"42c2f410d11e3d64fd6ab6ed9d2b45e259c5c391"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"fbf0dcebca40b4de37a16251982f7b5c2a920f25","unresolved":true,"context_lines":[{"line_number":159,"context_line":""},{"line_number":160,"context_line":"        hcg_load \u003d self._compute_hcg_primary_load(chassis_names\u003dgw_chassis)"},{"line_number":161,"context_line":"        scheduler \u003d evpn_scheduler.LeastLoadedChassisScheduler("},{"line_number":162,"context_line":"            load_fn\u003dlambda ch: hcg_load.get(ch, 0))"},{"line_number":163,"context_line":"        ordered_chassis \u003d scheduler.select(candidates\u003dcandidates)"},{"line_number":164,"context_line":"        if not ordered_chassis:"},{"line_number":165,"context_line":"            LOG.warning(\"No gateway chassis available for EVPN router %s. \""}],"source_content_type":"text/x-python","patch_set":5,"id":"10ab92a4_f77dfbd9","line":162,"range":{"start_line":162,"start_character":12,"end_line":162,"end_character":50},"updated":"2026-09-25 11:20:17.000000000","message":"This should be an internal operation. The `LeastLoadedChassisScheduler` is descriptive enough to know that we\u0027ll schedule the router using the least loaded chassis. We should not be passing any function.","commit_id":"42c2f410d11e3d64fd6ab6ed9d2b45e259c5c391"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"8225c576d82eebb5ec6e6b278f066bd04f558fed","unresolved":true,"context_lines":[{"line_number":159,"context_line":""},{"line_number":160,"context_line":"        hcg_load \u003d self._compute_hcg_primary_load(chassis_names\u003dgw_chassis)"},{"line_number":161,"context_line":"        scheduler \u003d evpn_scheduler.LeastLoadedChassisScheduler("},{"line_number":162,"context_line":"            load_fn\u003dlambda ch: hcg_load.get(ch, 0))"},{"line_number":163,"context_line":"        ordered_chassis \u003d scheduler.select(candidates\u003dcandidates)"},{"line_number":164,"context_line":"        if not ordered_chassis:"},{"line_number":165,"context_line":"            LOG.warning(\"No gateway chassis available for EVPN router %s. \""}],"source_content_type":"text/x-python","patch_set":5,"id":"ac4f7d29_0afe2b19","line":162,"range":{"start_line":162,"start_character":12,"end_line":162,"end_character":50},"in_reply_to":"10ab92a4_f77dfbd9","updated":"2026-09-25 12:15:59.000000000","message":"I disagree. The load scheduler calculates the order based on the load - but the load is not defined as it requires knowledge of how many evpns each chassis handles. The scheduler is responsible for scheduling only and the logic of obtaining the chassis should be separate.\n\nThat was also the reason why I couldn\u0027t use the OVN l3 gw scheduler - it does way too many things and there is a lot of logic baked in that should not be there. I prefer a clear logic separation in the code rather than a code that does everything.","commit_id":"42c2f410d11e3d64fd6ab6ed9d2b45e259c5c391"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"e5fa9d008212337e7c91977672e70d99ce798890","unresolved":false,"context_lines":[{"line_number":159,"context_line":""},{"line_number":160,"context_line":"        hcg_load \u003d self._compute_hcg_primary_load(chassis_names\u003dgw_chassis)"},{"line_number":161,"context_line":"        scheduler \u003d evpn_scheduler.LeastLoadedChassisScheduler("},{"line_number":162,"context_line":"            load_fn\u003dlambda ch: hcg_load.get(ch, 0))"},{"line_number":163,"context_line":"        ordered_chassis \u003d scheduler.select(candidates\u003dcandidates)"},{"line_number":164,"context_line":"        if not ordered_chassis:"},{"line_number":165,"context_line":"            LOG.warning(\"No gateway chassis available for EVPN router %s. \""}],"source_content_type":"text/x-python","patch_set":5,"id":"71d8f222_970c4bae","line":162,"range":{"start_line":162,"start_character":12,"end_line":162,"end_character":50},"in_reply_to":"60c1d77d_8d2a9cd7","updated":"2026-10-05 21:26:24.000000000","message":"Done","commit_id":"42c2f410d11e3d64fd6ab6ed9d2b45e259c5c391"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"15d6af33a3f77b0ee686267132c841afe8f92fad","unresolved":true,"context_lines":[{"line_number":159,"context_line":""},{"line_number":160,"context_line":"        hcg_load \u003d self._compute_hcg_primary_load(chassis_names\u003dgw_chassis)"},{"line_number":161,"context_line":"        scheduler \u003d evpn_scheduler.LeastLoadedChassisScheduler("},{"line_number":162,"context_line":"            load_fn\u003dlambda ch: hcg_load.get(ch, 0))"},{"line_number":163,"context_line":"        ordered_chassis \u003d scheduler.select(candidates\u003dcandidates)"},{"line_number":164,"context_line":"        if not ordered_chassis:"},{"line_number":165,"context_line":"            LOG.warning(\"No gateway chassis available for EVPN router %s. \""}],"source_content_type":"text/x-python","patch_set":5,"id":"60c1d77d_8d2a9cd7","line":162,"range":{"start_line":162,"start_character":12,"end_line":162,"end_character":50},"in_reply_to":"ac4f7d29_0afe2b19","updated":"2026-09-29 09:31:04.000000000","message":"Yes, this is why I\u0027m saying to implement this code inside your new scheduler, not providing an external function. What I\u0027m saying is to avoid passing `load_fn\u003dlambda ch: hcg_load.get(ch, 0)` and instead pass the needed information to the scheduler to calculate that internally (same as in other scheduler).\n\nBut that\u0027s a nit.","commit_id":"42c2f410d11e3d64fd6ab6ed9d2b45e259c5c391"}],"neutron/services/evpn/scheduler.py":[{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"3733d44843c296683223908678301bf707753ec5","unresolved":false,"context_lines":[{"line_number":19,"context_line":"class ChassisScheduler(abc.ABC):"},{"line_number":20,"context_line":"    \"\"\"Order chassis candidates for HA Chassis Group assignment.\"\"\""},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"    def select(self, candidates, existing_chassis\u003dNone, max_chassis\u003dNone):"},{"line_number":23,"context_line":"        \"\"\"Return an ordered list of chassis for HCG priority assignment."},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"        :param candidates: list of eligible chassis names"}],"source_content_type":"text/x-python","patch_set":2,"id":"37009482_9519ddac","line":22,"updated":"2026-09-22 15:33:51.000000000","message":"In the future this could detect whether a chassis is \"alive\" via the agent API.","commit_id":"137f16d0af5686edac48dc9635af71fd7501fee9"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"67411c5de926438718f060e9c0ac158fe8979909","unresolved":true,"context_lines":[{"line_number":16,"context_line":"import abc"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":""},{"line_number":19,"context_line":"class ChassisScheduler(abc.ABC):"},{"line_number":20,"context_line":"    \"\"\"Order chassis candidates for HA Chassis Group assignment.\"\"\""},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"    def select(self, candidates, existing_chassis\u003dNone, max_chassis\u003dNone):"}],"source_content_type":"text/x-python","patch_set":5,"id":"24458869_47b1cfaa","line":19,"updated":"2026-09-24 21:18:40.000000000","message":"IMO we should use the current L3 OVN schedulers. For example, the leastloaded class. That takes care of AZs, multihoming and the existing router GWs.","commit_id":"42c2f410d11e3d64fd6ab6ed9d2b45e259c5c391"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"79cb6c5305765572fad06ac35ee31dda1c1e7545","unresolved":true,"context_lines":[{"line_number":16,"context_line":"import abc"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":""},{"line_number":19,"context_line":"class ChassisScheduler(abc.ABC):"},{"line_number":20,"context_line":"    \"\"\"Order chassis candidates for HA Chassis Group assignment.\"\"\""},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"    def select(self, candidates, existing_chassis\u003dNone, max_chassis\u003dNone):"}],"source_content_type":"text/x-python","patch_set":5,"id":"e0f89a1e_d74e4f87","line":19,"in_reply_to":"24458869_47b1cfaa","updated":"2026-09-24 22:35:06.000000000","message":"I originally tried that but there were way too many things specific for the OVN gateway that it ended up inheriting it just for its name with all methods that were not usable for this case.","commit_id":"42c2f410d11e3d64fd6ab6ed9d2b45e259c5c391"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"fbf0dcebca40b4de37a16251982f7b5c2a920f25","unresolved":false,"context_lines":[{"line_number":16,"context_line":"import abc"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":""},{"line_number":19,"context_line":"class ChassisScheduler(abc.ABC):"},{"line_number":20,"context_line":"    \"\"\"Order chassis candidates for HA Chassis Group assignment.\"\"\""},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"    def select(self, candidates, existing_chassis\u003dNone, max_chassis\u003dNone):"}],"source_content_type":"text/x-python","patch_set":5,"id":"fc71c6a0_e3726eed","line":19,"in_reply_to":"e0f89a1e_d74e4f87","updated":"2026-09-25 11:20:17.000000000","message":"Agree with this but the `select` method should be improved, using the existing code in `OVNGatewayLeastLoadedScheduler`. The `OVNGatewayLeastLoadedScheduler._select_gateway_chassis` uses a complex loop (tuned after several try/error patches, testing, etc.) to assign the least loaded chassis as highest HA_Chassis, but also checking the lowest priority ones and balancing them too.\n\nThis code can be merged as is now but I would extract from `OVNGatewayLeastLoadedScheduler._select_gateway_chassis` some utility methods to, given a set of chassis, provide a balanced HA_Chassis list according to the existing ones.\n\nOut of context: I\u0027m also worried about the number of resources (GW, SRIOV, BGP, EVPN) that use HCG now and how differently we create them, not considering the others. But that\u0027s another story.","commit_id":"42c2f410d11e3d64fd6ab6ed9d2b45e259c5c391"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"fbf0dcebca40b4de37a16251982f7b5c2a920f25","unresolved":true,"context_lines":[{"line_number":38,"context_line":"        result \u003d existing_chassis + ordered"},{"line_number":39,"context_line":"        if max_chassis is not None:"},{"line_number":40,"context_line":"            result \u003d result[:max_chassis]"},{"line_number":41,"context_line":"        return result"},{"line_number":42,"context_line":""},{"line_number":43,"context_line":"    @abc.abstractmethod"},{"line_number":44,"context_line":"    def _order(self, candidates):"}],"source_content_type":"text/x-python","patch_set":5,"id":"58bb5741_ba6e4497","line":41,"range":{"start_line":41,"start_character":8,"end_line":41,"end_character":21},"updated":"2026-09-25 11:20:17.000000000","message":"I would add a note about using `OVNGatewayLeastLoadedScheduler._reorder_by_az`, to prioritize the AZ spreading.","commit_id":"42c2f410d11e3d64fd6ab6ed9d2b45e259c5c391"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"8225c576d82eebb5ec6e6b278f066bd04f558fed","unresolved":true,"context_lines":[{"line_number":38,"context_line":"        result \u003d existing_chassis + ordered"},{"line_number":39,"context_line":"        if max_chassis is not None:"},{"line_number":40,"context_line":"            result \u003d result[:max_chassis]"},{"line_number":41,"context_line":"        return result"},{"line_number":42,"context_line":""},{"line_number":43,"context_line":"    @abc.abstractmethod"},{"line_number":44,"context_line":"    def _order(self, candidates):"}],"source_content_type":"text/x-python","patch_set":5,"id":"715b563e_492a04b1","line":41,"range":{"start_line":41,"start_character":8,"end_line":41,"end_character":21},"in_reply_to":"58bb5741_ba6e4497","updated":"2026-09-25 12:15:59.000000000","message":"I think if we want to reuse the logic from `OVNGatewayLeastLoadedScheduler` we should refactor that first. I actually originally started doing that but after a few hours it seemed like the having a small EVPN scheduler was a lot cleaner approach.","commit_id":"42c2f410d11e3d64fd6ab6ed9d2b45e259c5c391"},{"author":{"_account_id":16688,"name":"Rodolfo Alonso","email":"ralonsoh@redhat.com","username":"rodolfo-alonso-hernandez"},"change_message_id":"15d6af33a3f77b0ee686267132c841afe8f92fad","unresolved":true,"context_lines":[{"line_number":38,"context_line":"        result \u003d existing_chassis + ordered"},{"line_number":39,"context_line":"        if max_chassis is not None:"},{"line_number":40,"context_line":"            result \u003d result[:max_chassis]"},{"line_number":41,"context_line":"        return result"},{"line_number":42,"context_line":""},{"line_number":43,"context_line":"    @abc.abstractmethod"},{"line_number":44,"context_line":"    def _order(self, candidates):"}],"source_content_type":"text/x-python","patch_set":5,"id":"d6afe70b_48ac1f35","line":41,"range":{"start_line":41,"start_character":8,"end_line":41,"end_character":21},"in_reply_to":"715b563e_492a04b1","updated":"2026-09-29 09:31:04.000000000","message":"Yes, this is why I said adding a note. I think the `OVNGatewayLeastLoadedScheduler` code can be refactored to have a generic method to pass the needed information (HCG with the current list, chassis, AZs) and return a list of HA_Chassis with the corresponding priority (or the updated HCG).\n\nBut the refactor is out of context. This is why I mentioned to add a note about the AZ reordering.","commit_id":"42c2f410d11e3d64fd6ab6ed9d2b45e259c5c391"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"e5fa9d008212337e7c91977672e70d99ce798890","unresolved":false,"context_lines":[{"line_number":38,"context_line":"        result \u003d existing_chassis + ordered"},{"line_number":39,"context_line":"        if max_chassis is not None:"},{"line_number":40,"context_line":"            result \u003d result[:max_chassis]"},{"line_number":41,"context_line":"        return result"},{"line_number":42,"context_line":""},{"line_number":43,"context_line":"    @abc.abstractmethod"},{"line_number":44,"context_line":"    def _order(self, candidates):"}],"source_content_type":"text/x-python","patch_set":5,"id":"8d5efcc3_3cc48db6","line":41,"range":{"start_line":41,"start_character":8,"end_line":41,"end_character":21},"in_reply_to":"d6afe70b_48ac1f35","updated":"2026-10-05 21:26:24.000000000","message":"Done","commit_id":"42c2f410d11e3d64fd6ab6ed9d2b45e259c5c391"}],"neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_impl_idl.py":[{"author":{"_account_id":5756,"name":"Terry Wilson","email":"twilson@redhat.com","username":"otherwiseguy"},"change_message_id":"3733d44843c296683223908678301bf707753ec5","unresolved":true,"context_lines":[{"line_number":265,"context_line":"    def _assert_chassis_subset(self, expected, actual):"},{"line_number":266,"context_line":"        \"\"\"Assert that all expected chassis are present in actual.\"\"\""},{"line_number":267,"context_line":"        actual_set \u003d set(actual)"},{"line_number":268,"context_line":"        for ch in expected:"},{"line_number":269,"context_line":"            self.assertIn(ch, actual_set)"},{"line_number":270,"context_line":""},{"line_number":271,"context_line":"    def test_get_gateway_chassis_with_az_filter_no_gw_chassis(self):"}],"source_content_type":"text/x-python","patch_set":2,"id":"c410f6f2_73de14cb","line":268,"updated":"2026-09-22 15:33:51.000000000","message":"nit: we control expected, so could just pass a set and use `issubset()` (and previous comment, `get_gateway_chassis_with_az_filter()` could also return sets)","commit_id":"137f16d0af5686edac48dc9635af71fd7501fee9"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"1182beef30a02c362cb682b4e379b8888eb2352f","unresolved":false,"context_lines":[{"line_number":265,"context_line":"    def _assert_chassis_subset(self, expected, actual):"},{"line_number":266,"context_line":"        \"\"\"Assert that all expected chassis are present in actual.\"\"\""},{"line_number":267,"context_line":"        actual_set \u003d set(actual)"},{"line_number":268,"context_line":"        for ch in expected:"},{"line_number":269,"context_line":"            self.assertIn(ch, actual_set)"},{"line_number":270,"context_line":""},{"line_number":271,"context_line":"    def test_get_gateway_chassis_with_az_filter_no_gw_chassis(self):"}],"source_content_type":"text/x-python","patch_set":2,"id":"8227c9db_dec59e19","line":268,"in_reply_to":"c410f6f2_73de14cb","updated":"2026-09-22 16:37:00.000000000","message":"Done","commit_id":"137f16d0af5686edac48dc9635af71fd7501fee9"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"324d76d2fc5383ce3c1beb45b3ea040012995889","unresolved":false,"context_lines":[{"line_number":264,"context_line":""},{"line_number":265,"context_line":"    def _assert_chassis_subset(self, expected, actual):"},{"line_number":266,"context_line":"        \"\"\"Assert that all expected chassis are present in actual.\"\"\""},{"line_number":267,"context_line":"        self.assertTrue(expected \u003c\u003d actual)"},{"line_number":268,"context_line":""},{"line_number":269,"context_line":"    def test_get_gateway_chassis_with_az_filter_no_gw_chassis(self):"},{"line_number":270,"context_line":"        # Chassis without enable-chassis-as-gw must be excluded."}],"source_content_type":"text/x-python","patch_set":3,"id":"2b3b0880_1934835b","line":267,"updated":"2026-09-22 18:33:10.000000000","message":"pep8: H205: Use assert{Greater,Less}[Equal]","commit_id":"18c3770095c0e6e0e97e150aa7b285f9336db5ef"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"0cc4987d61fa6d5752eb23124e696ffbd034e7a6","unresolved":false,"context_lines":[{"line_number":264,"context_line":""},{"line_number":265,"context_line":"    def _assert_chassis_subset(self, expected, actual):"},{"line_number":266,"context_line":"        \"\"\"Assert that all expected chassis are present in actual.\"\"\""},{"line_number":267,"context_line":"        self.assertTrue(expected \u003c\u003d actual)"},{"line_number":268,"context_line":""},{"line_number":269,"context_line":"    def test_get_gateway_chassis_with_az_filter_no_gw_chassis(self):"},{"line_number":270,"context_line":"        # Chassis without enable-chassis-as-gw must be excluded."}],"source_content_type":"text/x-python","patch_set":3,"id":"6af70981_7ce2d42a","line":267,"in_reply_to":"2b3b0880_1934835b","updated":"2026-09-22 18:38:19.000000000","message":"Done","commit_id":"18c3770095c0e6e0e97e150aa7b285f9336db5ef"}],"neutron/tests/unit/services/evpn/test_scheduler.py":[{"author":{"_account_id":34271,"name":"Miro Tomaska","display_name":"Miro Tomaska","email":"mtomaska@redhat.com","username":"mtomaska"},"change_message_id":"18118553489200ae6637b8f829249ce64f7210f7","unresolved":true,"context_lines":[{"line_number":1,"context_line":"# Copyright 2026 Red Hat, LLC"},{"line_number":2,"context_line":"# All Rights Reserved."},{"line_number":3,"context_line":"#"},{"line_number":4,"context_line":"#    Licensed under the Apache License, Version 2.0 (the \"License\"); you may"}],"source_content_type":"text/x-python","patch_set":4,"id":"8f18673a_dbd45342","line":1,"range":{"start_line":1,"start_character":0,"end_line":1,"end_character":29},"updated":"2026-09-22 20:52:23.000000000","message":"This is comment is not from my head but LLM :)\nApparently, `EvpnRepairSynchronizer` repair recreates HCGs without AZ hints or least-loaded ordering. Any sync/repair can undo the new scheduling policy\n\nhttps://opendev.org/openstack/neutron/src/branch/master/neutron/services/evpn/db_sync.py#L232","commit_id":"46e1b76a21b2371a7578613cc1424b0797fdf514"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"c0a2332028f1638256c0d6cd9c9e581bc7354e3a","unresolved":false,"context_lines":[{"line_number":1,"context_line":"# Copyright 2026 Red Hat, LLC"},{"line_number":2,"context_line":"# All Rights Reserved."},{"line_number":3,"context_line":"#"},{"line_number":4,"context_line":"#    Licensed under the Apache License, Version 2.0 (the \"License\"); you may"}],"source_content_type":"text/x-python","patch_set":4,"id":"294bf0df_1e86a918","line":1,"range":{"start_line":1,"start_character":0,"end_line":1,"end_character":29},"in_reply_to":"036f444f_73ba0019","updated":"2026-09-23 18:05:39.000000000","message":"I pushed it as a followup to ease the reviews https://review.opendev.org/c/openstack/neutron/+/1007011","commit_id":"46e1b76a21b2371a7578613cc1424b0797fdf514"},{"author":{"_account_id":8655,"name":"Jakub Libosvar","email":"libosvar@redhat.com","username":"jlibosva"},"change_message_id":"93217b98147f7bfd1a4c2ca5426df2dd227998b0","unresolved":true,"context_lines":[{"line_number":1,"context_line":"# Copyright 2026 Red Hat, LLC"},{"line_number":2,"context_line":"# All Rights Reserved."},{"line_number":3,"context_line":"#"},{"line_number":4,"context_line":"#    Licensed under the Apache License, Version 2.0 (the \"License\"); you may"}],"source_content_type":"text/x-python","patch_set":4,"id":"036f444f_73ba0019","line":1,"range":{"start_line":1,"start_character":0,"end_line":1,"end_character":29},"in_reply_to":"8f18673a_dbd45342","updated":"2026-09-22 20:55:03.000000000","message":"Good catch, I completely missed this.","commit_id":"46e1b76a21b2371a7578613cc1424b0797fdf514"}]}
