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 | node = factory.make_Machine_with_Interface_on_Subnet() |
7 | node.interface_set.all().delete() |
8 | bridge = factory.make_Interface( |
9 | - iftype=INTERFACE_TYPE.BRIDGE, node=node, disconnected=True) |
10 | + iftype=INTERFACE_TYPE.BRIDGE, node=node, link_connected=False) |
11 | physical = factory.make_Interface( |
12 | - iftype=INTERFACE_TYPE.PHYSICAL, node=node, disconnected=True) |
13 | + iftype=INTERFACE_TYPE.PHYSICAL, node=node, link_connected=False) |
14 | interfaces = get_known_host_interfaces(node) |
15 | self.assertItemsEqual( |
16 | interfaces, [ |
17 | diff --git a/src/maasserver/migrations/maasserver/0188_network_testing.py b/src/maasserver/migrations/maasserver/0188_network_testing.py |
18 | 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 | +# -*- coding: utf-8 -*- |
24 | +# Generated by Django 1.11.11 on 2019-06-07 19:40 |
25 | +from __future__ import unicode_literals |
26 | + |
27 | +from django.db import ( |
28 | + migrations, |
29 | + models, |
30 | +) |
31 | + |
32 | + |
33 | +class Migration(migrations.Migration): |
34 | + |
35 | + dependencies = [ |
36 | + ('maasserver', '0187_status_messages_change_event_logging_levels'), |
37 | + ] |
38 | + |
39 | + operations = [ |
40 | + migrations.AddField( |
41 | + model_name='interface', |
42 | + name='interface_speed', |
43 | + field=models.PositiveIntegerField(default=0), |
44 | + ), |
45 | + migrations.AddField( |
46 | + model_name='interface', |
47 | + name='link_connected', |
48 | + field=models.BooleanField(default=True), |
49 | + ), |
50 | + migrations.AddField( |
51 | + model_name='interface', |
52 | + name='link_speed', |
53 | + field=models.PositiveIntegerField(default=0), |
54 | + ), |
55 | + ] |
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 @@ |
61 | -# Copyright 2015-2018 Canonical Ltd. This software is licensed under the |
62 | +# Copyright 2015-2019 Canonical Ltd. This software is licensed under the |
63 | # GNU Affero General Public License version 3 (see the file LICENSE). |
64 | |
65 | """Model for interfaces.""" |
66 | @@ -28,6 +28,7 @@ from django.db.models import ( |
67 | ForeignKey, |
68 | Manager, |
69 | ManyToManyField, |
70 | + PositiveIntegerField, |
71 | PROTECT, |
72 | Q, |
73 | TextField, |
74 | @@ -571,6 +572,15 @@ class Interface(CleanSave, TimestampedModel): |
75 | max_length=255, blank=True, null=True, |
76 | help_text="Firmware version of the interface.") |
77 | |
78 | + # Whether or not the Interface is physically connected to an uplink. |
79 | + link_connected = BooleanField(default=True) |
80 | + |
81 | + # The speed of the interface in Mbit/s |
82 | + interface_speed = PositiveIntegerField(default=0) |
83 | + |
84 | + # The speed of the link in Mbit/s |
85 | + link_speed = PositiveIntegerField(default=0) |
86 | + |
87 | def __init__(self, *args, **kwargs): |
88 | type = kwargs.get('type', self.get_type()) |
89 | kwargs['type'] = type |
90 | @@ -1475,6 +1485,14 @@ class Interface(CleanSave, TimestampedModel): |
91 | 'mdns': self.mdns_discovery_state, |
92 | } |
93 | |
94 | + def save(self, *args, **kwargs): |
95 | + if (self.link_speed > self.interface_speed and |
96 | + self.interface_speed != 0): |
97 | + raise ValidationError('link_speed may not exceed interface_speed') |
98 | + if not self.link_connected: |
99 | + self.link_speed = 0 |
100 | + return super().save(*args, **kwargs) |
101 | + |
102 | |
103 | class InterfaceRelationship(CleanSave, TimestampedModel): |
104 | 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 @@ |
110 | -# Copyright 2015-2016 Canonical Ltd. This software is licensed under the |
111 | +# Copyright 2015-2019 Canonical Ltd. This software is licensed under the |
112 | # GNU Affero General Public License version 3 (see the file LICENSE). |
113 | |
114 | """Tests for the Interface model.""" |
115 | @@ -873,7 +873,7 @@ class InterfaceTest(MAASServerTestCase): |
116 | mac = factory.make_MAC() |
117 | interface = factory.make_Interface( |
118 | INTERFACE_TYPE.PHYSICAL, |
119 | - name=name, node=node, mac_address=mac, disconnected=True) |
120 | + name=name, node=node, mac_address=mac, link_connected=False) |
121 | self.assertThat(interface, MatchesStructure.byEquality( |
122 | name=name, node=node, mac_address=mac, |
123 | type=INTERFACE_TYPE.PHYSICAL, vlan=None)) |
124 | @@ -884,7 +884,7 @@ class InterfaceTest(MAASServerTestCase): |
125 | mac = factory.make_MAC() |
126 | interface = factory.make_Interface( |
127 | INTERFACE_TYPE.PHYSICAL, |
128 | - name=name, node=node, mac_address=mac, disconnected=True) |
129 | + name=name, node=node, mac_address=mac, link_connected=False) |
130 | interface.acquired = True |
131 | self.assertRaises(ValueError, interface.save) |
132 | |
133 | @@ -1103,6 +1103,27 @@ class InterfaceTest(MAASServerTestCase): |
134 | #: Test is this doesn't raise an exception |
135 | interface.remove_tag(tag) |
136 | |
137 | + def test_save_link_speed_may_not_exceed_interface_speed(self): |
138 | + interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL) |
139 | + interface.interface_speed = 100 |
140 | + interface.link_speed = 1000 |
141 | + self.assertRaises(ValidationError, interface.save) |
142 | + |
143 | + def test_save_link_speed_may_exceed_unknown_interface_speed(self): |
144 | + interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL) |
145 | + interface.interface_speed = 0 |
146 | + interface.link_speed = 1000 |
147 | + interface.save() |
148 | + interface = reload_object(interface) |
149 | + self.assertEquals(0, interface.interface_speed) |
150 | + self.assertEquals(1000, interface.link_speed) |
151 | + |
152 | + def test_save_if_link_disconnected_set_link_speed_to_zero(self): |
153 | + interface = factory.make_Interface(INTERFACE_TYPE.PHYSICAL) |
154 | + interface.link_connected = False |
155 | + interface.save() |
156 | + self.assertEquals(0, interface.link_speed) |
157 | + |
158 | |
159 | class InterfaceUpdateNeighbourTest(MAASServerTestCase): |
160 | """Tests for `Interface.update_neighbour`.""" |
161 | @@ -1378,7 +1399,7 @@ class InterfaceMTUTest(MAASServerTestCase): |
162 | |
163 | def test_get_effective_mtu_returns_default_mtu(self): |
164 | nic1 = factory.make_Interface( |
165 | - INTERFACE_TYPE.PHYSICAL, disconnected=True) |
166 | + INTERFACE_TYPE.PHYSICAL, link_connected=False) |
167 | self.assertEqual(DEFAULT_MTU, nic1.get_effective_mtu()) |
168 | |
169 | def test_get_effective_mtu_returns_interface_mtu(self): |
170 | @@ -2380,7 +2401,7 @@ class TestForceAutoOrDHCPLink(MAASServerTestCase): |
171 | |
172 | def test__does_nothing_when_disconnected(self): |
173 | interface = factory.make_Interface( |
174 | - INTERFACE_TYPE.PHYSICAL, disconnected=True) |
175 | + INTERFACE_TYPE.PHYSICAL, link_connected=False) |
176 | self.assertIsNone(interface.force_auto_or_dhcp_link()) |
177 | |
178 | def test__sets_to_AUTO_on_subnet(self): |
179 | @@ -2412,7 +2433,7 @@ class TestEnsureLinkUp(MAASServerTestCase): |
180 | |
181 | def test__does_nothing_if_no_vlan(self): |
182 | interface = factory.make_Interface( |
183 | - INTERFACE_TYPE.PHYSICAL, disconnected=True) |
184 | + INTERFACE_TYPE.PHYSICAL, link_connected=False) |
185 | interface.ensure_link_up() |
186 | interface = reload_object(interface) |
187 | 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 @@ |
193 | -# Copyright 2012-2018 Canonical Ltd. This software is licensed under the |
194 | +# Copyright 2012-2019 Canonical Ltd. This software is licensed under the |
195 | # GNU Affero General Public License version 3 (see the file LICENSE). |
196 | |
197 | """Test object factories.""" |
198 | @@ -1323,7 +1323,8 @@ class Factory(maastesting.factory.Factory): |
199 | self, iftype=INTERFACE_TYPE.PHYSICAL, node=None, mac_address=None, |
200 | vlan=None, parents=None, name=None, cluster_interface=None, |
201 | ip=None, subnet=None, enabled=True, fabric=None, tags=None, |
202 | - disconnected=False, params=""): |
203 | + link_connected=True, interface_speed=None, link_speed=None, |
204 | + params=""): |
205 | if subnet is None and cluster_interface is not None: |
206 | subnet = cluster_interface.subnet |
207 | if subnet is not None and vlan is None: |
208 | @@ -1344,7 +1345,7 @@ class Factory(maastesting.factory.Factory): |
209 | elif iftype == INTERFACE_TYPE.VLAN: |
210 | # Need to calculate this later based on the VID. |
211 | name = None |
212 | - if not disconnected: |
213 | + if link_connected: |
214 | if vlan is None: |
215 | if fabric is not None: |
216 | if iftype == INTERFACE_TYPE.VLAN: |
217 | @@ -1375,9 +1376,21 @@ class Factory(maastesting.factory.Factory): |
218 | node = parents[0].get_node() |
219 | if tags is None: |
220 | tags = [self.make_name('tag') for _ in range(3)] |
221 | + link_speeds = [10, 100, 1000, 10000, 20000, 40000, 50000, 100000] |
222 | + if interface_speed is None: |
223 | + interface_speed = random.choice(link_speeds) |
224 | + if link_speed is None: |
225 | + if not link_connected: |
226 | + link_speed = 0 |
227 | + else: |
228 | + link_speed = random.choice([ |
229 | + speed for speed in link_speeds |
230 | + if speed <= interface_speed]) |
231 | interface = Interface( |
232 | node=node, mac_address=mac_address, type=iftype, |
233 | - name=name, vlan=vlan, enabled=enabled, tags=tags, params=params) |
234 | + name=name, vlan=vlan, enabled=enabled, tags=tags, |
235 | + link_connected=link_connected, interface_speed=interface_speed, |
236 | + link_speed=link_speed, params=params) |
237 | interface.save() |
238 | if subnet is None and ip is not None: |
239 | 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 @@ |
245 | -# Copyright 2016 Canonical Ltd. This software is licensed under the |
246 | +# Copyright 2016-2019 Canonical Ltd. This software is licensed under the |
247 | # GNU Affero General Public License version 3 (see the file LICENSE). |
248 | |
249 | """Tests for `maasserver.routablepairs`.""" |
250 | @@ -136,7 +136,7 @@ class TestFindAddressesBetweenNodes(MAASServerTestCase): |
251 | # null space, one in a non-null space. |
252 | origin = factory.make_Node(hostname="origin") |
253 | origin_iface = factory.make_Interface( |
254 | - node=origin, disconnected=True) |
255 | + node=origin, link_connected=False) |
256 | origin_subnet = factory.make_Subnet( |
257 | space=space, cidr=next(networks)) |
258 | origin_subnet_null_space = factory.make_Subnet( |
259 | @@ -150,14 +150,14 @@ class TestFindAddressesBetweenNodes(MAASServerTestCase): |
260 | node_same_subnet = factory.make_Node(hostname="same-subnet") |
261 | sip_same_subnet = factory.make_StaticIPAddress( |
262 | interface=factory.make_Interface( |
263 | - node=node_same_subnet, disconnected=True), |
264 | + node=node_same_subnet, link_connected=False), |
265 | subnet=origin_subnet) |
266 | |
267 | # Same VLAN, different subnet, different node. |
268 | node_same_vlan = factory.make_Node(hostname="same-vlan") |
269 | sip_same_vlan = factory.make_StaticIPAddress( |
270 | interface=factory.make_Interface( |
271 | - node=node_same_vlan, disconnected=True), |
272 | + node=node_same_vlan, link_connected=False), |
273 | subnet=factory.make_Subnet( |
274 | space=space, vlan=origin_subnet.vlan, |
275 | cidr=next(networks))) |
276 | @@ -166,7 +166,7 @@ class TestFindAddressesBetweenNodes(MAASServerTestCase): |
277 | node_same_space = factory.make_Node(hostname="same-space") |
278 | sip_same_space = factory.make_StaticIPAddress( |
279 | interface=factory.make_Interface( |
280 | - node=node_same_space, disconnected=True), |
281 | + node=node_same_space, link_connected=False), |
282 | subnet=factory.make_Subnet( |
283 | space=space, cidr=next(networks))) |
284 | |
285 | @@ -174,7 +174,7 @@ class TestFindAddressesBetweenNodes(MAASServerTestCase): |
286 | node_null_space = factory.make_Node(hostname="null-space") |
287 | factory.make_StaticIPAddress( |
288 | interface=factory.make_Interface( |
289 | - node=node_null_space, disconnected=True), |
290 | + node=node_null_space, link_connected=False), |
291 | subnet=factory.make_Subnet( |
292 | space=None, cidr=next(networks))) |
293 | |
294 | @@ -208,7 +208,7 @@ class TestFindAddressesBetweenNodes(MAASServerTestCase): |
295 | # would have obscured the test. |
296 | origin_sip_2 = factory.make_StaticIPAddress( |
297 | interface=factory.make_Interface( |
298 | - node=origin, disconnected=True), |
299 | + node=origin, link_connected=False), |
300 | subnet=factory.make_Subnet( |
301 | space=space, cidr=next(networks))) |
302 | |
303 | @@ -239,7 +239,7 @@ class TestFindAddressesBetweenNodes(MAASServerTestCase): |
304 | # null space, one in a non-null space. |
305 | origin = factory.make_Node(hostname="origin") |
306 | origin_iface = factory.make_Interface( |
307 | - node=origin, disconnected=True) |
308 | + node=origin, link_connected=False) |
309 | origin_subnet_null_space = factory.make_Subnet( |
310 | space=None, cidr=network1) |
311 | factory.make_StaticIPAddress( |
312 | @@ -248,7 +248,7 @@ class TestFindAddressesBetweenNodes(MAASServerTestCase): |
313 | # Same subnet, different node. |
314 | node_no_match = factory.make_Node(hostname="no-match") |
315 | no_match_iface = factory.make_Interface( |
316 | - node=node_no_match, disconnected=True) |
317 | + node=node_no_match, link_connected=False) |
318 | no_match_subnet_null_space = factory.make_Subnet( |
319 | space=None, cidr=network2) |
320 | 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 @@ |
326 | -# Copyright 2017-2018 Canonical Ltd. This software is licensed under the |
327 | +# Copyright 2017-2019 Canonical Ltd. This software is licensed under the |
328 | # GNU Affero General Public License version 3 (see the file LICENSE). |
329 | |
330 | """Tests for `maasserver.websockets.handlers.script`""" |
331 | @@ -35,6 +35,7 @@ class TestScriptHandler(MAASServerTestCase): |
332 | 'for_hardware': script.for_hardware, |
333 | 'may_reboot': script.may_reboot, |
334 | 'recommission': script.recommission, |
335 | + 'apply_configured_networking': script.apply_configured_networking, |
336 | 'created': dehydrate_datetime(script.created), |
337 | 'updated': dehydrate_datetime(script.updated), |
338 | } |
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 @@ |
344 | -# Copyright 2012-2018 Canonical Ltd. This software is licensed under the |
345 | +# Copyright 2012-2019 Canonical Ltd. This software is licensed under the |
346 | # GNU Affero General Public License version 3 (see the file LICENSE). |
347 | |
348 | """Enumerations meaningful to the metadataserver application.""" |
349 | @@ -101,6 +101,7 @@ class HARDWARE_TYPE: |
350 | CPU = 1 |
351 | MEMORY = 2 |
352 | STORAGE = 3 |
353 | + NETWORK = 4 |
354 | |
355 | |
356 | # Labels are also used for autotagging scripts. |
357 | @@ -109,6 +110,7 @@ HARDWARE_TYPE_CHOICES = ( |
358 | (HARDWARE_TYPE.CPU, "CPU"), |
359 | (HARDWARE_TYPE.MEMORY, "Memory"), |
360 | (HARDWARE_TYPE.STORAGE, "Storage"), |
361 | + (HARDWARE_TYPE.NETWORK, "Network"), |
362 | ) |
363 | |
364 | |
365 | diff --git a/src/metadataserver/migrations/0020_network_testing.py b/src/metadataserver/migrations/0020_network_testing.py |
366 | 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 | +# -*- coding: utf-8 -*- |
372 | +# Generated by Django 1.11.11 on 2019-06-07 19:40 |
373 | +from __future__ import unicode_literals |
374 | + |
375 | +from django.db import ( |
376 | + migrations, |
377 | + models, |
378 | +) |
379 | +import django.db.models.deletion |
380 | + |
381 | + |
382 | +class Migration(migrations.Migration): |
383 | + |
384 | + dependencies = [ |
385 | + ('maasserver', '0188_network_testing'), |
386 | + ('metadataserver', '0019_add_script_result_suppressed'), |
387 | + ] |
388 | + |
389 | + operations = [ |
390 | + migrations.AddField( |
391 | + model_name='script', |
392 | + name='apply_configured_networking', |
393 | + field=models.BooleanField(default=False), |
394 | + ), |
395 | + migrations.AddField( |
396 | + model_name='scriptresult', |
397 | + name='interface', |
398 | + field=models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='maasserver.Interface'), |
399 | + ), |
400 | + migrations.AlterField( |
401 | + model_name='script', |
402 | + name='hardware_type', |
403 | + field=models.IntegerField(choices=[(0, 'Node'), (1, 'CPU'), (2, 'Memory'), (3, 'Storage'), (4, 'Network')], default=0), |
404 | + ), |
405 | + ] |
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 @@ |
411 | -# Copyright 2017 Canonical Ltd. This software is licensed under the |
412 | +# Copyright 2017-2019 Canonical Ltd. This software is licensed under the |
413 | # GNU Affero General Public License version 3 (see the file LICENSE). |
414 | |
415 | __all__ = [ |
416 | @@ -75,6 +75,8 @@ def translate_hardware_type(hardware_type): |
417 | return HARDWARE_TYPE.MEMORY |
418 | elif hardware_type in ['storage', 'disk', 'ssd']: |
419 | return HARDWARE_TYPE.STORAGE |
420 | + elif hardware_type in ['network', 'net', 'interface']: |
421 | + return HARDWARE_TYPE.NETWORK |
422 | else: |
423 | raise ValidationError( |
424 | 'Hardware type must be node, cpu, memory, or storage') |
425 | @@ -182,6 +184,10 @@ class Script(CleanSave, TimestampedModel): |
426 | # scripts after receiving the result. |
427 | recommission = BooleanField(default=False) |
428 | |
429 | + # Whether or not maas-run-remote-scripts should apply user configured |
430 | + # network settings before running the Script. |
431 | + apply_configured_networking = BooleanField(default=False) |
432 | + |
433 | @property |
434 | def ForHardware(self): |
435 | """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 | from maasserver.fields import JSONObjectField |
442 | from maasserver.models.cleansave import CleanSave |
443 | from maasserver.models.event import Event |
444 | +from maasserver.models.interface import Interface |
445 | from maasserver.models.physicalblockdevice import PhysicalBlockDevice |
446 | from maasserver.models.timestampedmodel import ( |
447 | now, |
448 | @@ -73,6 +74,10 @@ class ScriptResult(CleanSave, TimestampedModel): |
449 | PhysicalBlockDevice, editable=False, blank=True, null=True, |
450 | on_delete=CASCADE) |
451 | |
452 | + # If the result is in reference to a particular Interface link it. |
453 | + interface = ForeignKey( |
454 | + Interface, editable=False, blank=True, null=True, on_delete=CASCADE) |
455 | + |
456 | script_version = ForeignKey( |
457 | VersionedTextFile, blank=True, null=True, editable=False, |
458 | 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 @@ |
464 | -# Copyright 2017 Canonical Ltd. This software is licensed under the |
465 | +# Copyright 2017-2019 Canonical Ltd. This software is licensed under the |
466 | # GNU Affero General Public License version 3 (see the file LICENSE). |
467 | |
468 | __all__ = [] |
469 | @@ -162,6 +162,18 @@ class TestTranslateHardwareType(MAASServerTestCase): |
470 | 'value': 'ssd', |
471 | 'return_value': HARDWARE_TYPE.STORAGE, |
472 | }), |
473 | + ('network', { |
474 | + 'value': 'network', |
475 | + 'return_value': HARDWARE_TYPE.NETWORK, |
476 | + }), |
477 | + ('net', { |
478 | + 'value': 'net', |
479 | + 'return_value': HARDWARE_TYPE.NETWORK, |
480 | + }), |
481 | + ('interface', { |
482 | + 'value': 'interface', |
483 | + 'return_value': HARDWARE_TYPE.NETWORK, |
484 | + }), |
485 | ('invalid value', { |
486 | 'value': factory.make_name('value'), |
487 | 'exception': 'Hardware type must be node, cpu, memory, or storage', |
Follows the spec. Looks good.