Check vswitch type to deploy daemonsets for Neutron L3 agents

Neutron L3 agent daemonsets are only required if openvswitch is enabled.
However, currently, even when openvswitch is not used the L3 agent
daemonsets are being created, but never deployed. This increases the k8s
memory consumption and affects the platform scalability (number of
compute nodes supported).

This change enables the deployment of Neutron L3 agent daemonsets only
when openvswitch is enabled.

Test Plan:

PASS: build-pkg -c -l openstack
PASS: build openstack tarball
PASS: Upload and Apply openstack tarball on standard system
PASS: Check that Neutron L3 agents are not deployed
PASS: Check size reduction in Neutron release secret
PASS: Launch 3x Guest instances (centos-guest VMs)
PASS: Access instances through a remote console
PASS: Ping instances from remote console (all to all)
PASS: Ping instances from external server in the management network

Story: 2011304
Task: 51504

Change-Id: If22f63cf893d547e1e31da71ddb512622a25662c
Signed-off-by: Ingo Almendros Girao <ingo.almendrosgirao@windriver.com>
Co-authored-by: Alex Figueiredo <alex.fernandesfigueiredo@windriver.com>
This commit is contained in:
Ingo Almendros Girao
2025-01-09 20:13:24 +00:00
committed by Ingo Girao
co-authored by Alex Figueiredo
parent 42cbe2261a
commit c19b2bd5ad
4 changed files with 129 additions and 4 deletions
@@ -1,5 +1,5 @@
#
# Copyright (c) 2019-2024 Wind River Systems, Inc.
# Copyright (c) 2019-2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@@ -12,6 +12,7 @@ from sysinv.helm import common
from k8sapp_openstack.common import constants as app_constants
from k8sapp_openstack.helm import openstack
from k8sapp_openstack.utils import is_openvswitch_enabled
LOG = logging.getLogger(__name__)
@@ -53,6 +54,7 @@ class NeutronHelm(openstack.OpenstackBaseHelm):
},
},
'conf': self._get_conf_overrides(),
'manifests': self._get_manifests_overrides(),
'endpoints': self._get_endpoints_overrides(),
}
}
@@ -439,3 +441,10 @@ class NeutronHelm(openstack.OpenstackBaseHelm):
})
return overrides
def _get_manifests_overrides(self):
manifests_overrides = {}
hosts = self.dbapi.ihost_get_list()
openvswitch_enabled = is_openvswitch_enabled(hosts, self.labels_by_hostid)
manifests_overrides.update({'daemonset_l3_agent': openvswitch_enabled})
return manifests_overrides
@@ -1,5 +1,5 @@
#
# Copyright (c) 2020-2024 Wind River Systems, Inc.
# Copyright (c) 2020-2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@@ -20,6 +20,9 @@ class NeutronHelmTestCase(test_plugins.K8SAppOpenstackAppMixin,
def setUp(self):
super(NeutronHelmTestCase, self).setUp()
self.app = dbutils.create_test_app(name=self.app_name)
self.app.dbapi = mock.MagicMock()
self.neutron_helm = neutron.NeutronHelm(self.app.dbapi)
self.neutron_helm.labels_by_hostid = {}
class NeutronGetOverrideTest(NeutronHelmTestCase,
@@ -133,3 +136,31 @@ class NeutronGetOverrideTest(NeutronHelmTestCase,
'certificates': True,
},
})
@mock.patch('k8sapp_openstack.helm.neutron.is_openvswitch_enabled',
return_value=True)
def test_get_manifests_overrides_openvswitch_enabled(self, mock_is_openvswitch_enabled):
"""
Test for the _get_manifests_overrides function to ensure the correct
'daemonset_l3_agent' value is returned based on the openvswitch status.
"""
self.app.dbapi.ihost_get_list.return_value = [
mock.MagicMock(id=1),
mock.MagicMock(id=2)
]
overrides = self.neutron_helm._get_manifests_overrides()
self.assertEqual({'daemonset_l3_agent': True}, overrides)
@mock.patch('k8sapp_openstack.helm.neutron.is_openvswitch_enabled',
return_value=False)
def test_get_manifests_overrides_openvswitch_disabled(self, mock_is_openvswitch_enabled):
"""
Test for the _get_manifests_overrides function to ensure the correct
'daemonset_l3_agent' value is returned based on the openvswitch status.
"""
self.app.dbapi.ihost_get_list.return_value = [
mock.MagicMock(id=1),
mock.MagicMock(id=2)
]
overrides = self.neutron_helm._get_manifests_overrides()
self.assertEqual({'daemonset_l3_agent': False}, overrides)
@@ -1,10 +1,12 @@
#
# Copyright (c) 2022 Wind River Systems, Inc.
# Copyright (c) 2022-2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import mock
from sysinv.common import constants
from sysinv.helm import common as helm_common
from sysinv.tests.db import base as dbbase
from k8sapp_openstack import utils as app_utils
@@ -21,3 +23,52 @@ class UtilsTest(dbbase.ControllerHostTestCase):
@mock.patch('k8sapp_openstack.utils.is_openstack_https_ready', return_value=False)
def test_is_openstack_https_ready_false(self, *_):
self.assertFalse(app_utils.is_openstack_https_ready())
def test_is_openvswitch_enabled_true(self):
"""Test is_openvswitch_enabled returns True when openvswitch
is enabled.
"""
mock_host = mock.MagicMock()
mock_host.id = 1
mock_host.invprovision = constants.PROVISIONED
mock_host.ihost_action = constants.UNLOCK_ACTION
mock_label = mock.MagicMock()
mock_label.label_key = helm_common.LABEL_OPENVSWITCH
mock_label.label_value = helm_common.LABEL_VALUE_ENABLED
hosts = [mock_host]
labels_by_hostid = {
mock_host.id: [mock_label]
}
with mock.patch('k8sapp_openstack.utils.cutils.get_personalities',
return_value=[constants.WORKER]), \
mock.patch('k8sapp_openstack.utils.cutils.has_openstack_compute',
return_value=True):
result = app_utils.is_openvswitch_enabled(hosts, labels_by_hostid)
self.assertTrue(result)
def test_is_openvswitch_enabled_false(self):
"""Test is_openvswitch_enabled returns False when openvswitch
is not enabled.
"""
mock_host = mock.MagicMock()
mock_host.id = 1
mock_host.invprovision = constants.PROVISIONED
mock_host.ihost_action = constants.UNLOCK_ACTION
mock_label = mock.MagicMock()
mock_label.label_key = "fake_label"
mock_label.label_value = "fake_value"
hosts = [mock_host]
labels_by_hostid = {
mock_host.id: [mock_label]
}
with mock.patch('k8sapp_openstack.utils.cutils.get_personalities',
return_value=[constants.WORKER]), \
mock.patch('k8sapp_openstack.utils.cutils.has_openstack_compute',
return_value=True):
result = app_utils.is_openvswitch_enabled(hosts, labels_by_hostid)
self.assertFalse(result)
@@ -1,5 +1,5 @@
#
# Copyright (c) 2023-2024 Wind River Systems, Inc.
# Copyright (c) 2023-2025 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@@ -20,6 +20,7 @@ from sysinv.common import constants
from sysinv.common import kubernetes
from sysinv.common import utils as cutils
from sysinv.db import api as dbapi
from sysinv.helm import common as helm_common
import yaml
from k8sapp_openstack.common import constants as app_constants
@@ -538,3 +539,36 @@ def is_netapp_available() -> bool:
"""
netapp_backends = check_netapp_backends()
return netapp_backends["nfs"] or netapp_backends["iscsi"]
def is_openvswitch_enabled(hosts, labels_by_hostid) -> bool:
"""
Check if openvswitch is enabled.
Args:
hosts (list): A list of hosts registered in the database.
labels_by_hostid (dict): A dictionary of labels associated
with a specific host ID.
Returns:
bool: True if openvswitch is enabled or False if it is not.
"""
for host in hosts:
host_labels = labels_by_hostid.get(host.id, [])
if not host_labels:
LOG.debug(f"No labels found for host ID {host.id}")
labels = dict((label.label_key, label.label_value) for label in host_labels)
if (host.invprovision in [constants.PROVISIONED,
constants.PROVISIONING] or
host.ihost_action in [constants.UNLOCK_ACTION,
constants.FORCE_UNLOCK_ACTION]):
if (constants.WORKER in cutils.get_personalities(host) and
cutils.has_openstack_compute(host_labels)):
if (helm_common.LABEL_OPENVSWITCH in labels):
vswitch_label_value = labels.get(helm_common.LABEL_OPENVSWITCH)
LOG.debug(f"Open vSwitch label value for host {host.id}: {vswitch_label_value}")
return helm_common.LABEL_VALUE_ENABLED == vswitch_label_value.lower()
else:
LOG.debug(f"Openvswitch label not found for host {host.id}")
LOG.info("Openvswitch is not enabled on any of the hosts.")
return False