diff --git a/components/images-openstack.yaml b/components/images-openstack.yaml index d024a0d14..141b58c66 100644 --- a/components/images-openstack.yaml +++ b/components/images-openstack.yaml @@ -43,8 +43,9 @@ images: neutron_metadata: "ghcr.io/rackerlabs/understack/neutron:2026.1" neutron_ovn_metadata: "ghcr.io/rackerlabs/understack/neutron:2026.1" neutron_openvswitch_agent: "ghcr.io/rackerlabs/understack/neutron:2026.1" - neutron_server: "ghcr.io/rackerlabs/understack/neutron:2026.1" + neutron_server: "ghcr.io/rackerlabs/understack/neutron:pr-2262" neutron_rpc_server: "ghcr.io/rackerlabs/understack/neutron:2026.1" + neutron_ovn_maintenance_worker: "ghcr.io/rackerlabs/understack/neutron:pr-2262" neutron_bagpipe_bgp: "ghcr.io/rackerlabs/understack/neutron:2026.1" neutron_netns_cleanup_cron: "ghcr.io/rackerlabs/understack/neutron:2026.1" diff --git a/components/neutron/configmap-neutron-bin.yaml b/components/neutron/configmap-neutron-bin.yaml index 41f2223d2..e128932c7 100644 --- a/components/neutron/configmap-neutron-bin.yaml +++ b/components/neutron/configmap-neutron-bin.yaml @@ -1623,6 +1623,25 @@ data: kill -TERM 1 } + $COMMAND + neutron-ovn-maintenance-worker.sh: | + #!/bin/bash + + set -ex + COMMAND="${@:-start}" + + function start () { + exec neutron-ovn-maintenance-worker \ + --config-file /etc/neutron/neutron.conf \ + --config-file /tmp/pod-shared/ovn.ini \ + --config-file /etc/neutron/plugins/ml2/ml2_conf.ini \ + --config-dir /etc/neutron/neutron.conf.d + } + + function stop () { + kill -TERM 1 + } + $COMMAND neutron-server.sh: | #!/bin/bash diff --git a/components/neutron/values.yaml b/components/neutron/values.yaml index 5b8887eb8..0ccffc981 100644 --- a/components/neutron/values.yaml +++ b/components/neutron/values.yaml @@ -127,6 +127,9 @@ pod: neutron_server: - secret: name: neutron-ks-etc + neutron_ovn_maintenance_worker: + - secret: + name: neutron-ks-etc use_fqdn: neutron_agent: false @@ -179,6 +182,9 @@ dependencies: rpc_server: jobs: - neutron-db-sync + ovn_maintenance_worker: + jobs: + - neutron-db-sync ironic_agent: jobs: - neutron-db-sync @@ -204,6 +210,10 @@ manifests: daemonset_metadata_agent: false daemonset_ovs_agent: false deployment_rpc_server: false + deployment_ovn_maintenance_worker: true + # The janitor only needs the OVN maintenance worker. The chart enables the + # generic periodic worker by default; disable it. + deployment_periodic_worker: false daemonset_sriov_agent: false daemonset_l2gw_agent: false daemonset_bagpipe_bgp: false diff --git a/python/neutron-understack/neutron_understack/l3_router/vrf.py b/python/neutron-understack/neutron_understack/l3_router/vrf.py index 0be26f1c7..9cbd4c5d6 100644 --- a/python/neutron-understack/neutron_understack/l3_router/vrf.py +++ b/python/neutron-understack/neutron_understack/l3_router/vrf.py @@ -15,6 +15,7 @@ from neutron_understack import config from neutron_understack import evpn_compat +from neutron_understack import maintenance as understack_maintenance from neutron_understack.api.definitions import understack_vni as apidef from neutron_understack.l3_router import understack_vni_db @@ -129,6 +130,12 @@ def get_plugin_type(cls): def get_plugin_description(self): return "Understack router VNI allocation plugin" + def ovn_maintenance_periodics(self, ovn_client): + LOG.warning("NETDEV ovn_maintenance_periodics called") + return [ + understack_maintenance.NetdevRouterMaintenancePeriodics(self, ovn_client) + ] + @staticmethod @resource_extend.extends([apidef.COLLECTION_NAME]) def _extend_router_dict(router_res, router_db): diff --git a/python/neutron-understack/neutron_understack/maintenance.py b/python/neutron-understack/neutron_understack/maintenance.py new file mode 100644 index 000000000..684456b62 --- /dev/null +++ b/python/neutron-understack/neutron_understack/maintenance.py @@ -0,0 +1,42 @@ +"""Periodics run in the OVN maintenance worker. + +Proves the mechanism fires end to end (hook discovered, worker runs, once +cluster-wide) before the real reconciliation logic is added. +""" + +import socket + +from neutron.plugins.ml2.drivers.ovn.mech_driver.ovsdb import maintenance +from oslo_log import log as logging + +LOG = logging.getLogger(__name__) +RECONCILE_SPACING = 60 + + +class NetdevRouterMaintenancePeriodics: + """Reconcile netdev-router Ironic state from the OVN maintenance worker. + + Body is a no-op log line. + """ + + def __init__(self, plugin, ovn_client): + self._plugin = plugin + # Take the maintenance lock so exactly one neutron-server runs these + # periodics, mirroring the OVN maintenance pattern. + LOG.warning( + "NETDEV periodic __init__; _nb_idl=%r", + getattr(ovn_client, "_nb_idl", "MISSING"), + ) + self._idl = ovn_client._nb_idl.idl + self._idl.set_lock(maintenance.MAINTENANCE_NB_IDL_LOCK_NAME) + LOG.warning("NETDEV periodic lock set") + + @property + def has_lock(self): + return self._idl.has_lock + + @maintenance.has_lock_periodic(spacing=RECONCILE_SPACING, run_immediately=False) + def reconcile_netdev_routers(self): + # No-op: proves the periodic is scheduled and fires on exactly one + # neutron-server. host= lets us confirm it is not firing per-worker. + LOG.warning("NETDEV reconcile tick (host=%s)", socket.gethostname())