~allenap/maas/xxx-a-thon

« back to all changes in this revision

Viewing changes to src/provisioningserver/utils/tests/test_ipaddr.py

[r=blake-rouse][bug=1553617][author=mpontillo] Fix bug #1553617: rack registration fails when bond interfaces are present.

 * When parsing '/sbin/ip addr' and gathering driver information, ignore
   bonds with no backing interfaces.
 * After parsing '/sbin/ip addr', cross-reference data from
   /proc/net/bonding/* and update interface MACs with the original
   hardware MAC. (After a bond interface is added, the interface MAC is
   updated to be the same as the bond MAC, which was throwing off the data
   MAAS gathered.)

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
    _add_additional_interface_properties,
22
22
    _parse_interface_definition,
23
23
    annotate_with_driver_information,
 
24
    annotate_with_proc_net_bonding_original_macs,
24
25
    get_bonded_interfaces,
25
26
    get_interface_type,
26
27
    get_ip_addr,
33
34
from testtools.matchers import (
34
35
    Contains,
35
36
    Equals,
 
37
    HasLength,
36
38
    Not,
37
39
)
38
40
 
347
349
        self.assertThat(ip_link['ens11'], Not(Contains('inet')))
348
350
 
349
351
 
350
 
class TestGetInterfaceType(MAASTestCase):
 
352
class FakeSysProcTestCase(MAASTestCase):
351
353
 
352
354
    def setUp(self):
353
 
        super(TestGetInterfaceType, self).setUp()
 
355
        super().setUp()
354
356
        self.tmp_sys_net = mkdtemp('maas-unit-tests.sys-class-net')
355
 
        self.tmp_proc_net_vlan = mkdtemp('maas-unit-tests.proc-net-vlan')
 
357
        self.tmp_proc_net = mkdtemp('maas-unit-tests.proc-net')
 
358
        os.mkdir(os.path.join(self.tmp_proc_net, "vlan"))
 
359
        os.mkdir(os.path.join(self.tmp_proc_net, "bonding"))
356
360
 
357
361
    def tearDown(self):
358
 
        super(TestGetInterfaceType, self).tearDown()
 
362
        super().tearDown()
359
363
        rmtree(self.tmp_sys_net)
360
 
        rmtree(self.tmp_proc_net_vlan)
 
364
        rmtree(self.tmp_proc_net)
361
365
 
362
366
    def createInterfaceType(
363
367
            self, ifname, iftype, is_bridge=False, is_vlan=False,
371
375
        if is_bridge:
372
376
            os.mkdir(os.path.join(ifdir, 'bridge'))
373
377
        if is_vlan:
374
 
            with open(os.path.join(self.tmp_proc_net_vlan, ifname), 'w'):
 
378
            with open(os.path.join(self.tmp_proc_net, "vlan", ifname), 'w'):
375
379
                pass  # Just touch.
376
380
        if is_bond:
377
381
            os.mkdir(os.path.join(ifdir, 'bonding'))
395
399
    def createEthernetInterface(self, ifname, **kwargs):
396
400
        self.createInterfaceType(ifname, 1, **kwargs)
397
401
 
 
402
 
 
403
class TestGetInterfaceType(FakeSysProcTestCase):
 
404
 
398
405
    def test__identifies_missing_interface(self):
399
406
        self.assertThat(get_interface_type(
400
407
            'eth0', sys_class_net=self.tmp_sys_net),
405
412
        self.createEthernetInterface('br0', is_bridge=True)
406
413
        self.assertThat(get_interface_type(
407
414
            'br0', sys_class_net=self.tmp_sys_net,
408
 
            proc_net_vlan=self.tmp_proc_net_vlan),
 
415
            proc_net=self.tmp_proc_net),
409
416
            Equals('ethernet.bridge')
410
417
        )
411
418
 
413
420
        self.createEthernetInterface('bond0', is_bond=True)
414
421
        self.assertThat(get_interface_type(
415
422
            'bond0', sys_class_net=self.tmp_sys_net,
416
 
            proc_net_vlan=self.tmp_proc_net_vlan),
 
423
            proc_net=self.tmp_proc_net),
417
424
            Equals('ethernet.bond')
418
425
        )
419
426
 
429
436
        self.createEthernetInterface('vlan42', is_vlan=True)
430
437
        self.assertThat(get_interface_type(
431
438
            'vlan42', sys_class_net=self.tmp_sys_net,
432
 
            proc_net_vlan=self.tmp_proc_net_vlan),
 
439
            proc_net=self.tmp_proc_net),
433
440
            Equals('ethernet.vlan')
434
441
        )
435
442
 
437
444
        self.createEthernetInterface('eth0', is_physical=True)
438
445
        self.assertThat(get_interface_type(
439
446
            'eth0', sys_class_net=self.tmp_sys_net,
440
 
            proc_net_vlan=self.tmp_proc_net_vlan),
 
447
            proc_net=self.tmp_proc_net),
441
448
            Equals('ethernet.physical')
442
449
        )
443
450
 
445
452
        self.createEthernetInterface('wlan0', is_wireless=True)
446
453
        self.assertThat(get_interface_type(
447
454
            'wlan0', sys_class_net=self.tmp_sys_net,
448
 
            proc_net_vlan=self.tmp_proc_net_vlan),
 
455
            proc_net=self.tmp_proc_net),
449
456
            Equals('ethernet.wireless')
450
457
        )
451
458
 
453
460
        self.createEthernetInterface('eth1')
454
461
        self.assertThat(get_interface_type(
455
462
            'eth1', sys_class_net=self.tmp_sys_net,
456
 
            proc_net_vlan=self.tmp_proc_net_vlan),
 
463
            proc_net=self.tmp_proc_net),
457
464
            Equals('ethernet')
458
465
        )
459
466
 
461
468
        self.createLoopbackInterface('lo')
462
469
        self.assertThat(get_interface_type(
463
470
            'lo', sys_class_net=self.tmp_sys_net,
464
 
            proc_net_vlan=self.tmp_proc_net_vlan),
 
471
            proc_net=self.tmp_proc_net),
465
472
            Equals('loopback')
466
473
        )
467
474
 
469
476
        self.createIpIpInterface('tun0')
470
477
        self.assertThat(get_interface_type(
471
478
            'tun0', sys_class_net=self.tmp_sys_net,
472
 
            proc_net_vlan=self.tmp_proc_net_vlan),
 
479
            proc_net=self.tmp_proc_net),
473
480
            Equals('ipip')
474
481
        )
475
482
 
477
484
        self.createInterfaceType('avian0', 1149)
478
485
        self.assertThat(get_interface_type(
479
486
            'avian0', sys_class_net=self.tmp_sys_net,
480
 
            proc_net_vlan=self.tmp_proc_net_vlan),
 
487
            proc_net=self.tmp_proc_net),
481
488
            Equals('unknown-1149')
482
489
        )
483
490
 
484
491
 
485
 
class TestAnnotateWithDriverInformation(MAASTestCase):
 
492
class TestAnnotateWithDriverInformation(FakeSysProcTestCase):
486
493
 
487
494
    def test__populates_interface_type_for_each_interface(self):
488
495
        # Note: this is more of an end-to-end test, since we call
489
 
        # "/sbin/ip addr" on the host running the tests. This is necessary
490
 
        # because we don't have dependency injection for the directory names
491
 
        # all the way through.
 
496
        # "/sbin/ip addr" on the host running the tests.
492
497
        ip_addr_output = check_output(['/sbin/ip', 'addr'])
493
498
        interfaces = parse_ip_addr(ip_addr_output)
494
499
        interfaces_with_types = annotate_with_driver_information(interfaces)
502
507
            elif iface['type'] == 'ethernet.bridge':
503
508
                self.expectThat(iface, Contains('bridged_interfaces'))
504
509
 
 
510
    def test__ignores_bond_interfaces_with_no_parents(self):
 
511
        interfaces = {
 
512
            'eth0': {},
 
513
            'eth1': {},
 
514
            'bond0': {},
 
515
            'bond1': {},
 
516
        }
 
517
        self.createEthernetInterface('eth0', is_physical=True)
 
518
        self.createEthernetInterface('eth1', is_physical=True)
 
519
        self.createEthernetInterface(
 
520
            'bond0', is_bond=True, bonded_interfaces=['eth0, eth1'])
 
521
        self.createEthernetInterface(
 
522
            'bond1', is_bond=True, bonded_interfaces=[])
 
523
        interfaces = annotate_with_driver_information(
 
524
            interfaces, sys_class_net=self.tmp_sys_net,
 
525
            proc_net=self.tmp_proc_net)
 
526
        self.expectThat(interfaces, HasLength(3))
 
527
        self.expectThat(interfaces, Contains('eth0'))
 
528
        self.expectThat(interfaces, Contains('eth1'))
 
529
        self.expectThat(interfaces, Contains('bond0'))
 
530
 
 
531
    def test__finds_bond_members_original_mac_addresses(self):
 
532
        testdata = dedent("""\
 
533
            Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011)
 
534
 
 
535
            Bonding Mode: fault-tolerance (active-backup)
 
536
            Primary Slave: None
 
537
            Currently Active Slave: ens11
 
538
            MII Status: up
 
539
            MII Polling Interval (ms): 100
 
540
            Up Delay (ms): 200
 
541
            Down Delay (ms): 0
 
542
 
 
543
            Slave Interface: ens11
 
544
            MII Status: up
 
545
            Speed: Unknown
 
546
            Duplex: Unknown
 
547
            Link Failure Count: 0
 
548
            Permanent HW addr: 52:54:00:ea:1c:fc
 
549
            Slave queue ID: 0
 
550
 
 
551
            Slave Interface: ens3
 
552
            MII Status: up
 
553
            Speed: Unknown
 
554
            Duplex: Unknown
 
555
            Link Failure Count: 0
 
556
            Permanent HW addr: 52:54:00:13:0e:6f
 
557
            Slave queue ID: 0
 
558
            """)
 
559
        proc_net_bonding_bond0 = os.path.join(
 
560
            self.tmp_proc_net, "bonding", "bond0")
 
561
        with open(proc_net_bonding_bond0, mode='w') as f:
 
562
            f.write(testdata)
 
563
        interfaces = {
 
564
            "ens3": {"mac": "00:01:02:03:04:05"},
 
565
            "ens11": {"mac": "01:02:03:04:05:06"},
 
566
        }
 
567
        annotate_with_proc_net_bonding_original_macs(
 
568
            interfaces, proc_net=self.tmp_proc_net)
 
569
        self.assertEqual(
 
570
            {
 
571
                "ens3": {"mac": "52:54:00:13:0e:6f"},
 
572
                "ens11": {"mac": "52:54:00:ea:1c:fc"},
 
573
            },
 
574
            interfaces
 
575
        )
 
576
 
 
577
    def test__ignores_missing_proc_net_bonding(self):
 
578
        os.rmdir(os.path.join(self.tmp_proc_net, "bonding"))
 
579
        interfaces = {
 
580
            "ens3": {"mac": "00:01:02:03:04:05"},
 
581
            "ens11": {"mac": "01:02:03:04:05:06"},
 
582
        }
 
583
        annotate_with_proc_net_bonding_original_macs(
 
584
            interfaces, proc_net=self.tmp_proc_net)
 
585
        self.assertEqual(
 
586
            {
 
587
                "ens3": {"mac": "00:01:02:03:04:05"},
 
588
                "ens11": {"mac": "01:02:03:04:05:06"},
 
589
            },
 
590
            interfaces
 
591
        )
 
592
 
505
593
 
506
594
class TestGetIPAddr(MAASTestCase):
507
595
    """Tests for `get_ip_addr`, `get_ip_addr_json`, `get_mac_addresses`."""