Merge ~ltrager/maas:network_testing_models into maas:master
- Git
- lp:~ltrager/maas
- network_testing_models
- Merge into master
Proposed by
Lee Trager
Status: | Merged |
---|---|
Approved by: | Lee Trager |
Approved revision: | e8075505cb458a525fe871f4ff7e5f93780f1b15 |
Merge reported by: | MAAS Lander |
Merged at revision: | not available |
Proposed branch: | ~ltrager/maas:network_testing_models |
Merge into: | maas:master |
Diff against target: |
487 lines (+172/-26) 12 files modified
src/maasserver/forms/tests/test_pods.py (+2/-2) src/maasserver/migrations/maasserver/0188_network_testing.py (+33/-0) src/maasserver/models/interface.py (+19/-1) src/maasserver/models/tests/test_interface.py (+27/-6) src/maasserver/testing/factory.py (+17/-4) src/maasserver/tests/test_routablepairs.py (+9/-9) src/maasserver/websockets/handlers/tests/test_script.py (+2/-1) src/metadataserver/enum.py (+3/-1) src/metadataserver/migrations/0020_network_testing.py (+35/-0) src/metadataserver/models/script.py (+7/-1) src/metadataserver/models/scriptresult.py (+5/-0) src/metadataserver/models/tests/test_script.py (+13/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Blake Rouse (community) | Approve | ||
Newell Jensen (community) | Approve | ||
Review via email: mp+368567@code.launchpad.net |
Commit message
Add database columns for network testing
Description of the change
To post a comment you must log in.
Revision history for this message
Blake Rouse (blake-rouse) wrote : | # |
Looks good to me.
review:
Approve
Revision history for this message
MAAS Lander (maas-lander) wrote : | # |
LANDING
-b network_
STATUS: FAILED BUILD
LOG: http://
- e807550... by Lee Trager
-
Fix failing test
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/src/maasserver/forms/tests/test_pods.py b/src/maasserver/forms/tests/test_pods.py | |||
2 | index 948d4ce..03d332a 100644 | |||
3 | --- a/src/maasserver/forms/tests/test_pods.py | |||
4 | +++ b/src/maasserver/forms/tests/test_pods.py | |||
5 | @@ -1869,9 +1869,9 @@ class TestGetKnownHostInterfaces(MAASServerTestCase): | |||
6 | 1869 | node = factory.make_Machine_with_Interface_on_Subnet() | 1869 | node = factory.make_Machine_with_Interface_on_Subnet() |
7 | 1870 | node.interface_set.all().delete() | 1870 | node.interface_set.all().delete() |
8 | 1871 | bridge = factory.make_Interface( | 1871 | bridge = factory.make_Interface( |
10 | 1872 | iftype=INTERFACE_TYPE.BRIDGE, node=node, disconnected=True) | 1872 | iftype=INTERFACE_TYPE.BRIDGE, node=node, link_connected=False) |
11 | 1873 | physical = factory.make_Interface( | 1873 | physical = factory.make_Interface( |
13 | 1874 | iftype=INTERFACE_TYPE.PHYSICAL, node=node, disconnected=True) | 1874 | iftype=INTERFACE_TYPE.PHYSICAL, node=node, link_connected=False) |
14 | 1875 | interfaces = get_known_host_interfaces(node) | 1875 | interfaces = get_known_host_interfaces(node) |
15 | 1876 | self.assertItemsEqual( | 1876 | self.assertItemsEqual( |
16 | 1877 | interfaces, [ | 1877 | interfaces, [ |
17 | diff --git a/src/maasserver/migrations/maasserver/0188_network_testing.py b/src/maasserver/migrations/maasserver/0188_network_testing.py | |||
18 | 1878 | new file mode 100644 | 1878 | new file mode 100644 |
19 | index 0000000..bb9e267 | |||
20 | --- /dev/null | |||
21 | +++ b/src/maasserver/migrations/maasserver/0188_network_testing.py | |||
22 | @@ -0,0 +1,33 @@ | |||
23 | 1 | # -*- coding: utf-8 -*- | ||
24 | 2 | # Generated by Django 1.11.11 on 2019-06-07 19:40 | ||
25 | 3 | from __future__ import unicode_literals | ||
26 | 4 | |||
27 | 5 | from django.db import ( | ||
28 | 6 | migrations, | ||
29 | 7 | models, | ||
30 | 8 | ) | ||
31 | 9 | |||
32 | 10 | |||
33 | 11 | class Migration(migrations.Migration): | ||
34 | 12 | |||
35 | 13 | dependencies = [ | ||
36 | 14 | ('maasserver', '0187_status_messages_change_event_logging_levels'), | ||
37 | 15 | ] | ||
38 | 16 | |||
39 | 17 | operations = [ | ||
40 | 18 | migrations.AddField( | ||
41 | 19 | model_name='interface', | ||
42 | 20 | name='interface_speed', | ||
43 | 21 | field=models.PositiveIntegerField(default=0), | ||
44 | 22 | ), | ||
45 | 23 | migrations.AddField( | ||
46 | 24 | model_name='interface', | ||
47 | 25 | name='link_connected', | ||
48 | 26 | field=models.BooleanField(default=True), | ||
49 | 27 | ), | ||
50 | 28 | migrations.AddField( | ||
51 | 29 | model_name='interface', | ||
52 | 30 | name='link_speed', | ||
53 | 31 | field=models.PositiveIntegerField(default=0), | ||
54 | 32 | ), | ||
55 | 33 | ] | ||
56 | diff --git a/src/maasserver/models/interface.py b/src/maasserver/models/interface.py | |||
57 | index 842e0e8..6b5932e 100644 | |||
58 | --- a/src/maasserver/models/interface.py | |||
59 | +++ b/src/maasserver/models/interface.py | |||
60 | @@ -1,4 +1,4 @@ | |||
62 | 1 | # Copyright 2015-2018 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2015-2019 Canonical Ltd. This software is licensed under the |
63 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
64 | 3 | 3 | ||
65 | 4 | """Model for interfaces.""" | 4 | """Model for interfaces.""" |
66 | @@ -28,6 +28,7 @@ from django.db.models import ( | |||
67 | 28 | ForeignKey, | 28 | ForeignKey, |
68 | 29 | Manager, | 29 | Manager, |
69 | 30 | ManyToManyField, | 30 | ManyToManyField, |
70 | 31 | PositiveIntegerField, | ||
71 | 31 | PROTECT, | 32 | PROTECT, |
72 | 32 | Q, | 33 | Q, |
73 | 33 | TextField, | 34 | TextField, |
74 | @@ -571,6 +572,15 @@ class Interface(CleanSave, TimestampedModel): | |||
75 | 571 | max_length=255, blank=True, null=True, | 572 | max_length=255, blank=True, null=True, |
76 | 572 | help_text="Firmware version of the interface.") | 573 | help_text="Firmware version of the interface.") |
77 | 573 | 574 | ||
78 | 575 | # Whether or not the Interface is physically connected to an uplink. | ||
79 | 576 | link_connected = BooleanField(default=True) | ||
80 | 577 | |||
81 | 578 | # The speed of the interface in Mbit/s | ||
82 | 579 | interface_speed = PositiveIntegerField(default=0) | ||
83 | 580 | |||
84 | 581 | # The speed of the link in Mbit/s | ||
85 | 582 | link_speed = PositiveIntegerField(default=0) | ||
86 | 583 | |||
87 | 574 | def __init__(self, *args, **kwargs): | 584 | def __init__(self, *args, **kwargs): |
88 | 575 | type = kwargs.get('type', self.get_type()) | 585 | type = kwargs.get('type', self.get_type()) |
89 | 576 | kwargs['type'] = type | 586 | kwargs['type'] = type |
90 | @@ -1475,6 +1485,14 @@ class Interface(CleanSave, TimestampedModel): | |||
91 | 1475 | 'mdns': self.mdns_discovery_state, | 1485 | 'mdns': self.mdns_discovery_state, |
92 | 1476 | } | 1486 | } |
93 | 1477 | 1487 | ||
94 | 1488 | def save(self, *args, **kwargs): | ||
95 | 1489 | if (self.link_speed > self.interface_speed and | ||
96 | 1490 | self.interface_speed != 0): | ||
97 | 1491 | raise ValidationError('link_speed may not exceed interface_speed') | ||
98 | 1492 | if not self.link_connected: | ||
99 | 1493 | self.link_speed = 0 | ||
100 | 1494 | return super().save(*args, **kwargs) | ||
101 | 1495 | |||
102 | 1478 | 1496 | ||
103 | 1479 | class InterfaceRelationship(CleanSave, TimestampedModel): | 1497 | class InterfaceRelationship(CleanSave, TimestampedModel): |
104 | 1480 | child = ForeignKey( | 1498 | child = ForeignKey( |
105 | diff --git a/src/maasserver/models/tests/test_interface.py b/src/maasserver/models/tests/test_interface.py | |||
106 | index 36cd455..934705d 100644 | |||
107 | --- a/src/maasserver/models/tests/test_interface.py | |||
108 | +++ b/src/maasserver/models/tests/test_interface.py | |||
109 | @@ -1,4 +1,4 @@ | |||
111 | 1 | # Copyright 2015-2016 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2015-2019 Canonical Ltd. This software is licensed under the |
112 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
113 | 3 | 3 | ||
114 | 4 | """Tests for the Interface model.""" | 4 | """Tests for the Interface model.""" |
115 | @@ -873,7 +873,7 @@ class InterfaceTest(MAASServerTestCase): | |||
116 | 873 | mac = factory.make_MAC() | 873 | mac = factory.make_MAC() |
117 | 874 | interface = factory.make_Interface( | 874 | interface = factory.make_Interface( |
118 | 875 | INTERFACE_TYPE.PHYSICAL, | 875 | INTERFACE_TYPE.PHYSICAL, |
120 | 876 | name=name, node=node, mac_address=mac, disconnected=True) | 876 | name=name, node=node, mac_address=mac, link_connected=False) |
121 | 877 | self.assertThat(interface, MatchesStructure.byEquality( | 877 | self.assertThat(interface, MatchesStructure.byEquality( |
122 | 878 | name=name, node=node, mac_address=mac, | 878 | name=name, node=node, mac_address=mac, |
123 | 879 | type=INTERFACE_TYPE.PHYSICAL, vlan=None)) | 879 | type=INTERFACE_TYPE.PHYSICAL, vlan=None)) |
124 | @@ -884,7 +884,7 @@ class InterfaceTest(MAASServerTestCase): | |||
125 | 884 | mac = factory.make_MAC() | 884 | mac = factory.make_MAC() |
126 | 885 | interface = factory.make_Interface( | 885 | interface = factory.make_Interface( |
127 | 886 | INTERFACE_TYPE.PHYSICAL, | 886 | INTERFACE_TYPE.PHYSICAL, |
129 | 887 | name=name, node=node, mac_address=mac, disconnected=True) | 887 | name=name, node=node, mac_address=mac, link_connected=False) |
130 | 888 | interface.acquired = True | 888 | interface.acquired = True |
131 | 889 | self.assertRaises(ValueError, interface.save) | 889 | self.assertRaises(ValueError, interface.save) |
132 | 890 | 890 | ||
133 | @@ -1103,6 +1103,27 @@ class InterfaceTest(MAASServerTestCase): | |||
134 | 1103 | #: Test is this doesn't raise an exception | 1103 | #: Test is this doesn't raise an exception |
135 | 1104 | interface.remove_tag(tag) | 1104 | interface.remove_tag(tag) |
136 | 1105 | 1105 | ||
137 | 1106 | def test_save_link_speed_may_not_exceed_interface_speed(self): | ||
138 | 1107 | interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL) | ||
139 | 1108 | interface.interface_speed = 100 | ||
140 | 1109 | interface.link_speed = 1000 | ||
141 | 1110 | self.assertRaises(ValidationError, interface.save) | ||
142 | 1111 | |||
143 | 1112 | def test_save_link_speed_may_exceed_unknown_interface_speed(self): | ||
144 | 1113 | interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL) | ||
145 | 1114 | interface.interface_speed = 0 | ||
146 | 1115 | interface.link_speed = 1000 | ||
147 | 1116 | interface.save() | ||
148 | 1117 | interface = reload_object(interface) | ||
149 | 1118 | self.assertEquals(0, interface.interface_speed) | ||
150 | 1119 | self.assertEquals(1000, interface.link_speed) | ||
151 | 1120 | |||
152 | 1121 | def test_save_if_link_disconnected_set_link_speed_to_zero(self): | ||
153 | 1122 | interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL) | ||
154 | 1123 | interface.link_connected = False | ||
155 | 1124 | interface.save() | ||
156 | 1125 | self.assertEquals(0, interface.link_speed) | ||
157 | 1126 | |||
158 | 1106 | 1127 | ||
159 | 1107 | class InterfaceUpdateNeighbourTest(MAASServerTestCase): | 1128 | class InterfaceUpdateNeighbourTest(MAASServerTestCase): |
160 | 1108 | """Tests for `Interface.update_neighbour`.""" | 1129 | """Tests for `Interface.update_neighbour`.""" |
161 | @@ -1378,7 +1399,7 @@ class InterfaceMTUTest(MAASServerTestCase): | |||
162 | 1378 | 1399 | ||
163 | 1379 | def test_get_effective_mtu_returns_default_mtu(self): | 1400 | def test_get_effective_mtu_returns_default_mtu(self): |
164 | 1380 | nic1 = factory.make_Interface( | 1401 | nic1 = factory.make_Interface( |
166 | 1381 | INTERFACE_TYPE.PHYSICAL, disconnected=True) | 1402 | INTERFACE_TYPE.PHYSICAL, link_connected=False) |
167 | 1382 | self.assertEqual(DEFAULT_MTU, nic1.get_effective_mtu()) | 1403 | self.assertEqual(DEFAULT_MTU, nic1.get_effective_mtu()) |
168 | 1383 | 1404 | ||
169 | 1384 | def test_get_effective_mtu_returns_interface_mtu(self): | 1405 | def test_get_effective_mtu_returns_interface_mtu(self): |
170 | @@ -2380,7 +2401,7 @@ class TestForceAutoOrDHCPLink(MAASServerTestCase): | |||
171 | 2380 | 2401 | ||
172 | 2381 | def test__does_nothing_when_disconnected(self): | 2402 | def test__does_nothing_when_disconnected(self): |
173 | 2382 | interface = factory.make_Interface( | 2403 | interface = factory.make_Interface( |
175 | 2383 | INTERFACE_TYPE.PHYSICAL, disconnected=True) | 2404 | INTERFACE_TYPE.PHYSICAL, link_connected=False) |
176 | 2384 | self.assertIsNone(interface.force_auto_or_dhcp_link()) | 2405 | self.assertIsNone(interface.force_auto_or_dhcp_link()) |
177 | 2385 | 2406 | ||
178 | 2386 | def test__sets_to_AUTO_on_subnet(self): | 2407 | def test__sets_to_AUTO_on_subnet(self): |
179 | @@ -2412,7 +2433,7 @@ class TestEnsureLinkUp(MAASServerTestCase): | |||
180 | 2412 | 2433 | ||
181 | 2413 | def test__does_nothing_if_no_vlan(self): | 2434 | def test__does_nothing_if_no_vlan(self): |
182 | 2414 | interface = factory.make_Interface( | 2435 | interface = factory.make_Interface( |
184 | 2415 | INTERFACE_TYPE.PHYSICAL, disconnected=True) | 2436 | INTERFACE_TYPE.PHYSICAL, link_connected=False) |
185 | 2416 | interface.ensure_link_up() | 2437 | interface.ensure_link_up() |
186 | 2417 | interface = reload_object(interface) | 2438 | interface = reload_object(interface) |
187 | 2418 | self.assertEqual( | 2439 | self.assertEqual( |
188 | diff --git a/src/maasserver/testing/factory.py b/src/maasserver/testing/factory.py | |||
189 | index ec327a4..7ce4b7a 100644 | |||
190 | --- a/src/maasserver/testing/factory.py | |||
191 | +++ b/src/maasserver/testing/factory.py | |||
192 | @@ -1,4 +1,4 @@ | |||
194 | 1 | # Copyright 2012-2018 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2012-2019 Canonical Ltd. This software is licensed under the |
195 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
196 | 3 | 3 | ||
197 | 4 | """Test object factories.""" | 4 | """Test object factories.""" |
198 | @@ -1323,7 +1323,8 @@ class Factory(maastesting.factory.Factory): | |||
199 | 1323 | self, iftype=INTERFACE_TYPE.PHYSICAL, node=None, mac_address=None, | 1323 | self, iftype=INTERFACE_TYPE.PHYSICAL, node=None, mac_address=None, |
200 | 1324 | vlan=None, parents=None, name=None, cluster_interface=None, | 1324 | vlan=None, parents=None, name=None, cluster_interface=None, |
201 | 1325 | ip=None, subnet=None, enabled=True, fabric=None, tags=None, | 1325 | ip=None, subnet=None, enabled=True, fabric=None, tags=None, |
203 | 1326 | disconnected=False, params=""): | 1326 | link_connected=True, interface_speed=None, link_speed=None, |
204 | 1327 | params=""): | ||
205 | 1327 | if subnet is None and cluster_interface is not None: | 1328 | if subnet is None and cluster_interface is not None: |
206 | 1328 | subnet = cluster_interface.subnet | 1329 | subnet = cluster_interface.subnet |
207 | 1329 | if subnet is not None and vlan is None: | 1330 | if subnet is not None and vlan is None: |
208 | @@ -1344,7 +1345,7 @@ class Factory(maastesting.factory.Factory): | |||
209 | 1344 | elif iftype == INTERFACE_TYPE.VLAN: | 1345 | elif iftype == INTERFACE_TYPE.VLAN: |
210 | 1345 | # Need to calculate this later based on the VID. | 1346 | # Need to calculate this later based on the VID. |
211 | 1346 | name = None | 1347 | name = None |
213 | 1347 | if not disconnected: | 1348 | if link_connected: |
214 | 1348 | if vlan is None: | 1349 | if vlan is None: |
215 | 1349 | if fabric is not None: | 1350 | if fabric is not None: |
216 | 1350 | if iftype == INTERFACE_TYPE.VLAN: | 1351 | if iftype == INTERFACE_TYPE.VLAN: |
217 | @@ -1375,9 +1376,21 @@ class Factory(maastesting.factory.Factory): | |||
218 | 1375 | node = parents[0].get_node() | 1376 | node = parents[0].get_node() |
219 | 1376 | if tags is None: | 1377 | if tags is None: |
220 | 1377 | tags = [self.make_name('tag') for _ in range(3)] | 1378 | tags = [self.make_name('tag') for _ in range(3)] |
221 | 1379 | link_speeds = [10, 100, 1000, 10000, 20000, 40000, 50000, 100000] | ||
222 | 1380 | if interface_speed is None: | ||
223 | 1381 | interface_speed = random.choice(link_speeds) | ||
224 | 1382 | if link_speed is None: | ||
225 | 1383 | if not link_connected: | ||
226 | 1384 | link_speed = 0 | ||
227 | 1385 | else: | ||
228 | 1386 | link_speed = random.choice([ | ||
229 | 1387 | speed for speed in link_speeds | ||
230 | 1388 | if speed <= interface_speed]) | ||
231 | 1378 | interface = Interface( | 1389 | interface = Interface( |
232 | 1379 | node=node, mac_address=mac_address, type=iftype, | 1390 | node=node, mac_address=mac_address, type=iftype, |
234 | 1380 | name=name, vlan=vlan, enabled=enabled, tags=tags, params=params) | 1391 | name=name, vlan=vlan, enabled=enabled, tags=tags, |
235 | 1392 | link_connected=link_connected, interface_speed=interface_speed, | ||
236 | 1393 | link_speed=link_speed, params=params) | ||
237 | 1381 | interface.save() | 1394 | interface.save() |
238 | 1382 | if subnet is None and ip is not None: | 1395 | if subnet is None and ip is not None: |
239 | 1383 | subnet = Subnet.objects.get_best_subnet_for_ip(ip) | 1396 | subnet = Subnet.objects.get_best_subnet_for_ip(ip) |
240 | diff --git a/src/maasserver/tests/test_routablepairs.py b/src/maasserver/tests/test_routablepairs.py | |||
241 | index 7ba6fe8..45ca34c 100644 | |||
242 | --- a/src/maasserver/tests/test_routablepairs.py | |||
243 | +++ b/src/maasserver/tests/test_routablepairs.py | |||
244 | @@ -1,4 +1,4 @@ | |||
246 | 1 | # Copyright 2016 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2016-2019 Canonical Ltd. This software is licensed under the |
247 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
248 | 3 | 3 | ||
249 | 4 | """Tests for `maasserver.routablepairs`.""" | 4 | """Tests for `maasserver.routablepairs`.""" |
250 | @@ -136,7 +136,7 @@ class TestFindAddressesBetweenNodes(MAASServerTestCase): | |||
251 | 136 | # null space, one in a non-null space. | 136 | # null space, one in a non-null space. |
252 | 137 | origin = factory.make_Node(hostname="origin") | 137 | origin = factory.make_Node(hostname="origin") |
253 | 138 | origin_iface = factory.make_Interface( | 138 | origin_iface = factory.make_Interface( |
255 | 139 | node=origin, disconnected=True) | 139 | node=origin, link_connected=False) |
256 | 140 | origin_subnet = factory.make_Subnet( | 140 | origin_subnet = factory.make_Subnet( |
257 | 141 | space=space, cidr=next(networks)) | 141 | space=space, cidr=next(networks)) |
258 | 142 | origin_subnet_null_space = factory.make_Subnet( | 142 | origin_subnet_null_space = factory.make_Subnet( |
259 | @@ -150,14 +150,14 @@ class TestFindAddressesBetweenNodes(MAASServerTestCase): | |||
260 | 150 | node_same_subnet = factory.make_Node(hostname="same-subnet") | 150 | node_same_subnet = factory.make_Node(hostname="same-subnet") |
261 | 151 | sip_same_subnet = factory.make_StaticIPAddress( | 151 | sip_same_subnet = factory.make_StaticIPAddress( |
262 | 152 | interface=factory.make_Interface( | 152 | interface=factory.make_Interface( |
264 | 153 | node=node_same_subnet, disconnected=True), | 153 | node=node_same_subnet, link_connected=False), |
265 | 154 | subnet=origin_subnet) | 154 | subnet=origin_subnet) |
266 | 155 | 155 | ||
267 | 156 | # Same VLAN, different subnet, different node. | 156 | # Same VLAN, different subnet, different node. |
268 | 157 | node_same_vlan = factory.make_Node(hostname="same-vlan") | 157 | node_same_vlan = factory.make_Node(hostname="same-vlan") |
269 | 158 | sip_same_vlan = factory.make_StaticIPAddress( | 158 | sip_same_vlan = factory.make_StaticIPAddress( |
270 | 159 | interface=factory.make_Interface( | 159 | interface=factory.make_Interface( |
272 | 160 | node=node_same_vlan, disconnected=True), | 160 | node=node_same_vlan, link_connected=False), |
273 | 161 | subnet=factory.make_Subnet( | 161 | subnet=factory.make_Subnet( |
274 | 162 | space=space, vlan=origin_subnet.vlan, | 162 | space=space, vlan=origin_subnet.vlan, |
275 | 163 | cidr=next(networks))) | 163 | cidr=next(networks))) |
276 | @@ -166,7 +166,7 @@ class TestFindAddressesBetweenNodes(MAASServerTestCase): | |||
277 | 166 | node_same_space = factory.make_Node(hostname="same-space") | 166 | node_same_space = factory.make_Node(hostname="same-space") |
278 | 167 | sip_same_space = factory.make_StaticIPAddress( | 167 | sip_same_space = factory.make_StaticIPAddress( |
279 | 168 | interface=factory.make_Interface( | 168 | interface=factory.make_Interface( |
281 | 169 | node=node_same_space, disconnected=True), | 169 | node=node_same_space, link_connected=False), |
282 | 170 | subnet=factory.make_Subnet( | 170 | subnet=factory.make_Subnet( |
283 | 171 | space=space, cidr=next(networks))) | 171 | space=space, cidr=next(networks))) |
284 | 172 | 172 | ||
285 | @@ -174,7 +174,7 @@ class TestFindAddressesBetweenNodes(MAASServerTestCase): | |||
286 | 174 | node_null_space = factory.make_Node(hostname="null-space") | 174 | node_null_space = factory.make_Node(hostname="null-space") |
287 | 175 | factory.make_StaticIPAddress( | 175 | factory.make_StaticIPAddress( |
288 | 176 | interface=factory.make_Interface( | 176 | interface=factory.make_Interface( |
290 | 177 | node=node_null_space, disconnected=True), | 177 | node=node_null_space, link_connected=False), |
291 | 178 | subnet=factory.make_Subnet( | 178 | subnet=factory.make_Subnet( |
292 | 179 | space=None, cidr=next(networks))) | 179 | space=None, cidr=next(networks))) |
293 | 180 | 180 | ||
294 | @@ -208,7 +208,7 @@ class TestFindAddressesBetweenNodes(MAASServerTestCase): | |||
295 | 208 | # would have obscured the test. | 208 | # would have obscured the test. |
296 | 209 | origin_sip_2 = factory.make_StaticIPAddress( | 209 | origin_sip_2 = factory.make_StaticIPAddress( |
297 | 210 | interface=factory.make_Interface( | 210 | interface=factory.make_Interface( |
299 | 211 | node=origin, disconnected=True), | 211 | node=origin, link_connected=False), |
300 | 212 | subnet=factory.make_Subnet( | 212 | subnet=factory.make_Subnet( |
301 | 213 | space=space, cidr=next(networks))) | 213 | space=space, cidr=next(networks))) |
302 | 214 | 214 | ||
303 | @@ -239,7 +239,7 @@ class TestFindAddressesBetweenNodes(MAASServerTestCase): | |||
304 | 239 | # null space, one in a non-null space. | 239 | # null space, one in a non-null space. |
305 | 240 | origin = factory.make_Node(hostname="origin") | 240 | origin = factory.make_Node(hostname="origin") |
306 | 241 | origin_iface = factory.make_Interface( | 241 | origin_iface = factory.make_Interface( |
308 | 242 | node=origin, disconnected=True) | 242 | node=origin, link_connected=False) |
309 | 243 | origin_subnet_null_space = factory.make_Subnet( | 243 | origin_subnet_null_space = factory.make_Subnet( |
310 | 244 | space=None, cidr=network1) | 244 | space=None, cidr=network1) |
311 | 245 | factory.make_StaticIPAddress( | 245 | factory.make_StaticIPAddress( |
312 | @@ -248,7 +248,7 @@ class TestFindAddressesBetweenNodes(MAASServerTestCase): | |||
313 | 248 | # Same subnet, different node. | 248 | # Same subnet, different node. |
314 | 249 | node_no_match = factory.make_Node(hostname="no-match") | 249 | node_no_match = factory.make_Node(hostname="no-match") |
315 | 250 | no_match_iface = factory.make_Interface( | 250 | no_match_iface = factory.make_Interface( |
317 | 251 | node=node_no_match, disconnected=True) | 251 | node=node_no_match, link_connected=False) |
318 | 252 | no_match_subnet_null_space = factory.make_Subnet( | 252 | no_match_subnet_null_space = factory.make_Subnet( |
319 | 253 | space=None, cidr=network2) | 253 | space=None, cidr=network2) |
320 | 254 | factory.make_StaticIPAddress( | 254 | factory.make_StaticIPAddress( |
321 | diff --git a/src/maasserver/websockets/handlers/tests/test_script.py b/src/maasserver/websockets/handlers/tests/test_script.py | |||
322 | index 7d498d2..1108d6d 100644 | |||
323 | --- a/src/maasserver/websockets/handlers/tests/test_script.py | |||
324 | +++ b/src/maasserver/websockets/handlers/tests/test_script.py | |||
325 | @@ -1,4 +1,4 @@ | |||
327 | 1 | # Copyright 2017-2018 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2017-2019 Canonical Ltd. This software is licensed under the |
328 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
329 | 3 | 3 | ||
330 | 4 | """Tests for `maasserver.websockets.handlers.script`""" | 4 | """Tests for `maasserver.websockets.handlers.script`""" |
331 | @@ -35,6 +35,7 @@ class TestScriptHandler(MAASServerTestCase): | |||
332 | 35 | 'for_hardware': script.for_hardware, | 35 | 'for_hardware': script.for_hardware, |
333 | 36 | 'may_reboot': script.may_reboot, | 36 | 'may_reboot': script.may_reboot, |
334 | 37 | 'recommission': script.recommission, | 37 | 'recommission': script.recommission, |
335 | 38 | 'apply_configured_networking': script.apply_configured_networking, | ||
336 | 38 | 'created': dehydrate_datetime(script.created), | 39 | 'created': dehydrate_datetime(script.created), |
337 | 39 | 'updated': dehydrate_datetime(script.updated), | 40 | 'updated': dehydrate_datetime(script.updated), |
338 | 40 | } | 41 | } |
339 | diff --git a/src/metadataserver/enum.py b/src/metadataserver/enum.py | |||
340 | index 25222bc..983a5b3 100644 | |||
341 | --- a/src/metadataserver/enum.py | |||
342 | +++ b/src/metadataserver/enum.py | |||
343 | @@ -1,4 +1,4 @@ | |||
345 | 1 | # Copyright 2012-2018 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2012-2019 Canonical Ltd. This software is licensed under the |
346 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
347 | 3 | 3 | ||
348 | 4 | """Enumerations meaningful to the metadataserver application.""" | 4 | """Enumerations meaningful to the metadataserver application.""" |
349 | @@ -101,6 +101,7 @@ class HARDWARE_TYPE: | |||
350 | 101 | CPU = 1 | 101 | CPU = 1 |
351 | 102 | MEMORY = 2 | 102 | MEMORY = 2 |
352 | 103 | STORAGE = 3 | 103 | STORAGE = 3 |
353 | 104 | NETWORK = 4 | ||
354 | 104 | 105 | ||
355 | 105 | 106 | ||
356 | 106 | # Labels are also used for autotagging scripts. | 107 | # Labels are also used for autotagging scripts. |
357 | @@ -109,6 +110,7 @@ HARDWARE_TYPE_CHOICES = ( | |||
358 | 109 | (HARDWARE_TYPE.CPU, "CPU"), | 110 | (HARDWARE_TYPE.CPU, "CPU"), |
359 | 110 | (HARDWARE_TYPE.MEMORY, "Memory"), | 111 | (HARDWARE_TYPE.MEMORY, "Memory"), |
360 | 111 | (HARDWARE_TYPE.STORAGE, "Storage"), | 112 | (HARDWARE_TYPE.STORAGE, "Storage"), |
361 | 113 | (HARDWARE_TYPE.NETWORK, "Network"), | ||
362 | 112 | ) | 114 | ) |
363 | 113 | 115 | ||
364 | 114 | 116 | ||
365 | diff --git a/src/metadataserver/migrations/0020_network_testing.py b/src/metadataserver/migrations/0020_network_testing.py | |||
366 | 115 | new file mode 100644 | 117 | new file mode 100644 |
367 | index 0000000..2ea2ecb | |||
368 | --- /dev/null | |||
369 | +++ b/src/metadataserver/migrations/0020_network_testing.py | |||
370 | @@ -0,0 +1,35 @@ | |||
371 | 1 | # -*- coding: utf-8 -*- | ||
372 | 2 | # Generated by Django 1.11.11 on 2019-06-07 19:40 | ||
373 | 3 | from __future__ import unicode_literals | ||
374 | 4 | |||
375 | 5 | from django.db import ( | ||
376 | 6 | migrations, | ||
377 | 7 | models, | ||
378 | 8 | ) | ||
379 | 9 | import django.db.models.deletion | ||
380 | 10 | |||
381 | 11 | |||
382 | 12 | class Migration(migrations.Migration): | ||
383 | 13 | |||
384 | 14 | dependencies = [ | ||
385 | 15 | ('maasserver', '0188_network_testing'), | ||
386 | 16 | ('metadataserver', '0019_add_script_result_suppressed'), | ||
387 | 17 | ] | ||
388 | 18 | |||
389 | 19 | operations = [ | ||
390 | 20 | migrations.AddField( | ||
391 | 21 | model_name='script', | ||
392 | 22 | name='apply_configured_networking', | ||
393 | 23 | field=models.BooleanField(default=False), | ||
394 | 24 | ), | ||
395 | 25 | migrations.AddField( | ||
396 | 26 | model_name='scriptresult', | ||
397 | 27 | name='interface', | ||
398 | 28 | field=models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='maasserver.Interface'), | ||
399 | 29 | ), | ||
400 | 30 | migrations.AlterField( | ||
401 | 31 | model_name='script', | ||
402 | 32 | name='hardware_type', | ||
403 | 33 | field=models.IntegerField(choices=[(0, 'Node'), (1, 'CPU'), (2, 'Memory'), (3, 'Storage'), (4, 'Network')], default=0), | ||
404 | 34 | ), | ||
405 | 35 | ] | ||
406 | diff --git a/src/metadataserver/models/script.py b/src/metadataserver/models/script.py | |||
407 | index ffa4e69..3bfda14 100644 | |||
408 | --- a/src/metadataserver/models/script.py | |||
409 | +++ b/src/metadataserver/models/script.py | |||
410 | @@ -1,4 +1,4 @@ | |||
412 | 1 | # Copyright 2017 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2017-2019 Canonical Ltd. This software is licensed under the |
413 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
414 | 3 | 3 | ||
415 | 4 | __all__ = [ | 4 | __all__ = [ |
416 | @@ -75,6 +75,8 @@ def translate_hardware_type(hardware_type): | |||
417 | 75 | return HARDWARE_TYPE.MEMORY | 75 | return HARDWARE_TYPE.MEMORY |
418 | 76 | elif hardware_type in ['storage', 'disk', 'ssd']: | 76 | elif hardware_type in ['storage', 'disk', 'ssd']: |
419 | 77 | return HARDWARE_TYPE.STORAGE | 77 | return HARDWARE_TYPE.STORAGE |
420 | 78 | elif hardware_type in ['network', 'net', 'interface']: | ||
421 | 79 | return HARDWARE_TYPE.NETWORK | ||
422 | 78 | else: | 80 | else: |
423 | 79 | raise ValidationError( | 81 | raise ValidationError( |
424 | 80 | 'Hardware type must be node, cpu, memory, or storage') | 82 | 'Hardware type must be node, cpu, memory, or storage') |
425 | @@ -182,6 +184,10 @@ class Script(CleanSave, TimestampedModel): | |||
426 | 182 | # scripts after receiving the result. | 184 | # scripts after receiving the result. |
427 | 183 | recommission = BooleanField(default=False) | 185 | recommission = BooleanField(default=False) |
428 | 184 | 186 | ||
429 | 187 | # Whether or not maas-run-remote-scripts should apply user configured | ||
430 | 188 | # network settings before running the Script. | ||
431 | 189 | apply_configured_networking = BooleanField(default=False) | ||
432 | 190 | |||
433 | 185 | @property | 191 | @property |
434 | 186 | def ForHardware(self): | 192 | def ForHardware(self): |
435 | 187 | """Parses the for_hardware field and returns a ForHardware tuple.""" | 193 | """Parses the for_hardware field and returns a ForHardware tuple.""" |
436 | diff --git a/src/metadataserver/models/scriptresult.py b/src/metadataserver/models/scriptresult.py | |||
437 | index e3b80ff..5ec3c98 100644 | |||
438 | --- a/src/metadataserver/models/scriptresult.py | |||
439 | +++ b/src/metadataserver/models/scriptresult.py | |||
440 | @@ -24,6 +24,7 @@ from django.db.models import ( | |||
441 | 24 | from maasserver.fields import JSONObjectField | 24 | from maasserver.fields import JSONObjectField |
442 | 25 | from maasserver.models.cleansave import CleanSave | 25 | from maasserver.models.cleansave import CleanSave |
443 | 26 | from maasserver.models.event import Event | 26 | from maasserver.models.event import Event |
444 | 27 | from maasserver.models.interface import Interface | ||
445 | 27 | from maasserver.models.physicalblockdevice import PhysicalBlockDevice | 28 | from maasserver.models.physicalblockdevice import PhysicalBlockDevice |
446 | 28 | from maasserver.models.timestampedmodel import ( | 29 | from maasserver.models.timestampedmodel import ( |
447 | 29 | now, | 30 | now, |
448 | @@ -73,6 +74,10 @@ class ScriptResult(CleanSave, TimestampedModel): | |||
449 | 73 | PhysicalBlockDevice, editable=False, blank=True, null=True, | 74 | PhysicalBlockDevice, editable=False, blank=True, null=True, |
450 | 74 | on_delete=CASCADE) | 75 | on_delete=CASCADE) |
451 | 75 | 76 | ||
452 | 77 | # If the result is in reference to a particular Interface link it. | ||
453 | 78 | interface = ForeignKey( | ||
454 | 79 | Interface, editable=False, blank=True, null=True, on_delete=CASCADE) | ||
455 | 80 | |||
456 | 76 | script_version = ForeignKey( | 81 | script_version = ForeignKey( |
457 | 77 | VersionedTextFile, blank=True, null=True, editable=False, | 82 | VersionedTextFile, blank=True, null=True, editable=False, |
458 | 78 | on_delete=SET_NULL) | 83 | on_delete=SET_NULL) |
459 | diff --git a/src/metadataserver/models/tests/test_script.py b/src/metadataserver/models/tests/test_script.py | |||
460 | index ebf12d9..9c10e16 100644 | |||
461 | --- a/src/metadataserver/models/tests/test_script.py | |||
462 | +++ b/src/metadataserver/models/tests/test_script.py | |||
463 | @@ -1,4 +1,4 @@ | |||
465 | 1 | # Copyright 2017 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2017-2019 Canonical Ltd. This software is licensed under the |
466 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
467 | 3 | 3 | ||
468 | 4 | __all__ = [] | 4 | __all__ = [] |
469 | @@ -162,6 +162,18 @@ class TestTranslateHardwareType(MAASServerTestCase): | |||
470 | 162 | 'value': 'ssd', | 162 | 'value': 'ssd', |
471 | 163 | 'return_value': HARDWARE_TYPE.STORAGE, | 163 | 'return_value': HARDWARE_TYPE.STORAGE, |
472 | 164 | }), | 164 | }), |
473 | 165 | ('network', { | ||
474 | 166 | 'value': 'network', | ||
475 | 167 | 'return_value': HARDWARE_TYPE.NETWORK, | ||
476 | 168 | }), | ||
477 | 169 | ('net', { | ||
478 | 170 | 'value': 'net', | ||
479 | 171 | 'return_value': HARDWARE_TYPE.NETWORK, | ||
480 | 172 | }), | ||
481 | 173 | ('interface', { | ||
482 | 174 | 'value': 'interface', | ||
483 | 175 | 'return_value': HARDWARE_TYPE.NETWORK, | ||
484 | 176 | }), | ||
485 | 165 | ('invalid value', { | 177 | ('invalid value', { |
486 | 166 | 'value': factory.make_name('value'), | 178 | 'value': factory.make_name('value'), |
487 | 167 | 'exception': 'Hardware type must be node, cpu, memory, or storage', | 179 | 'exception': 'Hardware type must be node, cpu, memory, or storage', |
Follows the spec. Looks good.