Merge lp:~ltrager/maas/reset_node into lp:~maas-committers/maas/trunk
- reset_node
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Lee Trager | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 5003 | ||||
Proposed branch: | lp:~ltrager/maas/reset_node | ||||
Merge into: | lp:~maas-committers/maas/trunk | ||||
Diff against target: |
457 lines (+286/-2) 7 files modified
src/maasserver/api/devices.py (+28/-0) src/maasserver/api/machines.py (+44/-2) src/maasserver/api/tests/test_devices.py (+44/-0) src/maasserver/api/tests/test_machine.py (+91/-0) src/maasserver/models/node.py (+22/-0) src/maasserver/models/tests/test_node.py (+47/-0) src/maasserver/testing/factory.py (+10/-0) |
||||
To merge this branch: | bzr merge lp:~ltrager/maas/reset_node | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andres Rodriguez (community) | Approve | ||
Gavin Panella (community) | Approve | ||
Review via email: mp+293222@code.launchpad.net |
Commit message
Add the ability to reset machines and devices to default state.
Description of the change
Gavin Panella (allenap) wrote : | # |
[I wrote some comments on this yesterday and forgot to save them.]
Looks good to me. I've made some comments about `idempotent` which need addressing, but there's no need for me to block you on that.
You've just got to convince roaksoax now :)
Andres Rodriguez (andreserl) wrote : | # |
Hehe se actually discussed it yesterday and came to the conclusion that we
need to change reset to restore and have individual
Methods for storage and networking!
On Friday, April 29, 2016, Gavin Panella <email address hidden>
wrote:
> Review: Approve
>
> [I wrote some comments on this yesterday and forgot to save them.]
>
> Looks good to me. I've made some comments about `idempotent` which need
> addressing, but there's no need for me to block you on that.
>
> You've just got to convince roaksoax now :)
>
> Diff comments:
>
> > === modified file 'src/maasserver
> > --- src/maasserver/
> > +++ src/maasserver/
> > @@ -117,6 +118,22 @@
> > device.delete()
> > return rc.DELETED
> >
> > + @operation(
>
> I chose the argument name "idempotent" and unfortunately it wasn't a good
> choice. This reset operation is idempotent but it's also destructive, so
> this should be specified as idempotent=False. Ultimately this is used to
> specify an operation as available via GET (idempotent=True) or POST
> (idempotent=False), and this operation should definitely only be available
> via POST.
>
> > + def reset(self, request, system_id):
> > + """Reset a machine's network and storage options.
> > +
> > + Resets a machine's network and storage options as if the node
> was just
> > + commissioned.
> > +
> > + Returns 404 if the machine is not found
> > + Returns 403 if the user does not have permission to reset the
> machine.
>
> For this whole docstring, s/machine/device/ and remove mentions of storage
> options.
>
> > + """
> > + device = self.model.
> > + system_
> > + perm=NODE_
> > + device.
> > + return reload_
> > +
> > @operation(
> > def set_owner_
> > """Set key/value data for the current owner.
> >
> > === modified file 'src/maasserver
> > --- src/maasserver/
> > +++ src/maasserver/
> > @@ -697,6 +700,22 @@
> > request.
> > return node
> >
> > + @operation(
>
> Same here, re. idempotent.
>
> > + def reset(self, request, system_id):
> > + """Reset a machine's network and storage options.
> > +
> > + Resets a machine's network and storage options as if the node
> was just
> > + commissioned.
> > +
> > + Returns 404 if the machine is not found.
> > + Returns 403 if the user does not have permission to reset the
> machine.
> > + """
> > + machine = self.model.
> > + system_
> > + perm=NODE_
> > + machine.reset()
> > + return reload_
> > +
> > @operation(
> > def set_owner_data(...
Lee Trager (ltrager) wrote : | # |
I've added a set_initial_
Andres Rodriguez (andreserl) wrote : | # |
I thought we were gonna have a restore_
Lee Trager (ltrager) wrote : | # |
We have set_storage_config which can be used to set the storage layout. If you don't know what storage layout you have set you'd have todo
maas <profile> machine set-storage-layout <system_id> storage_
I could add some code so that setting storage_
Andres Rodriguez (andreserl) wrote : | # |
Hi Lee,
IIRC, we agreed to use restore for both and the restore for storage
wouldn't set the default layout but rather get it to original?
On Wednesday, May 4, 2016, Lee Trager <email address hidden> wrote:
> We have set_storage_config which can be used to set the storage layout. If
> you don't know what storage layout you have set you'd have todo
>
> maas <profile> machine set-storage-layout <system_id>
> storage_
>
> I could add some code so that setting storage_
> automatically look up what the default is or restore_
> as you suggested.
> --
> https:/
> You are reviewing the proposed merge of lp:~ltrager/maas/reset_node into
> lp:maas.
>
--
Andres Rodriguez (RoAkSoAx)
Ubuntu Server Developer
MSc. Telecom & Networking
Systems Engineer
Lee Trager (ltrager) wrote : | # |
As per our IRC discussion this renames all restore operations to use the format store_*
MAAS Lander (maas-lander) wrote : | # |
Attempt to merge into lp:maas failed due to conflicts:
text conflict in src/maasserver/
text conflict in src/maasserver/
MAAS Lander (maas-lander) wrote : | # |
The attempt to merge lp:~ltrager/maas/reset_node into lp:maas failed. Below is the output from the failed tests.
Hit:1 http://
Hit:2 http://
Get:3 http://
Hit:4 http://
Fetched 94.5 kB in 0s (197 kB/s)
Reading package lists...
sudo DEBIAN_
--no-
Reading package lists...
Building dependency tree...
Reading state information...
apache2 is already the newest version (2.4.18-2ubuntu3).
archdetect-deb is already the newest version (1.117ubuntu2).
authbind is already the newest version (2.1.1+nmu1).
bash is already the newest version (4.3-14ubuntu1).
build-essential is already the newest version (12.1ubuntu2).
bzr is already the newest version (2.7.0-2ubuntu1).
curl is already the newest version (7.47.0-1ubuntu2).
debhelper is already the newest version (9.20160115ubun
distro-info is already the newest version (0.14build1).
freeipmi-tools is already the newest version (1.4.11-1ubuntu1).
git is already the newest version (1:2.7.4-0ubuntu1).
isc-dhcp-common is already the newest version (4.3.3-5ubuntu12).
libjs-angularjs is already the newest version (1.2.28-1ubuntu2).
libjs-jquery is already the newest version (1.11.3+dfsg-4).
libjs-yui3-full is already the newest version (3.5.1-1ubuntu3).
libjs-yui3-min is already the newest version (3.5.1-1ubuntu3).
libpq-dev is already the newest version (9.5.2-1).
make is already the newest version (4.1-6).
postgresql is already the newest version (9.5+173).
pxelin...
Preview Diff
1 | === modified file 'src/maasserver/api/devices.py' |
2 | --- src/maasserver/api/devices.py 2016-04-28 01:14:14 +0000 |
3 | +++ src/maasserver/api/devices.py 2016-05-09 20:14:05 +0000 |
4 | @@ -12,6 +12,7 @@ |
5 | NodesHandler, |
6 | OwnerDataMixin, |
7 | ) |
8 | +from maasserver.api.support import operation |
9 | from maasserver.enum import NODE_PERMISSION |
10 | from maasserver.exceptions import MAASAPIValidationError |
11 | from maasserver.forms import ( |
12 | @@ -19,6 +20,7 @@ |
13 | DeviceWithMACsForm, |
14 | ) |
15 | from maasserver.models.node import Device |
16 | +from maasserver.utils.orm import reload_object |
17 | from piston3.utils import rc |
18 | |
19 | # Device's fields exposed on the API. |
20 | @@ -116,6 +118,32 @@ |
21 | device.delete() |
22 | return rc.DELETED |
23 | |
24 | + @operation(idempotent=False) |
25 | + def restore_networking_configuration(self, request, system_id): |
26 | + """Reset a device's network options. |
27 | + |
28 | + Returns 404 if the device is not found |
29 | + Returns 403 if the user does not have permission to reset the device. |
30 | + """ |
31 | + device = self.model.objects.get_node_or_404( |
32 | + system_id=system_id, user=request.user, |
33 | + perm=NODE_PERMISSION.ADMIN) |
34 | + device.set_initial_networking_configuration() |
35 | + return reload_object(device) |
36 | + |
37 | + @operation(idempotent=False) |
38 | + def restore_default_configuration(self, request, system_id): |
39 | + """Reset a device's configuration to its initial state. |
40 | + |
41 | + Returns 404 if the device is not found. |
42 | + Returns 403 if the user does not have permission to reset the device. |
43 | + """ |
44 | + device = self.model.objects.get_node_or_404( |
45 | + system_id=system_id, user=request.user, |
46 | + perm=NODE_PERMISSION.ADMIN) |
47 | + device.restore_default_configuration() |
48 | + return reload_object(device) |
49 | + |
50 | @classmethod |
51 | def resource_uri(cls, device=None): |
52 | # This method is called by piston in two different contexts: |
53 | |
54 | === modified file 'src/maasserver/api/machines.py' |
55 | --- src/maasserver/api/machines.py 2016-05-04 02:39:11 +0000 |
56 | +++ src/maasserver/api/machines.py 2016-05-09 20:14:05 +0000 |
57 | @@ -77,7 +77,10 @@ |
58 | StorageLayoutForm, |
59 | StorageLayoutMissingBootDiskError, |
60 | ) |
61 | -from maasserver.utils.orm import get_first |
62 | +from maasserver.utils.orm import ( |
63 | + get_first, |
64 | + reload_object, |
65 | +) |
66 | import yaml |
67 | |
68 | # Machine's fields exposed on the API. |
69 | @@ -420,7 +423,7 @@ |
70 | Note: This will clear the current storage layout and any extra |
71 | configuration and replace it will the new layout. |
72 | |
73 | - :param storage_layout: Storage layout for the machine. (flat, lvm |
74 | + :param storage_layout: Storage layout for the machine. (flat, lvm, |
75 | and bcache) |
76 | |
77 | The following are optional for all layouts: |
78 | @@ -583,6 +586,45 @@ |
79 | content_type='text/plain') |
80 | |
81 | @operation(idempotent=False) |
82 | + def restore_networking_configuration(self, request, system_id): |
83 | + """Reset a machine's networking options to its initial state. |
84 | + |
85 | + Returns 404 if the machine is not found. |
86 | + Returns 403 if the user does not have permission to reset the machine. |
87 | + """ |
88 | + machine = self.model.objects.get_node_or_404( |
89 | + system_id=system_id, user=request.user, |
90 | + perm=NODE_PERMISSION.ADMIN) |
91 | + machine.set_initial_networking_configuration() |
92 | + return reload_object(machine) |
93 | + |
94 | + @operation(idempotent=False) |
95 | + def restore_storage_configuration(self, request, system_id): |
96 | + """Reset a machine's storage options to its initial state. |
97 | + |
98 | + Returns 404 if the machine is not found. |
99 | + Returns 403 if the user does not have permission to reset the machine. |
100 | + """ |
101 | + machine = self.model.objects.get_node_or_404( |
102 | + system_id=system_id, user=request.user, |
103 | + perm=NODE_PERMISSION.ADMIN) |
104 | + machine.set_default_storage_layout() |
105 | + return reload_object(machine) |
106 | + |
107 | + @operation(idempotent=False) |
108 | + def restore_default_configuration(self, request, system_id): |
109 | + """Reset a machine's configuration to its initial state. |
110 | + |
111 | + Returns 404 if the machine is not found. |
112 | + Returns 403 if the user does not have permission to reset the machine. |
113 | + """ |
114 | + machine = self.model.objects.get_node_or_404( |
115 | + system_id=system_id, user=request.user, |
116 | + perm=NODE_PERMISSION.ADMIN) |
117 | + machine.restore_default_configuration() |
118 | + return reload_object(machine) |
119 | + |
120 | + @operation(idempotent=False) |
121 | def mark_broken(self, request, system_id): |
122 | """Mark a node as 'broken'. |
123 | |
124 | |
125 | === modified file 'src/maasserver/api/tests/test_devices.py' |
126 | --- src/maasserver/api/tests/test_devices.py 2016-04-22 17:28:15 +0000 |
127 | +++ src/maasserver/api/tests/test_devices.py 2016-05-09 20:14:05 +0000 |
128 | @@ -16,11 +16,13 @@ |
129 | from maasserver.models import ( |
130 | Device, |
131 | Domain, |
132 | + node as node_module, |
133 | ) |
134 | from maasserver.testing.api import APITestCase |
135 | from maasserver.testing.factory import factory |
136 | from maasserver.utils.converters import json_load_bytes |
137 | from maasserver.utils.orm import reload_object |
138 | +from maastesting.matchers import MockCalledOnce |
139 | |
140 | |
141 | class DeviceOwnerDataTest(APITestCase): |
142 | @@ -348,3 +350,45 @@ |
143 | response = self.client.delete(get_device_uri(device)) |
144 | self.assertEqual(http.client.FORBIDDEN, response.status_code) |
145 | self.assertEqual(device, reload_object(device)) |
146 | + |
147 | + def test_restore_networking_configuration(self): |
148 | + self.become_admin() |
149 | + device = factory.make_Device() |
150 | + mock_set_initial_networking_config = self.patch( |
151 | + node_module.Device, 'set_initial_networking_configuration') |
152 | + response = self.client.post( |
153 | + get_device_uri(device), |
154 | + {'op': 'restore_networking_configuration'}) |
155 | + self.assertEqual(http.client.OK, response.status_code) |
156 | + self.assertEqual( |
157 | + device.system_id, json_load_bytes(response.content)['system_id']) |
158 | + self.assertThat(mock_set_initial_networking_config, MockCalledOnce()) |
159 | + |
160 | + def test_restore_networking_configuration_requires_admin(self): |
161 | + device = factory.make_Device() |
162 | + response = self.client.post( |
163 | + get_device_uri(device), |
164 | + {'op': 'restore_networking_configuration'}) |
165 | + self.assertEqual( |
166 | + http.client.FORBIDDEN, response.status_code, response.content) |
167 | + |
168 | + def test_restore_default_configuration(self): |
169 | + self.become_admin() |
170 | + device = factory.make_Device() |
171 | + mock_set_initial_networking_config = self.patch( |
172 | + node_module.Device, 'restore_default_configuration') |
173 | + response = self.client.post( |
174 | + get_device_uri(device), |
175 | + {'op': 'restore_default_configuration'}) |
176 | + self.assertEqual(http.client.OK, response.status_code) |
177 | + self.assertEqual( |
178 | + device.system_id, json_load_bytes(response.content)['system_id']) |
179 | + self.assertThat(mock_set_initial_networking_config, MockCalledOnce()) |
180 | + |
181 | + def test_restore_default_configuration_requires_admin(self): |
182 | + device = factory.make_Device() |
183 | + response = self.client.post( |
184 | + get_device_uri(device), |
185 | + {'op': 'restore_default_configuration'}) |
186 | + self.assertEqual( |
187 | + http.client.FORBIDDEN, response.status_code, response.content) |
188 | |
189 | === modified file 'src/maasserver/api/tests/test_machine.py' |
190 | --- src/maasserver/api/tests/test_machine.py 2016-05-04 02:39:11 +0000 |
191 | +++ src/maasserver/api/tests/test_machine.py 2016-05-09 20:14:05 +0000 |
192 | @@ -57,6 +57,7 @@ |
193 | from maastesting.matchers import ( |
194 | Equals, |
195 | HasLength, |
196 | + MockCalledOnce, |
197 | MockCalledOnceWith, |
198 | ) |
199 | from metadataserver.models import ( |
200 | @@ -1885,6 +1886,96 @@ |
201 | mock_get_curtin_merged_config, MockCalledOnceWith(machine)) |
202 | |
203 | |
204 | +class TestRestoreNetworkingConfiguration(APITestCase): |
205 | + """Tests for |
206 | + /api/2.0/machines/<machine>/?op=restore_networking_configuration""" |
207 | + |
208 | + def get_machine_uri(self, machine): |
209 | + """Get the API URI for `machine`.""" |
210 | + return reverse('machine_handler', args=[machine.system_id]) |
211 | + |
212 | + def test_(self): |
213 | + self.become_admin() |
214 | + machine = factory.make_Machine(status=NODE_STATUS.READY) |
215 | + mock_set_initial_networking_config = self.patch( |
216 | + node_module.Machine, 'set_initial_networking_configuration') |
217 | + response = self.client.post( |
218 | + self.get_machine_uri(machine), |
219 | + {'op': 'restore_networking_configuration'}) |
220 | + self.assertEqual(http.client.OK, response.status_code) |
221 | + self.assertEqual( |
222 | + machine.system_id, json_load_bytes(response.content)['system_id']) |
223 | + self.assertThat(mock_set_initial_networking_config, MockCalledOnce()) |
224 | + |
225 | + def test_restore_networking_configuration_requires_admin(self): |
226 | + machine = factory.make_Machine() |
227 | + response = self.client.post( |
228 | + self.get_machine_uri(machine), |
229 | + {'op': 'restore_networking_configuration'}) |
230 | + self.assertEqual( |
231 | + http.client.FORBIDDEN, response.status_code, response.content) |
232 | + |
233 | + |
234 | +class TestRestoreStorageConfiguration(APITestCase): |
235 | + """Tests for |
236 | + /api/2.0/machines/<machine>/?op=restore_storage_configuration""" |
237 | + |
238 | + def get_machine_uri(self, machine): |
239 | + """Get the API URI for `machine`.""" |
240 | + return reverse('machine_handler', args=[machine.system_id]) |
241 | + |
242 | + def test_restore_storage_configuration(self): |
243 | + self.become_admin() |
244 | + machine = factory.make_Machine(status=NODE_STATUS.READY) |
245 | + mock_set_default_storage_layout = self.patch( |
246 | + node_module.Machine, 'set_default_storage_layout') |
247 | + response = self.client.post( |
248 | + self.get_machine_uri(machine), |
249 | + {'op': 'restore_storage_configuration'}) |
250 | + self.assertEqual(http.client.OK, response.status_code) |
251 | + self.assertEqual( |
252 | + machine.system_id, json_load_bytes(response.content)['system_id']) |
253 | + self.assertThat(mock_set_default_storage_layout, MockCalledOnce()) |
254 | + |
255 | + def test_restore_storage_configuration_requires_admin(self): |
256 | + machine = factory.make_Machine() |
257 | + response = self.client.post( |
258 | + self.get_machine_uri(machine), |
259 | + {'op': 'restore_storage_configuration'}) |
260 | + self.assertEqual( |
261 | + http.client.FORBIDDEN, response.status_code, response.content) |
262 | + |
263 | + |
264 | +class TestRestoreDefaultConfiguration(APITestCase): |
265 | + """Tests for |
266 | + /api/2.0/machines/<machine>/?op=restore_default_configuration""" |
267 | + |
268 | + def get_machine_uri(self, machine): |
269 | + """Get the API URI for `machine`.""" |
270 | + return reverse('machine_handler', args=[machine.system_id]) |
271 | + |
272 | + def test_restore_default_configuration(self): |
273 | + self.become_admin() |
274 | + machine = factory.make_Machine(status=NODE_STATUS.READY) |
275 | + mock_restore_default_configuration = self.patch( |
276 | + node_module.Machine, 'restore_default_configuration') |
277 | + response = self.client.post( |
278 | + self.get_machine_uri(machine), |
279 | + {'op': 'restore_default_configuration'}) |
280 | + self.assertEqual(http.client.OK, response.status_code) |
281 | + self.assertEqual( |
282 | + machine.system_id, json_load_bytes(response.content)['system_id']) |
283 | + self.assertThat(mock_restore_default_configuration, MockCalledOnce()) |
284 | + |
285 | + def test_restore_default_configuration_requires_admin(self): |
286 | + machine = factory.make_Machine() |
287 | + response = self.client.post( |
288 | + self.get_machine_uri(machine), |
289 | + {'op': 'restore_default_configuration'}) |
290 | + self.assertEqual( |
291 | + http.client.FORBIDDEN, response.status_code, response.content) |
292 | + |
293 | + |
294 | class TestMarkBroken(APITestCase): |
295 | |
296 | def get_node_uri(self, machine): |
297 | |
298 | === modified file 'src/maasserver/models/node.py' |
299 | --- src/maasserver/models/node.py 2016-05-09 17:19:23 +0000 |
300 | +++ src/maasserver/models/node.py 2016-05-09 20:14:05 +0000 |
301 | @@ -2423,6 +2423,13 @@ |
302 | # No interfaces on the node. Nothing to do. |
303 | return |
304 | |
305 | + if self.node_type == NODE_TYPE.MACHINE and self.status not in [ |
306 | + NODE_STATUS.NEW, NODE_STATUS.READY, NODE_STATUS.ALLOCATED, |
307 | + NODE_STATUS.FAILED_DEPLOYMENT]: |
308 | + raise ValidationError( |
309 | + "Machine must be in a new, ready, allocated, or failed " |
310 | + "deployment state to be reset.") |
311 | + |
312 | # Set AUTO mode on the boot interface. |
313 | auto_set = False |
314 | discovered_addresses = boot_interface.ip_addresses.filter( |
315 | @@ -3066,6 +3073,17 @@ |
316 | super(Machine, self).__init__( |
317 | node_type=NODE_TYPE.MACHINE, *args, **kwargs) |
318 | |
319 | + def restore_default_configuration(self): |
320 | + """Restores a machine's configuration to default settings.""" |
321 | + if self.status not in [ |
322 | + NODE_STATUS.NEW, NODE_STATUS.READY, NODE_STATUS.ALLOCATED, |
323 | + NODE_STATUS.FAILED_DEPLOYMENT]: |
324 | + raise ValidationError( |
325 | + "Machine must be in a new, ready, allocated, or failed " |
326 | + "deployment state to restore default configuration.") |
327 | + self.set_default_storage_layout() |
328 | + self.set_initial_networking_configuration() |
329 | + |
330 | |
331 | class Controller(Node): |
332 | """A node which is either a rack or region controller.""" |
333 | @@ -3795,6 +3813,10 @@ |
334 | super(Device, self).__init__( |
335 | node_type=NODE_TYPE.DEVICE, *args, **kwargs) |
336 | |
337 | + def restore_default_configuration(self): |
338 | + """Restores a device's configuration to default settings.""" |
339 | + self.set_initial_networking_configuration() |
340 | + |
341 | def clean_architecture(self, prev): |
342 | # Devices aren't required to have a defined architecture |
343 | pass |
344 | |
345 | === modified file 'src/maasserver/models/tests/test_node.py' |
346 | --- src/maasserver/models/tests/test_node.py 2016-05-04 16:23:11 +0000 |
347 | +++ src/maasserver/models/tests/test_node.py 2016-05-09 20:14:05 +0000 |
348 | @@ -106,6 +106,7 @@ |
349 | deferToDatabase, |
350 | ) |
351 | from maastesting.matchers import ( |
352 | + MockCalledOnce, |
353 | MockCalledOnceWith, |
354 | MockCallsMatch, |
355 | MockNotCalled, |
356 | @@ -293,6 +294,30 @@ |
357 | list(Machine.objects.get_available_machines_for_acquisition(user))) |
358 | |
359 | |
360 | +class TestMachine(MAASServerTestCase): |
361 | + def test_restore_default_configuration(self): |
362 | + machine = factory.make_Machine(status=NODE_STATUS.NEW) |
363 | + mock_set_default_storage_layout = self.patch( |
364 | + machine, 'set_default_storage_layout') |
365 | + mock_set_initial_networking_configuration = self.patch( |
366 | + machine, 'set_initial_networking_configuration') |
367 | + machine.restore_default_configuration() |
368 | + self.assertThat(mock_set_default_storage_layout, MockCalledOnce()) |
369 | + self.assertThat( |
370 | + mock_set_initial_networking_configuration, MockCalledOnce()) |
371 | + |
372 | + def test_restore_default_configuration_error_wrong_status(self): |
373 | + machine = factory.make_Machine_with_Interface_on_Subnet( |
374 | + status=factory.pick_choice( |
375 | + NODE_STATUS_CHOICES, |
376 | + but_not=[ |
377 | + NODE_STATUS.NEW, NODE_STATUS.READY, NODE_STATUS.ALLOCATED, |
378 | + NODE_STATUS.FAILED_DEPLOYMENT]) |
379 | + ) |
380 | + self.assertRaises( |
381 | + ValidationError, machine.restore_default_configuration) |
382 | + |
383 | + |
384 | class TestControllerManager(MAASServerTestCase): |
385 | def test_controller_lists_node_type_rack_and_region(self): |
386 | racks_and_regions = set() |
387 | @@ -481,6 +506,17 @@ |
388 | self.assertEqual('', device.architecture) |
389 | |
390 | |
391 | +class TestDevice(MAASServerTestCase): |
392 | + |
393 | + def test_restore_default_configuration(self): |
394 | + device = factory.make_Device() |
395 | + mock_set_initial_networking_configuration = self.patch( |
396 | + device, 'set_initial_networking_configuration') |
397 | + device.restore_default_configuration() |
398 | + self.assertThat( |
399 | + mock_set_initial_networking_configuration, MockCalledOnce()) |
400 | + |
401 | + |
402 | class TestNode(MAASServerTestCase): |
403 | |
404 | def setUp(self): |
405 | @@ -3610,6 +3646,17 @@ |
406 | alloc_type=IPADDRESS_TYPE.AUTO).first() |
407 | self.assertIsNone(auto_ip) |
408 | |
409 | + def test_set_initial_net_config_rasies_validation_error_wrong_status(self): |
410 | + machine = factory.make_Machine_with_Interface_on_Subnet( |
411 | + status=factory.pick_choice( |
412 | + NODE_STATUS_CHOICES, |
413 | + but_not=[ |
414 | + NODE_STATUS.NEW, NODE_STATUS.READY, NODE_STATUS.ALLOCATED, |
415 | + NODE_STATUS.FAILED_DEPLOYMENT]) |
416 | + ) |
417 | + self.assertRaises( |
418 | + ValidationError, machine.set_initial_networking_configuration) |
419 | + |
420 | def test_set_initial_networking_configuration_auto_on_boot_nic(self): |
421 | node = factory.make_Node_with_Interface_on_Subnet() |
422 | boot_interface = node.get_boot_interface() |
423 | |
424 | === modified file 'src/maasserver/testing/factory.py' |
425 | --- src/maasserver/testing/factory.py 2016-05-05 17:22:16 +0000 |
426 | +++ src/maasserver/testing/factory.py 2016-05-09 20:14:05 +0000 |
427 | @@ -66,6 +66,7 @@ |
428 | IPRange, |
429 | LargeFile, |
430 | LicenseKey, |
431 | + Machine, |
432 | Node, |
433 | OwnerData, |
434 | Partition, |
435 | @@ -426,6 +427,10 @@ |
436 | Node.objects.filter(id=node.id).update(created=created) |
437 | return reload_object(node) |
438 | |
439 | + def make_Machine(self, *args, **kwargs): |
440 | + machine = self.make_Node(*args, node_type=NODE_TYPE.MACHINE, **kwargs) |
441 | + return typecast_node(machine, Machine) |
442 | + |
443 | def make_RackController( |
444 | self, last_image_sync=undefined, owner=None, **kwargs): |
445 | if owner is None: |
446 | @@ -680,6 +685,11 @@ |
447 | vlan.save() |
448 | return reload_object(node) |
449 | |
450 | + def make_Machine_with_Interface_on_Subnet(self, *args, **kwargs): |
451 | + machine = self.make_Node_with_Interface_on_Subnet( |
452 | + *args, node_type=NODE_TYPE.MACHINE, **kwargs) |
453 | + return typecast_node(machine, Machine) |
454 | + |
455 | UNDEFINED = float('NaN') |
456 | |
457 | def _get_exclude_list(self, subnet): |
A method already exists that allows setting the storage back to how it was after commission. We discussed that a similar method needed to be added for the networking and I'm not seeing that method here.
As far as adding a 'reset' Is is a nice improvement but wasn't the discussed solution. Can we discuss this?