Merge lp:~mpontillo/maas/bug-1451852-remove-legacy-esxi-probe-and-enlist into lp:~maas-committers/maas/trunk
- bug-1451852-remove-legacy-esxi-probe-and-enlist
- Merge into trunk
Proposed by
Mike Pontillo
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Mike Pontillo | ||||
Approved revision: | no longer in the source branch. | ||||
Merged at revision: | 3895 | ||||
Proposed branch: | lp:~mpontillo/maas/bug-1451852-remove-legacy-esxi-probe-and-enlist | ||||
Merge into: | lp:~maas-committers/maas/trunk | ||||
Prerequisite: | lp:~mpontillo/maas/add-pycharm-project-files | ||||
Diff against target: |
948 lines (+6/-767) 13 files modified
etc/maas/templates/power/esxi.template (+0/-65) src/maasserver/api/nodegroups.py (+1/-26) src/maasserver/api/tests/test_nodegroup.py (+0/-40) src/maasserver/models/nodegroup.py (+0/-27) src/maasserver/models/tests/test_nodegroup.py (+0/-54) src/maasserver/static/js/angular/controllers/add_hardware.js (+1/-39) src/maastesting/tests/test_scss.py (+1/-1) src/provisioningserver/drivers/hardware/esxi.py (+0/-116) src/provisioningserver/drivers/hardware/tests/test_esxi.py (+0/-315) src/provisioningserver/power_schema.py (+1/-11) src/provisioningserver/rpc/clusterservice.py (+1/-15) src/provisioningserver/rpc/power.py (+0/-1) src/provisioningserver/rpc/tests/test_clusterservice.py (+1/-57) |
||||
To merge this branch: | bzr merge lp:~mpontillo/maas/bug-1451852-remove-legacy-esxi-probe-and-enlist | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andres Rodriguez (community) | Approve | ||
Review via email: mp+259075@code.launchpad.net |
Commit message
Remove legacy (never shipped) VMware probe-and-enlist option.
Description of the change
Remove redundant VMware probe-and-enlist option.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === removed file 'etc/maas/templates/power/esxi.template' | |||
2 | --- etc/maas/templates/power/esxi.template 2015-02-19 17:31:32 +0000 | |||
3 | +++ etc/maas/templates/power/esxi.template 1970-01-01 00:00:00 +0000 | |||
4 | @@ -1,65 +0,0 @@ | |||
5 | 1 | # -*- mode: shell-script -*- | ||
6 | 2 | # | ||
7 | 3 | # Control virtual system's "power" through virsh for ESXi | ||
8 | 4 | # | ||
9 | 5 | |||
10 | 6 | # Exit with failure message. | ||
11 | 7 | # Parameters: exit code, and error message. | ||
12 | 8 | fail() { | ||
13 | 9 | echo "$2" >&2 | ||
14 | 10 | exit $1 | ||
15 | 11 | } | ||
16 | 12 | |||
17 | 13 | issue_virsh_command() { | ||
18 | 14 | python - << END | ||
19 | 15 | import sys | ||
20 | 16 | from provisioningserver.drivers.hardware.esxi import power_control_esxi | ||
21 | 17 | try: | ||
22 | 18 | power_control_esxi( | ||
23 | 19 | {{escape_py_literal(power_address).decode("ascii") | safe}}, | ||
24 | 20 | {{escape_py_literal(power_id).decode("ascii") | safe}}, | ||
25 | 21 | {{escape_py_literal(power_change).decode("ascii") | safe}}, | ||
26 | 22 | {{escape_py_literal(power_user).decode("ascii") | safe}}, | ||
27 | 23 | {{escape_py_literal(power_pass).decode("ascii") | safe}}, | ||
28 | 24 | ) | ||
29 | 25 | except Exception as e: | ||
30 | 26 | # This gets in the node event log: print the exception's message | ||
31 | 27 | # and not the stacktrace. | ||
32 | 28 | print(unicode(e)) | ||
33 | 29 | sys.exit(1) | ||
34 | 30 | END | ||
35 | 31 | } | ||
36 | 32 | |||
37 | 33 | query_state() { | ||
38 | 34 | python - << END | ||
39 | 35 | import sys | ||
40 | 36 | from provisioningserver.drivers.hardware.esxi import power_state_esxi | ||
41 | 37 | try: | ||
42 | 38 | print(power_state_esxi( | ||
43 | 39 | {{escape_py_literal(power_address).decode("ascii") | safe}}, | ||
44 | 40 | {{escape_py_literal(power_id).decode("ascii") | safe}}, | ||
45 | 41 | {{escape_py_literal(power_user).decode("ascii") | safe}}, | ||
46 | 42 | {{escape_py_literal(power_pass).decode("ascii") | safe}}, | ||
47 | 43 | )) | ||
48 | 44 | except Exception as e: | ||
49 | 45 | # This gets in the node event log: print the exception's message | ||
50 | 46 | # and not the stacktrace. | ||
51 | 47 | print(unicode(e)) | ||
52 | 48 | sys.exit(1) | ||
53 | 49 | END | ||
54 | 50 | } | ||
55 | 51 | |||
56 | 52 | main() { | ||
57 | 53 | case $1 in | ||
58 | 54 | 'on'|'off') | ||
59 | 55 | issue_virsh_command | ||
60 | 56 | ;; | ||
61 | 57 | 'query') | ||
62 | 58 | query_state | ||
63 | 59 | ;; | ||
64 | 60 | *) | ||
65 | 61 | fail 2 "Unknown power command: '$1'" | ||
66 | 62 | esac | ||
67 | 63 | } | ||
68 | 64 | |||
69 | 65 | main "{{power_change}}" | ||
70 | 66 | 0 | ||
71 | === modified file 'src/maasserver/api/nodegroups.py' | |||
72 | --- src/maasserver/api/nodegroups.py 2015-05-07 18:14:38 +0000 | |||
73 | +++ src/maasserver/api/nodegroups.py 2015-05-14 16:27:22 +0000 | |||
74 | @@ -372,11 +372,10 @@ | |||
75 | 372 | """Add special hardware types. | 372 | """Add special hardware types. |
76 | 373 | 373 | ||
77 | 374 | :param model: The type of hardware. 'seamicro15k', 'virsh', 'vsphere', | 374 | :param model: The type of hardware. 'seamicro15k', 'virsh', 'vsphere', |
79 | 375 | 'esxi', 'powerkvm', 'mscm', 'msftocs' and 'ucsm' are supported. | 375 | 'powerkvm', 'mscm', 'msftocs' and 'ucsm' are supported. |
80 | 376 | 376 | ||
81 | 377 | seamicro15k is the model for the Seamicro 1500 Chassis. | 377 | seamicro15k is the model for the Seamicro 1500 Chassis. |
82 | 378 | virsh is the model for Virtual Machines managed by Virsh. | 378 | virsh is the model for Virtual Machines managed by Virsh. |
83 | 379 | esxi is the model for Virtual Machines managed by ESXi. | ||
84 | 380 | powerkvm is the model for Virtual Machines on Power KVM, | 379 | powerkvm is the model for Virtual Machines on Power KVM, |
85 | 381 | managed by Virsh. | 380 | managed by Virsh. |
86 | 382 | mscm is the model for the Moonshot Chassis Manager. | 381 | mscm is the model for the Moonshot Chassis Manager. |
87 | @@ -419,20 +418,6 @@ | |||
88 | 419 | :param prefix_filter: Filter nodes with supplied prefix. | 418 | :param prefix_filter: Filter nodes with supplied prefix. |
89 | 420 | :type prefix_filter: unicode | 419 | :type prefix_filter: unicode |
90 | 421 | 420 | ||
91 | 422 | The following are required if you are probing esxi: | ||
92 | 423 | |||
93 | 424 | :param address: The IP address of the esxi machine. | ||
94 | 425 | :type address: unicode | ||
95 | 426 | :param username: esxi username. | ||
96 | 427 | :type username: unicode | ||
97 | 428 | :param password: esxi password. | ||
98 | 429 | :type password: unicode | ||
99 | 430 | |||
100 | 431 | The following are optional if you are probing esxi: | ||
101 | 432 | |||
102 | 433 | :param prefix_filter: Filter nodes with supplied prefix. | ||
103 | 434 | :type prefix_filter: unicode | ||
104 | 435 | |||
105 | 436 | The following are required if you are probing mscm: | 421 | The following are required if you are probing mscm: |
106 | 437 | 422 | ||
107 | 438 | :param host: IP Address for the Moonshot Chassis Manager. | 423 | :param host: IP Address for the Moonshot Chassis Manager. |
108 | @@ -514,16 +499,6 @@ | |||
109 | 514 | user, host, username, password, port=port, | 499 | user, host, username, password, port=port, |
110 | 515 | protocol=protocol, prefix_filter=prefix_filter, | 500 | protocol=protocol, prefix_filter=prefix_filter, |
111 | 516 | accept_all=accept_all) | 501 | accept_all=accept_all) |
112 | 517 | elif model == 'esxi': | ||
113 | 518 | poweraddr = get_mandatory_param(request.data, 'address') | ||
114 | 519 | poweruser = get_mandatory_param(request.data, 'username') | ||
115 | 520 | password = get_mandatory_param(request.data, 'password') | ||
116 | 521 | prefix_filter = get_optional_param( | ||
117 | 522 | request.data, 'prefix_filter', default=None) | ||
118 | 523 | |||
119 | 524 | nodegroup.add_esxi( | ||
120 | 525 | user, poweruser, poweraddr, password=password, | ||
121 | 526 | prefix_filter=prefix_filter, accept_all=accept_all) | ||
122 | 527 | else: | 502 | else: |
123 | 528 | return HttpResponse(status=httplib.BAD_REQUEST) | 503 | return HttpResponse(status=httplib.BAD_REQUEST) |
124 | 529 | 504 | ||
125 | 530 | 505 | ||
126 | === modified file 'src/maasserver/api/tests/test_nodegroup.py' | |||
127 | --- src/maasserver/api/tests/test_nodegroup.py 2015-05-07 18:14:38 +0000 | |||
128 | +++ src/maasserver/api/tests/test_nodegroup.py 2015-05-14 16:27:22 +0000 | |||
129 | @@ -57,7 +57,6 @@ | |||
130 | 57 | ) | 57 | ) |
131 | 58 | from mock import Mock | 58 | from mock import Mock |
132 | 59 | from provisioningserver.rpc.cluster import ( | 59 | from provisioningserver.rpc.cluster import ( |
133 | 60 | AddESXi, | ||
134 | 61 | AddSeaMicro15k, | 60 | AddSeaMicro15k, |
135 | 62 | AddVirsh, | 61 | AddVirsh, |
136 | 63 | AddVsphere, | 62 | AddVsphere, |
137 | @@ -447,45 +446,6 @@ | |||
138 | 447 | port=None, prefix_filter=prefix_filter, | 446 | port=None, prefix_filter=prefix_filter, |
139 | 448 | accept_all=True)) | 447 | accept_all=True)) |
140 | 449 | 448 | ||
141 | 450 | def test_probe_and_enlist_hardware_adds_esxi(self): | ||
142 | 451 | self.become_admin() | ||
143 | 452 | user = self.logged_in_user | ||
144 | 453 | nodegroup = factory.make_NodeGroup() | ||
145 | 454 | model = 'esxi' | ||
146 | 455 | poweraddr = factory.make_ipv4_address() | ||
147 | 456 | password = factory.make_name('password') | ||
148 | 457 | poweruser = factory.make_name('poweruser') | ||
149 | 458 | prefix_filter = factory.make_name('filter') | ||
150 | 459 | accept_all = True | ||
151 | 460 | |||
152 | 461 | getClientFor = self.patch(nodegroup_module, 'getClientFor') | ||
153 | 462 | client = getClientFor.return_value | ||
154 | 463 | nodegroup = factory.make_NodeGroup() | ||
155 | 464 | |||
156 | 465 | response = self.client.post( | ||
157 | 466 | reverse('nodegroup_handler', args=[nodegroup.uuid]), | ||
158 | 467 | { | ||
159 | 468 | 'op': 'probe_and_enlist_hardware', | ||
160 | 469 | 'model': model, | ||
161 | 470 | 'user': user.username, | ||
162 | 471 | 'address': poweraddr, | ||
163 | 472 | 'username': poweruser, | ||
164 | 473 | 'password': password, | ||
165 | 474 | 'prefix_filter': prefix_filter, | ||
166 | 475 | 'accept_all': accept_all, | ||
167 | 476 | }) | ||
168 | 477 | |||
169 | 478 | self.assertEqual( | ||
170 | 479 | httplib.OK, response.status_code, | ||
171 | 480 | explain_unexpected_response(httplib.OK, response)) | ||
172 | 481 | |||
173 | 482 | self.expectThat( | ||
174 | 483 | client, | ||
175 | 484 | MockCalledOnceWith( | ||
176 | 485 | AddESXi, user=user.username, poweruser=poweruser, | ||
177 | 486 | poweraddr=poweraddr, password=password, | ||
178 | 487 | prefix_filter=prefix_filter, accept_all=True)) | ||
179 | 488 | |||
180 | 489 | def test_probe_and_enlist_hardware_adds_msftocs(self): | 449 | def test_probe_and_enlist_hardware_adds_msftocs(self): |
181 | 490 | self.become_admin() | 450 | self.become_admin() |
182 | 491 | user = self.logged_in_user | 451 | user = self.logged_in_user |
183 | 492 | 452 | ||
184 | === modified file 'src/maasserver/models/nodegroup.py' | |||
185 | --- src/maasserver/models/nodegroup.py 2015-05-07 18:14:38 +0000 | |||
186 | +++ src/maasserver/models/nodegroup.py 2015-05-14 16:27:22 +0000 | |||
187 | @@ -50,7 +50,6 @@ | |||
188 | 50 | ) | 50 | ) |
189 | 51 | from provisioningserver.dhcp.omshell import generate_omapi_key | 51 | from provisioningserver.dhcp.omshell import generate_omapi_key |
190 | 52 | from provisioningserver.rpc.cluster import ( | 52 | from provisioningserver.rpc.cluster import ( |
191 | 53 | AddESXi, | ||
192 | 54 | AddSeaMicro15k, | 53 | AddSeaMicro15k, |
193 | 55 | AddVirsh, | 54 | AddVirsh, |
194 | 56 | AddVsphere, | 55 | AddVsphere, |
195 | @@ -437,32 +436,6 @@ | |||
196 | 437 | password=password, protocol=protocol, port=port, | 436 | password=password, protocol=protocol, port=port, |
197 | 438 | prefix_filter=prefix_filter, accept_all=accept_all) | 437 | prefix_filter=prefix_filter, accept_all=accept_all) |
198 | 439 | 438 | ||
199 | 440 | def add_esxi(self, user, poweruser, poweraddr, password, | ||
200 | 441 | prefix_filter=None, accept_all=False): | ||
201 | 442 | """ Add all of the virtual machines inside a virsh controller. | ||
202 | 443 | |||
203 | 444 | :param user: user for the ESXi host. | ||
204 | 445 | :param poweraddr: IP address of esxi host string. | ||
205 | 446 | :param password: password. | ||
206 | 447 | :param prefix_filter: import based on prefix. | ||
207 | 448 | :param accept_all: commission enlisted nodes. | ||
208 | 449 | |||
209 | 450 | :raises NoConnectionsAvailable: If no connections to the cluster | ||
210 | 451 | are available. | ||
211 | 452 | """ | ||
212 | 453 | try: | ||
213 | 454 | client = getClientFor(self.uuid, timeout=1) | ||
214 | 455 | except NoConnectionsAvailable: | ||
215 | 456 | # No connection to the cluster so we can't do anything. We | ||
216 | 457 | # let the caller handle the error, since we don't want to | ||
217 | 458 | # just drop it. | ||
218 | 459 | raise | ||
219 | 460 | else: | ||
220 | 461 | return client( | ||
221 | 462 | AddESXi, user=user, poweruser=poweruser, poweraddr=poweraddr, | ||
222 | 463 | password=password, prefix_filter=prefix_filter, | ||
223 | 464 | accept_all=accept_all) | ||
224 | 465 | |||
225 | 466 | def enlist_nodes_from_ucsm(self, user, url, username, | 439 | def enlist_nodes_from_ucsm(self, user, url, username, |
226 | 467 | password, accept_all=False): | 440 | password, accept_all=False): |
227 | 468 | """ Add the servers from a Cicso UCS Manager. | 441 | """ Add the servers from a Cicso UCS Manager. |
228 | 469 | 442 | ||
229 | === modified file 'src/maasserver/models/tests/test_nodegroup.py' | |||
230 | --- src/maasserver/models/tests/test_nodegroup.py 2015-05-07 18:14:38 +0000 | |||
231 | +++ src/maasserver/models/tests/test_nodegroup.py 2015-05-14 16:27:22 +0000 | |||
232 | @@ -54,7 +54,6 @@ | |||
233 | 54 | ) | 54 | ) |
234 | 55 | from provisioningserver.dhcp.omshell import generate_omapi_key | 55 | from provisioningserver.dhcp.omshell import generate_omapi_key |
235 | 56 | from provisioningserver.rpc.cluster import ( | 56 | from provisioningserver.rpc.cluster import ( |
236 | 57 | AddESXi, | ||
237 | 58 | AddSeaMicro15k, | 57 | AddSeaMicro15k, |
238 | 59 | AddVirsh, | 58 | AddVirsh, |
239 | 60 | AddVsphere, | 59 | AddVsphere, |
240 | @@ -683,59 +682,6 @@ | |||
241 | 683 | username, password, protocol=None, port=None, | 682 | username, password, protocol=None, port=None, |
242 | 684 | prefix_filter=None, accept_all=True) | 683 | prefix_filter=None, accept_all=True) |
243 | 685 | 684 | ||
244 | 686 | def test_add_esxi_end_to_end(self): | ||
245 | 687 | nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ACCEPTED) | ||
246 | 688 | |||
247 | 689 | self.useFixture(RegionEventLoopFixture("rpc")) | ||
248 | 690 | self.useFixture(RunningEventLoopFixture()) | ||
249 | 691 | fixture = self.useFixture(MockLiveRegionToClusterRPCFixture()) | ||
250 | 692 | protocol = fixture.makeCluster(nodegroup, AddESXi) | ||
251 | 693 | protocol.AddESXi.return_value = defer.succeed( | ||
252 | 694 | {'system_id': factory.make_name('system-id')}) | ||
253 | 695 | |||
254 | 696 | user = factory.make_name('user') | ||
255 | 697 | poweruser = factory.make_name('poweruser') | ||
256 | 698 | poweraddr = factory.make_name('poweraddr') | ||
257 | 699 | password = factory.make_name('password') | ||
258 | 700 | nodegroup.add_esxi( | ||
259 | 701 | user, poweruser, poweraddr, password, None, True).wait(10) | ||
260 | 702 | |||
261 | 703 | self.expectThat( | ||
262 | 704 | protocol.AddESXi, | ||
263 | 705 | MockCalledOnceWith( | ||
264 | 706 | ANY, user=user, poweruser=poweruser, poweraddr=poweraddr, | ||
265 | 707 | password=password, prefix_filter=None, accept_all=True)) | ||
266 | 708 | |||
267 | 709 | def test_add_esxi_calls_client_with_resource_endpoint(self): | ||
268 | 710 | getClientFor = self.patch(nodegroup_module, 'getClientFor') | ||
269 | 711 | client = getClientFor.return_value | ||
270 | 712 | nodegroup = factory.make_NodeGroup() | ||
271 | 713 | |||
272 | 714 | user = factory.make_name('user') | ||
273 | 715 | poweruser = factory.make_name('poweruser') | ||
274 | 716 | poweraddr = factory.make_name('poweraddr') | ||
275 | 717 | password = factory.make_name('password') | ||
276 | 718 | nodegroup.add_esxi(user, poweruser, poweraddr, password, None, True) | ||
277 | 719 | |||
278 | 720 | self.expectThat( | ||
279 | 721 | client, | ||
280 | 722 | MockCalledOnceWith( | ||
281 | 723 | AddESXi, user=user, poweruser=poweruser, poweraddr=poweraddr, | ||
282 | 724 | password=password, prefix_filter=None, accept_all=True)) | ||
283 | 725 | |||
284 | 726 | def test_add_esxi_raises_if_no_connection_to_cluster(self): | ||
285 | 727 | getClientFor = self.patch(nodegroup_module, 'getClientFor') | ||
286 | 728 | getClientFor.side_effect = NoConnectionsAvailable() | ||
287 | 729 | nodegroup = factory.make_NodeGroup() | ||
288 | 730 | |||
289 | 731 | user = factory.make_name('user') | ||
290 | 732 | poweraddr = factory.make_name('poweraddr') | ||
291 | 733 | password = factory.make_name('password') | ||
292 | 734 | |||
293 | 735 | self.assertRaises( | ||
294 | 736 | NoConnectionsAvailable, nodegroup.add_esxi, user, | ||
295 | 737 | poweraddr, password, True) | ||
296 | 738 | |||
297 | 739 | def test_add_seamicro15k_end_to_end(self): | 685 | def test_add_seamicro15k_end_to_end(self): |
298 | 740 | nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ACCEPTED) | 686 | nodegroup = factory.make_NodeGroup(status=NODEGROUP_STATUS.ACCEPTED) |
299 | 741 | 687 | ||
300 | 742 | 688 | ||
301 | === modified file 'src/maasserver/static/js/angular/controllers/add_hardware.js' | |||
302 | --- src/maasserver/static/js/angular/controllers/add_hardware.js 2015-05-07 15:00:36 +0000 | |||
303 | +++ src/maasserver/static/js/angular/controllers/add_hardware.js 2015-05-14 16:27:22 +0000 | |||
304 | @@ -172,46 +172,8 @@ | |||
305 | 172 | fields: virshFields | 172 | fields: virshFields |
306 | 173 | }, | 173 | }, |
307 | 174 | { | 174 | { |
308 | 175 | name: 'esxi', | ||
309 | 176 | description: 'VMWare ESXi (virsh)', | ||
310 | 177 | fields: [ | ||
311 | 178 | { | ||
312 | 179 | name: 'address', | ||
313 | 180 | label: 'Address', | ||
314 | 181 | field_type: 'string', | ||
315 | 182 | "default": '', | ||
316 | 183 | choices: [], | ||
317 | 184 | required: true | ||
318 | 185 | }, | ||
319 | 186 | { | ||
320 | 187 | name: 'username', | ||
321 | 188 | label: 'Username', | ||
322 | 189 | field_type: 'string', | ||
323 | 190 | "default": '', | ||
324 | 191 | choices: [], | ||
325 | 192 | required: true | ||
326 | 193 | }, | ||
327 | 194 | { | ||
328 | 195 | name: 'password', | ||
329 | 196 | label: 'Password', | ||
330 | 197 | field_type: 'string', | ||
331 | 198 | "default": '', | ||
332 | 199 | choices: [], | ||
333 | 200 | required: true | ||
334 | 201 | }, | ||
335 | 202 | { | ||
336 | 203 | name: 'prefix_filter', | ||
337 | 204 | label: 'Prefix filter', | ||
338 | 205 | field_type: 'string', | ||
339 | 206 | "default": '', | ||
340 | 207 | choices: [], | ||
341 | 208 | required: false | ||
342 | 209 | } | ||
343 | 210 | ] | ||
344 | 211 | }, | ||
345 | 212 | { | ||
346 | 213 | name: 'vsphere', | 175 | name: 'vsphere', |
348 | 214 | description: 'VMWare (python-vmomi)', | 176 | description: 'VMWare', |
349 | 215 | fields: [ | 177 | fields: [ |
350 | 216 | { | 178 | { |
351 | 217 | name: 'host', | 179 | name: 'host', |
352 | 218 | 180 | ||
353 | === modified file 'src/maastesting/tests/test_scss.py' | |||
354 | --- src/maastesting/tests/test_scss.py 2015-05-12 12:38:12 +0000 | |||
355 | +++ src/maastesting/tests/test_scss.py 2015-05-14 16:27:22 +0000 | |||
356 | @@ -70,4 +70,4 @@ | |||
357 | 70 | tmp_css = self.read_content( | 70 | tmp_css = self.read_content( |
358 | 71 | os.path.join(output_dir, "maas-styles.css")) | 71 | os.path.join(output_dir, "maas-styles.css")) |
359 | 72 | if in_tree_css != tmp_css: | 72 | if in_tree_css != tmp_css: |
361 | 73 | self.fail("maas-styles.css is out-of-date.") | 73 | self.fail("maas-styles.css is out-of-date. (run 'make styles')") |
362 | 74 | 74 | ||
363 | === removed file 'src/provisioningserver/drivers/hardware/esxi.py' | |||
364 | --- src/provisioningserver/drivers/hardware/esxi.py 2015-05-07 18:14:38 +0000 | |||
365 | +++ src/provisioningserver/drivers/hardware/esxi.py 1970-01-01 00:00:00 +0000 | |||
366 | @@ -1,116 +0,0 @@ | |||
367 | 1 | # Copyright 2015 Canonical Ltd. This software is licensed under the | ||
368 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
369 | 3 | |||
370 | 4 | from __future__ import ( | ||
371 | 5 | absolute_import, | ||
372 | 6 | print_function, | ||
373 | 7 | unicode_literals, | ||
374 | 8 | ) | ||
375 | 9 | |||
376 | 10 | str = None | ||
377 | 11 | |||
378 | 12 | __metaclass__ = type | ||
379 | 13 | __all__ = [ | ||
380 | 14 | 'probe_esxi_and_enlist', | ||
381 | 15 | ] | ||
382 | 16 | |||
383 | 17 | from provisioningserver.drivers.hardware.virsh import ( | ||
384 | 18 | VirshSSH, | ||
385 | 19 | VirshVMState, | ||
386 | 20 | VM_STATE_TO_POWER_STATE, | ||
387 | 21 | ) | ||
388 | 22 | from provisioningserver.utils import ( | ||
389 | 23 | commission_node, | ||
390 | 24 | create_node, | ||
391 | 25 | ) | ||
392 | 26 | from provisioningserver.utils.twisted import synchronous | ||
393 | 27 | |||
394 | 28 | |||
395 | 29 | class ESXiError(Exception): | ||
396 | 30 | """Failure communicating to ESXi. """ | ||
397 | 31 | |||
398 | 32 | |||
399 | 33 | def compose_esxi_url(poweruser, poweraddr): | ||
400 | 34 | return "esx://%s@%s/?no_verify=1" % (poweruser, poweraddr) | ||
401 | 35 | |||
402 | 36 | |||
403 | 37 | @synchronous | ||
404 | 38 | def probe_esxi_and_enlist( | ||
405 | 39 | user, poweruser, poweraddr, password, | ||
406 | 40 | prefix_filter=None, accept_all=False): | ||
407 | 41 | """Extracts all of the virtual machines from virsh and enlists them | ||
408 | 42 | into MAAS. | ||
409 | 43 | |||
410 | 44 | :param user: user for the nodes. | ||
411 | 45 | :param poweraddr: IP Address of ESXi host. | ||
412 | 46 | :param password: password connection string. | ||
413 | 47 | :param prefix_filter: only enlist nodes that have the prefix. | ||
414 | 48 | :param accept_all: if True, commission enlisted nodes. | ||
415 | 49 | """ | ||
416 | 50 | conn = VirshSSH(dom_prefix=prefix_filter) | ||
417 | 51 | virsh_poweraddr = compose_esxi_url(poweruser, poweraddr) | ||
418 | 52 | if not conn.login(virsh_poweraddr, password): | ||
419 | 53 | raise ESXiError('Failed to login to virsh console.') | ||
420 | 54 | |||
421 | 55 | for machine in conn.list(): | ||
422 | 56 | arch = conn.get_arch(machine) | ||
423 | 57 | state = conn.get_state(machine) | ||
424 | 58 | macs = conn.get_mac_addresses(machine) | ||
425 | 59 | |||
426 | 60 | # Force the machine off, as MAAS will control the machine | ||
427 | 61 | # and it needs to be in a known state of off. | ||
428 | 62 | if state == VirshVMState.ON: | ||
429 | 63 | conn.poweroff(machine) | ||
430 | 64 | |||
431 | 65 | params = { | ||
432 | 66 | 'power_address': poweraddr, | ||
433 | 67 | 'power_user': poweruser, | ||
434 | 68 | 'power_id': machine, | ||
435 | 69 | 'power_pass': password, | ||
436 | 70 | } | ||
437 | 71 | system_id = create_node(macs, arch, 'esxi', params).wait(30) | ||
438 | 72 | |||
439 | 73 | if accept_all: | ||
440 | 74 | commission_node(system_id, user).wait(30) | ||
441 | 75 | |||
442 | 76 | conn.logout() | ||
443 | 77 | |||
444 | 78 | |||
445 | 79 | def power_control_esxi(poweraddr, machine, power_change, poweruser, password): | ||
446 | 80 | """Powers controls a virtual machine using virsh.""" | ||
447 | 81 | |||
448 | 82 | conn = VirshSSH() | ||
449 | 83 | virsh_poweraddr = compose_esxi_url(poweruser, poweraddr) | ||
450 | 84 | if not conn.login(virsh_poweraddr, password): | ||
451 | 85 | raise ESXiError('Failed to login to virsh console.') | ||
452 | 86 | |||
453 | 87 | state = conn.get_state(machine) | ||
454 | 88 | if state is None: | ||
455 | 89 | raise ESXiError('Failed to get virtual domain: %s' % machine) | ||
456 | 90 | |||
457 | 91 | if state == VirshVMState.OFF: | ||
458 | 92 | if power_change == 'on': | ||
459 | 93 | if not conn.poweron(machine): | ||
460 | 94 | raise ESXiError('Failed to power on domain: %s' % machine) | ||
461 | 95 | elif state == VirshVMState.ON: | ||
462 | 96 | if power_change == 'off': | ||
463 | 97 | if not conn.poweroff(machine): | ||
464 | 98 | raise ESXiError('Failed to power off domain: %s' % machine) | ||
465 | 99 | |||
466 | 100 | |||
467 | 101 | def power_state_esxi(poweraddr, machine, poweruser, password): | ||
468 | 102 | """Return the power state for the virtual machine using virsh.""" | ||
469 | 103 | |||
470 | 104 | conn = VirshSSH() | ||
471 | 105 | virsh_poweraddr = compose_esxi_url(poweruser, poweraddr) | ||
472 | 106 | if not conn.login(virsh_poweraddr, password): | ||
473 | 107 | raise ESXiError('Failed to login to virsh console.') | ||
474 | 108 | |||
475 | 109 | state = conn.get_state(machine) | ||
476 | 110 | if state is None: | ||
477 | 111 | raise ESXiError('Failed to get domain: %s' % machine) | ||
478 | 112 | |||
479 | 113 | try: | ||
480 | 114 | return VM_STATE_TO_POWER_STATE[state] | ||
481 | 115 | except KeyError: | ||
482 | 116 | raise ESXiError('Unknown power state: %s' % state) | ||
483 | 117 | 0 | ||
484 | === removed file 'src/provisioningserver/drivers/hardware/tests/test_esxi.py' | |||
485 | --- src/provisioningserver/drivers/hardware/tests/test_esxi.py 2015-05-07 18:14:38 +0000 | |||
486 | +++ src/provisioningserver/drivers/hardware/tests/test_esxi.py 1970-01-01 00:00:00 +0000 | |||
487 | @@ -1,315 +0,0 @@ | |||
488 | 1 | # Copyright 2015 Canonical Ltd. This software is licensed under the | ||
489 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
490 | 3 | |||
491 | 4 | """Tests for `provisioningserver.drivers.hardware.esxi`. | ||
492 | 5 | """ | ||
493 | 6 | |||
494 | 7 | from __future__ import ( | ||
495 | 8 | absolute_import, | ||
496 | 9 | print_function, | ||
497 | 10 | unicode_literals, | ||
498 | 11 | ) | ||
499 | 12 | |||
500 | 13 | str = None | ||
501 | 14 | |||
502 | 15 | __metaclass__ = type | ||
503 | 16 | __all__ = [] | ||
504 | 17 | |||
505 | 18 | from textwrap import dedent | ||
506 | 19 | |||
507 | 20 | from maastesting.factory import factory | ||
508 | 21 | from maastesting.matchers import ( | ||
509 | 22 | MockCalledOnceWith, | ||
510 | 23 | MockCalledWith, | ||
511 | 24 | MockCallsMatch, | ||
512 | 25 | ) | ||
513 | 26 | from maastesting.testcase import ( | ||
514 | 27 | MAASTestCase, | ||
515 | 28 | MAASTwistedRunTest, | ||
516 | 29 | ) | ||
517 | 30 | from mock import call | ||
518 | 31 | from provisioningserver.drivers.hardware import esxi as virsh | ||
519 | 32 | from provisioningserver.utils.twisted import asynchronous | ||
520 | 33 | from testtools.testcase import ExpectedException | ||
521 | 34 | from twisted.internet.defer import inlineCallbacks | ||
522 | 35 | from twisted.internet.threads import deferToThread | ||
523 | 36 | |||
524 | 37 | |||
525 | 38 | SAMPLE_IFLIST = dedent(""" | ||
526 | 39 | Interface Type Source Model MAC | ||
527 | 40 | ------------------------------------------------------- | ||
528 | 41 | - bridge br0 e1000 %s | ||
529 | 42 | - bridge br1 e1000 %s | ||
530 | 43 | """) | ||
531 | 44 | |||
532 | 45 | SAMPLE_DUMPXML = dedent(""" | ||
533 | 46 | <domain type='kvm'> | ||
534 | 47 | <name>test</name> | ||
535 | 48 | <memory unit='KiB'>4096576</memory> | ||
536 | 49 | <currentMemory unit='KiB'>4096576</currentMemory> | ||
537 | 50 | <vcpu placement='static'>1</vcpu> | ||
538 | 51 | <os> | ||
539 | 52 | <type arch='%s'>hvm</type> | ||
540 | 53 | <boot dev='network'/> | ||
541 | 54 | </os> | ||
542 | 55 | </domain> | ||
543 | 56 | """) | ||
544 | 57 | |||
545 | 58 | |||
546 | 59 | class TestESXi(MAASTestCase): | ||
547 | 60 | """Tests for `probe_esxi_and_enlist`.""" | ||
548 | 61 | |||
549 | 62 | run_tests_with = MAASTwistedRunTest.make_factory(timeout=5) | ||
550 | 63 | |||
551 | 64 | @inlineCallbacks | ||
552 | 65 | def test_probe_and_enlist(self): | ||
553 | 66 | # Patch VirshSSH list so that some machines are returned | ||
554 | 67 | # with some fake architectures. | ||
555 | 68 | user = factory.make_name('user') | ||
556 | 69 | system_id = factory.make_name('system_id') | ||
557 | 70 | machines = [factory.make_name('machine') for _ in range(3)] | ||
558 | 71 | self.patch(virsh.VirshSSH, 'list').return_value = machines | ||
559 | 72 | fake_arch = factory.make_name('arch') | ||
560 | 73 | mock_arch = self.patch(virsh.VirshSSH, 'get_arch') | ||
561 | 74 | mock_arch.return_value = fake_arch | ||
562 | 75 | |||
563 | 76 | # Patch get_state so that one of the machines is on, so we | ||
564 | 77 | # can check that it will be forced off. | ||
565 | 78 | fake_states = [ | ||
566 | 79 | virsh.VirshVMState.ON, | ||
567 | 80 | virsh.VirshVMState.OFF, | ||
568 | 81 | virsh.VirshVMState.OFF | ||
569 | 82 | ] | ||
570 | 83 | mock_state = self.patch(virsh.VirshSSH, 'get_state') | ||
571 | 84 | mock_state.side_effect = fake_states | ||
572 | 85 | |||
573 | 86 | # Setup the power parameters that we should expect to be | ||
574 | 87 | # the output of the probe_and_enlist | ||
575 | 88 | fake_password = factory.make_string() | ||
576 | 89 | poweruser = factory.make_name('poweruser') | ||
577 | 90 | poweraddr = factory.make_name('poweraddr') | ||
578 | 91 | esx_poweraddr = "esx://%s@%s/?no_verify=1" % (user, poweraddr) | ||
579 | 92 | called_params = [] | ||
580 | 93 | fake_macs = [] | ||
581 | 94 | for machine in machines: | ||
582 | 95 | macs = [factory.make_mac_address() for _ in range(3)] | ||
583 | 96 | fake_macs.append(macs) | ||
584 | 97 | called_params.append({ | ||
585 | 98 | 'power_address': poweraddr, | ||
586 | 99 | 'power_id': machine, | ||
587 | 100 | 'power_pass': fake_password, | ||
588 | 101 | 'power_user': poweruser, | ||
589 | 102 | }) | ||
590 | 103 | |||
591 | 104 | # Patch the get_mac_addresses so we get a known list of | ||
592 | 105 | # mac addresses for each machine. | ||
593 | 106 | mock_macs = self.patch(virsh.VirshSSH, 'get_mac_addresses') | ||
594 | 107 | mock_macs.side_effect = fake_macs | ||
595 | 108 | |||
596 | 109 | # Patch the poweroff and create as we really don't want these | ||
597 | 110 | # actions to occur, but want to also check that they are called. | ||
598 | 111 | mock_poweroff = self.patch(virsh.VirshSSH, 'poweroff') | ||
599 | 112 | mock_create_node = self.patch(virsh, 'create_node') | ||
600 | 113 | mock_create_node.side_effect = asynchronous(lambda *args: system_id) | ||
601 | 114 | mock_commission_node = self.patch(virsh, 'commission_node') | ||
602 | 115 | |||
603 | 116 | # Patch login and logout so that we don't really contact | ||
604 | 117 | # a server at the fake poweraddr | ||
605 | 118 | mock_login = self.patch(virsh.VirshSSH, 'login') | ||
606 | 119 | mock_login.return_value = True | ||
607 | 120 | mock_logout = self.patch(virsh.VirshSSH, 'logout') | ||
608 | 121 | |||
609 | 122 | # Perform the probe and enlist | ||
610 | 123 | yield deferToThread( | ||
611 | 124 | virsh.probe_esxi_and_enlist, user, poweruser, poweraddr, | ||
612 | 125 | password=fake_password, accept_all=True) | ||
613 | 126 | |||
614 | 127 | # Check that login was called with the provided poweraddr and | ||
615 | 128 | # password. | ||
616 | 129 | self.expectThat( | ||
617 | 130 | mock_login, MockCalledOnceWith(esx_poweraddr, fake_password)) | ||
618 | 131 | |||
619 | 132 | # The first machine should have poweroff called on it, as it | ||
620 | 133 | # was initial in the on state. | ||
621 | 134 | self.expectThat( | ||
622 | 135 | mock_poweroff, MockCalledOnceWith(machines[0])) | ||
623 | 136 | |||
624 | 137 | # Check that the create command had the correct parameters for | ||
625 | 138 | # each machine. | ||
626 | 139 | self.expectThat( | ||
627 | 140 | mock_create_node, MockCallsMatch( | ||
628 | 141 | call( | ||
629 | 142 | fake_macs[0], fake_arch, 'esxi', called_params[0]), | ||
630 | 143 | call( | ||
631 | 144 | fake_macs[1], fake_arch, 'esxi', called_params[1]), | ||
632 | 145 | call( | ||
633 | 146 | fake_macs[2], fake_arch, | ||
634 | 147 | 'esxi', called_params[2]))) | ||
635 | 148 | mock_logout.assert_called() | ||
636 | 149 | self.expectThat( | ||
637 | 150 | mock_commission_node, | ||
638 | 151 | MockCalledWith(system_id, user)) | ||
639 | 152 | |||
640 | 153 | @inlineCallbacks | ||
641 | 154 | def test_probe_and_enlist_login_failure(self): | ||
642 | 155 | user = factory.make_name('user') | ||
643 | 156 | poweruser = factory.make_name('poweruser') | ||
644 | 157 | poweraddr = factory.make_name('poweraddr') | ||
645 | 158 | mock_login = self.patch(virsh.VirshSSH, 'login') | ||
646 | 159 | mock_login.return_value = False | ||
647 | 160 | with ExpectedException(virsh.ESXiError): | ||
648 | 161 | yield deferToThread( | ||
649 | 162 | virsh.probe_esxi_and_enlist, | ||
650 | 163 | user, poweruser, poweraddr, password=factory.make_string()) | ||
651 | 164 | |||
652 | 165 | |||
653 | 166 | class TestESXiPowerControl(MAASTestCase): | ||
654 | 167 | """Tests for `power_control_esxi`.""" | ||
655 | 168 | |||
656 | 169 | def test_power_control_login_failure(self): | ||
657 | 170 | mock_login = self.patch(virsh.VirshSSH, 'login') | ||
658 | 171 | mock_login.return_value = False | ||
659 | 172 | self.assertRaises( | ||
660 | 173 | virsh.ESXiError, virsh.power_control_esxi, | ||
661 | 174 | factory.make_name('poweraddr'), factory.make_name('machine'), 'on', | ||
662 | 175 | factory.make_name('username'), password=factory.make_string()) | ||
663 | 176 | |||
664 | 177 | def test_power_control_on(self): | ||
665 | 178 | mock_login = self.patch(virsh.VirshSSH, 'login') | ||
666 | 179 | mock_login.return_value = True | ||
667 | 180 | mock_state = self.patch(virsh.VirshSSH, 'get_state') | ||
668 | 181 | mock_state.return_value = virsh.VirshVMState.OFF | ||
669 | 182 | mock_poweron = self.patch(virsh.VirshSSH, 'poweron') | ||
670 | 183 | |||
671 | 184 | poweraddr = factory.make_name('poweraddr') | ||
672 | 185 | machine = factory.make_name('machine') | ||
673 | 186 | username = factory.make_name('user') | ||
674 | 187 | password = factory.make_string() | ||
675 | 188 | esx_poweraddr = "esx://%s@%s/?no_verify=1" % (username, poweraddr) | ||
676 | 189 | virsh.power_control_esxi(poweraddr, machine, 'on', username, password) | ||
677 | 190 | |||
678 | 191 | self.assertThat( | ||
679 | 192 | mock_login, MockCalledOnceWith(esx_poweraddr, password)) | ||
680 | 193 | self.assertThat( | ||
681 | 194 | mock_state, MockCalledOnceWith(machine)) | ||
682 | 195 | self.assertThat( | ||
683 | 196 | mock_poweron, MockCalledOnceWith(machine)) | ||
684 | 197 | |||
685 | 198 | def test_power_control_off(self): | ||
686 | 199 | mock_login = self.patch(virsh.VirshSSH, 'login') | ||
687 | 200 | mock_login.return_value = True | ||
688 | 201 | mock_state = self.patch(virsh.VirshSSH, 'get_state') | ||
689 | 202 | mock_state.return_value = virsh.VirshVMState.ON | ||
690 | 203 | mock_poweroff = self.patch(virsh.VirshSSH, 'poweroff') | ||
691 | 204 | |||
692 | 205 | poweraddr = factory.make_name('poweraddr') | ||
693 | 206 | machine = factory.make_name('machine') | ||
694 | 207 | username = factory.make_name('user') | ||
695 | 208 | password = factory.make_string() | ||
696 | 209 | esx_poweraddr = "esx://%s@%s/?no_verify=1" % (username, poweraddr) | ||
697 | 210 | virsh.power_control_esxi(poweraddr, machine, 'off', username, password) | ||
698 | 211 | |||
699 | 212 | self.assertThat( | ||
700 | 213 | mock_login, MockCalledOnceWith(esx_poweraddr, password)) | ||
701 | 214 | self.assertThat( | ||
702 | 215 | mock_state, MockCalledOnceWith(machine)) | ||
703 | 216 | self.assertThat( | ||
704 | 217 | mock_poweroff, MockCalledOnceWith(machine)) | ||
705 | 218 | |||
706 | 219 | def test_power_control_bad_domain(self): | ||
707 | 220 | mock_login = self.patch(virsh.VirshSSH, 'login') | ||
708 | 221 | mock_login.return_value = True | ||
709 | 222 | mock_state = self.patch(virsh.VirshSSH, 'get_state') | ||
710 | 223 | mock_state.return_value = None | ||
711 | 224 | |||
712 | 225 | poweraddr = factory.make_name('poweraddr') | ||
713 | 226 | machine = factory.make_name('machine') | ||
714 | 227 | username = factory.make_name('user') | ||
715 | 228 | password = factory.make_string() | ||
716 | 229 | self.assertRaises( | ||
717 | 230 | virsh.ESXiError, virsh.power_control_esxi, | ||
718 | 231 | poweraddr, machine, 'on', username, password) | ||
719 | 232 | |||
720 | 233 | def test_power_control_power_failure(self): | ||
721 | 234 | mock_login = self.patch(virsh.VirshSSH, 'login') | ||
722 | 235 | mock_login.return_value = True | ||
723 | 236 | mock_state = self.patch(virsh.VirshSSH, 'get_state') | ||
724 | 237 | mock_state.return_value = virsh.VirshVMState.ON | ||
725 | 238 | mock_poweroff = self.patch(virsh.VirshSSH, 'poweroff') | ||
726 | 239 | mock_poweroff.return_value = False | ||
727 | 240 | |||
728 | 241 | poweraddr = factory.make_name('poweraddr') | ||
729 | 242 | machine = factory.make_name('machine') | ||
730 | 243 | username = factory.make_name('user') | ||
731 | 244 | password = factory.make_string() | ||
732 | 245 | self.assertRaises( | ||
733 | 246 | virsh.ESXiError, virsh.power_control_esxi, | ||
734 | 247 | poweraddr, machine, 'off', username, password) | ||
735 | 248 | |||
736 | 249 | |||
737 | 250 | class TestESXiPowerState(MAASTestCase): | ||
738 | 251 | """Tests for `power_state_esxi`.""" | ||
739 | 252 | |||
740 | 253 | def test_power_state_login_failure(self): | ||
741 | 254 | mock_login = self.patch(virsh.VirshSSH, 'login') | ||
742 | 255 | mock_login.return_value = False | ||
743 | 256 | self.assertRaises( | ||
744 | 257 | virsh.ESXiError, virsh.power_state_esxi, | ||
745 | 258 | factory.make_name('poweraddr'), factory.make_name('machine'), | ||
746 | 259 | factory.make_name('user'), password=factory.make_string()) | ||
747 | 260 | |||
748 | 261 | def test_power_state_get_on(self): | ||
749 | 262 | mock_login = self.patch(virsh.VirshSSH, 'login') | ||
750 | 263 | mock_login.return_value = True | ||
751 | 264 | mock_state = self.patch(virsh.VirshSSH, 'get_state') | ||
752 | 265 | mock_state.return_value = virsh.VirshVMState.ON | ||
753 | 266 | |||
754 | 267 | poweraddr = factory.make_name('poweraddr') | ||
755 | 268 | machine = factory.make_name('machine') | ||
756 | 269 | username = factory.make_name('user') | ||
757 | 270 | password = factory.make_string() | ||
758 | 271 | self.assertEqual( | ||
759 | 272 | 'on', virsh.power_state_esxi(poweraddr, machine, | ||
760 | 273 | username, password)) | ||
761 | 274 | |||
762 | 275 | def test_power_state_get_off(self): | ||
763 | 276 | mock_login = self.patch(virsh.VirshSSH, 'login') | ||
764 | 277 | mock_login.return_value = True | ||
765 | 278 | mock_state = self.patch(virsh.VirshSSH, 'get_state') | ||
766 | 279 | mock_state.return_value = virsh.VirshVMState.OFF | ||
767 | 280 | |||
768 | 281 | poweraddr = factory.make_name('poweraddr') | ||
769 | 282 | machine = factory.make_name('machine') | ||
770 | 283 | username = factory.make_name('user') | ||
771 | 284 | password = factory.make_string() | ||
772 | 285 | self.assertEqual( | ||
773 | 286 | 'off', virsh.power_state_esxi(poweraddr, machine, | ||
774 | 287 | username, password)) | ||
775 | 288 | |||
776 | 289 | def test_power_control_bad_domain(self): | ||
777 | 290 | mock_login = self.patch(virsh.VirshSSH, 'login') | ||
778 | 291 | mock_login.return_value = True | ||
779 | 292 | mock_state = self.patch(virsh.VirshSSH, 'get_state') | ||
780 | 293 | mock_state.return_value = None | ||
781 | 294 | |||
782 | 295 | poweraddr = factory.make_name('poweraddr') | ||
783 | 296 | machine = factory.make_name('machine') | ||
784 | 297 | username = factory.make_name('user') | ||
785 | 298 | password = factory.make_string() | ||
786 | 299 | self.assertRaises( | ||
787 | 300 | virsh.ESXiError, virsh.power_state_esxi, | ||
788 | 301 | poweraddr, machine, username, password) | ||
789 | 302 | |||
790 | 303 | def test_power_state_error_on_unknown_state(self): | ||
791 | 304 | mock_login = self.patch(virsh.VirshSSH, 'login') | ||
792 | 305 | mock_login.return_value = True | ||
793 | 306 | mock_state = self.patch(virsh.VirshSSH, 'get_state') | ||
794 | 307 | mock_state.return_value = 'unknown' | ||
795 | 308 | |||
796 | 309 | poweraddr = factory.make_name('poweraddr') | ||
797 | 310 | machine = factory.make_name('machine') | ||
798 | 311 | username = factory.make_name('user') | ||
799 | 312 | password = factory.make_string() | ||
800 | 313 | self.assertRaises( | ||
801 | 314 | virsh.ESXiError, virsh.power_state_esxi, | ||
802 | 315 | poweraddr, machine, username, password) | ||
803 | 316 | 0 | ||
804 | === modified file 'src/provisioningserver/power_schema.py' | |||
805 | --- src/provisioningserver/power_schema.py 2015-05-07 18:14:38 +0000 | |||
806 | +++ src/provisioningserver/power_schema.py 2015-05-14 16:27:22 +0000 | |||
807 | @@ -174,18 +174,8 @@ | |||
808 | 174 | ], | 174 | ], |
809 | 175 | }, | 175 | }, |
810 | 176 | { | 176 | { |
811 | 177 | 'name': 'esxi', | ||
812 | 178 | 'description': 'VMWare ESXi (virsh)', | ||
813 | 179 | 'fields': [ | ||
814 | 180 | make_json_field('power_address', "Power address"), | ||
815 | 181 | make_json_field('power_id', "Power ID"), | ||
816 | 182 | make_json_field('power_user', "Power user"), | ||
817 | 183 | make_json_field('power_pass', "Power password"), | ||
818 | 184 | ], | ||
819 | 185 | }, | ||
820 | 186 | { | ||
821 | 187 | 'name': 'vsphere', | 177 | 'name': 'vsphere', |
823 | 188 | 'description': 'VMWare (python-pyvmomi)', | 178 | 'description': 'VMWare', |
824 | 189 | 'fields': [ | 179 | 'fields': [ |
825 | 190 | make_json_field( | 180 | make_json_field( |
826 | 191 | 'power_vm_name', "VM Name (if UUID unknown)", required=False), | 181 | 'power_vm_name', "VM Name (if UUID unknown)", required=False), |
827 | 192 | 182 | ||
828 | === modified file 'src/provisioningserver/rpc/clusterservice.py' | |||
829 | --- src/provisioningserver/rpc/clusterservice.py 2015-05-07 18:14:38 +0000 | |||
830 | +++ src/provisioningserver/rpc/clusterservice.py 2015-05-14 16:27:22 +0000 | |||
831 | @@ -34,7 +34,6 @@ | |||
832 | 34 | ArchitectureRegistry, | 34 | ArchitectureRegistry, |
833 | 35 | PowerTypeRegistry, | 35 | PowerTypeRegistry, |
834 | 36 | ) | 36 | ) |
835 | 37 | from provisioningserver.drivers.hardware.esxi import probe_esxi_and_enlist | ||
836 | 38 | from provisioningserver.drivers.hardware.mscm import probe_and_enlist_mscm | 37 | from provisioningserver.drivers.hardware.mscm import probe_and_enlist_mscm |
837 | 39 | from provisioningserver.drivers.hardware.msftocs import ( | 38 | from provisioningserver.drivers.hardware.msftocs import ( |
838 | 40 | probe_and_enlist_msftocs, | 39 | probe_and_enlist_msftocs, |
839 | @@ -368,19 +367,6 @@ | |||
840 | 368 | d.addErrback(partial(catch_probe_and_enlist_error, "virsh")) | 367 | d.addErrback(partial(catch_probe_and_enlist_error, "virsh")) |
841 | 369 | return {} | 368 | return {} |
842 | 370 | 369 | ||
843 | 371 | @cluster.AddESXi.responder | ||
844 | 372 | def add_esxi(self, user, poweruser, poweraddr, | ||
845 | 373 | password, prefix_filter, accept_all): | ||
846 | 374 | """add_esxi() | ||
847 | 375 | |||
848 | 376 | Implementation of :py:class:`~provisioningserver.rpc.cluster.AddESXi`. | ||
849 | 377 | """ | ||
850 | 378 | d = deferToThread( | ||
851 | 379 | probe_esxi_and_enlist, | ||
852 | 380 | user, poweruser, poweraddr, password, prefix_filter, accept_all) | ||
853 | 381 | d.addErrback(partial(catch_probe_and_enlist_error, "esxi")) | ||
854 | 382 | return {} | ||
855 | 383 | |||
856 | 384 | @cluster.AddSeaMicro15k.responder | 370 | @cluster.AddSeaMicro15k.responder |
857 | 385 | def add_seamicro15k(self, user, mac, username, | 371 | def add_seamicro15k(self, user, mac, username, |
858 | 386 | password, power_control, accept_all): | 372 | password, power_control, accept_all): |
859 | @@ -417,7 +403,7 @@ | |||
860 | 417 | port=port, protocol=protocol, prefix_filter=prefix_filter, | 403 | port=port, protocol=protocol, prefix_filter=prefix_filter, |
861 | 418 | accept_all=accept_all) | 404 | accept_all=accept_all) |
862 | 419 | d.addErrback( | 405 | d.addErrback( |
864 | 420 | partial(catch_probe_and_enlist_error, "vSphere")) | 406 | partial(catch_probe_and_enlist_error, "VMware")) |
865 | 421 | return {} | 407 | return {} |
866 | 422 | 408 | ||
867 | 423 | @cluster.EnlistNodesFromMSCM.responder | 409 | @cluster.EnlistNodesFromMSCM.responder |
868 | 424 | 410 | ||
869 | === modified file 'src/provisioningserver/rpc/power.py' | |||
870 | --- src/provisioningserver/rpc/power.py 2015-05-12 16:12:15 +0000 | |||
871 | +++ src/provisioningserver/rpc/power.py 2015-05-14 16:27:22 +0000 | |||
872 | @@ -67,7 +67,6 @@ | |||
873 | 67 | QUERY_POWER_TYPES = [ | 67 | QUERY_POWER_TYPES = [ |
874 | 68 | 'amt', | 68 | 'amt', |
875 | 69 | 'dli', | 69 | 'dli', |
876 | 70 | 'esxi', | ||
877 | 71 | 'ipmi', | 70 | 'ipmi', |
878 | 72 | 'mscm', | 71 | 'mscm', |
879 | 73 | 'msftocs', | 72 | 'msftocs', |
880 | 74 | 73 | ||
881 | === modified file 'src/provisioningserver/rpc/tests/test_clusterservice.py' | |||
882 | --- src/provisioningserver/rpc/tests/test_clusterservice.py 2015-05-07 18:14:38 +0000 | |||
883 | +++ src/provisioningserver/rpc/tests/test_clusterservice.py 2015-05-14 16:27:22 +0000 | |||
884 | @@ -2082,63 +2082,7 @@ | |||
885 | 2082 | clusterservice.maaslog.error, | 2082 | clusterservice.maaslog.error, |
886 | 2083 | MockAnyCall( | 2083 | MockAnyCall( |
887 | 2084 | "Failed to probe and enlist %s nodes: %s", | 2084 | "Failed to probe and enlist %s nodes: %s", |
945 | 2085 | "vSphere", fake_error)) | 2085 | "VMware", fake_error)) |
889 | 2086 | |||
890 | 2087 | |||
891 | 2088 | class TestClusterProtocol_AddESXi(MAASTestCase): | ||
892 | 2089 | |||
893 | 2090 | def test__is_registered(self): | ||
894 | 2091 | protocol = Cluster() | ||
895 | 2092 | responder = protocol.locateResponder( | ||
896 | 2093 | cluster.AddESXi.commandName) | ||
897 | 2094 | self.assertIsNotNone(responder) | ||
898 | 2095 | |||
899 | 2096 | def test__calls_deferToThread_with_probe_esxi_and_enlist(self): | ||
900 | 2097 | mock_deferToThread = self.patch_autospec( | ||
901 | 2098 | clusterservice, 'deferToThread') | ||
902 | 2099 | user = factory.make_name('user') | ||
903 | 2100 | poweruser = factory.make_name('poweruser') | ||
904 | 2101 | poweraddr = factory.make_name('poweraddr') | ||
905 | 2102 | password = factory.make_name('password') | ||
906 | 2103 | prefix_filter = factory.make_name('prefix_filter') | ||
907 | 2104 | call_responder(Cluster(), cluster.AddESXi, { | ||
908 | 2105 | "user": user, | ||
909 | 2106 | "poweruser": poweruser, | ||
910 | 2107 | "poweraddr": poweraddr, | ||
911 | 2108 | "password": password, | ||
912 | 2109 | "prefix_filter": prefix_filter, | ||
913 | 2110 | "accept_all": True, | ||
914 | 2111 | }) | ||
915 | 2112 | self.assertThat( | ||
916 | 2113 | mock_deferToThread, MockCalledOnceWith( | ||
917 | 2114 | clusterservice.probe_esxi_and_enlist, | ||
918 | 2115 | user, poweruser, poweraddr, password, | ||
919 | 2116 | prefix_filter, True)) | ||
920 | 2117 | |||
921 | 2118 | def test__logs_error_to_maaslog(self): | ||
922 | 2119 | fake_error = factory.make_name('error') | ||
923 | 2120 | self.patch(clusterservice, 'maaslog') | ||
924 | 2121 | mock_deferToThread = self.patch_autospec( | ||
925 | 2122 | clusterservice, 'deferToThread') | ||
926 | 2123 | mock_deferToThread.return_value = fail(Exception(fake_error)) | ||
927 | 2124 | user = factory.make_name('user') | ||
928 | 2125 | poweruser = factory.make_name('poweruser') | ||
929 | 2126 | poweraddr = factory.make_name('poweraddr') | ||
930 | 2127 | password = factory.make_name('password') | ||
931 | 2128 | prefix_filter = factory.make_name('prefix_filter') | ||
932 | 2129 | call_responder(Cluster(), cluster.AddESXi, { | ||
933 | 2130 | "user": user, | ||
934 | 2131 | "poweruser": poweruser, | ||
935 | 2132 | "poweraddr": poweraddr, | ||
936 | 2133 | "password": password, | ||
937 | 2134 | "prefix_filter": prefix_filter, | ||
938 | 2135 | "accept_all": True, | ||
939 | 2136 | }) | ||
940 | 2137 | self.assertThat( | ||
941 | 2138 | clusterservice.maaslog.error, | ||
942 | 2139 | MockAnyCall( | ||
943 | 2140 | "Failed to probe and enlist %s nodes: %s", | ||
944 | 2141 | "esxi", fake_error)) | ||
946 | 2142 | 2086 | ||
947 | 2143 | 2087 | ||
948 | 2144 | class TestClusterProtocol_AddSeaMicro15k(MAASTestCase): | 2088 | class TestClusterProtocol_AddSeaMicro15k(MAASTestCase): |
lgtm!