Exemple #1
0
 def _testNics(self):
     """Creates a test fixture so that nics() reports:
     physical nics: em, me, me0, me1, hid0 and hideous
     dummies: fake and fake0
     bonds: jbond (over me0 and me1)"""
     return [
         ipwrapper.Link(address='f0:de:f1:da:aa:e7',
                        index=2,
                        linkType=ipwrapper.LinkType.NIC,
                        mtu=1500,
                        name='em',
                        qdisc='pfifo_fast',
                        state='up'),
         ipwrapper.Link(address='ff:de:f1:da:aa:e7',
                        index=3,
                        linkType=ipwrapper.LinkType.NIC,
                        mtu=1500,
                        name='me',
                        qdisc='pfifo_fast',
                        state='up'),
         ipwrapper.Link(address='ff:de:fa:da:aa:e7',
                        index=4,
                        linkType=ipwrapper.LinkType.NIC,
                        mtu=1500,
                        name='hid0',
                        qdisc='pfifo_fast',
                        state='up'),
         ipwrapper.Link(address='ff:de:11:da:aa:e7',
                        index=5,
                        linkType=ipwrapper.LinkType.NIC,
                        mtu=1500,
                        name='hideous',
                        qdisc='pfifo_fast',
                        state='up'),
         ipwrapper.Link(address='66:de:f1:da:aa:e7',
                        index=6,
                        linkType=ipwrapper.LinkType.NIC,
                        mtu=1500,
                        name='me0',
                        qdisc='pfifo_fast',
                        state='up',
                        master='jbond'),
         ipwrapper.Link(address='66:de:f1:da:aa:e7',
                        index=7,
                        linkType=ipwrapper.LinkType.NIC,
                        mtu=1500,
                        name='me1',
                        qdisc='pfifo_fast',
                        state='up',
                        master='jbond'),
         ipwrapper.Link(address='ff:aa:f1:da:aa:e7',
                        index=34,
                        linkType=ipwrapper.LinkType.DUMMY,
                        mtu=1500,
                        name='fake0',
                        qdisc='pfifo_fast',
                        state='up'),
         ipwrapper.Link(address='ff:aa:f1:da:bb:e7',
                        index=35,
                        linkType=ipwrapper.LinkType.DUMMY,
                        mtu=1500,
                        name='fake',
                        qdisc='pfifo_fast',
                        state='up'),
         ipwrapper.Link(address='66:de:f1:da:aa:e7',
                        index=419,
                        linkType=ipwrapper.LinkType.BOND,
                        mtu=1500,
                        name='jbond',
                        qdisc='pfifo_fast',
                        state='up')
     ]
Exemple #2
0
class TestNetinfo(TestCaseBase):

    @mock.patch.object(dns, 'open', create=True)
    def test_get_host_nameservers(self, mock_open):
        RESOLV_CONF = (
            '# Generated by NetworkManager\n'
            'search example.com company.net\n'
            'domain example.com\n'
            'nameserver 192.168.0.100\n'
            'nameserver 8.8.8.8\n'
            'nameserver 8.8.4.4\n'
        )
        expected_nameservers = ['192.168.0.100', '8.8.8.8', '8.8.4.4']
        resolv_conf_stream = six.StringIO(RESOLV_CONF)
        mock_open.return_value.__enter__.return_value = resolv_conf_stream

        resulted_nameservers = dns.get_host_nameservers()

        self.assertEqual(expected_nameservers, resulted_nameservers)

    @mock.patch.object(dns, 'open', create=True)
    def test_get_host_nameservers_no_resolvconf(self, mock_open):
        mock_open.return_value.__enter__.side_effect = IOError()

        nameservers = dns.get_host_nameservers()

        self.assertEqual(nameservers, [])

    def test_netmask_conversions(self):
        path = os.path.join(os.path.dirname(__file__), "netmaskconversions")
        with open(path) as netmaskFile:
            for line in netmaskFile:
                if line.startswith('#'):
                    continue
                bitmask, address = [value.strip() for value in line.split()]
                self.assertEqual(prefix2netmask(int(bitmask)), address)
        self.assertRaises(ValueError, prefix2netmask, -1)
        self.assertRaises(ValueError, prefix2netmask, 33)

    def test_speed_on_an_iface_that_does_not_support_speed(self):
        self.assertEqual(nic.speed('lo'), 0)

    def test_speed_in_range(self):
        for d in nics.nics():
            s = nic.speed(d)
            self.assertFalse(s < 0)
            self.assertTrue(s in ETHTOOL_SPEEDS or s == 0)

    @mock.patch.object(nic, 'iface')
    @mock.patch.object(nics.io, 'open')
    def test_valid_nic_speed(self, mock_io_open, mock_iface):
        IS_UP = True
        values = ((b'0', IS_UP, 0),
                  (b'-10', IS_UP, 0),
                  (six.b(str(2 ** 16 - 1)), IS_UP, 0),
                  (six.b(str(2 ** 32 - 1)), IS_UP, 0),
                  (b'123', IS_UP, 123),
                  (b'', IS_UP, 0),
                  (b'', not IS_UP, 0),
                  (b'123', not IS_UP, 0))

        for passed, is_nic_up, expected in values:
            mock_io_open.return_value = io.BytesIO(passed)
            mock_iface.return_value.is_oper_up.return_value = is_nic_up

            self.assertEqual(nic.speed('fake_nic'), expected)

    def test_dpdk_device_speed(self):
        self.assertEqual(nic.speed('dpdk0'), 0)

    def test_dpdk_operstate_always_up(self):
        self.assertEqual(nics.operstate('dpdk0'), nics.OPERSTATE_UP)

    @mock.patch.object(bonding, 'permanent_address', lambda: {})
    @mock.patch('vdsm.network.netinfo.cache.RunningConfig')
    def test_get_non_existing_bridge_info(self, mock_runningconfig):
        # Getting info of non existing bridge should not raise an exception,
        # just log a traceback. If it raises an exception the test will fail as
        # it should.
        mock_runningconfig.return_value.networks = {'fake': {'bridged': True}}
        get()

    @mock.patch.object(bonding, 'permanent_address', lambda: {})
    @mock.patch('vdsm.network.netinfo.cache.getLinks')
    @mock.patch('vdsm.network.netinfo.cache.RunningConfig')
    def test_get_empty(self, mock_networks, mock_getLinks):
        result = {}
        result.update(get())
        self.assertEqual(result['networks'], {})
        self.assertEqual(result['bridges'], {})
        self.assertEqual(result['nics'], {})
        self.assertEqual(result['bondings'], {})
        self.assertEqual(result['vlans'], {})

    def test_ipv4_to_mapped(self):
        self.assertEqual('::ffff:127.0.0.1',
                         addresses.IPv4toMapped('127.0.0.1'))

    def test_get_device_by_ip(self):
        NL_ADDRESS4 = {'label': 'iface0',
                       'address': '127.0.0.1/32',
                       'family': 'inet'}
        NL_ADDRESS6 = {'label': 'iface1',
                       'address': '2001::1:1:1/48',
                       'family': 'inet6'}
        NL_ADDRESSES = [NL_ADDRESS4, NL_ADDRESS6]

        with mock.patch.object(addresses.nl_addr, 'iter_addrs',
                               lambda: NL_ADDRESSES):
            for nl_addr in NL_ADDRESSES:
                self.assertEqual(
                    nl_addr['label'],
                    addresses.getDeviceByIP(nl_addr['address'].split('/')[0]))

    @mock.patch.object(ipwrapper.Link, '_hiddenNics', ['hid*'])
    @mock.patch.object(ipwrapper.Link, '_hiddenBonds', ['jb*'])
    @mock.patch.object(ipwrapper.Link, '_fakeNics', ['fake*'])
    @mock.patch.object(ipwrapper.Link, '_detectType', lambda x: None)
    @mock.patch.object(ipwrapper, '_bondExists', lambda x: x == 'jbond')
    @mock.patch.object(misc, 'getLinks')
    def test_nics(self, mock_getLinks):
        """
        managed by vdsm: em, me, fake0, fake1
        not managed due to hidden bond (jbond) enslavement: me0, me1
        not managed due to being hidden nics: hid0, hideous
        """
        mock_getLinks.return_value = self._LINKS_REPORT

        self.assertEqual(set(nics.nics()), set(['em', 'me', 'fake', 'fake0']))

    # Creates a test fixture so that nics() reports:
    # physical nics: em, me, me0, me1, hid0 and hideous
    # dummies: fake and fake0
    # bonds: jbond (over me0 and me1)
    _LINKS_REPORT = [
        ipwrapper.Link(address='f0:de:f1:da:aa:e7', index=2,
                       linkType=ipwrapper.LinkType.NIC, mtu=1500,
                       name='em', qdisc='pfifo_fast', state='up'),
        ipwrapper.Link(address='ff:de:f1:da:aa:e7', index=3,
                       linkType=ipwrapper.LinkType.NIC, mtu=1500,
                       name='me', qdisc='pfifo_fast', state='up'),
        ipwrapper.Link(address='ff:de:fa:da:aa:e7', index=4,
                       linkType=ipwrapper.LinkType.NIC, mtu=1500,
                       name='hid0', qdisc='pfifo_fast', state='up'),
        ipwrapper.Link(address='ff:de:11:da:aa:e7', index=5,
                       linkType=ipwrapper.LinkType.NIC, mtu=1500,
                       name='hideous', qdisc='pfifo_fast', state='up'),
        ipwrapper.Link(address='66:de:f1:da:aa:e7', index=6,
                       linkType=ipwrapper.LinkType.NIC, mtu=1500,
                       name='me0', qdisc='pfifo_fast', state='up',
                       master='jbond'),
        ipwrapper.Link(address='66:de:f1:da:aa:e7', index=7,
                       linkType=ipwrapper.LinkType.NIC, mtu=1500,
                       name='me1', qdisc='pfifo_fast', state='up',
                       master='jbond'),
        ipwrapper.Link(address='ff:aa:f1:da:aa:e7', index=34,
                       linkType=ipwrapper.LinkType.DUMMY, mtu=1500,
                       name='fake0', qdisc='pfifo_fast', state='up'),
        ipwrapper.Link(address='ff:aa:f1:da:bb:e7', index=35,
                       linkType=ipwrapper.LinkType.DUMMY, mtu=1500,
                       name='fake', qdisc='pfifo_fast', state='up'),
        ipwrapper.Link(address='66:de:f1:da:aa:e7', index=419,
                       linkType=ipwrapper.LinkType.BOND, mtu=1500,
                       name='jbond', qdisc='pfifo_fast', state='up')
    ]

    @attr(type='integration')
    @ValidateRunningAsRoot
    @mock.patch.object(ipwrapper.Link, '_fakeNics', ['veth_*', 'dummy_*'])
    def test_fake_nics(self):
        with veth_pair() as (v1a, v1b):
            with dummy_device() as d1:
                fakes = set([d1, v1a, v1b])
                _nics = nics.nics()
                self.assertTrue(fakes.issubset(_nics),
                                'Fake devices %s are not listed in nics '
                                '%s' % (fakes, _nics))

        with veth_pair(prefix='mehv_') as (v2a, v2b):
            with dummy_device(prefix='mehd_') as d2:
                hiddens = set([d2, v2a, v2b])
                _nics = nics.nics()
                self.assertFalse(hiddens.intersection(_nics), 'Some of '
                                 'hidden devices %s is shown in nics %s' %
                                 (hiddens, _nics))

    @mock.patch.object(misc, 'open', create=True)
    def test_get_ifcfg(self, mock_open):
        gateway = '1.1.1.1'
        netmask = '255.255.0.0'

        ifcfg = "GATEWAY0={}\nNETMASK={}\n".format(gateway, netmask)
        ifcfg_stream = six.StringIO(ifcfg)
        mock_open.return_value.__enter__.return_value = ifcfg_stream

        resulted_ifcfg = misc.getIfaceCfg('eth0')

        self.assertEqual(resulted_ifcfg['GATEWAY'], gateway)
        self.assertEqual(resulted_ifcfg['NETMASK'], netmask)

    @mock.patch.object(misc, 'open', create=True)
    def test_missing_ifcfg_file(self, mock_open):
        mock_open.return_value.__enter__.side_effect = IOError()

        ifcfg = misc.getIfaceCfg('eth0')

        self.assertEqual(ifcfg, {})

    @broken_on_ci('Bond options scanning is fragile on CI',
                  exception=AssertionError)
    @attr(type='integration')
    @ValidateRunningAsRoot
    @RequireBondingMod
    def test_get_bonding_options(self):
        INTERVAL = '12345'
        bondName = random_iface_name()

        with open(BONDING_MASTERS, 'w') as bonds:
            bonds.write('+' + bondName)
            bonds.flush()

            try:  # no error is anticipated but let's make sure we can clean up
                self.assertEqual(
                    self._bond_opts_without_mode(bondName), {},
                    'This test fails when a new bonding option is added to '
                    'the kernel. Please run vdsm-tool dump-bonding-options` '
                    'and retest.')

                with open(bonding.BONDING_OPT % (bondName, 'miimon'),
                          'w') as opt:
                    opt.write(INTERVAL)

                self.assertEqual(self._bond_opts_without_mode(bondName),
                                 {'miimon': INTERVAL})

            finally:
                bonds.write('-' + bondName)

    @staticmethod
    def _bond_opts_without_mode(bond_name):
        opts = Bond(bond_name).options
        opts.pop('mode')
        return opts

    def test_get_gateway(self):
        TEST_IFACE = 'test_iface'
        # different tables but the gateway is the same so it should be reported
        DUPLICATED_GATEWAY = {TEST_IFACE: [
            {
                'destination': 'none',
                'family': 'inet',
                'gateway': '12.34.56.1',
                'oif': TEST_IFACE,
                'oif_index': 8,
                'scope': 'global',
                'source': None,
                'table': 203569230,  # lucky us, we got the address 12.34.56.78
            }, {
                'destination': 'none',
                'family': 'inet',
                'gateway': '12.34.56.1',
                'oif': TEST_IFACE,
                'oif_index': 8,
                'scope': 'global',
                'source': None,
                'table': 254,
            }]}
        SINGLE_GATEWAY = {TEST_IFACE: [DUPLICATED_GATEWAY[TEST_IFACE][0]]}

        gateway = routes.get_gateway(SINGLE_GATEWAY, TEST_IFACE)
        self.assertEqual(gateway, '12.34.56.1')
        gateway = routes.get_gateway(DUPLICATED_GATEWAY, TEST_IFACE)
        self.assertEqual(gateway, '12.34.56.1')

    @broken_on_ci('IPv6 not supported on travis', name='TRAVIS_CI')
    @attr(type='integration')
    @ValidateRunningAsRoot
    def test_ip_info(self):
        IPV4_ADDR1 = '192.168.99.2'
        IPV4_GATEWAY1 = '192.168.99.1'
        IPV4_ADDR2 = '192.168.199.2'
        IPV4_GATEWAY2 = '192.168.199.1'
        IPV4_ADDR3 = '192.168.200.2'
        IPV4_NETMASK = '255.255.255.0'
        IPV4_PREFIX_LENGTH = 24
        IPV6_ADDR = '2607:f0d0:1002:51::4'
        IPV6_PREFIX_LENGTH = 64

        IPV4_ADDR1_CIDR = self._cidr_form(IPV4_ADDR1, IPV4_PREFIX_LENGTH)
        IPV4_ADDR2_CIDR = self._cidr_form(IPV4_ADDR2, IPV4_PREFIX_LENGTH)
        IPV4_ADDR3_CIDR = self._cidr_form(IPV4_ADDR3, 32)
        IPV6_ADDR_CIDR = self._cidr_form(IPV6_ADDR, IPV6_PREFIX_LENGTH)

        with dummy_device() as device:
            with waitfor.waitfor_ipv4_addr(device, address=IPV4_ADDR1_CIDR):
                ipwrapper.addrAdd(device, IPV4_ADDR1, IPV4_PREFIX_LENGTH)
            with waitfor.waitfor_ipv4_addr(device, address=IPV4_ADDR2_CIDR):
                ipwrapper.addrAdd(device, IPV4_ADDR2, IPV4_PREFIX_LENGTH)
            with waitfor.waitfor_ipv6_addr(device, address=IPV6_ADDR_CIDR):
                ipwrapper.addrAdd(
                    device, IPV6_ADDR, IPV6_PREFIX_LENGTH, family=6)

            # 32 bit addresses are reported slashless by netlink
            with waitfor.waitfor_ipv4_addr(device, address=IPV4_ADDR3):
                ipwrapper.addrAdd(device, IPV4_ADDR3, 32)

            self.assertEqual(
                addresses.getIpInfo(device),
                (IPV4_ADDR1, IPV4_NETMASK,
                 [IPV4_ADDR1_CIDR, IPV4_ADDR2_CIDR, IPV4_ADDR3_CIDR],
                 [IPV6_ADDR_CIDR]))
            self.assertEqual(
                addresses.getIpInfo(device, ipv4_gateway=IPV4_GATEWAY1),
                (IPV4_ADDR1, IPV4_NETMASK,
                 [IPV4_ADDR1_CIDR, IPV4_ADDR2_CIDR, IPV4_ADDR3_CIDR],
                 [IPV6_ADDR_CIDR]))
            self.assertEqual(
                addresses.getIpInfo(device, ipv4_gateway=IPV4_GATEWAY2),
                (IPV4_ADDR2, IPV4_NETMASK,
                 [IPV4_ADDR1_CIDR, IPV4_ADDR2_CIDR, IPV4_ADDR3_CIDR],
                 [IPV6_ADDR_CIDR]))

    def test_netinfo_ignoring_link_scope_ip(self):
        v4_link = {'family': 'inet', 'address': '169.254.0.0/16',
                   'scope': 'link', 'prefixlen': 16, 'flags': ['permanent']}
        v4_global = {'family': 'inet', 'address': '192.0.2.2/24',
                     'scope': 'global', 'prefixlen': 24,
                     'flags': ['permanent']}
        v6_link = {'family': 'inet6', 'address': 'fe80::5054:ff:fea3:f9f3/64',
                   'scope': 'link', 'prefixlen': 64, 'flags': ['permanent']}
        v6_global = {'family': 'inet6',
                     'address': 'ee80::5054:ff:fea3:f9f3/64',
                     'scope': 'global', 'prefixlen': 64,
                     'flags': ['permanent']}
        ipaddrs = {'eth0': (v4_link, v4_global, v6_link, v6_global)}
        ipv4addr, ipv4netmask, ipv4addrs, ipv6addrs = \
            addresses.getIpInfo('eth0', ipaddrs=ipaddrs)
        self.assertEqual(ipv4addrs, ['192.0.2.2/24'])
        self.assertEqual(ipv6addrs, ['ee80::5054:ff:fea3:f9f3/64'])

    def _cidr_form(self, ip_addr, prefix_length):
        return '{}/{}'.format(ip_addr, prefix_length)

    def test_parse_bond_options(self):
        self.assertEqual(bonding.parse_bond_options('mode=4 custom=foo:bar'),
                         {'custom': {'foo': 'bar'}, 'mode': '4'})
Exemple #3
0
class TestNetinfo(object):
    def test_netmask_conversions(self):
        path = os.path.join(os.path.dirname(__file__), "netmaskconversions")
        with open(path) as netmaskFile:
            for line in netmaskFile:
                if line.startswith('#'):
                    continue
                bitmask, address = [value.strip() for value in line.split()]
                assert prefix2netmask(int(bitmask)) == address
        pytest.raises(ValueError, prefix2netmask, -1)
        pytest.raises(ValueError, prefix2netmask, 33)

    @mock.patch.object(nic, 'iface')
    @mock.patch.object(nics.io, 'open')
    def test_valid_nic_speed(self, mock_io_open, mock_iface):
        IS_UP = True
        values = (
            (b'0', IS_UP, 0),
            (b'-10', IS_UP, 0),
            (six.b(str(2 ** 16 - 1)), IS_UP, 0),
            (six.b(str(2 ** 32 - 1)), IS_UP, 0),
            (b'123', IS_UP, 123),
            (b'', IS_UP, 0),
            (b'', not IS_UP, 0),
            (b'123', not IS_UP, 0),
        )

        for passed, is_nic_up, expected in values:
            mock_io_open.return_value = io.BytesIO(passed)
            mock_iface.return_value.is_oper_up.return_value = is_nic_up

            assert nic.speed('fake_nic') == expected

    def test_dpdk_device_speed(self):
        assert nic.speed('dpdk0') == 0

    def test_dpdk_operstate_always_up(self):
        assert nics.operstate('dpdk0') == nics.OPERSTATE_UP

    @mock.patch.object(bonding, 'permanent_address', lambda: {})
    @mock.patch('vdsm.network.netinfo.cache.RunningConfig')
    def test_get_non_existing_bridge_info(
        self, mock_runningconfig, current_state_mock
    ):
        # Getting info of non existing bridge should not raise an exception,
        # just log a traceback. If it raises an exception the test will fail as
        # it should.
        mock_runningconfig.return_value.networks = {'fake': {'bridged': True}}
        get()

    @mock.patch.object(bonding, 'permanent_address', lambda: {})
    @mock.patch('vdsm.network.netinfo.cache.getLinks')
    @mock.patch('vdsm.network.netinfo.cache.RunningConfig')
    def test_get_empty(self, mock_networks, mock_getLinks, current_state_mock):
        result = {}
        result.update(get())
        assert result['networks'] == {}
        assert result['bridges'] == {}
        assert result['nics'] == {}
        assert result['bondings'] == {}
        assert result['vlans'] == {}

    def test_ipv4_to_mapped(self):
        assert '::ffff:127.0.0.1' == addresses.IPv4toMapped('127.0.0.1')

    def test_get_device_by_ip(self):
        NL_ADDRESS4 = {
            'label': 'iface0',
            'address': '127.0.0.1/32',
            'family': 'inet',
        }
        NL_ADDRESS6 = {
            'label': 'iface1',
            'address': '2001::1:1:1/48',
            'family': 'inet6',
        }
        NL_ADDRESSES = [NL_ADDRESS4, NL_ADDRESS6]

        with mock.patch.object(
            addresses.nl_addr, 'iter_addrs', lambda: NL_ADDRESSES
        ):
            for nl_addr in NL_ADDRESSES:
                lbl = addresses.getDeviceByIP(nl_addr['address'].split('/')[0])
                assert nl_addr['label'] == lbl

    @mock.patch.object(ipwrapper.Link, '_hiddenNics', ['hid*'])
    @mock.patch.object(ipwrapper.Link, '_hiddenBonds', ['jb*'])
    @mock.patch.object(ipwrapper.Link, '_fakeNics', ['fake*'])
    @mock.patch.object(ipwrapper.Link, '_detectType', lambda x: None)
    @mock.patch.object(ipwrapper, '_bondExists', lambda x: x == 'jbond')
    @mock.patch.object(misc, 'getLinks')
    def test_nics(self, mock_getLinks):
        """
        managed by vdsm: em, me, fake0, fake1
        not managed due to hidden bond (jbond) enslavement: me0, me1
        not managed due to being hidden nics: hid0, hideous
        """
        mock_getLinks.return_value = self._LINKS_REPORT

        assert set(nics.nics()) == set(['em', 'me', 'fake', 'fake0'])

    # Creates a test fixture so that nics() reports:
    # physical nics: em, me, me0, me1, hid0 and hideous
    # dummies: fake and fake0
    # bonds: jbond (over me0 and me1)
    _LINKS_REPORT = [
        ipwrapper.Link(
            address='f0:de:f1:da:aa:e7',
            index=2,
            linkType=ipwrapper.LinkType.NIC,
            mtu=1500,
            name='em',
            qdisc='pfifo_fast',
            state='up',
        ),
        ipwrapper.Link(
            address='ff:de:f1:da:aa:e7',
            index=3,
            linkType=ipwrapper.LinkType.NIC,
            mtu=1500,
            name='me',
            qdisc='pfifo_fast',
            state='up',
        ),
        ipwrapper.Link(
            address='ff:de:fa:da:aa:e7',
            index=4,
            linkType=ipwrapper.LinkType.NIC,
            mtu=1500,
            name='hid0',
            qdisc='pfifo_fast',
            state='up',
        ),
        ipwrapper.Link(
            address='ff:de:11:da:aa:e7',
            index=5,
            linkType=ipwrapper.LinkType.NIC,
            mtu=1500,
            name='hideous',
            qdisc='pfifo_fast',
            state='up',
        ),
        ipwrapper.Link(
            address='66:de:f1:da:aa:e7',
            index=6,
            linkType=ipwrapper.LinkType.NIC,
            mtu=1500,
            name='me0',
            qdisc='pfifo_fast',
            state='up',
            master='jbond',
        ),
        ipwrapper.Link(
            address='66:de:f1:da:aa:e7',
            index=7,
            linkType=ipwrapper.LinkType.NIC,
            mtu=1500,
            name='me1',
            qdisc='pfifo_fast',
            state='up',
            master='jbond',
        ),
        ipwrapper.Link(
            address='ff:aa:f1:da:aa:e7',
            index=34,
            linkType=ipwrapper.LinkType.DUMMY,
            mtu=1500,
            name='fake0',
            qdisc='pfifo_fast',
            state='up',
        ),
        ipwrapper.Link(
            address='ff:aa:f1:da:bb:e7',
            index=35,
            linkType=ipwrapper.LinkType.DUMMY,
            mtu=1500,
            name='fake',
            qdisc='pfifo_fast',
            state='up',
        ),
        ipwrapper.Link(
            address='66:de:f1:da:aa:e7',
            index=419,
            linkType=ipwrapper.LinkType.BOND,
            mtu=1500,
            name='jbond',
            qdisc='pfifo_fast',
            state='up',
        ),
    ]

    @mock.patch.object(misc, 'open', create=True)
    def test_get_ifcfg(self, mock_open):
        gateway = '1.1.1.1'
        netmask = '255.255.0.0'

        ifcfg = "GATEWAY0={}\nNETMASK={}\n".format(gateway, netmask)
        ifcfg_stream = six.StringIO(ifcfg)
        mock_open.return_value.__enter__.return_value = ifcfg_stream

        resulted_ifcfg = misc.getIfaceCfg('eth0')

        assert resulted_ifcfg['GATEWAY'] == gateway
        assert resulted_ifcfg['NETMASK'] == netmask

    @mock.patch.object(misc, 'open', create=True)
    def test_missing_ifcfg_file(self, mock_open):
        mock_open.return_value.__enter__.side_effect = IOError()

        ifcfg = misc.getIfaceCfg('eth0')

        assert ifcfg == {}

    @staticmethod
    def _bond_opts_without_mode(bond_name):
        opts = Bond(bond_name).options
        opts.pop('mode')
        return opts

    def test_get_gateway(self):
        TEST_IFACE = 'test_iface'
        # different tables but the gateway is the same so it should be reported
        DUPLICATED_GATEWAY = {
            TEST_IFACE: [
                {
                    'destination': 'none',
                    'family': 'inet',
                    'gateway': '12.34.56.1',
                    'oif': TEST_IFACE,
                    'oif_index': 8,
                    'scope': 'global',
                    'source': None,
                    'table': 203569230,  # we got the address 12.34.56.78
                },
                {
                    'destination': 'none',
                    'family': 'inet',
                    'gateway': '12.34.56.1',
                    'oif': TEST_IFACE,
                    'oif_index': 8,
                    'scope': 'global',
                    'source': None,
                    'table': 254,
                },
            ]
        }
        SINGLE_GATEWAY = {TEST_IFACE: [DUPLICATED_GATEWAY[TEST_IFACE][0]]}

        gateway = routes.get_gateway(SINGLE_GATEWAY, TEST_IFACE)
        assert gateway == '12.34.56.1'
        gateway = routes.get_gateway(DUPLICATED_GATEWAY, TEST_IFACE)
        assert gateway == '12.34.56.1'

    def test_netinfo_ignoring_link_scope_ip(self):
        v4_link = {
            'family': 'inet',
            'address': '169.254.0.0/16',
            'scope': 'link',
            'prefixlen': 16,
            'flags': ['permanent'],
        }
        v4_global = {
            'family': 'inet',
            'address': '192.0.2.2/24',
            'scope': 'global',
            'prefixlen': 24,
            'flags': ['permanent'],
        }
        v6_link = {
            'family': 'inet6',
            'address': 'fe80::5054:ff:fea3:f9f3/64',
            'scope': 'link',
            'prefixlen': 64,
            'flags': ['permanent'],
        }
        v6_global = {
            'family': 'inet6',
            'address': 'ee80::5054:ff:fea3:f9f3/64',
            'scope': 'global',
            'prefixlen': 64,
            'flags': ['permanent'],
        }
        ipaddrs = {'eth0': (v4_link, v4_global, v6_link, v6_global)}
        ipv4addr, ipv4netmask, ipv4addrs, ipv6addrs = addresses.getIpInfo(
            'eth0', ipaddrs=ipaddrs
        )
        assert ipv4addrs == ['192.0.2.2/24']
        assert ipv6addrs == ['ee80::5054:ff:fea3:f9f3/64']

    def test_parse_bond_options(self):
        expected = {'mode': '4', 'miimon': '100'}
        assert expected == bonding.parse_bond_options('mode=4 miimon=100')
Exemple #4
0
class TestNetinfo(TestCaseBase):

    def testGetHostNameservers(self):
        RESOLV_CONF = (
            '# Generated by NetworkManager\n'
            'search example.com company.net\n'
            'domain example.com\n'
            'nameserver 192.168.0.100\n'
            'nameserver 8.8.8.8\n'
            'nameserver 8.8.4.4\n'
        )
        nameservers = ['192.168.0.100', '8.8.8.8', '8.8.4.4']
        with namedTemporaryDir() as temp_dir:
            file_path = os.path.join(temp_dir, 'resolv.conf')

            with mock.patch.object(dns, 'DNS_CONF_FILE', file_path):
                for content in (RESOLV_CONF, RESOLV_CONF + '\n'):
                    with open(file_path, 'w') as file_object:
                        file_object.write(content)

                    self.assertEqual(dns.get_host_nameservers(), nameservers)

    def testNetmaskConversions(self):
        path = os.path.join(os.path.dirname(__file__), "netmaskconversions")
        with open(path) as netmaskFile:
            for line in netmaskFile:
                if line.startswith('#'):
                    continue
                bitmask, address = [value.strip() for value in line.split()]
                self.assertEqual(addresses.prefix2netmask(int(bitmask)),
                                 address)
        self.assertRaises(ValueError, addresses.prefix2netmask, -1)
        self.assertRaises(ValueError, addresses.prefix2netmask, 33)

    def testSpeedInvalidNic(self):
        nicName = '0' * 20  # devices can't have so long names
        self.assertEqual(nics.speed(nicName), 0)

    def testSpeedInRange(self):
        for d in nics.nics():
            s = nics.speed(d)
            self.assertFalse(s < 0)
            self.assertTrue(s in ETHTOOL_SPEEDS or s == 0)

    @mock.patch.object(nics, 'operstate')
    @mock.patch.object(nics.io, 'open')
    def testValidNicSpeed(self, mock_io_open, mock_operstate):
        values = ((0,           nics.OPERSTATE_UP, 0),
                  (-10,         nics.OPERSTATE_UP, 0),
                  (2 ** 16 - 1, nics.OPERSTATE_UP, 0),
                  (2 ** 32 - 1, nics.OPERSTATE_UP, 0),
                  (123,         nics.OPERSTATE_UP, 123),
                  ('',          nics.OPERSTATE_UP, 0),
                  ('',          'unknown',    0),
                  (123,         'unknown',    0))

        for passed, operstate, expected in values:
            mock_io_open.return_value = io.BytesIO(str(passed))
            mock_operstate.return_value = operstate

            self.assertEqual(nics.speed('fake_nic'), expected)

    @mock.patch('vdsm.network.netinfo.cache.libvirt.networks',
                lambda: {'fake': {'bridged': True}})
    def testGetNonExistantBridgeInfo(self):
        # Getting info of non existing bridge should not raise an exception,
        # just log a traceback. If it raises an exception the test will fail as
        # it should.
        get()

    @mock.patch('vdsm.network.netinfo.cache.getLinks')
    @mock.patch('vdsm.network.netinfo.cache.libvirt.networks')
    def testGetEmpty(self, mock_networks, mock_getLinks):
        result = {}
        result.update(get())
        self.assertEqual(result['networks'], {})
        self.assertEqual(result['bridges'], {})
        self.assertEqual(result['nics'], {})
        self.assertEqual(result['bondings'], {})
        self.assertEqual(result['vlans'], {})

    def testIPv4toMapped(self):
        self.assertEqual('::ffff:127.0.0.1',
                         addresses.IPv4toMapped('127.0.0.1'))

    def testGetDeviceByIP(self):
        NL_ADDRESS4 = {'label': 'iface0',
                       'address': '127.0.0.1/32',
                       'family': 'inet'}
        NL_ADDRESS6 = {'label': 'iface1',
                       'address': '2001::1:1:1/48',
                       'family': 'inet6'}
        NL_ADDRESSES = [NL_ADDRESS4, NL_ADDRESS6]

        with mock.patch.object(addresses.nl_addr, 'iter_addrs',
                               lambda: NL_ADDRESSES):
            for nl_addr in NL_ADDRESSES:
                self.assertEqual(
                    nl_addr['label'],
                    addresses.getDeviceByIP(nl_addr['address'].split('/')[0]))

    @mock.patch.object(ipwrapper.Link, '_hiddenNics', ['hid*'])
    @mock.patch.object(ipwrapper.Link, '_hiddenBonds', ['jb*'])
    @mock.patch.object(ipwrapper.Link, '_fakeNics', ['fake*'])
    @mock.patch.object(ipwrapper.Link, '_detectType', lambda x: None)
    @mock.patch.object(ipwrapper, '_bondExists', lambda x: x == 'jbond')
    @mock.patch.object(misc, 'getLinks')
    def testNics(self, mock_getLinks):
        """
        managed by vdsm: em, me, fake0, fake1
        not managed due to hidden bond (jbond) enslavement: me0, me1
        not managed due to being hidden nics: hid0, hideous
        """
        mock_getLinks.return_value = self._LINKS_REPORT

        self.assertEqual(set(nics.nics()), set(['em', 'me', 'fake', 'fake0']))

    # Creates a test fixture so that nics() reports:
    # physical nics: em, me, me0, me1, hid0 and hideous
    # dummies: fake and fake0
    # bonds: jbond (over me0 and me1)
    _LINKS_REPORT = [
        ipwrapper.Link(address='f0:de:f1:da:aa:e7', index=2,
                       linkType=ipwrapper.LinkType.NIC, mtu=1500,
                       name='em', qdisc='pfifo_fast', state='up'),
        ipwrapper.Link(address='ff:de:f1:da:aa:e7', index=3,
                       linkType=ipwrapper.LinkType.NIC, mtu=1500,
                       name='me', qdisc='pfifo_fast', state='up'),
        ipwrapper.Link(address='ff:de:fa:da:aa:e7', index=4,
                       linkType=ipwrapper.LinkType.NIC, mtu=1500,
                       name='hid0', qdisc='pfifo_fast', state='up'),
        ipwrapper.Link(address='ff:de:11:da:aa:e7', index=5,
                       linkType=ipwrapper.LinkType.NIC, mtu=1500,
                       name='hideous', qdisc='pfifo_fast', state='up'),
        ipwrapper.Link(address='66:de:f1:da:aa:e7', index=6,
                       linkType=ipwrapper.LinkType.NIC, mtu=1500,
                       name='me0', qdisc='pfifo_fast', state='up',
                       master='jbond'),
        ipwrapper.Link(address='66:de:f1:da:aa:e7', index=7,
                       linkType=ipwrapper.LinkType.NIC, mtu=1500,
                       name='me1', qdisc='pfifo_fast', state='up',
                       master='jbond'),
        ipwrapper.Link(address='ff:aa:f1:da:aa:e7', index=34,
                       linkType=ipwrapper.LinkType.DUMMY, mtu=1500,
                       name='fake0', qdisc='pfifo_fast', state='up'),
        ipwrapper.Link(address='ff:aa:f1:da:bb:e7', index=35,
                       linkType=ipwrapper.LinkType.DUMMY, mtu=1500,
                       name='fake', qdisc='pfifo_fast', state='up'),
        ipwrapper.Link(address='66:de:f1:da:aa:e7', index=419,
                       linkType=ipwrapper.LinkType.BOND, mtu=1500,
                       name='jbond', qdisc='pfifo_fast', state='up')
    ]

    @attr(type='integration')
    @ValidateRunningAsRoot
    @mock.patch.object(ipwrapper.Link, '_fakeNics', ['veth_*', 'dummy_*'])
    def testFakeNics(self):
        with veth_pair() as (v1a, v1b):
            with dummy_device() as d1:
                fakes = set([d1, v1a, v1b])
                _nics = nics.nics()
                self.assertTrue(fakes.issubset(_nics),
                                'Fake devices %s are not listed in nics '
                                '%s' % (fakes, _nics))

        with veth_pair(prefix='mehv_') as (v2a, v2b):
            with dummy_device(prefix='mehd_') as d2:
                hiddens = set([d2, v2a, v2b])
                _nics = nics.nics()
                self.assertFalse(hiddens.intersection(_nics), 'Some of '
                                 'hidden devices %s is shown in nics %s' %
                                 (hiddens, _nics))

    def testGetIfaceCfg(self):
        deviceName = "___This_could_never_be_a_device_name___"
        ifcfg = ('GATEWAY0=1.1.1.1\n' 'NETMASK=255.255.0.0\n')
        with namedTemporaryDir() as tempDir:
            ifcfgPrefix = os.path.join(tempDir, 'ifcfg-')
            filePath = ifcfgPrefix + deviceName

            with mock.patch.object(misc, 'NET_CONF_PREF', ifcfgPrefix):
                with open(filePath, 'w') as ifcfgFile:
                    ifcfgFile.write(ifcfg)
                self.assertEqual(
                    misc.getIfaceCfg(deviceName)['GATEWAY'], '1.1.1.1')
                self.assertEqual(
                    misc.getIfaceCfg(deviceName)['NETMASK'], '255.255.0.0')

    @broken_on_ci(exception=AssertionError)
    @mock.patch.object(bonding, 'BONDING_DEFAULTS',
                       bonding.BONDING_DEFAULTS
                       if os.path.exists(bonding.BONDING_DEFAULTS)
                       else '../static/usr/share/vdsm/bonding-defaults.json')
    @attr(type='integration')
    @ValidateRunningAsRoot
    @RequireBondingMod
    def testGetBondingOptions(self):
        INTERVAL = '12345'
        bondName = random_iface_name()

        with open(bonding.BONDING_MASTERS, 'w') as bonds:
            bonds.write('+' + bondName)
            bonds.flush()

            try:  # no error is anticipated but let's make sure we can clean up
                self.assertEqual(
                    self._bond_opts_without_mode(bondName), {},
                    'This test fails when a new bonding option is added to '
                    'the kernel. Please run vdsm-tool dump-bonding-options` '
                    'and retest.')

                with open(bonding.BONDING_OPT % (bondName, 'miimon'),
                          'w') as opt:
                    opt.write(INTERVAL)

                self.assertEqual(self._bond_opts_without_mode(bondName),
                                 {'miimon': INTERVAL})

            finally:
                bonds.write('-' + bondName)

    @staticmethod
    def _bond_opts_without_mode(bond_name):
        opts = bonding._getBondingOptions(bond_name)
        opts.pop('mode')
        return opts

    @mock.patch.object(bonding, 'BONDING_NAME2NUMERIC_PATH',
                       bonding.BONDING_NAME2NUMERIC_PATH
                       if os.path.exists(bonding.BONDING_NAME2NUMERIC_PATH)
                       else
                       '../static/usr/share/vdsm/bonding-name2numeric.json')
    def test_get_bonding_option_numeric_val_exists(self):
        mode_num = bonding.BONDING_MODES_NAME_TO_NUMBER["balance-rr"]
        self.assertNotEqual(bonding.get_bonding_option_numeric_val(
                            mode_num, "ad_select", "stable"),
                            None)

    @mock.patch.object(bonding, 'BONDING_NAME2NUMERIC_PATH',
                       bonding.BONDING_NAME2NUMERIC_PATH
                       if os.path.exists(bonding.BONDING_NAME2NUMERIC_PATH)
                       else
                       '../static/usr/share/vdsm/bonding-name2numeric.json')
    def test_get_bonding_option_numeric_val_does_not_exists(self):
        mode_num = bonding.BONDING_MODES_NAME_TO_NUMBER["balance-rr"]
        self.assertEqual(bonding.get_bonding_option_numeric_val(
                         mode_num, "opt_does_not_exist", "none"),
                         None)

    def test_get_gateway(self):
        TEST_IFACE = 'test_iface'
        # different tables but the gateway is the same so it should be reported
        DUPLICATED_GATEWAY = {TEST_IFACE: [
            {
                'destination': 'none',
                'family': 'inet',
                'gateway': '12.34.56.1',
                'oif': TEST_IFACE,
                'oif_index': 8,
                'scope': 'global',
                'source': None,
                'table': 203569230,  # lucky us, we got the address 12.34.56.78
            }, {
                'destination': 'none',
                'family': 'inet',
                'gateway': '12.34.56.1',
                'oif': TEST_IFACE,
                'oif_index': 8,
                'scope': 'global',
                'source': None,
                'table': 254,
            }]}
        SINGLE_GATEWAY = {TEST_IFACE: [DUPLICATED_GATEWAY[TEST_IFACE][0]]}

        gateway = routes.get_gateway(SINGLE_GATEWAY, TEST_IFACE)
        self.assertEqual(gateway, '12.34.56.1')
        gateway = routes.get_gateway(DUPLICATED_GATEWAY, TEST_IFACE)
        self.assertEqual(gateway, '12.34.56.1')

    @attr(type='integration')
    @ValidateRunningAsRoot
    def test_ip_info(self):
        def get_ip_info(*a, **kw):
            """filter away ipv6 link local addresses that may or may not exist
            on the device depending on OS configuration"""
            ipv4addr, ipv4netmask, ipv4addrs, ipv6addrs = \
                addresses.getIpInfo(*a, **kw)
            return ipv4addr, ipv4netmask, ipv4addrs, ipv6addrs

        IP_ADDR = '192.0.2.2'
        IP_ADDR_SECOND = '192.0.2.3'
        IP_ADDR_GW = '192.0.2.1'
        IP_ADDR2 = '198.51.100.9'
        IP_ADDR3 = '198.51.100.11'
        IP_ADDR2_GW = '198.51.100.1'
        IPV6_ADDR = '2607:f0d0:1002:51::4'
        NET_MASK = '255.255.255.0'
        PREFIX_LENGTH = 24
        IPV6_PREFIX_LENGTH = 64
        IP_ADDR_CIDR = self._cidr_form(IP_ADDR, PREFIX_LENGTH)
        IP_ADDR_2ND_CIDR = self._cidr_form(IP_ADDR_SECOND, PREFIX_LENGTH)
        IP_ADDR2_CIDR = self._cidr_form(IP_ADDR2, PREFIX_LENGTH)
        IP_ADDR3_CIDR = self._cidr_form(IP_ADDR3, 32)
        IPV6_ADDR_CIDR = self._cidr_form(IPV6_ADDR, IPV6_PREFIX_LENGTH)
        with dummy_device() as device:
            with waitfor.waitfor_ipv4_addr(device, address=IP_ADDR_CIDR):
                ipwrapper.addrAdd(device, IP_ADDR, PREFIX_LENGTH)
            with waitfor.waitfor_ipv4_addr(device, address=IP_ADDR_2ND_CIDR):
                ipwrapper.addrAdd(device, IP_ADDR_SECOND, PREFIX_LENGTH)
            with waitfor.waitfor_ipv4_addr(device, address=IP_ADDR2_CIDR):
                ipwrapper.addrAdd(device, IP_ADDR2, PREFIX_LENGTH)
            with waitfor.waitfor_ipv6_addr(device, address=IPV6_ADDR_CIDR):
                ipwrapper.addrAdd(
                    device, IPV6_ADDR, IPV6_PREFIX_LENGTH, family=6)
            # 32 bit addresses are reported slashless by netlink
            with waitfor.waitfor_ipv4_addr(device, address=IP_ADDR3):
                ipwrapper.addrAdd(device, IP_ADDR3, 32)

            self.assertEqual(
                get_ip_info(device),
                (IP_ADDR, NET_MASK,
                 [IP_ADDR_CIDR, IP_ADDR2_CIDR, IP_ADDR3_CIDR,
                  IP_ADDR_2ND_CIDR],
                 [IPV6_ADDR_CIDR]))
            self.assertEqual(
                get_ip_info(device, ipv4_gateway=IP_ADDR_GW),
                (IP_ADDR, NET_MASK,
                 [IP_ADDR_CIDR, IP_ADDR2_CIDR, IP_ADDR3_CIDR,
                  IP_ADDR_2ND_CIDR],
                 [IPV6_ADDR_CIDR]))
            self.assertEqual(
                get_ip_info(device, ipv4_gateway=IP_ADDR2_GW),
                (IP_ADDR2, NET_MASK,
                 [IP_ADDR_CIDR, IP_ADDR2_CIDR, IP_ADDR3_CIDR,
                  IP_ADDR_2ND_CIDR],
                 [IPV6_ADDR_CIDR]))

    def test_netinfo_ignoring_link_scope_ip(self):
        v4_link = {'family': 'inet', 'address': '169.254.0.0/16',
                   'scope': 'link', 'prefixlen': 16, 'flags': ['permanent']}
        v4_global = {'family': 'inet', 'address': '192.0.2.2/24',
                     'scope': 'global', 'prefixlen': 24,
                     'flags': ['permanent']}
        v6_link = {'family': 'inet6', 'address': 'fe80::5054:ff:fea3:f9f3/64',
                   'scope': 'link', 'prefixlen': 64, 'flags': ['permanent']}
        v6_global = {'family': 'inet6',
                     'address': 'ee80::5054:ff:fea3:f9f3/64',
                     'scope': 'global', 'prefixlen': 64,
                     'flags': ['permanent']}
        ipaddrs = {'eth0': (v4_link, v4_global, v6_link, v6_global)}
        ipv4addr, ipv4netmask, ipv4addrs, ipv6addrs = \
            addresses.getIpInfo('eth0', ipaddrs=ipaddrs)
        self.assertEqual(ipv4addrs, ['192.0.2.2/24'])
        self.assertEqual(ipv6addrs, ['ee80::5054:ff:fea3:f9f3/64'])

    def _cidr_form(self, ip_addr, prefix_length):
        return '{}/{}'.format(ip_addr, prefix_length)

    def test_parse_bond_options(self):
        self.assertEqual(bonding.parse_bond_options('mode=4 custom=foo:bar'),
                         {'custom': {'foo': 'bar'}, 'mode': '4'})