Blame cloudinit/net/tests/test_init.py

Packit bc9a3a
# This file is part of cloud-init. See LICENSE file for license information.
Packit bc9a3a
Packit bc9a3a
import copy
Packit bc9a3a
import errno
Packit bc9a3a
import httpretty
Packit bc9a3a
import mock
Packit bc9a3a
import os
Packit bc9a3a
import requests
Packit bc9a3a
import textwrap
Packit bc9a3a
Packit bc9a3a
import cloudinit.net as net
Packit bc9a3a
from cloudinit.util import ensure_file, write_file, ProcessExecutionError
Packit bc9a3a
from cloudinit.tests.helpers import CiTestCase, HttprettyTestCase
Packit bc9a3a
from cloudinit import safeyaml as yaml
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestSysDevPath(CiTestCase):
Packit bc9a3a
Packit bc9a3a
    def test_sys_dev_path(self):
Packit bc9a3a
        """sys_dev_path returns a path under SYS_CLASS_NET for a device."""
Packit bc9a3a
        dev = 'something'
Packit bc9a3a
        path = 'attribute'
Packit bc9a3a
        expected = net.SYS_CLASS_NET + dev + '/' + path
Packit bc9a3a
        self.assertEqual(expected, net.sys_dev_path(dev, path))
Packit bc9a3a
Packit bc9a3a
    def test_sys_dev_path_without_path(self):
Packit bc9a3a
        """When path param isn't provided it defaults to empty string."""
Packit bc9a3a
        dev = 'something'
Packit bc9a3a
        expected = net.SYS_CLASS_NET + dev + '/'
Packit bc9a3a
        self.assertEqual(expected, net.sys_dev_path(dev))
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestReadSysNet(CiTestCase):
Packit bc9a3a
    with_logs = True
Packit bc9a3a
Packit bc9a3a
    def setUp(self):
Packit bc9a3a
        super(TestReadSysNet, self).setUp()
Packit bc9a3a
        sys_mock = mock.patch('cloudinit.net.get_sys_class_path')
Packit bc9a3a
        self.m_sys_path = sys_mock.start()
Packit bc9a3a
        self.sysdir = self.tmp_dir() + '/'
Packit bc9a3a
        self.m_sys_path.return_value = self.sysdir
Packit bc9a3a
        self.addCleanup(sys_mock.stop)
Packit bc9a3a
Packit bc9a3a
    def test_read_sys_net_strips_contents_of_sys_path(self):
Packit bc9a3a
        """read_sys_net strips whitespace from the contents of a sys file."""
Packit bc9a3a
        content = 'some stuff with trailing whitespace\t\r\n'
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'dev', 'attr'), content)
Packit bc9a3a
        self.assertEqual(content.strip(), net.read_sys_net('dev', 'attr'))
Packit bc9a3a
Packit bc9a3a
    def test_read_sys_net_reraises_oserror(self):
Packit bc9a3a
        """read_sys_net raises OSError/IOError when file doesn't exist."""
Packit bc9a3a
        # Non-specific Exception because versions of python OSError vs IOError.
Packit bc9a3a
        with self.assertRaises(Exception) as context_manager:  # noqa: H202
Packit bc9a3a
            net.read_sys_net('dev', 'attr')
Packit bc9a3a
        error = context_manager.exception
Packit bc9a3a
        self.assertIn('No such file or directory', str(error))
Packit bc9a3a
Packit bc9a3a
    def test_read_sys_net_handles_error_with_on_enoent(self):
Packit bc9a3a
        """read_sys_net handles OSError/IOError with on_enoent if provided."""
Packit bc9a3a
        handled_errors = []
Packit bc9a3a
Packit bc9a3a
        def on_enoent(e):
Packit bc9a3a
            handled_errors.append(e)
Packit bc9a3a
Packit bc9a3a
        net.read_sys_net('dev', 'attr', on_enoent=on_enoent)
Packit bc9a3a
        error = handled_errors[0]
Packit bc9a3a
        self.assertIsInstance(error, Exception)
Packit bc9a3a
        self.assertIn('No such file or directory', str(error))
Packit bc9a3a
Packit bc9a3a
    def test_read_sys_net_translates_content(self):
Packit bc9a3a
        """read_sys_net translates content when translate dict is provided."""
Packit bc9a3a
        content = "you're welcome\n"
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'dev', 'attr'), content)
Packit bc9a3a
        translate = {"you're welcome": 'de nada'}
Packit bc9a3a
        self.assertEqual(
Packit bc9a3a
            'de nada',
Packit bc9a3a
            net.read_sys_net('dev', 'attr', translate=translate))
Packit bc9a3a
Packit bc9a3a
    def test_read_sys_net_errors_on_translation_failures(self):
Packit bc9a3a
        """read_sys_net raises a KeyError and logs details on failure."""
Packit bc9a3a
        content = "you're welcome\n"
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'dev', 'attr'), content)
Packit bc9a3a
        with self.assertRaises(KeyError) as context_manager:
Packit bc9a3a
            net.read_sys_net('dev', 'attr', translate={})
Packit bc9a3a
        error = context_manager.exception
Packit bc9a3a
        self.assertEqual('"you\'re welcome"', str(error))
Packit bc9a3a
        self.assertIn(
Packit bc9a3a
            "Found unexpected (not translatable) value 'you're welcome' in "
Packit bc9a3a
            "'{0}dev/attr".format(self.sysdir),
Packit bc9a3a
            self.logs.getvalue())
Packit bc9a3a
Packit bc9a3a
    def test_read_sys_net_handles_handles_with_onkeyerror(self):
Packit bc9a3a
        """read_sys_net handles translation errors calling on_keyerror."""
Packit bc9a3a
        content = "you're welcome\n"
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'dev', 'attr'), content)
Packit bc9a3a
        handled_errors = []
Packit bc9a3a
Packit bc9a3a
        def on_keyerror(e):
Packit bc9a3a
            handled_errors.append(e)
Packit bc9a3a
Packit bc9a3a
        net.read_sys_net('dev', 'attr', translate={}, on_keyerror=on_keyerror)
Packit bc9a3a
        error = handled_errors[0]
Packit bc9a3a
        self.assertIsInstance(error, KeyError)
Packit bc9a3a
        self.assertEqual('"you\'re welcome"', str(error))
Packit bc9a3a
Packit bc9a3a
    def test_read_sys_net_safe_false_on_translate_failure(self):
Packit bc9a3a
        """read_sys_net_safe returns False on translation failures."""
Packit bc9a3a
        content = "you're welcome\n"
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'dev', 'attr'), content)
Packit bc9a3a
        self.assertFalse(net.read_sys_net_safe('dev', 'attr', translate={}))
Packit bc9a3a
Packit bc9a3a
    def test_read_sys_net_safe_returns_false_on_noent_failure(self):
Packit bc9a3a
        """read_sys_net_safe returns False on file not found failures."""
Packit bc9a3a
        self.assertFalse(net.read_sys_net_safe('dev', 'attr'))
Packit bc9a3a
Packit bc9a3a
    def test_read_sys_net_int_returns_none_on_error(self):
Packit bc9a3a
        """read_sys_net_safe returns None on failures."""
Packit bc9a3a
        self.assertFalse(net.read_sys_net_int('dev', 'attr'))
Packit bc9a3a
Packit bc9a3a
    def test_read_sys_net_int_returns_none_on_valueerror(self):
Packit bc9a3a
        """read_sys_net_safe returns None when content is not an int."""
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'dev', 'attr'), 'NOTINT\n')
Packit bc9a3a
        self.assertFalse(net.read_sys_net_int('dev', 'attr'))
Packit bc9a3a
Packit bc9a3a
    def test_read_sys_net_int_returns_integer_from_content(self):
Packit bc9a3a
        """read_sys_net_safe returns None on failures."""
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'dev', 'attr'), '1\n')
Packit bc9a3a
        self.assertEqual(1, net.read_sys_net_int('dev', 'attr'))
Packit bc9a3a
Packit bc9a3a
    def test_is_up_true(self):
Packit bc9a3a
        """is_up is True if sys/net/devname/operstate is 'up' or 'unknown'."""
Packit bc9a3a
        for state in ['up', 'unknown']:
Packit bc9a3a
            write_file(os.path.join(self.sysdir, 'eth0', 'operstate'), state)
Packit bc9a3a
            self.assertTrue(net.is_up('eth0'))
Packit bc9a3a
Packit bc9a3a
    def test_is_up_false(self):
Packit bc9a3a
        """is_up is False if sys/net/devname/operstate is 'down' or invalid."""
Packit bc9a3a
        for state in ['down', 'incomprehensible']:
Packit bc9a3a
            write_file(os.path.join(self.sysdir, 'eth0', 'operstate'), state)
Packit bc9a3a
            self.assertFalse(net.is_up('eth0'))
Packit bc9a3a
Packit bc9a3a
    def test_is_wireless(self):
Packit bc9a3a
        """is_wireless is True when /sys/net/devname/wireless exists."""
Packit bc9a3a
        self.assertFalse(net.is_wireless('eth0'))
Packit bc9a3a
        ensure_file(os.path.join(self.sysdir, 'eth0', 'wireless'))
Packit bc9a3a
        self.assertTrue(net.is_wireless('eth0'))
Packit bc9a3a
Packit bc9a3a
    def test_is_bridge(self):
Packit bc9a3a
        """is_bridge is True when /sys/net/devname/bridge exists."""
Packit bc9a3a
        self.assertFalse(net.is_bridge('eth0'))
Packit bc9a3a
        ensure_file(os.path.join(self.sysdir, 'eth0', 'bridge'))
Packit bc9a3a
        self.assertTrue(net.is_bridge('eth0'))
Packit bc9a3a
Packit bc9a3a
    def test_is_bond(self):
Packit bc9a3a
        """is_bond is True when /sys/net/devname/bonding exists."""
Packit bc9a3a
        self.assertFalse(net.is_bond('eth0'))
Packit bc9a3a
        ensure_file(os.path.join(self.sysdir, 'eth0', 'bonding'))
Packit bc9a3a
        self.assertTrue(net.is_bond('eth0'))
Packit bc9a3a
Packit bc9a3a
    def test_get_master(self):
Packit bc9a3a
        """get_master returns the path when /sys/net/devname/master exists."""
Packit bc9a3a
        self.assertIsNone(net.get_master('enP1s1'))
Packit bc9a3a
        master_path = os.path.join(self.sysdir, 'enP1s1', 'master')
Packit bc9a3a
        ensure_file(master_path)
Packit bc9a3a
        self.assertEqual(master_path, net.get_master('enP1s1'))
Packit bc9a3a
Packit bc9a3a
    def test_master_is_bridge_or_bond(self):
Packit bc9a3a
        bridge_mac = 'aa:bb:cc:aa:bb:cc'
Packit bc9a3a
        bond_mac = 'cc:bb:aa:cc:bb:aa'
Packit bc9a3a
Packit bc9a3a
        # No master => False
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'address'), bridge_mac)
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth2', 'address'), bond_mac)
Packit bc9a3a
Packit bc9a3a
        self.assertFalse(net.master_is_bridge_or_bond('eth1'))
Packit bc9a3a
        self.assertFalse(net.master_is_bridge_or_bond('eth2'))
Packit bc9a3a
Packit bc9a3a
        # masters without bridge/bonding => False
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'br0', 'address'), bridge_mac)
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'bond0', 'address'), bond_mac)
Packit bc9a3a
Packit bc9a3a
        os.symlink('../br0', os.path.join(self.sysdir, 'eth1', 'master'))
Packit bc9a3a
        os.symlink('../bond0', os.path.join(self.sysdir, 'eth2', 'master'))
Packit bc9a3a
Packit bc9a3a
        self.assertFalse(net.master_is_bridge_or_bond('eth1'))
Packit bc9a3a
        self.assertFalse(net.master_is_bridge_or_bond('eth2'))
Packit bc9a3a
Packit bc9a3a
        # masters with bridge/bonding => True
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'br0', 'bridge'), '')
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'bond0', 'bonding'), '')
Packit bc9a3a
Packit bc9a3a
        self.assertTrue(net.master_is_bridge_or_bond('eth1'))
Packit bc9a3a
        self.assertTrue(net.master_is_bridge_or_bond('eth2'))
Packit bc9a3a
Packit bc9a3a
    def test_is_vlan(self):
Packit bc9a3a
        """is_vlan is True when /sys/net/devname/uevent has DEVTYPE=vlan."""
Packit bc9a3a
        ensure_file(os.path.join(self.sysdir, 'eth0', 'uevent'))
Packit bc9a3a
        self.assertFalse(net.is_vlan('eth0'))
Packit bc9a3a
        content = 'junk\nDEVTYPE=vlan\njunk\n'
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth0', 'uevent'), content)
Packit bc9a3a
        self.assertTrue(net.is_vlan('eth0'))
Packit bc9a3a
Packit bc9a3a
    def test_is_connected_when_physically_connected(self):
Packit bc9a3a
        """is_connected is True when /sys/net/devname/iflink reports 2."""
Packit bc9a3a
        self.assertFalse(net.is_connected('eth0'))
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth0', 'iflink'), "2")
Packit bc9a3a
        self.assertTrue(net.is_connected('eth0'))
Packit bc9a3a
Packit bc9a3a
    def test_is_connected_when_wireless_and_carrier_active(self):
Packit bc9a3a
        """is_connected is True if wireless /sys/net/devname/carrier is 1."""
Packit bc9a3a
        self.assertFalse(net.is_connected('eth0'))
Packit bc9a3a
        ensure_file(os.path.join(self.sysdir, 'eth0', 'wireless'))
Packit bc9a3a
        self.assertFalse(net.is_connected('eth0'))
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth0', 'carrier'), "1")
Packit bc9a3a
        self.assertTrue(net.is_connected('eth0'))
Packit bc9a3a
Packit bc9a3a
    def test_is_physical(self):
Packit bc9a3a
        """is_physical is True when /sys/net/devname/device exists."""
Packit bc9a3a
        self.assertFalse(net.is_physical('eth0'))
Packit bc9a3a
        ensure_file(os.path.join(self.sysdir, 'eth0', 'device'))
Packit bc9a3a
        self.assertTrue(net.is_physical('eth0'))
Packit bc9a3a
Packit bc9a3a
    def test_is_present(self):
Packit bc9a3a
        """is_present is True when /sys/net/devname exists."""
Packit bc9a3a
        self.assertFalse(net.is_present('eth0'))
Packit bc9a3a
        ensure_file(os.path.join(self.sysdir, 'eth0', 'device'))
Packit bc9a3a
        self.assertTrue(net.is_present('eth0'))
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestGenerateFallbackConfig(CiTestCase):
Packit bc9a3a
Packit bc9a3a
    def setUp(self):
Packit bc9a3a
        super(TestGenerateFallbackConfig, self).setUp()
Packit bc9a3a
        sys_mock = mock.patch('cloudinit.net.get_sys_class_path')
Packit bc9a3a
        self.m_sys_path = sys_mock.start()
Packit bc9a3a
        self.sysdir = self.tmp_dir() + '/'
Packit bc9a3a
        self.m_sys_path.return_value = self.sysdir
Packit bc9a3a
        self.addCleanup(sys_mock.stop)
Packit bc9a3a
        self.add_patch('cloudinit.net.util.is_container', 'm_is_container',
Packit bc9a3a
                       return_value=False)
Packit bc9a3a
        self.add_patch('cloudinit.net.util.udevadm_settle', 'm_settle')
Packit bc9a3a
        self.add_patch('cloudinit.net.is_netfailover', 'm_netfail',
Packit bc9a3a
                       return_value=False)
Packit bc9a3a
        self.add_patch('cloudinit.net.is_netfail_master', 'm_netfail_master',
Packit bc9a3a
                       return_value=False)
Packit bc9a3a
Packit bc9a3a
    def test_generate_fallback_finds_connected_eth_with_mac(self):
Packit bc9a3a
        """generate_fallback_config finds any connected device with a mac."""
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth0', 'carrier'), '1')
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'carrier'), '1')
Packit bc9a3a
        mac = 'aa:bb:cc:aa:bb:cc'
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'address'), mac)
Packit bc9a3a
        expected = {
Packit bc9a3a
            'ethernets': {'eth1': {'match': {'macaddress': mac},
Packit bc9a3a
                                   'dhcp4': True, 'set-name': 'eth1'}},
Packit bc9a3a
            'version': 2}
Packit bc9a3a
        self.assertEqual(expected, net.generate_fallback_config())
Packit bc9a3a
Packit bc9a3a
    def test_generate_fallback_finds_dormant_eth_with_mac(self):
Packit bc9a3a
        """generate_fallback_config finds any dormant device with a mac."""
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth0', 'dormant'), '1')
Packit bc9a3a
        mac = 'aa:bb:cc:aa:bb:cc'
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth0', 'address'), mac)
Packit bc9a3a
        expected = {
Packit bc9a3a
            'ethernets': {'eth0': {'match': {'macaddress': mac}, 'dhcp4': True,
Packit bc9a3a
                                   'set-name': 'eth0'}},
Packit bc9a3a
            'version': 2}
Packit bc9a3a
        self.assertEqual(expected, net.generate_fallback_config())
Packit bc9a3a
Packit bc9a3a
    def test_generate_fallback_finds_eth_by_operstate(self):
Packit bc9a3a
        """generate_fallback_config finds any dormant device with a mac."""
Packit bc9a3a
        mac = 'aa:bb:cc:aa:bb:cc'
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth0', 'address'), mac)
Packit bc9a3a
        expected = {
Packit bc9a3a
            'ethernets': {
Packit bc9a3a
                'eth0': {'dhcp4': True, 'match': {'macaddress': mac},
Packit bc9a3a
                         'set-name': 'eth0'}},
Packit bc9a3a
            'version': 2}
Packit bc9a3a
        valid_operstates = ['dormant', 'down', 'lowerlayerdown', 'unknown']
Packit bc9a3a
        for state in valid_operstates:
Packit bc9a3a
            write_file(os.path.join(self.sysdir, 'eth0', 'operstate'), state)
Packit bc9a3a
            self.assertEqual(expected, net.generate_fallback_config())
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth0', 'operstate'), 'noworky')
Packit bc9a3a
        self.assertIsNone(net.generate_fallback_config())
Packit bc9a3a
Packit bc9a3a
    def test_generate_fallback_config_skips_veth(self):
Packit bc9a3a
        """generate_fallback_config will skip any veth interfaces."""
Packit bc9a3a
        # A connected veth which gets ignored
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'veth0', 'carrier'), '1')
Packit bc9a3a
        self.assertIsNone(net.generate_fallback_config())
Packit bc9a3a
Packit bc9a3a
    def test_generate_fallback_config_skips_bridges(self):
Packit bc9a3a
        """generate_fallback_config will skip any bridges interfaces."""
Packit bc9a3a
        # A connected veth which gets ignored
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth0', 'carrier'), '1')
Packit bc9a3a
        mac = 'aa:bb:cc:aa:bb:cc'
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth0', 'address'), mac)
Packit bc9a3a
        ensure_file(os.path.join(self.sysdir, 'eth0', 'bridge'))
Packit bc9a3a
        self.assertIsNone(net.generate_fallback_config())
Packit bc9a3a
Packit bc9a3a
    def test_generate_fallback_config_skips_bonds(self):
Packit bc9a3a
        """generate_fallback_config will skip any bonded interfaces."""
Packit bc9a3a
        # A connected veth which gets ignored
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth0', 'carrier'), '1')
Packit bc9a3a
        mac = 'aa:bb:cc:aa:bb:cc'
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth0', 'address'), mac)
Packit bc9a3a
        ensure_file(os.path.join(self.sysdir, 'eth0', 'bonding'))
Packit bc9a3a
        self.assertIsNone(net.generate_fallback_config())
Packit bc9a3a
Packit bc9a3a
    def test_generate_fallback_config_skips_netfail_devs(self):
Packit bc9a3a
        """gen_fallback_config ignores netfail primary,sby no mac on master."""
Packit bc9a3a
        mac = 'aa:bb:cc:aa:bb:cc'  # netfailover devs share the same mac
Packit bc9a3a
        for iface in ['ens3', 'ens3sby', 'enP0s1f3']:
Packit bc9a3a
            write_file(os.path.join(self.sysdir, iface, 'carrier'), '1')
Packit bc9a3a
            write_file(
Packit bc9a3a
                os.path.join(self.sysdir, iface, 'addr_assign_type'), '0')
Packit bc9a3a
            write_file(
Packit bc9a3a
                os.path.join(self.sysdir, iface, 'address'), mac)
Packit bc9a3a
Packit bc9a3a
        def is_netfail(iface, _driver=None):
Packit bc9a3a
            # ens3 is the master
Packit bc9a3a
            if iface == 'ens3':
Packit bc9a3a
                return False
Packit bc9a3a
            return True
Packit bc9a3a
        self.m_netfail.side_effect = is_netfail
Packit bc9a3a
Packit bc9a3a
        def is_netfail_master(iface, _driver=None):
Packit bc9a3a
            # ens3 is the master
Packit bc9a3a
            if iface == 'ens3':
Packit bc9a3a
                return True
Packit bc9a3a
            return False
Packit bc9a3a
        self.m_netfail_master.side_effect = is_netfail_master
Packit bc9a3a
        expected = {
Packit bc9a3a
            'ethernets': {
Packit bc9a3a
                'ens3': {'dhcp4': True, 'match': {'name': 'ens3'},
Packit bc9a3a
                         'set-name': 'ens3'}},
Packit bc9a3a
            'version': 2}
Packit bc9a3a
        result = net.generate_fallback_config()
Packit bc9a3a
        self.assertEqual(expected, result)
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestNetFindFallBackNic(CiTestCase):
Packit bc9a3a
Packit bc9a3a
    with_logs = True
Packit bc9a3a
Packit bc9a3a
    def setUp(self):
Packit bc9a3a
        super(TestNetFindFallBackNic, self).setUp()
Packit bc9a3a
        sys_mock = mock.patch('cloudinit.net.get_sys_class_path')
Packit bc9a3a
        self.m_sys_path = sys_mock.start()
Packit bc9a3a
        self.sysdir = self.tmp_dir() + '/'
Packit bc9a3a
        self.m_sys_path.return_value = self.sysdir
Packit bc9a3a
        self.addCleanup(sys_mock.stop)
Packit bc9a3a
        self.add_patch('cloudinit.net.util.is_container', 'm_is_container',
Packit bc9a3a
                       return_value=False)
Packit bc9a3a
        self.add_patch('cloudinit.net.util.udevadm_settle', 'm_settle')
Packit bc9a3a
Packit bc9a3a
    def test_generate_fallback_finds_first_connected_eth_with_mac(self):
Packit bc9a3a
        """find_fallback_nic finds any connected device with a mac."""
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth0', 'carrier'), '1')
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'carrier'), '1')
Packit bc9a3a
        mac = 'aa:bb:cc:aa:bb:cc'
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'address'), mac)
Packit bc9a3a
        self.assertEqual('eth1', net.find_fallback_nic())
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestGetDeviceList(CiTestCase):
Packit bc9a3a
Packit bc9a3a
    def setUp(self):
Packit bc9a3a
        super(TestGetDeviceList, self).setUp()
Packit bc9a3a
        sys_mock = mock.patch('cloudinit.net.get_sys_class_path')
Packit bc9a3a
        self.m_sys_path = sys_mock.start()
Packit bc9a3a
        self.sysdir = self.tmp_dir() + '/'
Packit bc9a3a
        self.m_sys_path.return_value = self.sysdir
Packit bc9a3a
        self.addCleanup(sys_mock.stop)
Packit bc9a3a
Packit bc9a3a
    def test_get_devicelist_raise_oserror(self):
Packit bc9a3a
        """get_devicelist raise any non-ENOENT OSerror."""
Packit bc9a3a
        error = OSError('Can not do it')
Packit bc9a3a
        error.errno = errno.EPERM  # Set non-ENOENT
Packit bc9a3a
        self.m_sys_path.side_effect = error
Packit bc9a3a
        with self.assertRaises(OSError) as context_manager:
Packit bc9a3a
            net.get_devicelist()
Packit bc9a3a
        exception = context_manager.exception
Packit bc9a3a
        self.assertEqual('Can not do it', str(exception))
Packit bc9a3a
Packit bc9a3a
    def test_get_devicelist_empty_without_sys_net(self):
Packit bc9a3a
        """get_devicelist returns empty list when missing SYS_CLASS_NET."""
Packit bc9a3a
        self.m_sys_path.return_value = 'idontexist'
Packit bc9a3a
        self.assertEqual([], net.get_devicelist())
Packit bc9a3a
Packit bc9a3a
    def test_get_devicelist_empty_with_no_devices_in_sys_net(self):
Packit bc9a3a
        """get_devicelist returns empty directoty listing for SYS_CLASS_NET."""
Packit bc9a3a
        self.assertEqual([], net.get_devicelist())
Packit bc9a3a
Packit bc9a3a
    def test_get_devicelist_lists_any_subdirectories_in_sys_net(self):
Packit bc9a3a
        """get_devicelist returns a directory listing for SYS_CLASS_NET."""
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth0', 'operstate'), 'up')
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'operstate'), 'up')
Packit bc9a3a
        self.assertItemsEqual(['eth0', 'eth1'], net.get_devicelist())
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestGetInterfaceMAC(CiTestCase):
Packit bc9a3a
Packit bc9a3a
    def setUp(self):
Packit bc9a3a
        super(TestGetInterfaceMAC, self).setUp()
Packit bc9a3a
        sys_mock = mock.patch('cloudinit.net.get_sys_class_path')
Packit bc9a3a
        self.m_sys_path = sys_mock.start()
Packit bc9a3a
        self.sysdir = self.tmp_dir() + '/'
Packit bc9a3a
        self.m_sys_path.return_value = self.sysdir
Packit bc9a3a
        self.addCleanup(sys_mock.stop)
Packit bc9a3a
Packit bc9a3a
    def test_get_interface_mac_false_with_no_mac(self):
Packit bc9a3a
        """get_device_list returns False when no mac is reported."""
Packit bc9a3a
        ensure_file(os.path.join(self.sysdir, 'eth0', 'bonding'))
Packit bc9a3a
        mac_path = os.path.join(self.sysdir, 'eth0', 'address')
Packit bc9a3a
        self.assertFalse(os.path.exists(mac_path))
Packit bc9a3a
        self.assertFalse(net.get_interface_mac('eth0'))
Packit bc9a3a
Packit bc9a3a
    def test_get_interface_mac(self):
Packit bc9a3a
        """get_interfaces returns the mac from SYS_CLASS_NET/dev/address."""
Packit bc9a3a
        mac = 'aa:bb:cc:aa:bb:cc'
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'address'), mac)
Packit bc9a3a
        self.assertEqual(mac, net.get_interface_mac('eth1'))
Packit bc9a3a
Packit bc9a3a
    def test_get_interface_mac_grabs_bonding_address(self):
Packit bc9a3a
        """get_interfaces returns the source device mac for bonded devices."""
Packit bc9a3a
        source_dev_mac = 'aa:bb:cc:aa:bb:cc'
Packit bc9a3a
        bonded_mac = 'dd:ee:ff:dd:ee:ff'
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'address'), bonded_mac)
Packit bc9a3a
        write_file(
Packit bc9a3a
            os.path.join(self.sysdir, 'eth1', 'bonding_slave', 'perm_hwaddr'),
Packit bc9a3a
            source_dev_mac)
Packit bc9a3a
        self.assertEqual(source_dev_mac, net.get_interface_mac('eth1'))
Packit bc9a3a
Packit bc9a3a
    def test_get_interfaces_empty_list_without_sys_net(self):
Packit bc9a3a
        """get_interfaces returns an empty list when missing SYS_CLASS_NET."""
Packit bc9a3a
        self.m_sys_path.return_value = 'idontexist'
Packit bc9a3a
        self.assertEqual([], net.get_interfaces())
Packit bc9a3a
Packit bc9a3a
    def test_get_interfaces_by_mac_skips_empty_mac(self):
Packit bc9a3a
        """Ignore 00:00:00:00:00:00 addresses from get_interfaces_by_mac."""
Packit bc9a3a
        empty_mac = '00:00:00:00:00:00'
Packit bc9a3a
        mac = 'aa:bb:cc:aa:bb:cc'
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'address'), empty_mac)
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'addr_assign_type'), '0')
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth2', 'addr_assign_type'), '0')
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth2', 'address'), mac)
Packit bc9a3a
        expected = [('eth2', 'aa:bb:cc:aa:bb:cc', None, None)]
Packit bc9a3a
        self.assertEqual(expected, net.get_interfaces())
Packit bc9a3a
Packit bc9a3a
    def test_get_interfaces_by_mac_skips_missing_mac(self):
Packit bc9a3a
        """Ignore interfaces without an address from get_interfaces_by_mac."""
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'addr_assign_type'), '0')
Packit bc9a3a
        address_path = os.path.join(self.sysdir, 'eth1', 'address')
Packit bc9a3a
        self.assertFalse(os.path.exists(address_path))
Packit bc9a3a
        mac = 'aa:bb:cc:aa:bb:cc'
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth2', 'addr_assign_type'), '0')
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth2', 'address'), mac)
Packit bc9a3a
        expected = [('eth2', 'aa:bb:cc:aa:bb:cc', None, None)]
Packit bc9a3a
        self.assertEqual(expected, net.get_interfaces())
Packit bc9a3a
Packit bc9a3a
    def test_get_interfaces_by_mac_skips_master_devs(self):
Packit bc9a3a
        """Ignore interfaces with a master device which would have dup mac."""
Packit bc9a3a
        mac1 = mac2 = 'aa:bb:cc:aa:bb:cc'
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'addr_assign_type'), '0')
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'address'), mac1)
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'master'), "blah")
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth2', 'addr_assign_type'), '0')
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth2', 'address'), mac2)
Packit bc9a3a
        expected = [('eth2', mac2, None, None)]
Packit bc9a3a
        self.assertEqual(expected, net.get_interfaces())
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.is_netfailover')
Packit bc9a3a
    def test_get_interfaces_by_mac_skips_netfailvoer(self, m_netfail):
Packit bc9a3a
        """Ignore interfaces if netfailover primary or standby."""
Packit bc9a3a
        mac = 'aa:bb:cc:aa:bb:cc'  # netfailover devs share the same mac
Packit bc9a3a
        for iface in ['ens3', 'ens3sby', 'enP0s1f3']:
Packit bc9a3a
            write_file(
Packit bc9a3a
                os.path.join(self.sysdir, iface, 'addr_assign_type'), '0')
Packit bc9a3a
            write_file(
Packit bc9a3a
                os.path.join(self.sysdir, iface, 'address'), mac)
Packit bc9a3a
Packit bc9a3a
        def is_netfail(iface, _driver=None):
Packit bc9a3a
            # ens3 is the master
Packit bc9a3a
            if iface == 'ens3':
Packit bc9a3a
                return False
Packit bc9a3a
            else:
Packit bc9a3a
                return True
Packit bc9a3a
        m_netfail.side_effect = is_netfail
Packit bc9a3a
        expected = [('ens3', mac, None, None)]
Packit bc9a3a
        self.assertEqual(expected, net.get_interfaces())
Packit bc9a3a
Packit bc9a3a
    def test_get_interfaces_does_not_skip_phys_members_of_bridges_and_bonds(
Packit bc9a3a
        self
Packit bc9a3a
    ):
Packit bc9a3a
        bridge_mac = 'aa:bb:cc:aa:bb:cc'
Packit bc9a3a
        bond_mac = 'cc:bb:aa:cc:bb:aa'
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'br0', 'address'), bridge_mac)
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'br0', 'bridge'), '')
Packit bc9a3a
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'bond0', 'address'), bond_mac)
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'bond0', 'bonding'), '')
Packit bc9a3a
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'address'), bridge_mac)
Packit bc9a3a
        os.symlink('../br0', os.path.join(self.sysdir, 'eth1', 'master'))
Packit bc9a3a
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth2', 'address'), bond_mac)
Packit bc9a3a
        os.symlink('../bond0', os.path.join(self.sysdir, 'eth2', 'master'))
Packit bc9a3a
Packit bc9a3a
        interface_names = [interface[0] for interface in net.get_interfaces()]
Packit bc9a3a
        self.assertEqual(['eth1', 'eth2'], sorted(interface_names))
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestInterfaceHasOwnMAC(CiTestCase):
Packit bc9a3a
Packit bc9a3a
    def setUp(self):
Packit bc9a3a
        super(TestInterfaceHasOwnMAC, self).setUp()
Packit bc9a3a
        sys_mock = mock.patch('cloudinit.net.get_sys_class_path')
Packit bc9a3a
        self.m_sys_path = sys_mock.start()
Packit bc9a3a
        self.sysdir = self.tmp_dir() + '/'
Packit bc9a3a
        self.m_sys_path.return_value = self.sysdir
Packit bc9a3a
        self.addCleanup(sys_mock.stop)
Packit bc9a3a
Packit bc9a3a
    def test_interface_has_own_mac_false_when_stolen(self):
Packit bc9a3a
        """Return False from interface_has_own_mac when address is stolen."""
Packit bc9a3a
        write_file(os.path.join(self.sysdir, 'eth1', 'addr_assign_type'), '2')
Packit bc9a3a
        self.assertFalse(net.interface_has_own_mac('eth1'))
Packit bc9a3a
Packit bc9a3a
    def test_interface_has_own_mac_true_when_not_stolen(self):
Packit bc9a3a
        """Return False from interface_has_own_mac when mac isn't stolen."""
Packit bc9a3a
        valid_assign_types = ['0', '1', '3']
Packit bc9a3a
        assign_path = os.path.join(self.sysdir, 'eth1', 'addr_assign_type')
Packit bc9a3a
        for _type in valid_assign_types:
Packit bc9a3a
            write_file(assign_path, _type)
Packit bc9a3a
            self.assertTrue(net.interface_has_own_mac('eth1'))
Packit bc9a3a
Packit bc9a3a
    def test_interface_has_own_mac_strict_errors_on_absent_assign_type(self):
Packit bc9a3a
        """When addr_assign_type is absent, interface_has_own_mac errors."""
Packit bc9a3a
        with self.assertRaises(ValueError):
Packit bc9a3a
            net.interface_has_own_mac('eth1', strict=True)
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
@mock.patch('cloudinit.net.util.subp')
Packit bc9a3a
class TestEphemeralIPV4Network(CiTestCase):
Packit bc9a3a
Packit bc9a3a
    with_logs = True
Packit bc9a3a
Packit bc9a3a
    def setUp(self):
Packit bc9a3a
        super(TestEphemeralIPV4Network, self).setUp()
Packit bc9a3a
        sys_mock = mock.patch('cloudinit.net.get_sys_class_path')
Packit bc9a3a
        self.m_sys_path = sys_mock.start()
Packit bc9a3a
        self.sysdir = self.tmp_dir() + '/'
Packit bc9a3a
        self.m_sys_path.return_value = self.sysdir
Packit bc9a3a
        self.addCleanup(sys_mock.stop)
Packit bc9a3a
Packit bc9a3a
    def test_ephemeral_ipv4_network_errors_on_missing_params(self, m_subp):
Packit bc9a3a
        """No required params for EphemeralIPv4Network can be None."""
Packit bc9a3a
        required_params = {
Packit bc9a3a
            'interface': 'eth0', 'ip': '192.168.2.2',
Packit bc9a3a
            'prefix_or_mask': '255.255.255.0', 'broadcast': '192.168.2.255'}
Packit bc9a3a
        for key in required_params.keys():
Packit bc9a3a
            params = copy.deepcopy(required_params)
Packit bc9a3a
            params[key] = None
Packit bc9a3a
            with self.assertRaises(ValueError) as context_manager:
Packit bc9a3a
                net.EphemeralIPv4Network(**params)
Packit bc9a3a
            error = context_manager.exception
Packit bc9a3a
            self.assertIn('Cannot init network on', str(error))
Packit bc9a3a
            self.assertEqual(0, m_subp.call_count)
Packit bc9a3a
Packit bc9a3a
    def test_ephemeral_ipv4_network_errors_invalid_mask_prefix(self, m_subp):
Packit bc9a3a
        """Raise an error when prefix_or_mask is not a netmask or prefix."""
Packit bc9a3a
        params = {
Packit bc9a3a
            'interface': 'eth0', 'ip': '192.168.2.2',
Packit bc9a3a
            'broadcast': '192.168.2.255'}
Packit bc9a3a
        invalid_masks = ('invalid', 'invalid.', '123.123.123')
Packit bc9a3a
        for error_val in invalid_masks:
Packit bc9a3a
            params['prefix_or_mask'] = error_val
Packit bc9a3a
            with self.assertRaises(ValueError) as context_manager:
Packit bc9a3a
                with net.EphemeralIPv4Network(**params):
Packit bc9a3a
                    pass
Packit bc9a3a
            error = context_manager.exception
Packit bc9a3a
            self.assertIn('Cannot setup network: netmask', str(error))
Packit bc9a3a
            self.assertEqual(0, m_subp.call_count)
Packit bc9a3a
Packit bc9a3a
    def test_ephemeral_ipv4_network_performs_teardown(self, m_subp):
Packit bc9a3a
        """EphemeralIPv4Network performs teardown on the device if setup."""
Packit bc9a3a
        expected_setup_calls = [
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/24',
Packit bc9a3a
                 'broadcast', '192.168.2.255', 'dev', 'eth0'],
Packit bc9a3a
                capture=True, update_env={'LANG': 'C'}),
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-family', 'inet', 'link', 'set', 'dev', 'eth0', 'up'],
Packit bc9a3a
                capture=True)]
Packit bc9a3a
        expected_teardown_calls = [
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-family', 'inet', 'link', 'set', 'dev', 'eth0',
Packit bc9a3a
                 'down'], capture=True),
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-family', 'inet', 'addr', 'del', '192.168.2.2/24',
Packit bc9a3a
                 'dev', 'eth0'], capture=True)]
Packit bc9a3a
        params = {
Packit bc9a3a
            'interface': 'eth0', 'ip': '192.168.2.2',
Packit bc9a3a
            'prefix_or_mask': '255.255.255.0', 'broadcast': '192.168.2.255'}
Packit bc9a3a
        with net.EphemeralIPv4Network(**params):
Packit bc9a3a
            self.assertEqual(expected_setup_calls, m_subp.call_args_list)
Packit bc9a3a
        m_subp.assert_has_calls(expected_teardown_calls)
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.readurl')
Packit bc9a3a
    def test_ephemeral_ipv4_no_network_if_url_connectivity(
Packit bc9a3a
            self, m_readurl, m_subp):
Packit bc9a3a
        """No network setup is performed if we can successfully connect to
Packit bc9a3a
        connectivity_url."""
Packit bc9a3a
        params = {
Packit bc9a3a
            'interface': 'eth0', 'ip': '192.168.2.2',
Packit bc9a3a
            'prefix_or_mask': '255.255.255.0', 'broadcast': '192.168.2.255',
Packit bc9a3a
            'connectivity_url': 'http://example.org/index.html'}
Packit bc9a3a
Packit bc9a3a
        with net.EphemeralIPv4Network(**params):
Packit bc9a3a
            self.assertEqual([mock.call('http://example.org/index.html',
Packit bc9a3a
                                        timeout=5)], m_readurl.call_args_list)
Packit bc9a3a
        # Ensure that no teardown happens:
Packit bc9a3a
        m_subp.assert_has_calls([])
Packit bc9a3a
Packit bc9a3a
    def test_ephemeral_ipv4_network_noop_when_configured(self, m_subp):
Packit bc9a3a
        """EphemeralIPv4Network handles exception when address is setup.
Packit bc9a3a
Packit bc9a3a
        It performs no cleanup as the interface was already setup.
Packit bc9a3a
        """
Packit bc9a3a
        params = {
Packit bc9a3a
            'interface': 'eth0', 'ip': '192.168.2.2',
Packit bc9a3a
            'prefix_or_mask': '255.255.255.0', 'broadcast': '192.168.2.255'}
Packit bc9a3a
        m_subp.side_effect = ProcessExecutionError(
Packit bc9a3a
            '', 'RTNETLINK answers: File exists', 2)
Packit bc9a3a
        expected_calls = [
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/24',
Packit bc9a3a
                 'broadcast', '192.168.2.255', 'dev', 'eth0'],
Packit bc9a3a
                capture=True, update_env={'LANG': 'C'})]
Packit bc9a3a
        with net.EphemeralIPv4Network(**params):
Packit bc9a3a
            pass
Packit bc9a3a
        self.assertEqual(expected_calls, m_subp.call_args_list)
Packit bc9a3a
        self.assertIn(
Packit bc9a3a
            'Skip ephemeral network setup, eth0 already has address',
Packit bc9a3a
            self.logs.getvalue())
Packit bc9a3a
Packit bc9a3a
    def test_ephemeral_ipv4_network_with_prefix(self, m_subp):
Packit bc9a3a
        """EphemeralIPv4Network takes a valid prefix to setup the network."""
Packit bc9a3a
        params = {
Packit bc9a3a
            'interface': 'eth0', 'ip': '192.168.2.2',
Packit bc9a3a
            'prefix_or_mask': '24', 'broadcast': '192.168.2.255'}
Packit bc9a3a
        for prefix_val in ['24', 16]:  # prefix can be int or string
Packit bc9a3a
            params['prefix_or_mask'] = prefix_val
Packit bc9a3a
            with net.EphemeralIPv4Network(**params):
Packit bc9a3a
                pass
Packit bc9a3a
        m_subp.assert_has_calls([mock.call(
Packit bc9a3a
            ['ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/24',
Packit bc9a3a
             'broadcast', '192.168.2.255', 'dev', 'eth0'],
Packit bc9a3a
            capture=True, update_env={'LANG': 'C'})])
Packit bc9a3a
        m_subp.assert_has_calls([mock.call(
Packit bc9a3a
            ['ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/16',
Packit bc9a3a
             'broadcast', '192.168.2.255', 'dev', 'eth0'],
Packit bc9a3a
            capture=True, update_env={'LANG': 'C'})])
Packit bc9a3a
Packit bc9a3a
    def test_ephemeral_ipv4_network_with_new_default_route(self, m_subp):
Packit bc9a3a
        """Add the route when router is set and no default route exists."""
Packit bc9a3a
        params = {
Packit bc9a3a
            'interface': 'eth0', 'ip': '192.168.2.2',
Packit bc9a3a
            'prefix_or_mask': '255.255.255.0', 'broadcast': '192.168.2.255',
Packit bc9a3a
            'router': '192.168.2.1'}
Packit bc9a3a
        m_subp.return_value = '', ''  # Empty response from ip route gw check
Packit bc9a3a
        expected_setup_calls = [
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/24',
Packit bc9a3a
                 'broadcast', '192.168.2.255', 'dev', 'eth0'],
Packit bc9a3a
                capture=True, update_env={'LANG': 'C'}),
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-family', 'inet', 'link', 'set', 'dev', 'eth0', 'up'],
Packit bc9a3a
                capture=True),
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', 'route', 'show', '0.0.0.0/0'], capture=True),
Packit bc9a3a
            mock.call(['ip', '-4', 'route', 'add', '192.168.2.1',
Packit bc9a3a
                       'dev', 'eth0', 'src', '192.168.2.2'], capture=True),
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-4', 'route', 'add', 'default', 'via',
Packit bc9a3a
                 '192.168.2.1', 'dev', 'eth0'], capture=True)]
Packit bc9a3a
        expected_teardown_calls = [
Packit bc9a3a
            mock.call(['ip', '-4', 'route', 'del', 'default', 'dev', 'eth0'],
Packit bc9a3a
                      capture=True),
Packit bc9a3a
            mock.call(['ip', '-4', 'route', 'del', '192.168.2.1',
Packit bc9a3a
                       'dev', 'eth0', 'src', '192.168.2.2'], capture=True),
Packit bc9a3a
        ]
Packit bc9a3a
Packit bc9a3a
        with net.EphemeralIPv4Network(**params):
Packit bc9a3a
            self.assertEqual(expected_setup_calls, m_subp.call_args_list)
Packit bc9a3a
        m_subp.assert_has_calls(expected_teardown_calls)
Packit bc9a3a
Packit bc9a3a
    def test_ephemeral_ipv4_network_with_rfc3442_static_routes(self, m_subp):
Packit bc9a3a
        params = {
Packit bc9a3a
            'interface': 'eth0', 'ip': '192.168.2.2',
Packit bc9a3a
            'prefix_or_mask': '255.255.255.0', 'broadcast': '192.168.2.255',
Packit bc9a3a
            'static_routes': [('169.254.169.254/32', '192.168.2.1'),
Packit bc9a3a
                              ('0.0.0.0/0', '192.168.2.1')],
Packit bc9a3a
            'router': '192.168.2.1'}
Packit bc9a3a
        expected_setup_calls = [
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/24',
Packit bc9a3a
                 'broadcast', '192.168.2.255', 'dev', 'eth0'],
Packit bc9a3a
                capture=True, update_env={'LANG': 'C'}),
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-family', 'inet', 'link', 'set', 'dev', 'eth0', 'up'],
Packit bc9a3a
                capture=True),
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-4', 'route', 'add', '169.254.169.254/32',
Packit bc9a3a
                 'via', '192.168.2.1', 'dev', 'eth0'], capture=True),
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-4', 'route', 'add', '0.0.0.0/0',
Packit bc9a3a
                 'via', '192.168.2.1', 'dev', 'eth0'], capture=True)]
Packit bc9a3a
        expected_teardown_calls = [
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-4', 'route', 'del', '0.0.0.0/0',
Packit bc9a3a
                 'via', '192.168.2.1', 'dev', 'eth0'], capture=True),
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-4', 'route', 'del', '169.254.169.254/32',
Packit bc9a3a
                 'via', '192.168.2.1', 'dev', 'eth0'], capture=True),
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-family', 'inet', 'link', 'set', 'dev',
Packit bc9a3a
                 'eth0', 'down'], capture=True),
Packit bc9a3a
            mock.call(
Packit bc9a3a
                ['ip', '-family', 'inet', 'addr', 'del',
Packit bc9a3a
                 '192.168.2.2/24', 'dev', 'eth0'], capture=True)
Packit bc9a3a
        ]
Packit bc9a3a
        with net.EphemeralIPv4Network(**params):
Packit bc9a3a
            self.assertEqual(expected_setup_calls, m_subp.call_args_list)
Packit bc9a3a
        m_subp.assert_has_calls(expected_setup_calls + expected_teardown_calls)
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestApplyNetworkCfgNames(CiTestCase):
Packit bc9a3a
    V1_CONFIG = textwrap.dedent("""\
Packit bc9a3a
        version: 1
Packit bc9a3a
        config:
Packit bc9a3a
            - type: physical
Packit bc9a3a
              name: interface0
Packit bc9a3a
              mac_address: "52:54:00:12:34:00"
Packit bc9a3a
              subnets:
Packit bc9a3a
                  - type: static
Packit bc9a3a
                    address: 10.0.2.15
Packit bc9a3a
                    netmask: 255.255.255.0
Packit bc9a3a
                    gateway: 10.0.2.2
Packit bc9a3a
    """)
Packit bc9a3a
    V2_CONFIG = textwrap.dedent("""\
Packit bc9a3a
      version: 2
Packit bc9a3a
      ethernets:
Packit bc9a3a
          interface0:
Packit bc9a3a
            match:
Packit bc9a3a
              macaddress: "52:54:00:12:34:00"
Packit bc9a3a
            addresses:
Packit bc9a3a
              - 10.0.2.15/24
Packit bc9a3a
            gateway4: 10.0.2.2
Packit bc9a3a
            set-name: interface0
Packit bc9a3a
    """)
Packit bc9a3a
Packit bc9a3a
    V2_CONFIG_NO_SETNAME = textwrap.dedent("""\
Packit bc9a3a
      version: 2
Packit bc9a3a
      ethernets:
Packit bc9a3a
          interface0:
Packit bc9a3a
            match:
Packit bc9a3a
              macaddress: "52:54:00:12:34:00"
Packit bc9a3a
            addresses:
Packit bc9a3a
              - 10.0.2.15/24
Packit bc9a3a
            gateway4: 10.0.2.2
Packit bc9a3a
    """)
Packit bc9a3a
Packit bc9a3a
    V2_CONFIG_NO_MAC = textwrap.dedent("""\
Packit bc9a3a
      version: 2
Packit bc9a3a
      ethernets:
Packit bc9a3a
          interface0:
Packit bc9a3a
            match:
Packit bc9a3a
              driver: virtio-net
Packit bc9a3a
            addresses:
Packit bc9a3a
              - 10.0.2.15/24
Packit bc9a3a
            gateway4: 10.0.2.2
Packit bc9a3a
            set-name: interface0
Packit bc9a3a
    """)
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.device_devid')
Packit bc9a3a
    @mock.patch('cloudinit.net.device_driver')
Packit bc9a3a
    @mock.patch('cloudinit.net._rename_interfaces')
Packit bc9a3a
    def test_apply_v1_renames(self, m_rename_interfaces, m_device_driver,
Packit bc9a3a
                              m_device_devid):
Packit bc9a3a
        m_device_driver.return_value = 'virtio_net'
Packit bc9a3a
        m_device_devid.return_value = '0x15d8'
Packit bc9a3a
Packit bc9a3a
        net.apply_network_config_names(yaml.load(self.V1_CONFIG))
Packit bc9a3a
Packit bc9a3a
        call = ['52:54:00:12:34:00', 'interface0', 'virtio_net', '0x15d8']
Packit bc9a3a
        m_rename_interfaces.assert_called_with([call])
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.device_devid')
Packit bc9a3a
    @mock.patch('cloudinit.net.device_driver')
Packit bc9a3a
    @mock.patch('cloudinit.net._rename_interfaces')
Packit bc9a3a
    def test_apply_v2_renames(self, m_rename_interfaces, m_device_driver,
Packit bc9a3a
                              m_device_devid):
Packit bc9a3a
        m_device_driver.return_value = 'virtio_net'
Packit bc9a3a
        m_device_devid.return_value = '0x15d8'
Packit bc9a3a
Packit bc9a3a
        net.apply_network_config_names(yaml.load(self.V2_CONFIG))
Packit bc9a3a
Packit bc9a3a
        call = ['52:54:00:12:34:00', 'interface0', 'virtio_net', '0x15d8']
Packit bc9a3a
        m_rename_interfaces.assert_called_with([call])
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net._rename_interfaces')
Packit bc9a3a
    def test_apply_v2_renames_skips_without_setname(self, m_rename_interfaces):
Packit bc9a3a
        net.apply_network_config_names(yaml.load(self.V2_CONFIG_NO_SETNAME))
Packit bc9a3a
        m_rename_interfaces.assert_called_with([])
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net._rename_interfaces')
Packit bc9a3a
    def test_apply_v2_renames_skips_without_mac(self, m_rename_interfaces):
Packit bc9a3a
        net.apply_network_config_names(yaml.load(self.V2_CONFIG_NO_MAC))
Packit bc9a3a
        m_rename_interfaces.assert_called_with([])
Packit bc9a3a
Packit bc9a3a
    def test_apply_v2_renames_raises_runtime_error_on_unknown_version(self):
Packit bc9a3a
        with self.assertRaises(RuntimeError):
Packit bc9a3a
            net.apply_network_config_names(yaml.load("version: 3"))
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestHasURLConnectivity(HttprettyTestCase):
Packit bc9a3a
Packit bc9a3a
    def setUp(self):
Packit bc9a3a
        super(TestHasURLConnectivity, self).setUp()
Packit bc9a3a
        self.url = 'http://fake/'
Packit bc9a3a
        self.kwargs = {'allow_redirects': True, 'timeout': 5.0}
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.readurl')
Packit bc9a3a
    def test_url_timeout_on_connectivity_check(self, m_readurl):
Packit bc9a3a
        """A timeout of 5 seconds is provided when reading a url."""
Packit bc9a3a
        self.assertTrue(
Packit bc9a3a
            net.has_url_connectivity(self.url), 'Expected True on url connect')
Packit bc9a3a
Packit bc9a3a
    def test_true_on_url_connectivity_success(self):
Packit bc9a3a
        httpretty.register_uri(httpretty.GET, self.url)
Packit bc9a3a
        self.assertTrue(
Packit bc9a3a
            net.has_url_connectivity(self.url), 'Expected True on url connect')
Packit bc9a3a
Packit bc9a3a
    @mock.patch('requests.Session.request')
Packit bc9a3a
    def test_true_on_url_connectivity_timeout(self, m_request):
Packit bc9a3a
        """A timeout raised accessing the url will return False."""
Packit bc9a3a
        m_request.side_effect = requests.Timeout('Fake Connection Timeout')
Packit bc9a3a
        self.assertFalse(
Packit bc9a3a
            net.has_url_connectivity(self.url),
Packit bc9a3a
            'Expected False on url timeout')
Packit bc9a3a
Packit bc9a3a
    def test_true_on_url_connectivity_failure(self):
Packit bc9a3a
        httpretty.register_uri(httpretty.GET, self.url, body={}, status=404)
Packit bc9a3a
        self.assertFalse(
Packit bc9a3a
            net.has_url_connectivity(self.url), 'Expected False on url fail')
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
def _mk_v1_phys(mac, name, driver, device_id):
Packit bc9a3a
    v1_cfg = {'type': 'physical', 'name': name, 'mac_address': mac}
Packit bc9a3a
    params = {}
Packit bc9a3a
    if driver:
Packit bc9a3a
        params.update({'driver': driver})
Packit bc9a3a
    if device_id:
Packit bc9a3a
        params.update({'device_id': device_id})
Packit bc9a3a
Packit bc9a3a
    if params:
Packit bc9a3a
        v1_cfg.update({'params': params})
Packit bc9a3a
Packit bc9a3a
    return v1_cfg
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
def _mk_v2_phys(mac, name, driver=None, device_id=None):
Packit bc9a3a
    v2_cfg = {'set-name': name, 'match': {'macaddress': mac}}
Packit bc9a3a
    if driver:
Packit bc9a3a
        v2_cfg['match'].update({'driver': driver})
Packit bc9a3a
    if device_id:
Packit bc9a3a
        v2_cfg['match'].update({'device_id': device_id})
Packit bc9a3a
Packit bc9a3a
    return v2_cfg
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestExtractPhysdevs(CiTestCase):
Packit bc9a3a
Packit bc9a3a
    def setUp(self):
Packit bc9a3a
        super(TestExtractPhysdevs, self).setUp()
Packit bc9a3a
        self.add_patch('cloudinit.net.device_driver', 'm_driver')
Packit bc9a3a
        self.add_patch('cloudinit.net.device_devid', 'm_devid')
Packit bc9a3a
Packit bc9a3a
    def test_extract_physdevs_looks_up_driver_v1(self):
Packit bc9a3a
        driver = 'virtio'
Packit bc9a3a
        self.m_driver.return_value = driver
Packit bc9a3a
        physdevs = [
Packit bc9a3a
            ['aa:bb:cc:dd:ee:ff', 'eth0', None, '0x1000'],
Packit bc9a3a
        ]
Packit bc9a3a
        netcfg = {
Packit bc9a3a
            'version': 1,
Packit bc9a3a
            'config': [_mk_v1_phys(*args) for args in physdevs],
Packit bc9a3a
        }
Packit bc9a3a
        # insert the driver value for verification
Packit bc9a3a
        physdevs[0][2] = driver
Packit bc9a3a
        self.assertEqual(sorted(physdevs),
Packit bc9a3a
                         sorted(net.extract_physdevs(netcfg)))
Packit bc9a3a
        self.m_driver.assert_called_with('eth0')
Packit bc9a3a
Packit bc9a3a
    def test_extract_physdevs_looks_up_driver_v2(self):
Packit bc9a3a
        driver = 'virtio'
Packit bc9a3a
        self.m_driver.return_value = driver
Packit bc9a3a
        physdevs = [
Packit bc9a3a
            ['aa:bb:cc:dd:ee:ff', 'eth0', None, '0x1000'],
Packit bc9a3a
        ]
Packit bc9a3a
        netcfg = {
Packit bc9a3a
            'version': 2,
Packit bc9a3a
            'ethernets': {args[1]: _mk_v2_phys(*args) for args in physdevs},
Packit bc9a3a
        }
Packit bc9a3a
        # insert the driver value for verification
Packit bc9a3a
        physdevs[0][2] = driver
Packit bc9a3a
        self.assertEqual(sorted(physdevs),
Packit bc9a3a
                         sorted(net.extract_physdevs(netcfg)))
Packit bc9a3a
        self.m_driver.assert_called_with('eth0')
Packit bc9a3a
Packit bc9a3a
    def test_extract_physdevs_looks_up_devid_v1(self):
Packit bc9a3a
        devid = '0x1000'
Packit bc9a3a
        self.m_devid.return_value = devid
Packit bc9a3a
        physdevs = [
Packit bc9a3a
            ['aa:bb:cc:dd:ee:ff', 'eth0', 'virtio', None],
Packit bc9a3a
        ]
Packit bc9a3a
        netcfg = {
Packit bc9a3a
            'version': 1,
Packit bc9a3a
            'config': [_mk_v1_phys(*args) for args in physdevs],
Packit bc9a3a
        }
Packit bc9a3a
        # insert the driver value for verification
Packit bc9a3a
        physdevs[0][3] = devid
Packit bc9a3a
        self.assertEqual(sorted(physdevs),
Packit bc9a3a
                         sorted(net.extract_physdevs(netcfg)))
Packit bc9a3a
        self.m_devid.assert_called_with('eth0')
Packit bc9a3a
Packit bc9a3a
    def test_extract_physdevs_looks_up_devid_v2(self):
Packit bc9a3a
        devid = '0x1000'
Packit bc9a3a
        self.m_devid.return_value = devid
Packit bc9a3a
        physdevs = [
Packit bc9a3a
            ['aa:bb:cc:dd:ee:ff', 'eth0', 'virtio', None],
Packit bc9a3a
        ]
Packit bc9a3a
        netcfg = {
Packit bc9a3a
            'version': 2,
Packit bc9a3a
            'ethernets': {args[1]: _mk_v2_phys(*args) for args in physdevs},
Packit bc9a3a
        }
Packit bc9a3a
        # insert the driver value for verification
Packit bc9a3a
        physdevs[0][3] = devid
Packit bc9a3a
        self.assertEqual(sorted(physdevs),
Packit bc9a3a
                         sorted(net.extract_physdevs(netcfg)))
Packit bc9a3a
        self.m_devid.assert_called_with('eth0')
Packit bc9a3a
Packit bc9a3a
    def test_get_v1_type_physical(self):
Packit bc9a3a
        physdevs = [
Packit bc9a3a
            ['aa:bb:cc:dd:ee:ff', 'eth0', 'virtio', '0x1000'],
Packit bc9a3a
            ['00:11:22:33:44:55', 'ens3', 'e1000', '0x1643'],
Packit bc9a3a
            ['09:87:65:43:21:10', 'ens0p1', 'mlx4_core', '0:0:1000'],
Packit bc9a3a
        ]
Packit bc9a3a
        netcfg = {
Packit bc9a3a
            'version': 1,
Packit bc9a3a
            'config': [_mk_v1_phys(*args) for args in physdevs],
Packit bc9a3a
        }
Packit bc9a3a
        self.assertEqual(sorted(physdevs),
Packit bc9a3a
                         sorted(net.extract_physdevs(netcfg)))
Packit bc9a3a
Packit bc9a3a
    def test_get_v2_type_physical(self):
Packit bc9a3a
        physdevs = [
Packit bc9a3a
            ['aa:bb:cc:dd:ee:ff', 'eth0', 'virtio', '0x1000'],
Packit bc9a3a
            ['00:11:22:33:44:55', 'ens3', 'e1000', '0x1643'],
Packit bc9a3a
            ['09:87:65:43:21:10', 'ens0p1', 'mlx4_core', '0:0:1000'],
Packit bc9a3a
        ]
Packit bc9a3a
        netcfg = {
Packit bc9a3a
            'version': 2,
Packit bc9a3a
            'ethernets': {args[1]: _mk_v2_phys(*args) for args in physdevs},
Packit bc9a3a
        }
Packit bc9a3a
        self.assertEqual(sorted(physdevs),
Packit bc9a3a
                         sorted(net.extract_physdevs(netcfg)))
Packit bc9a3a
Packit bc9a3a
    def test_get_v2_type_physical_skips_if_no_set_name(self):
Packit bc9a3a
        netcfg = {
Packit bc9a3a
            'version': 2,
Packit bc9a3a
            'ethernets': {
Packit bc9a3a
                'ens3': {
Packit bc9a3a
                    'match': {'macaddress': '00:11:22:33:44:55'},
Packit bc9a3a
                }
Packit bc9a3a
            }
Packit bc9a3a
        }
Packit bc9a3a
        self.assertEqual([], net.extract_physdevs(netcfg))
Packit bc9a3a
Packit bc9a3a
    def test_runtime_error_on_unknown_netcfg_version(self):
Packit bc9a3a
        with self.assertRaises(RuntimeError):
Packit bc9a3a
            net.extract_physdevs({'version': 3, 'awesome_config': []})
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestWaitForPhysdevs(CiTestCase):
Packit bc9a3a
Packit bc9a3a
    with_logs = True
Packit bc9a3a
Packit bc9a3a
    def setUp(self):
Packit bc9a3a
        super(TestWaitForPhysdevs, self).setUp()
Packit bc9a3a
        self.add_patch('cloudinit.net.get_interfaces_by_mac',
Packit bc9a3a
                       'm_get_iface_mac')
Packit bc9a3a
        self.add_patch('cloudinit.util.udevadm_settle', 'm_udev_settle')
Packit bc9a3a
Packit bc9a3a
    def test_wait_for_physdevs_skips_settle_if_all_present(self):
Packit bc9a3a
        physdevs = [
Packit bc9a3a
            ['aa:bb:cc:dd:ee:ff', 'eth0', 'virtio', '0x1000'],
Packit bc9a3a
            ['00:11:22:33:44:55', 'ens3', 'e1000', '0x1643'],
Packit bc9a3a
        ]
Packit bc9a3a
        netcfg = {
Packit bc9a3a
            'version': 2,
Packit bc9a3a
            'ethernets': {args[1]: _mk_v2_phys(*args)
Packit bc9a3a
                          for args in physdevs},
Packit bc9a3a
        }
Packit bc9a3a
        self.m_get_iface_mac.side_effect = iter([
Packit bc9a3a
            {'aa:bb:cc:dd:ee:ff': 'eth0',
Packit bc9a3a
             '00:11:22:33:44:55': 'ens3'},
Packit bc9a3a
        ])
Packit bc9a3a
        net.wait_for_physdevs(netcfg)
Packit bc9a3a
        self.assertEqual(0, self.m_udev_settle.call_count)
Packit bc9a3a
Packit bc9a3a
    def test_wait_for_physdevs_calls_udev_settle_on_missing(self):
Packit bc9a3a
        physdevs = [
Packit bc9a3a
            ['aa:bb:cc:dd:ee:ff', 'eth0', 'virtio', '0x1000'],
Packit bc9a3a
            ['00:11:22:33:44:55', 'ens3', 'e1000', '0x1643'],
Packit bc9a3a
        ]
Packit bc9a3a
        netcfg = {
Packit bc9a3a
            'version': 2,
Packit bc9a3a
            'ethernets': {args[1]: _mk_v2_phys(*args)
Packit bc9a3a
                          for args in physdevs},
Packit bc9a3a
        }
Packit bc9a3a
        self.m_get_iface_mac.side_effect = iter([
Packit bc9a3a
            {'aa:bb:cc:dd:ee:ff': 'eth0'},   # first call ens3 is missing
Packit bc9a3a
            {'aa:bb:cc:dd:ee:ff': 'eth0',
Packit bc9a3a
             '00:11:22:33:44:55': 'ens3'},   # second call has both
Packit bc9a3a
        ])
Packit bc9a3a
        net.wait_for_physdevs(netcfg)
Packit bc9a3a
        self.m_udev_settle.assert_called_with(exists=net.sys_dev_path('ens3'))
Packit bc9a3a
Packit bc9a3a
    def test_wait_for_physdevs_raise_runtime_error_if_missing_and_strict(self):
Packit bc9a3a
        physdevs = [
Packit bc9a3a
            ['aa:bb:cc:dd:ee:ff', 'eth0', 'virtio', '0x1000'],
Packit bc9a3a
            ['00:11:22:33:44:55', 'ens3', 'e1000', '0x1643'],
Packit bc9a3a
        ]
Packit bc9a3a
        netcfg = {
Packit bc9a3a
            'version': 2,
Packit bc9a3a
            'ethernets': {args[1]: _mk_v2_phys(*args)
Packit bc9a3a
                          for args in physdevs},
Packit bc9a3a
        }
Packit bc9a3a
        self.m_get_iface_mac.return_value = {}
Packit bc9a3a
        with self.assertRaises(RuntimeError):
Packit bc9a3a
            net.wait_for_physdevs(netcfg)
Packit bc9a3a
Packit bc9a3a
        self.assertEqual(5 * len(physdevs), self.m_udev_settle.call_count)
Packit bc9a3a
Packit bc9a3a
    def test_wait_for_physdevs_no_raise_if_not_strict(self):
Packit bc9a3a
        physdevs = [
Packit bc9a3a
            ['aa:bb:cc:dd:ee:ff', 'eth0', 'virtio', '0x1000'],
Packit bc9a3a
            ['00:11:22:33:44:55', 'ens3', 'e1000', '0x1643'],
Packit bc9a3a
        ]
Packit bc9a3a
        netcfg = {
Packit bc9a3a
            'version': 2,
Packit bc9a3a
            'ethernets': {args[1]: _mk_v2_phys(*args)
Packit bc9a3a
                          for args in physdevs},
Packit bc9a3a
        }
Packit bc9a3a
        self.m_get_iface_mac.return_value = {}
Packit bc9a3a
        net.wait_for_physdevs(netcfg, strict=False)
Packit bc9a3a
        self.assertEqual(5 * len(physdevs), self.m_udev_settle.call_count)
Packit bc9a3a
Packit bc9a3a
Packit bc9a3a
class TestNetFailOver(CiTestCase):
Packit bc9a3a
Packit bc9a3a
    with_logs = True
Packit bc9a3a
Packit bc9a3a
    def setUp(self):
Packit bc9a3a
        super(TestNetFailOver, self).setUp()
Packit bc9a3a
        self.add_patch('cloudinit.net.util', 'm_util')
Packit bc9a3a
        self.add_patch('cloudinit.net.read_sys_net', 'm_read_sys_net')
Packit bc9a3a
        self.add_patch('cloudinit.net.device_driver', 'm_device_driver')
Packit bc9a3a
Packit bc9a3a
    def test_get_dev_features(self):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        features = self.random_string()
Packit bc9a3a
        self.m_read_sys_net.return_value = features
Packit bc9a3a
Packit bc9a3a
        self.assertEqual(features, net.get_dev_features(devname))
Packit bc9a3a
        self.assertEqual(1, self.m_read_sys_net.call_count)
Packit bc9a3a
        self.assertEqual(mock.call(devname, 'device/features'),
Packit bc9a3a
                         self.m_read_sys_net.call_args_list[0])
Packit bc9a3a
Packit bc9a3a
    def test_get_dev_features_none_returns_empty_string(self):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        self.m_read_sys_net.side_effect = Exception('error')
Packit bc9a3a
        self.assertEqual('', net.get_dev_features(devname))
Packit bc9a3a
        self.assertEqual(1, self.m_read_sys_net.call_count)
Packit bc9a3a
        self.assertEqual(mock.call(devname, 'device/features'),
Packit bc9a3a
                         self.m_read_sys_net.call_args_list[0])
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.get_dev_features')
Packit bc9a3a
    def test_has_netfail_standby_feature(self, m_dev_features):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        standby_features = ('0' * 62) + '1' + '0'
Packit bc9a3a
        m_dev_features.return_value = standby_features
Packit bc9a3a
        self.assertTrue(net.has_netfail_standby_feature(devname))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.get_dev_features')
Packit bc9a3a
    def test_has_netfail_standby_feature_short_is_false(self, m_dev_features):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        standby_features = self.random_string()
Packit bc9a3a
        m_dev_features.return_value = standby_features
Packit bc9a3a
        self.assertFalse(net.has_netfail_standby_feature(devname))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.get_dev_features')
Packit bc9a3a
    def test_has_netfail_standby_feature_not_present_is_false(self,
Packit bc9a3a
                                                              m_dev_features):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        standby_features = '0' * 64
Packit bc9a3a
        m_dev_features.return_value = standby_features
Packit bc9a3a
        self.assertFalse(net.has_netfail_standby_feature(devname))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.get_dev_features')
Packit bc9a3a
    def test_has_netfail_standby_feature_no_features_is_false(self,
Packit bc9a3a
                                                              m_dev_features):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        standby_features = None
Packit bc9a3a
        m_dev_features.return_value = standby_features
Packit bc9a3a
        self.assertFalse(net.has_netfail_standby_feature(devname))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.has_netfail_standby_feature')
Packit bc9a3a
    @mock.patch('cloudinit.net.os.path.exists')
Packit bc9a3a
    def test_is_netfail_master(self, m_exists, m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = 'virtio_net'
Packit bc9a3a
        m_exists.return_value = False  # no master sysfs attr
Packit bc9a3a
        m_standby.return_value = True  # has standby feature flag
Packit bc9a3a
        self.assertTrue(net.is_netfail_master(devname, driver))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.sys_dev_path')
Packit bc9a3a
    def test_is_netfail_master_checks_master_attr(self, m_sysdev):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = 'virtio_net'
Packit bc9a3a
        m_sysdev.return_value = self.random_string()
Packit bc9a3a
        self.assertFalse(net.is_netfail_master(devname, driver))
Packit bc9a3a
        self.assertEqual(1, m_sysdev.call_count)
Packit bc9a3a
        self.assertEqual(mock.call(devname, path='master'),
Packit bc9a3a
                         m_sysdev.call_args_list[0])
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.has_netfail_standby_feature')
Packit bc9a3a
    @mock.patch('cloudinit.net.os.path.exists')
Packit bc9a3a
    def test_is_netfail_master_wrong_driver(self, m_exists, m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = self.random_string()
Packit bc9a3a
        self.assertFalse(net.is_netfail_master(devname, driver))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.has_netfail_standby_feature')
Packit bc9a3a
    @mock.patch('cloudinit.net.os.path.exists')
Packit bc9a3a
    def test_is_netfail_master_has_master_attr(self, m_exists, m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = 'virtio_net'
Packit bc9a3a
        m_exists.return_value = True  # has master sysfs attr
Packit bc9a3a
        self.assertFalse(net.is_netfail_master(devname, driver))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.has_netfail_standby_feature')
Packit bc9a3a
    @mock.patch('cloudinit.net.os.path.exists')
Packit bc9a3a
    def test_is_netfail_master_no_standby_feat(self, m_exists, m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = 'virtio_net'
Packit bc9a3a
        m_exists.return_value = False  # no master sysfs attr
Packit bc9a3a
        m_standby.return_value = False  # no standby feature flag
Packit bc9a3a
        self.assertFalse(net.is_netfail_master(devname, driver))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.has_netfail_standby_feature')
Packit bc9a3a
    @mock.patch('cloudinit.net.os.path.exists')
Packit bc9a3a
    @mock.patch('cloudinit.net.sys_dev_path')
Packit bc9a3a
    def test_is_netfail_primary(self, m_sysdev, m_exists, m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = self.random_string()  # device not virtio_net
Packit bc9a3a
        master_devname = self.random_string()
Packit bc9a3a
        m_sysdev.return_value = "%s/%s" % (self.random_string(),
Packit bc9a3a
                                           master_devname)
Packit bc9a3a
        m_exists.return_value = True  # has master sysfs attr
Packit bc9a3a
        self.m_device_driver.return_value = 'virtio_net'  # master virtio_net
Packit bc9a3a
        m_standby.return_value = True  # has standby feature flag
Packit bc9a3a
        self.assertTrue(net.is_netfail_primary(devname, driver))
Packit bc9a3a
        self.assertEqual(1, self.m_device_driver.call_count)
Packit bc9a3a
        self.assertEqual(mock.call(master_devname),
Packit bc9a3a
                         self.m_device_driver.call_args_list[0])
Packit bc9a3a
        self.assertEqual(1, m_standby.call_count)
Packit bc9a3a
        self.assertEqual(mock.call(master_devname),
Packit bc9a3a
                         m_standby.call_args_list[0])
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.has_netfail_standby_feature')
Packit bc9a3a
    @mock.patch('cloudinit.net.os.path.exists')
Packit bc9a3a
    @mock.patch('cloudinit.net.sys_dev_path')
Packit bc9a3a
    def test_is_netfail_primary_wrong_driver(self, m_sysdev, m_exists,
Packit bc9a3a
                                             m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = 'virtio_net'
Packit bc9a3a
        self.assertFalse(net.is_netfail_primary(devname, driver))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.has_netfail_standby_feature')
Packit bc9a3a
    @mock.patch('cloudinit.net.os.path.exists')
Packit bc9a3a
    @mock.patch('cloudinit.net.sys_dev_path')
Packit bc9a3a
    def test_is_netfail_primary_no_master(self, m_sysdev, m_exists, m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = self.random_string()  # device not virtio_net
Packit bc9a3a
        m_exists.return_value = False  # no master sysfs attr
Packit bc9a3a
        self.assertFalse(net.is_netfail_primary(devname, driver))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.has_netfail_standby_feature')
Packit bc9a3a
    @mock.patch('cloudinit.net.os.path.exists')
Packit bc9a3a
    @mock.patch('cloudinit.net.sys_dev_path')
Packit bc9a3a
    def test_is_netfail_primary_bad_master(self, m_sysdev, m_exists,
Packit bc9a3a
                                           m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = self.random_string()  # device not virtio_net
Packit bc9a3a
        master_devname = self.random_string()
Packit bc9a3a
        m_sysdev.return_value = "%s/%s" % (self.random_string(),
Packit bc9a3a
                                           master_devname)
Packit bc9a3a
        m_exists.return_value = True  # has master sysfs attr
Packit bc9a3a
        self.m_device_driver.return_value = 'XXXX'  # master not virtio_net
Packit bc9a3a
        self.assertFalse(net.is_netfail_primary(devname, driver))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.has_netfail_standby_feature')
Packit bc9a3a
    @mock.patch('cloudinit.net.os.path.exists')
Packit bc9a3a
    @mock.patch('cloudinit.net.sys_dev_path')
Packit bc9a3a
    def test_is_netfail_primary_no_standby(self, m_sysdev, m_exists,
Packit bc9a3a
                                           m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = self.random_string()  # device not virtio_net
Packit bc9a3a
        master_devname = self.random_string()
Packit bc9a3a
        m_sysdev.return_value = "%s/%s" % (self.random_string(),
Packit bc9a3a
                                           master_devname)
Packit bc9a3a
        m_exists.return_value = True  # has master sysfs attr
Packit bc9a3a
        self.m_device_driver.return_value = 'virtio_net'  # master virtio_net
Packit bc9a3a
        m_standby.return_value = False  # master has no standby feature flag
Packit bc9a3a
        self.assertFalse(net.is_netfail_primary(devname, driver))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.has_netfail_standby_feature')
Packit bc9a3a
    @mock.patch('cloudinit.net.os.path.exists')
Packit bc9a3a
    def test_is_netfail_standby(self, m_exists, m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = 'virtio_net'
Packit bc9a3a
        m_exists.return_value = True  # has master sysfs attr
Packit bc9a3a
        m_standby.return_value = True  # has standby feature flag
Packit bc9a3a
        self.assertTrue(net.is_netfail_standby(devname, driver))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.has_netfail_standby_feature')
Packit bc9a3a
    @mock.patch('cloudinit.net.os.path.exists')
Packit bc9a3a
    def test_is_netfail_standby_wrong_driver(self, m_exists, m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = self.random_string()
Packit bc9a3a
        self.assertFalse(net.is_netfail_standby(devname, driver))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.has_netfail_standby_feature')
Packit bc9a3a
    @mock.patch('cloudinit.net.os.path.exists')
Packit bc9a3a
    def test_is_netfail_standby_no_master(self, m_exists, m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = 'virtio_net'
Packit bc9a3a
        m_exists.return_value = False  # has master sysfs attr
Packit bc9a3a
        self.assertFalse(net.is_netfail_standby(devname, driver))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.has_netfail_standby_feature')
Packit bc9a3a
    @mock.patch('cloudinit.net.os.path.exists')
Packit bc9a3a
    def test_is_netfail_standby_no_standby_feature(self, m_exists, m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = 'virtio_net'
Packit bc9a3a
        m_exists.return_value = True  # has master sysfs attr
Packit bc9a3a
        m_standby.return_value = False  # has standby feature flag
Packit bc9a3a
        self.assertFalse(net.is_netfail_standby(devname, driver))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.is_netfail_standby')
Packit bc9a3a
    @mock.patch('cloudinit.net.is_netfail_primary')
Packit bc9a3a
    def test_is_netfailover_primary(self, m_primary, m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = self.random_string()
Packit bc9a3a
        m_primary.return_value = True
Packit bc9a3a
        m_standby.return_value = False
Packit bc9a3a
        self.assertTrue(net.is_netfailover(devname, driver))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.is_netfail_standby')
Packit bc9a3a
    @mock.patch('cloudinit.net.is_netfail_primary')
Packit bc9a3a
    def test_is_netfailover_standby(self, m_primary, m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = self.random_string()
Packit bc9a3a
        m_primary.return_value = False
Packit bc9a3a
        m_standby.return_value = True
Packit bc9a3a
        self.assertTrue(net.is_netfailover(devname, driver))
Packit bc9a3a
Packit bc9a3a
    @mock.patch('cloudinit.net.is_netfail_standby')
Packit bc9a3a
    @mock.patch('cloudinit.net.is_netfail_primary')
Packit bc9a3a
    def test_is_netfailover_returns_false(self, m_primary, m_standby):
Packit bc9a3a
        devname = self.random_string()
Packit bc9a3a
        driver = self.random_string()
Packit bc9a3a
        m_primary.return_value = False
Packit bc9a3a
        m_standby.return_value = False
Packit bc9a3a
        self.assertFalse(net.is_netfailover(devname, driver))
Packit bc9a3a
Packit bc9a3a
# vi: ts=4 expandtab