#! /usr/bin/python3 # SPDX-License-Identifier: GPL-2.0-or-later # # tasst - Test A Simple Socket Transport # library of test helpers for passt & pasta # # tasst/dhcp.py - Helpers for testing DHCP # # Copyright Red Hat # Author: David Gibson import ipaddress import os from tasst import Tasst, TasstSubData from tasst.address import IpiAllocator, TEST_NET_1 from tasst.nstool import UnshareSite class BaseDhcpTasst(Tasst): """ Test DHCP behaviour. :avocado: disable """ DHCLIENT = '/sbin/dhclient' def subsetup(self, site, ifname, addr, gw, mtu): site.require_cmds(self.DHCLIENT) pidfile = os.path.join(self.workdir, 'dhclient.pid') leasefile = os.path.join(self.workdir, 'dhclient.leases') # We need '-nc' because we may be running with capabilities # but not UID 0. Without -nc dhclient drops capabilities # before invoking dhclient-script, so it's unable to actually # configure the interface site.fg('{} -4 -v -nc -pf {} -lf {} {}' .format(self.DHCLIENT, pidfile, leasefile, ifname), sudo=True) Tasst.subsetup(self, BaseDhcpTasst, TasstSubData(site=site, ifname=ifname, addr=addr, gw=gw, mtu=mtu)) def test_addr(self): sub = self.get_subsetup(BaseDhcpTasst) (addr,) = sub.site.addrs(sub.ifname, family='inet', scope='global') self.assertEquals(addr.ip, sub.addr) def test_route(self): sub = self.get_subsetup(BaseDhcpTasst) (defroute,) = sub.site.routes4(dst='default') self.assertEquals(ipaddress.ip_address(defroute['gateway']), sub.gw) def test_mtu(self): sub = self.get_subsetup(BaseDhcpTasst) self.assertEquals(sub.site.mtu(sub.ifname), sub.mtu) class MetaDhcpTasst(BaseDhcpTasst): """Ugly workaround for https://github.com/avocado-framework/avocado/issues/5680. Explicitly apply the "meta" tag to inherited tests :avocado: disable :avocado: tags=meta """ def test_addr(self): super().test_addr() def test_route(self): super().test_route() def test_mtu(self): super().test_mtu() class DhcpdTasst(MetaDhcpTasst): DHCPD = 'dhcpd' SUBNET = TEST_NET_1 def setUp(self): super().setUp() ifname = 'clientif' server_ifname = 'serverif' self.client = UnshareSite(self.__class__.__name__ + '.client', '-Un') self.server = UnshareSite(self.__class__.__name__ + '.server', '-n', parent=self.client, sudo=True) self.server.require_cmds(self.DHCPD) self.client.veth(ifname, server_ifname, self.server) # Configure the DHCP server ipa = IpiAllocator(self.SUBNET) (server_ip4,) = ipa.next_ipis() (client_ip4,) = ipa.next_ipis() confpath = os.path.join(self.workdir, 'dhcpd.conf') open(confpath, 'w').write(''' subnet {} netmask {} {{ option routers {}; range {} {}; }} '''.format(self.SUBNET.network_address, self.SUBNET.netmask, server_ip4.ip, client_ip4.ip, client_ip4.ip)) self.pidpath = os.path.join(self.workdir, 'dhcpd.pid') leasepath = os.path.join(self.workdir, 'dhcpd.leases') open(leasepath, 'w').write('') self.server.ifup('lo') self.server.ifup(server_ifname, server_ip4) opts = ('-f -d -4 -cf {} -lf {} -pf {}'.format(confpath, leasepath, self.pidpath)) self.server.fg('{} -t {}'.format(self.DHCPD, opts)) # test config self.dhcpd = self.server.bg('{} {}'.format(self.DHCPD, opts), sudo=True) # Configure the client self.client.ifup('lo') BaseDhcpTasst.subsetup(self, self.client, ifname, client_ip4.ip, server_ip4.ip, 1500) def tearDown(self): pid = int(open(self.pidpath).read()) self.server.fg('kill {}'.format(pid)) status = self.dhcpd.wait() self.server.close() self.client.close() super().tearDown()