From 4cedbe3c03a2d83143e5ced13b522a0f4ed7b44a Mon Sep 17 00:00:00 2001 From: Eduardo Olivares Date: Fri, 20 Aug 2021 13:05:31 +0200 Subject: [PATCH] Add extra-dhcp-opts test Create a server with a port using extra-dhcp-opts parameter and check the opts provided are actually applied to the VM instance Change-Id: I2670d1fe122bf6736eea4d17c0b360e02272e415 --- tobiko/openstack/neutron/__init__.py | 1 + tobiko/openstack/neutron/_client.py | 5 +++++ tobiko/openstack/stacks/__init__.py | 2 ++ tobiko/openstack/stacks/_cirros.py | 4 ++++ tobiko/openstack/stacks/nova/server.yaml | 21 ++++++++++++++++++ tobiko/tests/scenario/neutron/test_port.py | 25 ++++++++++++++++++++++ 6 files changed, 58 insertions(+) diff --git a/tobiko/openstack/neutron/__init__.py b/tobiko/openstack/neutron/__init__.py index fda0bdef9..e27f12d93 100644 --- a/tobiko/openstack/neutron/__init__.py +++ b/tobiko/openstack/neutron/__init__.py @@ -53,6 +53,7 @@ get_neutron_client = _client.get_neutron_client find_subnet = _client.find_subnet find_port = _client.find_port list_ports = _client.list_ports +get_port_extra_dhcp_opts = _client.get_port_extra_dhcp_opts create_port = _client.create_port delete_port = _client.delete_port list_subnets = _client.list_subnets diff --git a/tobiko/openstack/neutron/_client.py b/tobiko/openstack/neutron/_client.py index dbffea38e..c7eb440c5 100644 --- a/tobiko/openstack/neutron/_client.py +++ b/tobiko/openstack/neutron/_client.py @@ -115,6 +115,11 @@ def list_ports(client=None, **params): return tobiko.select(ports) +def get_port_extra_dhcp_opts(port_id, client=None, **params): + port = neutron_client(client).show_port(port_id, **params)['port'] + return port['extra_dhcp_opts'] + + NeutronSubnetType = typing.Dict[str, typing.Any] diff --git a/tobiko/openstack/stacks/__init__.py b/tobiko/openstack/stacks/__init__.py index 670490188..d80500d54 100644 --- a/tobiko/openstack/stacks/__init__.py +++ b/tobiko/openstack/stacks/__init__.py @@ -41,6 +41,8 @@ CirrosSameHostServerStackFixture = _cirros.CirrosSameHostServerStackFixture RebootCirrosServerOperation = _cirros.RebootCirrosServerOperation EvacuableCirrosImageFixture = _cirros.EvacuableCirrosImageFixture EvacuableServerStackFixture = _cirros.EvacuableServerStackFixture +ExtraDhcpOptsCirrosServerStackFixture = ( + _cirros.ExtraDhcpOptsCirrosServerStackFixture) FedoraFlavorStackFixture = _fedora.FedoraFlavorStackFixture FedoraImageFixture = _fedora.FedoraImageFixture diff --git a/tobiko/openstack/stacks/_cirros.py b/tobiko/openstack/stacks/_cirros.py index c553ea92f..a2f74e931 100644 --- a/tobiko/openstack/stacks/_cirros.py +++ b/tobiko/openstack/stacks/_cirros.py @@ -91,3 +91,7 @@ class EvacuableServerStackFixture(CirrosServerStackFixture): #: Glance image used to create a Nova server instance image_fixture = tobiko.required_setup_fixture(EvacuableCirrosImageFixture) + + +class ExtraDhcpOptsCirrosServerStackFixture(CirrosServerStackFixture): + use_extra_dhcp_opts = True diff --git a/tobiko/openstack/stacks/nova/server.yaml b/tobiko/openstack/stacks/nova/server.yaml index 55d71e05a..d12a7a1bb 100644 --- a/tobiko/openstack/stacks/nova/server.yaml +++ b/tobiko/openstack/stacks/nova/server.yaml @@ -41,6 +41,11 @@ parameters: description: Security groups to subscrive server port default: [] + use_extra_dhcp_opts: + type: boolean + description: A set of zero or more extra DHCP option pairs + default: false + has_floating_ip: type: boolean description: Whenever server has floating IP associated @@ -72,6 +77,8 @@ conditions: has_floating_ip: get_param: has_floating_ip + use_extra_dhcp_opts: + get_param: use_extra_dhcp_opts resources: @@ -82,6 +89,20 @@ resources: network: {get_param: network} port_security_enabled: {get_param: port_security_enabled} security_groups: {get_param: security_groups} + value_specs: + # TODO(eolivare): I tried a different approach to define + # extra_dhcp_opts, but it did not work: providing a list of + # dictionaries from the python class + # ExtraDhcpOptsCirrosServerStackFixture would have been my preferred + # option but I got the following error from neutron: + # No valid key specs matched for: ... + # Apparently heat does not parse correctly the list of dictionaries and + # instead it provides a list of strings to neutron + extra_dhcp_opts: + if: + - 'use_extra_dhcp_opts' + - [{'opt_name': 'domain-name', 'opt_value': '"tobiko.domain"'}] + - [] server_name: type: OS::Heat::RandomString diff --git a/tobiko/tests/scenario/neutron/test_port.py b/tobiko/tests/scenario/neutron/test_port.py index 492cb6fd8..91c69a002 100644 --- a/tobiko/tests/scenario/neutron/test_port.py +++ b/tobiko/tests/scenario/neutron/test_port.py @@ -15,6 +15,7 @@ from __future__ import absolute_import import json +import re import typing import netaddr @@ -24,6 +25,7 @@ import testtools import tobiko from tobiko.shell import ping from tobiko.shell import ip +from tobiko.shell import sh from tobiko.openstack import neutron from tobiko.openstack import nova from tobiko.openstack import stacks @@ -195,3 +197,26 @@ class PortLogsTest(testtools.TestCase): responses_text = ''.join(f'\t{r}\n' for r in responses) tobiko.fail(f"Unexpected events found after '{name}':\n" f"{responses_text}") + + +class ExtraDhcpOptsPortTest(PortTest): + """Test extra-dhcp-options port parameter""" + stack = tobiko.required_setup_fixture( + stacks.ExtraDhcpOptsCirrosServerStackFixture) + + def test_extra_dhcp_opts(self): + extra_dhcp_options = neutron.get_port_extra_dhcp_opts( + self.stack.port_id) + for option in extra_dhcp_options: + if 'domain-name' == option['opt_name']: + domain = option['opt_value'].replace('"', '') + break + else: + tobiko.fail('No extra-dhcp-opt found for domain-name') + + vm_resolv_conf = sh.execute('cat /etc/resolv.conf', + ssh_client=self.stack.ssh_client).stdout + self.assertIsNotNone( + re.search(r'^search\s+{domain}$'.format(domain=domain), + vm_resolv_conf, + re.MULTILINE))