Merge ~mpontillo/maas:fix-subnet-links-for-juju--bug-1789495 into maas:master

Proposed by Mike Pontillo
Status: Merged
Approved by: Mike Pontillo
Approved revision: 1a3efec0c969a9aa815e803eeb41e60cb84eefe9
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~mpontillo/maas:fix-subnet-links-for-juju--bug-1789495
Merge into: maas:master
Diff against target: 188 lines (+64/-10)
4 files modified
src/maasserver/models/bmc.py (+16/-6)
src/maasserver/models/tests/test_bmc.py (+26/-4)
src/provisioningserver/utils/constraints.py (+5/-0)
src/provisioningserver/utils/tests/test_constraints.py (+17/-0)
Reviewer Review Type Date Requested Status
Newell Jensen (community) Approve
Review via email: mp+354141@code.launchpad.net

Commit message

LP: #1789495 - Fix subnet links for composed machines.

To post a comment you must log in.
Revision history for this message
Newell Jensen (newell-jensen) wrote :

Looks good. Approving but I did have a question inline and won't block.

review: Approve
Revision history for this message
Mike Pontillo (mpontillo) wrote :

Thanks for the comments; reply below!

7fcdd2e... by Mike Pontillo

Fix typo.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/maasserver/models/bmc.py b/src/maasserver/models/bmc.py
index 01f23a3..f813057 100644
--- a/src/maasserver/models/bmc.py
+++ b/src/maasserver/models/bmc.py
@@ -83,6 +83,7 @@ from provisioningserver.drivers.power.registry import PowerDriverRegistry
83from provisioningserver.enum import MACVLAN_MODE_CHOICES83from provisioningserver.enum import MACVLAN_MODE_CHOICES
84from provisioningserver.logger import get_maas_logger84from provisioningserver.logger import get_maas_logger
85from provisioningserver.utils.constraints import LabeledConstraintMap85from provisioningserver.utils.constraints import LabeledConstraintMap
86from provisioningserver.utils.network import get_ifname_for_label
86from provisioningserver.utils.twisted import asynchronous87from provisioningserver.utils.twisted import asynchronous
87from twisted.internet.defer import inlineCallbacks88from twisted.internet.defer import inlineCallbacks
8889
@@ -97,7 +98,10 @@ def get_requested_ips(requested_machine):
97 requested_ips = {98 requested_ips = {
98 interface.ifname: interface.requested_ips99 interface.ifname: interface.requested_ips
99 for interface in requested_machine.interfaces100 for interface in requested_machine.interfaces
100 if interface.ifname is not None101 if (
102 interface.ifname is not None and
103 len(interface.requested_ips) > 0
104 )
101 }105 }
102 else:106 else:
103 requested_ips = {}107 requested_ips = {}
@@ -748,7 +752,10 @@ class Pod(BMC):
748 # New machines get commission started immediately unless skipped.752 # New machines get commission started immediately unless skipped.
749 if not skip_commissioning:753 if not skip_commissioning:
750 skip_networking = False754 skip_networking = False
751 if len(requested_ips) > 0:755 # If an interfaces constraint was specified, don't reset the
756 # networking parameters. (Instead, allow them to be set based on
757 # what was requested in the constraints string.)
758 if interfaces is not None and len(interfaces) > 0:
752 skip_networking = True759 skip_networking = True
753 machine.start_commissioning(760 machine.start_commissioning(
754 commissioning_user, skip_networking=skip_networking)761 commissioning_user, skip_networking=skip_networking)
@@ -790,7 +797,7 @@ class Pod(BMC):
790 # dictionaries in Python 3.6+ preserve insertion order.)797 # dictionaries in Python 3.6+ preserve insertion order.)
791 if interface_constraints is not None:798 if interface_constraints is not None:
792 interface_names = [799 interface_names = [
793 label[:15]800 get_ifname_for_label(label)
794 for label in interface_constraints801 for label in interface_constraints
795 ]802 ]
796 else:803 else:
@@ -882,9 +889,12 @@ class Pod(BMC):
882 # the VM has been attached to. Update the VLAN (but889 # the VM has been attached to. Update the VLAN (but
883 # only if necessary).890 # only if necessary).
884 host_vlan = host_attach_interface.vlan891 host_vlan = host_attach_interface.vlan
885 if host_vlan != created_interfaces[idx].vlan:892 interface = created_interfaces[idx]
886 created_interfaces[idx].vlan = host_vlan893 if host_vlan != interface.vlan:
887 created_interfaces[idx].save()894 interface.vlan = host_vlan
895 interface.save()
896 if interface.ip_addresses.count() == 0:
897 interface.force_auto_or_dhcp_link()
888 continue898 continue
889899
890 def _sync_machine(self, discovered_machine, existing_machine):900 def _sync_machine(self, discovered_machine, existing_machine):
diff --git a/src/maasserver/models/tests/test_bmc.py b/src/maasserver/models/tests/test_bmc.py
index bdb6624..00a5ad2 100644
--- a/src/maasserver/models/tests/test_bmc.py
+++ b/src/maasserver/models/tests/test_bmc.py
@@ -1043,7 +1043,7 @@ class TestPod(MAASServerTestCase):
1043 sip3 = StaticIPAddress.objects.filter(ip=ip3).first()1043 sip3 = StaticIPAddress.objects.filter(ip=ip3).first()
1044 self.assertThat(sip3.get_interface().node, Equals(machine))1044 self.assertThat(sip3.get_interface().node, Equals(machine))
10451045
1046 def test_create_machine_sets_interface_vlans_using_attach_names(self):1046 def test_create_machine_sets_up_interface_vlans_correctly(self):
1047 discovered_machine = self.make_discovered_machine()1047 discovered_machine = self.make_discovered_machine()
1048 self.patch(Machine, "set_default_storage_layout")1048 self.patch(Machine, "set_default_storage_layout")
1049 self.patch(Machine, "set_initial_networking_configuration")1049 self.patch(Machine, "set_initial_networking_configuration")
@@ -1052,11 +1052,14 @@ class TestPod(MAASServerTestCase):
1052 controller = factory.make_RackController()1052 controller = factory.make_RackController()
1053 vlan = factory.make_VLAN(1053 vlan = factory.make_VLAN(
1054 fabric=fabric, dhcp_on=True, primary_rack=controller)1054 fabric=fabric, dhcp_on=True, primary_rack=controller)
1055 subnet = factory.make_Subnet()
1056 vlan2 = factory.make_VLAN(1055 vlan2 = factory.make_VLAN(
1057 fabric=fabric, dhcp_on=False, primary_rack=controller)1056 fabric=fabric, dhcp_on=False, primary_rack=controller)
1058 vlan3 = factory.make_VLAN(1057 vlan3 = factory.make_VLAN(
1059 fabric=fabric, dhcp_on=False, primary_rack=controller)1058 fabric=fabric, dhcp_on=False, primary_rack=controller)
1059 # Create subnets, so we can test to ensure they get linked up.
1060 subnet = factory.make_Subnet(vlan=vlan)
1061 factory.make_Subnet(vlan=vlan2)
1062 factory.make_Subnet(vlan=vlan3)
1060 eth0 = factory.make_Interface(node=controller, vlan=vlan)1063 eth0 = factory.make_Interface(node=controller, vlan=vlan)
1061 eth1 = factory.make_Interface(node=controller, vlan=vlan2)1064 eth1 = factory.make_Interface(node=controller, vlan=vlan2)
1062 eth2 = factory.make_Interface(node=controller, vlan=vlan3)1065 eth2 = factory.make_Interface(node=controller, vlan=vlan3)
@@ -1074,11 +1077,13 @@ class TestPod(MAASServerTestCase):
1074 InterfaceAttachType.MACVLAN)1077 InterfaceAttachType.MACVLAN)
1075 discovered_machine.interfaces[2].attach_name = eth2.name1078 discovered_machine.interfaces[2].attach_name = eth2.name
1076 pod = factory.make_Pod(ip_address=ip)1079 pod = factory.make_Pod(ip_address=ip)
1077 print(pod.ip_address)1080 # Skip commissioning on creation so that we can test that VLANs
1081 # are properly set based on the interface constraint.
1078 machine = pod.create_machine(1082 machine = pod.create_machine(
1079 discovered_machine, factory.make_User(),1083 discovered_machine, factory.make_User(),
1084 # Use numeric names to mimic what Juju will do.
1080 interfaces=LabeledConstraintMap(1085 interfaces=LabeledConstraintMap(
1081 'eth0:vlan=id:%d;eth1:vlan=id:%d;eth2:vlan=id:%d' % (1086 '0:vlan=id:%d;1:vlan=id:%d;2:vlan=id:%d' % (
1082 vlan.id, vlan2.id, vlan3.id),1087 vlan.id, vlan2.id, vlan3.id),
1083 )1088 )
1084 )1089 )
@@ -1089,6 +1094,10 @@ class TestPod(MAASServerTestCase):
1089 self.assertThat(interfaces['eth0'].vlan, Equals(vlan))1094 self.assertThat(interfaces['eth0'].vlan, Equals(vlan))
1090 self.assertThat(interfaces['eth1'].vlan, Equals(vlan2))1095 self.assertThat(interfaces['eth1'].vlan, Equals(vlan2))
1091 self.assertThat(interfaces['eth2'].vlan, Equals(vlan3))1096 self.assertThat(interfaces['eth2'].vlan, Equals(vlan3))
1097 # Make sure all interfaces also have a subnet link.
1098 self.assertThat(interfaces['eth0'].ip_addresses.count(), Equals(1))
1099 self.assertThat(interfaces['eth1'].ip_addresses.count(), Equals(1))
1100 self.assertThat(interfaces['eth2'].ip_addresses.count(), Equals(1))
10921101
1093 def test_create_machine_uses_default_ifnames_if_discovered_mismatch(self):1102 def test_create_machine_uses_default_ifnames_if_discovered_mismatch(self):
1094 """This makes sure that if the discovered machine comes back with1103 """This makes sure that if the discovered machine comes back with
@@ -1766,3 +1775,16 @@ class TestGetRequestedIPs(MAASServerTestCase):
1766 "eth0": ['10.0.0.1', '2001:db8::1'],1775 "eth0": ['10.0.0.1', '2001:db8::1'],
1767 "eth1": ['10.0.0.2', '2001:db8::2']1776 "eth1": ['10.0.0.2', '2001:db8::2']
1768 }))1777 }))
1778
1779 def test__leaves_out_keys_with_no_assigned_ips(self):
1780 interface = RequestedMachineInterface(
1781 ifname='eth0', requested_ips=['10.0.0.1', '2001:db8::1'])
1782 interface2 = RequestedMachineInterface(
1783 ifname='eth1', requested_ips=[])
1784 interfaces = [interface, interface2]
1785 requested_machine = RequestedMachine(
1786 factory.make_hostname(), 'amd64', 1, 1024, [], interfaces)
1787 self.assertThat(
1788 get_requested_ips(requested_machine), Equals({
1789 "eth0": ['10.0.0.1', '2001:db8::1'],
1790 }))
diff --git a/src/provisioningserver/utils/constraints.py b/src/provisioningserver/utils/constraints.py
index e38fc23..d00c9c7 100644
--- a/src/provisioningserver/utils/constraints.py
+++ b/src/provisioningserver/utils/constraints.py
@@ -30,6 +30,11 @@ class LabeledConstraintMap(object):
30 def __str__(self):30 def __str__(self):
31 return self.value31 return self.value
3232
33 def __len__(self):
34 if self.map is None:
35 return 0
36 return len(self.map)
37
33 def __iter__(self):38 def __iter__(self):
34 if self.map is None:39 if self.map is None:
35 return iter([])40 return iter([])
diff --git a/src/provisioningserver/utils/tests/test_constraints.py b/src/provisioningserver/utils/tests/test_constraints.py
index d797d11..c3a26bf 100644
--- a/src/provisioningserver/utils/tests/test_constraints.py
+++ b/src/provisioningserver/utils/tests/test_constraints.py
@@ -7,12 +7,14 @@ __all__ = []
77
8from maastesting.testcase import MAASTestCase8from maastesting.testcase import MAASTestCase
9from provisioningserver.utils.constraints import (9from provisioningserver.utils.constraints import (
10 LabeledConstraintMap,
10 parse_labeled_constraint_map,11 parse_labeled_constraint_map,
11 validate_constraint_label_name,12 validate_constraint_label_name,
12)13)
13from testtools import ExpectedException14from testtools import ExpectedException
14from testtools.matchers import (15from testtools.matchers import (
15 Equals,16 Equals,
17 HasLength,
16 Is,18 Is,
17)19)
1820
@@ -113,3 +115,18 @@ class TestGetLabeledConstraintsMap(MAASTestCase):
113 "foo": {"a": ["b"], "c": ["d"]},115 "foo": {"a": ["b"], "c": ["d"]},
114 "bar": {"e": ["f"], "g": ["h"]},116 "bar": {"e": ["f"], "g": ["h"]},
115 }))117 }))
118
119
120class TestLabeledConstraintMap(MAASTestCase):
121
122 def test__len__for_null_map(self):
123 lcm = LabeledConstraintMap(None)
124 self.assertThat(lcm, HasLength(0))
125
126 def test__len__for_empty_map(self):
127 lcm = LabeledConstraintMap('')
128 self.assertThat(lcm, HasLength(0))
129
130 def test__len__for_populated_map(self):
131 lcm = LabeledConstraintMap('eth0:space=1;eth1:space=2')
132 self.assertThat(lcm, HasLength(2))

Subscribers

People subscribed via source and target branches