summaryrefslogtreecommitdiff
path: root/ironic/tests/unit
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2022-09-22 13:22:33 +0000
committerGerrit Code Review <review@openstack.org>2022-09-22 13:22:33 +0000
commit0773a80f91620202d565e2827bab9ceb1358434a (patch)
treef487ee8a9faefa4297d6a4eed28af5d44dd0354a /ironic/tests/unit
parent37a0e9771272264b1cf83d9d4906b5d89de0f8a4 (diff)
parent754e6bb6629a87d52304d736261860683d37da3f (diff)
downloadironic-0773a80f91620202d565e2827bab9ceb1358434a.tar.gz
Merge "Implement a DHCP driver backed by dnsmasq"
Diffstat (limited to 'ironic/tests/unit')
-rw-r--r--ironic/tests/unit/common/test_pxe_utils.py20
-rw-r--r--ironic/tests/unit/dhcp/test_dnsmasq.py140
2 files changed, 154 insertions, 6 deletions
diff --git a/ironic/tests/unit/common/test_pxe_utils.py b/ironic/tests/unit/common/test_pxe_utils.py
index 4d4fbb5b5..b775c68a1 100644
--- a/ironic/tests/unit/common/test_pxe_utils.py
+++ b/ironic/tests/unit/common/test_pxe_utils.py
@@ -25,6 +25,7 @@ from oslo_config import cfg
from oslo_utils import fileutils
from oslo_utils import uuidutils
+from ironic.common import dhcp_factory
from ironic.common import exception
from ironic.common.glance_service import image_service
from ironic.common import image_service as base_image_service
@@ -45,6 +46,11 @@ DRV_INFO_DICT = db_utils.get_test_pxe_driver_info()
DRV_INTERNAL_INFO_DICT = db_utils.get_test_pxe_driver_internal_info()
+def _reset_dhcp_provider(config, provider_name):
+ config(dhcp_provider=provider_name, group='dhcp')
+ dhcp_factory.DHCPFactory._dhcp_provider = None
+
+
# Prevent /httpboot validation on creating the node
@mock.patch('ironic.drivers.modules.pxe.PXEBoot.__init__', lambda self: None)
class TestPXEUtils(db_base.DbTestCase):
@@ -674,7 +680,7 @@ class TestPXEUtils(db_base.DbTestCase):
# TODO(TheJulia): We should... like... fix the template to
# enable mac address usage.....
grub_tmplte = "ironic/drivers/modules/pxe_grub_config.template"
- self.config(dhcp_provider='none', group='dhcp')
+ _reset_dhcp_provider(self.config, 'none')
self.config(tftp_root=tempfile.mkdtemp(), group='pxe')
link_ip_configs_mock.side_effect = \
exception.FailedToGetIPAddressOnPort(port_id='blah')
@@ -898,7 +904,7 @@ class TestPXEUtils(db_base.DbTestCase):
{'opt_name': '150',
'opt_value': '192.0.2.1',
'ip_version': ip_version},
- {'opt_name': 'server-ip-address',
+ {'opt_name': '255',
'opt_value': '192.0.2.1',
'ip_version': ip_version}
]
@@ -1904,7 +1910,8 @@ class iPXEBuildConfigOptionsTestCase(db_base.DbTestCase):
self.config(tftp_server='ff80::1', group='pxe')
self.config(http_url='http://[ff80::1]:1234', group='deploy')
- self.config(dhcp_provider='isc', group='dhcp')
+ _reset_dhcp_provider(self.config, 'none')
+
if ip_version == 6:
# NOTE(TheJulia): DHCPv6 RFCs seem to indicate that the prior
# options are not imported, although they may be supported
@@ -1932,7 +1939,7 @@ class iPXEBuildConfigOptionsTestCase(db_base.DbTestCase):
{'opt_name': '67',
'opt_value': expected_boot_script_url,
'ip_version': ip_version},
- {'opt_name': 'server-ip-address',
+ {'opt_name': '255',
'opt_value': '192.0.2.1',
'ip_version': ip_version}]
@@ -1940,7 +1947,8 @@ class iPXEBuildConfigOptionsTestCase(db_base.DbTestCase):
pxe_utils.dhcp_options_for_instance(
task, ipxe_enabled=True))
- self.config(dhcp_provider='neutron', group='dhcp')
+ _reset_dhcp_provider(self.config, 'neutron')
+
if ip_version == 6:
# Boot URL variable set from prior test of isc parameters.
expected_info = [{'opt_name': 'tag:!ipxe6,59',
@@ -1963,7 +1971,7 @@ class iPXEBuildConfigOptionsTestCase(db_base.DbTestCase):
{'opt_name': 'tag:ipxe,67',
'opt_value': expected_boot_script_url,
'ip_version': ip_version},
- {'opt_name': 'server-ip-address',
+ {'opt_name': '255',
'opt_value': '192.0.2.1',
'ip_version': ip_version}]
diff --git a/ironic/tests/unit/dhcp/test_dnsmasq.py b/ironic/tests/unit/dhcp/test_dnsmasq.py
new file mode 100644
index 000000000..64fe46f33
--- /dev/null
+++ b/ironic/tests/unit/dhcp/test_dnsmasq.py
@@ -0,0 +1,140 @@
+#
+# Copyright 2022 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import os
+import tempfile
+
+from ironic.common import dhcp_factory
+from ironic.common import utils as common_utils
+from ironic.conductor import task_manager
+from ironic.tests.unit.db import base as db_base
+from ironic.tests.unit.objects import utils as object_utils
+
+
+class TestDnsmasqDHCPApi(db_base.DbTestCase):
+
+ def setUp(self):
+ super(TestDnsmasqDHCPApi, self).setUp()
+ self.config(dhcp_provider='dnsmasq',
+ group='dhcp')
+ self.node = object_utils.create_test_node(self.context)
+
+ self.ports = [
+ object_utils.create_test_port(
+ self.context, node_id=self.node.id, id=2,
+ uuid='1be26c0b-03f2-4d2e-ae87-c02d7f33c782',
+ address='52:54:00:cf:2d:32',
+ pxe_enabled=True)]
+
+ self.optsdir = tempfile.mkdtemp()
+ self.addCleanup(lambda: common_utils.rmtree_without_raise(
+ self.optsdir))
+ self.config(dhcp_optsdir=self.optsdir, group='dnsmasq')
+
+ self.hostsdir = tempfile.mkdtemp()
+ self.addCleanup(lambda: common_utils.rmtree_without_raise(
+ self.hostsdir))
+ self.config(dhcp_hostsdir=self.hostsdir, group='dnsmasq')
+
+ dhcp_factory.DHCPFactory._dhcp_provider = None
+ self.api = dhcp_factory.DHCPFactory()
+ self.opts = [
+ {
+ 'ip_version': 4,
+ 'opt_name': '67',
+ 'opt_value': 'bootx64.efi'
+ },
+ {
+ 'ip_version': 4,
+ 'opt_name': '210',
+ 'opt_value': '/tftpboot/'
+ },
+ {
+ 'ip_version': 4,
+ 'opt_name': '66',
+ 'opt_value': '192.0.2.135',
+ },
+ {
+ 'ip_version': 4,
+ 'opt_name': '150',
+ 'opt_value': '192.0.2.135'
+ },
+ {
+ 'ip_version': 4,
+ 'opt_name': '255',
+ 'opt_value': '192.0.2.135'
+ }
+ ]
+
+ def test_update_dhcp(self):
+ with task_manager.acquire(self.context,
+ self.node.uuid) as task:
+ self.api.update_dhcp(task, self.opts)
+
+ dnsmasq_tag = task.node.driver_internal_info.get('dnsmasq_tag')
+ self.assertEqual(36, len(dnsmasq_tag))
+
+ hostfile = os.path.join(self.hostsdir,
+ 'ironic-52:54:00:cf:2d:32.conf')
+ with open(hostfile, 'r') as f:
+ self.assertEqual(
+ '52:54:00:cf:2d:32,set:%s,set:ironic\n' % dnsmasq_tag,
+ f.readline())
+
+ optsfile = os.path.join(self.optsdir,
+ 'ironic-%s.conf' % self.node.uuid)
+ with open(optsfile, 'r') as f:
+ self.assertEqual([
+ 'tag:%s,67,bootx64.efi\n' % dnsmasq_tag,
+ 'tag:%s,210,/tftpboot/\n' % dnsmasq_tag,
+ 'tag:%s,66,192.0.2.135\n' % dnsmasq_tag,
+ 'tag:%s,150,192.0.2.135\n' % dnsmasq_tag,
+ 'tag:%s,255,192.0.2.135\n' % dnsmasq_tag],
+ f.readlines())
+
+ def test_get_ip_addresses(self):
+ with task_manager.acquire(self.context,
+ self.node.uuid) as task:
+ with tempfile.NamedTemporaryFile() as fp:
+ self.config(dhcp_leasefile=fp.name, group='dnsmasq')
+ fp.write(b"1659975057 52:54:00:cf:2d:32 192.0.2.198 * *\n")
+ fp.flush()
+ self.assertEqual(
+ ['192.0.2.198'],
+ self.api.provider.get_ip_addresses(task))
+
+ def test_clean_dhcp_opts(self):
+ with task_manager.acquire(self.context,
+ self.node.uuid) as task:
+ self.api.update_dhcp(task, self.opts)
+
+ hostfile = os.path.join(self.hostsdir,
+ 'ironic-52:54:00:cf:2d:32.conf')
+ optsfile = os.path.join(self.optsdir,
+ 'ironic-%s.conf' % self.node.uuid)
+ self.assertTrue(os.path.isfile(hostfile))
+ self.assertTrue(os.path.isfile(optsfile))
+
+ with task_manager.acquire(self.context,
+ self.node.uuid) as task:
+ self.api.clean_dhcp(task)
+
+ # assert the host file remains with the ignore directive, and the opts
+ # file is deleted
+ with open(hostfile, 'r') as f:
+ self.assertEqual(
+ '52:54:00:cf:2d:32,ignore\n',
+ f.readline())
+ self.assertFalse(os.path.isfile(optsfile))