22
23
NODEGROUPINTERFACE_MANAGEMENT,
24
25
from maasserver.exceptions import StaticIPAddressTypeClash
26
from maasserver.forms import create_Network_from_NodeGroupInterface
25
27
from maasserver.models import (
27
28
NodeGroupInterface,
30
31
from maasserver.models.macaddress import (
31
32
find_cluster_interface_responsible_for_ip,
34
update_mac_cluster_interfaces,
36
from maasserver.models.network import Network
33
37
from maasserver.testing.factory import factory
34
38
from maasserver.testing.orm import reload_object
35
39
from maasserver.testing.testcase import MAASServerTestCase
36
40
from netaddr import (
40
45
from testtools.matchers import (
52
def get_random_ip_from_interface_range(interface, use_static_range=None):
53
"""Return a random IP from the pool available to an interface.
55
:return: An IP address as a string."""
58
interface.static_ip_range_low, interface.static_ip_range_high)
61
interface.ip_range_low, interface.ip_range_high)
62
chosen_ip = random.choice(ip_range)
63
return unicode(chosen_ip)
46
66
class MACAddressTest(MAASServerTestCase):
48
68
def test_stores_to_database(self):
49
mac = factory.make_mac_address()
69
mac = factory.make_MACAddress()
50
70
self.assertEqual([mac], list(MACAddress.objects.all()))
52
72
def test_invalid_address_raises_validation_error(self):
54
mac_address='aa:bb:ccxdd:ee:ff', node=factory.make_node())
74
mac_address='aa:bb:ccxdd:ee:ff', node=factory.make_Node())
55
75
self.assertRaises(ValidationError, mac.full_clean)
57
77
def test_mac_not_in_any_network_by_default(self):
58
mac = factory.make_mac_address()
78
mac = factory.make_MACAddress()
59
79
self.assertItemsEqual([], mac.networks.all())
61
81
def test_mac_can_be_connected_to_multiple_networks(self):
62
networks = factory.make_networks(3)
63
mac = factory.make_mac_address(networks=networks)
82
networks = factory.make_Networks(3)
83
mac = factory.make_MACAddress(networks=networks)
64
84
self.assertItemsEqual(networks, reload_object(mac).networks.all())
66
86
def test_get_networks_returns_empty_if_no_networks(self):
67
mac = factory.make_mac_address(networks=[])
87
mac = factory.make_MACAddress(networks=[])
68
88
self.assertEqual([], list(mac.get_networks()))
70
90
def test_get_networks_returns_networks(self):
71
network = factory.make_network()
72
mac = factory.make_mac_address(networks=[network])
91
network = factory.make_Network()
92
mac = factory.make_MACAddress(networks=[network])
73
93
self.assertEqual([network], list(mac.get_networks()))
75
95
def test_get_networks_sorts_by_network_name(self):
76
networks = factory.make_networks(3, sortable_name=True)
77
mac = factory.make_mac_address(networks=networks)
96
networks = factory.make_Networks(3, sortable_name=True)
97
mac = factory.make_MACAddress(networks=networks)
79
99
sorted(networks, key=attrgetter('name')),
80
100
list(mac.get_networks()))
638
658
# both those cluster interfaces are included.
639
659
# XXX jtv 2014-08-18 bug=1358130: The way we look up the IPv6 interface
640
660
# from the IPv4 one is set to change. It may affect this test.
641
cluster = factory.make_node_group()
661
cluster = factory.make_NodeGroup()
642
662
network_interface = factory.make_name('eth', sep='')
643
ipv4_interface = factory.make_node_group_interface(
663
ipv4_interface = factory.make_NodeGroupInterface(
644
664
nodegroup=cluster, network=factory.getRandomNetwork(),
645
665
interface=network_interface)
646
ipv6_interface = factory.make_node_group_interface(
666
ipv6_interface = factory.make_NodeGroupInterface(
647
667
nodegroup=cluster, network=factory.make_ipv6_network(),
648
668
interface=network_interface)
649
mac = factory.make_mac_address(cluster_interface=ipv4_interface)
669
mac = factory.make_MACAddress(cluster_interface=ipv4_interface)
650
670
self.assertItemsEqual(
651
671
[ipv4_interface, ipv6_interface],
652
672
mac.get_cluster_interfaces())
654
674
def test__ignores_other_cluster_interfaces(self):
655
cluster = factory.make_node_group()
656
factory.make_node_group_interface(
675
cluster = factory.make_NodeGroup()
676
factory.make_NodeGroupInterface(
657
677
nodegroup=cluster, network=factory.getRandomNetwork())
658
factory.make_node_group_interface(
678
factory.make_NodeGroupInterface(
659
679
nodegroup=cluster, network=factory.make_ipv6_network())
660
node = factory.make_node(nodegroup=cluster)
680
node = factory.make_Node(nodegroup=cluster)
661
681
self.assertItemsEqual(
663
factory.make_mac_address(node=node).get_cluster_interfaces())
683
factory.make_MACAddress(node=node).get_cluster_interfaces())
665
685
def test__ignores_other_clusters(self):
666
my_cluster = factory.make_node_group()
667
unrelated_cluster = factory.make_node_group()
668
my_interface = factory.make_node_group_interface(
686
my_cluster = factory.make_NodeGroup()
687
unrelated_cluster = factory.make_NodeGroup()
688
my_interface = factory.make_NodeGroupInterface(
669
689
my_cluster, network=factory.getRandomNetwork(),
670
690
name='eth0', interface='eth0')
671
factory.make_node_group_interface(
691
factory.make_NodeGroupInterface(
672
692
unrelated_cluster, network=factory.make_ipv6_network(),
673
693
name='eth0', interface='eth0')
674
my_node = factory.make_node(nodegroup=my_cluster)
675
my_mac = factory.make_mac_address(
694
my_node = factory.make_Node(nodegroup=my_cluster)
695
my_mac = factory.make_MACAddress(
676
696
node=my_node, cluster_interface=my_interface)
677
697
self.assertItemsEqual([my_interface], my_mac.get_cluster_interfaces())
700
class TestUpdateMacClusterInterfaces(MAASServerTestCase):
701
"""Tests for `update_mac_cluster_interfaces`()."""
703
def make_cluster_with_macs_and_leases(self, use_static_range=False):
704
cluster = factory.make_NodeGroup()
706
factory.make_MACAddress(): factory.make_NodeGroupInterface(
711
get_random_ip_from_interface_range(interface, use_static_range): (
712
mac_address.mac_address)
713
for mac_address, interface in mac_addresses.viewitems()
715
return cluster, mac_addresses, leases
717
def test_updates_mac_cluster_interfaces(self):
718
cluster, mac_addresses, leases = (
719
self.make_cluster_with_macs_and_leases())
720
update_mac_cluster_interfaces(leases, cluster)
722
mac_address: mac_address.cluster_interface
723
for mac_address in MACAddress.objects.filter(
724
mac_address__in=leases.values())
726
self.assertEqual(mac_addresses, results)
728
def test_considers_static_range_when_updating_interfaces(self):
729
cluster, mac_addresses, leases = (
730
self.make_cluster_with_macs_and_leases(use_static_range=True))
731
update_mac_cluster_interfaces(leases, cluster)
733
mac_address: mac_address.cluster_interface
734
for mac_address in MACAddress.objects.filter(
735
mac_address__in=leases.values())
737
self.assertEqual(mac_addresses, results)
739
def test_updates_network_relations(self):
740
# update_mac_cluster_interfaces should also associate the mac
741
# with the network on which it resides.
742
cluster, mac_addresses, leases = (
743
self.make_cluster_with_macs_and_leases())
744
expected_relations = []
745
for mac, interface in mac_addresses.viewitems():
746
net = create_Network_from_NodeGroupInterface(interface)
747
expected_relations.append((net, mac))
748
update_mac_cluster_interfaces(leases, cluster)
749
# Doing a single giant comparison here would be unintuitive and
750
# fugly, so I'm iterating.
751
for net, mac in expected_relations:
752
[observed_macddress] = net.macaddress_set.all()
753
self.expectThat(mac, Equals(observed_macddress))
754
interface = mac_addresses[mac]
756
net, MatchesStructure.byEquality(
757
default_gateway=interface.router_ip,
758
netmask=interface.subnet_mask,
761
def test_does_not_overwrite_network_with_same_name(self):
762
cluster = factory.make_NodeGroup()
763
ngi = factory.make_NodeGroupInterface(nodegroup=cluster)
764
net1 = create_Network_from_NodeGroupInterface(ngi)
766
other_ngi = factory.make_NodeGroupInterface(nodegroup=cluster)
767
other_ngi.interface = ngi.interface
768
net2 = create_Network_from_NodeGroupInterface(ngi)
769
self.assertEqual(None, net2)
770
self.assertItemsEqual([net1], Network.objects.all())
772
def test_ignores_mac_not_attached_to_cluster(self):
773
cluster = factory.make_NodeGroup()
774
mac_address = factory.make_MACAddress()
776
factory.getRandomIPAddress(): mac_address.mac_address
778
update_mac_cluster_interfaces(leases, cluster)
779
mac_address = MACAddress.objects.get(
781
self.assertIsNone(mac_address.cluster_interface)
783
def test_ignores_unknown_macs(self):
784
cluster = factory.make_NodeGroup()
785
mac_address = factory.getRandomMACAddress()
787
factory.getRandomIPAddress(): mac_address
789
# This is a test to show that update_mac_cluster_interfaces()
790
# doesn't raise an Http404 when it comes across something it
791
# doesn't know, hence the lack of meaningful assertions.
792
update_mac_cluster_interfaces(leases, cluster)
794
MACAddress.objects.filter(mac_address=mac_address).exists())
796
def test_ignores_unconfigured_interfaces(self):
797
cluster = factory.make_NodeGroup()
798
factory.make_NodeGroupInterface(
799
nodegroup=cluster, subnet_mask='', broadcast_ip='',
800
static_ip_range_low='', static_ip_range_high='',
801
ip_range_low='', ip_range_high='', router_ip='',
802
ip=factory.getRandomIPAddress(),
803
management=NODEGROUPINTERFACE_MANAGEMENT.UNMANAGED)
804
mac_address = factory.getRandomMACAddress()
806
factory.getRandomIPAddress(): mac_address
808
self.assertIsNone(update_mac_cluster_interfaces(leases, cluster))
809
# The real test is that update_mac_cluster_interfaces() doesn't
810
# stacktrace because of the unconfigured interface (see bug