Merge lp:~newell-jensen/maas/add-mscm-power-query-bug-1384428 into lp:~maas-committers/maas/trunk

Proposed by Newell Jensen
Status: Merged
Approved by: Newell Jensen
Approved revision: no longer in the source branch.
Merged at revision: 3325
Proposed branch: lp:~newell-jensen/maas/add-mscm-power-query-bug-1384428
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 545 lines (+259/-128)
4 files modified
etc/maas/templates/power/mscm.template (+58/-8)
src/provisioningserver/drivers/hardware/mscm.py (+44/-15)
src/provisioningserver/drivers/hardware/tests/test_mscm.py (+156/-104)
src/provisioningserver/rpc/power.py (+1/-1)
To merge this branch: bzr merge lp:~newell-jensen/maas/add-mscm-power-query-bug-1384428
Reviewer Review Type Date Requested Status
Raphaël Badin (community) Approve
Blake Rouse (community) Approve
Review via email: mp+239917@code.launchpad.net

Commit message

This branch adds power querying capabilities to MSCM. Many of the tests for MSCM have also been cleaned up and reorganized.

Description of the change

This was tested with packages on an MSCM system.

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

This passed CI testing as well.

Revision history for this message
Christian Reis (kiko) wrote :

Could you ask Sean F. or Narinder to test this?

Revision history for this message
Newell Jensen (newell-jensen) wrote :

Kiko,

Sean tested it and says it works good. I also tested it.

Revision history for this message
Sean Feole (sfeole) wrote :

Tested and verified on maas 1.7

Revision history for this message
Blake Rouse (blake-rouse) wrote :

Looks great.

Only one comment inline.

review: Approve
Revision history for this message
Raphaël Badin (rvb) wrote :

Looks good, couple of remarks but nothing major.

review: Approve
Revision history for this message
Newell Jensen (newell-jensen) wrote :

In commit I said "fixed error" but should have said "fixed exception message".

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'etc/maas/templates/power/mscm.template'
--- etc/maas/templates/power/mscm.template 2014-07-18 17:05:57 +0000
+++ etc/maas/templates/power/mscm.template 2014-10-30 20:06:36 +0000
@@ -2,13 +2,63 @@
2#2#
3# Control a system via Moonshot HP iLO Chassis Manager (MSCM).3# Control a system via Moonshot HP iLO Chassis Manager (MSCM).
44
5# Exit with failure message.
6# Parameters: exit code, and error message.
7fail() {
8 echo "$2" >&2
9 exit $1
10}
11
12issue_mscm_command() {
5python - << END13python - << END
14import sys
6from provisioningserver.drivers.hardware.mscm import power_control_mscm15from provisioningserver.drivers.hardware.mscm import power_control_mscm
7power_control_mscm(16try:
8 {{escape_py_literal(power_address) | safe}},17 power_control_mscm(
9 {{escape_py_literal(power_user) | safe}},18 {{escape_py_literal(power_address) | safe}},
10 {{escape_py_literal(power_pass) | safe}},19 {{escape_py_literal(power_user) | safe}},
11 {{escape_py_literal(node_id) | safe}},20 {{escape_py_literal(power_pass) | safe}},
12 {{escape_py_literal(power_change) | safe}},21 {{escape_py_literal(node_id) | safe}},
13)22 {{escape_py_literal(power_change) | safe}},
14END23 )
24except Exception as e:
25 # This gets in the node event log: print the exception's message
26 # and not the stacktrace.
27 print(unicode(e))
28 sys.exit(1)
29END
30}
31
32query_state() {
33python - << END
34import sys
35from provisioningserver.drivers.hardware.mscm import power_state_mscm
36try:
37 print(power_state_mscm(
38 {{escape_py_literal(power_address) | safe}},
39 {{escape_py_literal(power_user) | safe}},
40 {{escape_py_literal(power_pass) | safe}},
41 {{escape_py_literal(node_id) | safe}},
42 ))
43except Exception as e:
44 # This gets in the node event log: print the exception's message
45 # and not the stacktrace.
46 print(unicode(e))
47 sys.exit(1)
48END
49}
50
51main() {
52 case $1 in
53 'on'|'off')
54 issue_mscm_command
55 ;;
56 'query')
57 query_state
58 ;;
59 *)
60 fail 2 "Unknown power command: '$1'"
61 esac
62}
63
64main "{{power_change}}"
1565
=== modified file 'src/provisioningserver/drivers/hardware/mscm.py'
--- src/provisioningserver/drivers/hardware/mscm.py 2014-09-24 22:20:11 +0000
+++ src/provisioningserver/drivers/hardware/mscm.py 2014-10-30 20:06:36 +0000
@@ -18,6 +18,7 @@
18__metaclass__ = type18__metaclass__ = type
19__all__ = [19__all__ = [
20 'power_control_mscm',20 'power_control_mscm',
21 'power_state_mscm',
21 'probe_and_enlist_mscm',22 'probe_and_enlist_mscm',
22]23]
2324
@@ -43,6 +44,15 @@
43}44}
4445
4546
47class MSCMState:
48 OFF = "Off"
49 ON = "On"
50
51
52class MSCMError(Exception):
53 """Failure communicating to MSCM. """
54
55
46class MSCM_CLI_API:56class MSCM_CLI_API:
47 """An API for interacting with the Moonshot iLO CM CLI."""57 """An API for interacting with the Moonshot iLO CM CLI."""
4858
@@ -117,7 +127,7 @@
117 else:127 else:
118 return cartridge_mapping['Default']128 return cartridge_mapping['Default']
119129
120 def get_node_power_status(self, node_id):130 def get_node_power_state(self, node_id):
121 """Get power state of node (on/off).131 """Get power state of node (on/off).
122132
123 Example of stdout from running "show node power <node_id>":133 Example of stdout from running "show node power <node_id>":
@@ -152,30 +162,49 @@
152 of 'mscm'.162 of 'mscm'.
153 """163 """
154 mscm = MSCM_CLI_API(host, username, password)164 mscm = MSCM_CLI_API(host, username, password)
155 power_status = mscm.get_node_power_status(node_id)
156165
157 if power_change == 'off':166 if power_change == 'off':
158 mscm.power_node_off(node_id)167 mscm.power_node_off(node_id)
159 return168 elif power_change == 'on':
160169 if mscm.get_node_power_state(node_id) == MSCMState.ON:
161 if power_change != 'on':170 mscm.power_node_off(node_id)
162 raise AssertionError('Unexpected maas power mode.')171 mscm.configure_node_bootonce_pxe(node_id)
163172 mscm.power_node_on(node_id)
164 if power_status == 'On':173 else:
165 mscm.power_node_off(node_id)174 raise MSCMError("Unexpected maas power mode.")
166175
167 mscm.configure_node_bootonce_pxe(node_id)176
168 mscm.power_node_on(node_id)177def power_state_mscm(host, username, password, node_id):
178 """Return the power state for the mscm machine."""
179 mscm = MSCM_CLI_API(host, username, password)
180 try:
181 power_state = mscm.get_node_power_state(node_id)
182 except:
183 raise MSCMError("Failed to retrieve power state.")
184
185 if power_state == MSCMState.OFF:
186 return 'off'
187 elif power_state == MSCMState.ON:
188 return 'on'
189 raise MSCMError('Unknown power state: %s' % power_state)
169190
170191
171def probe_and_enlist_mscm(host, username, password):192def probe_and_enlist_mscm(host, username, password):
172 """ Extracts all of nodes from mscm, sets all of them to boot via HDD by,193 """ Extracts all of nodes from mscm, sets all of them to boot via M.2 by,
173 default, sets them to bootonce via PXE, and then enlists them into MAAS.194 default, sets them to bootonce via PXE, and then enlists them into MAAS.
174 """195 """
175 mscm = MSCM_CLI_API(host, username, password)196 mscm = MSCM_CLI_API(host, username, password)
176 nodes = mscm.discover_nodes()197 try:
198 # if discover_nodes works, we have access to the system
199 nodes = mscm.discover_nodes()
200 except:
201 raise MSCMError(
202 "Failed to probe nodes for mscm with host=%s, "
203 "username=%s, password=%s"
204 % (host, username, password))
205
177 for node_id in nodes:206 for node_id in nodes:
178 # Set default boot to HDD207 # Set default boot to M.2
179 mscm.configure_node_boot_m2(node_id)208 mscm.configure_node_boot_m2(node_id)
180 params = {209 params = {
181 'power_address': host,210 'power_address': host,
182211
=== modified file 'src/provisioningserver/drivers/hardware/tests/test_mscm.py'
--- src/provisioningserver/drivers/hardware/tests/test_mscm.py 2014-09-18 12:44:38 +0000
+++ src/provisioningserver/drivers/hardware/tests/test_mscm.py 2014-10-30 20:06:36 +0000
@@ -19,16 +19,24 @@
19from StringIO import StringIO19from StringIO import StringIO
2020
21from maastesting.factory import factory21from maastesting.factory import factory
22from maastesting.matchers import MockCalledOnceWith22from maastesting.matchers import (
23 MockAnyCall,
24 MockCalledOnceWith,
25 MockCalledWith,
26 )
23from maastesting.testcase import MAASTestCase27from maastesting.testcase import MAASTestCase
24from mock import Mock28from mock import Mock
25from provisioningserver.drivers.hardware.mscm import (29from provisioningserver.drivers.hardware.mscm import (
26 cartridge_mapping,30 cartridge_mapping,
27 MSCM_CLI_API,31 MSCM_CLI_API,
32 MSCMError,
33 MSCMState,
28 power_control_mscm,34 power_control_mscm,
35 power_state_mscm,
29 probe_and_enlist_mscm,36 probe_and_enlist_mscm,
30 )37 )
31import provisioningserver.utils as utils38import provisioningserver.utils as utils
39from testtools.matchers import Equals
3240
3341
34def make_mscm_api():42def make_mscm_api():
@@ -56,10 +64,19 @@
56 for _ in xrange(length))64 for _ in xrange(length))
5765
5866
59class TestRunCliCommand(MAASTestCase):67class TestMSCMCliApi(MAASTestCase):
60 """Tests for ``MSCM_CLI_API.run_cli_command``."""68 """Tests for `MSCM_CLI_API`."""
6169
62 def test_returns_output(self):70 scenarios = [
71 ('power_node_on',
72 dict(method='power_node_on')),
73 ('power_node_off',
74 dict(method='power_node_off')),
75 ('configure_node_bootonce_pxe',
76 dict(method='configure_node_bootonce_pxe')),
77 ]
78
79 def test_run_cli_command_returns_output(self):
63 api = make_mscm_api()80 api = make_mscm_api()
64 ssh_mock = self.patch(api, '_ssh')81 ssh_mock = self.patch(api, '_ssh')
65 expected = factory.make_name('output')82 expected = factory.make_name('output')
@@ -69,18 +86,18 @@
69 output = api._run_cli_command(factory.make_name('command'))86 output = api._run_cli_command(factory.make_name('command'))
70 self.assertEqual(expected, output)87 self.assertEqual(expected, output)
7188
72 def test_connects_and_closes_ssh_client(self):89 def test_run_cli_command_connects_and_closes_ssh_client(self):
73 api = make_mscm_api()90 api = make_mscm_api()
74 ssh_mock = self.patch(api, '_ssh')91 ssh_mock = self.patch(api, '_ssh')
75 ssh_mock.exec_command = Mock(return_value=factory.make_streams())92 ssh_mock.exec_command = Mock(return_value=factory.make_streams())
76 api._run_cli_command(factory.make_name('command'))93 api._run_cli_command(factory.make_name('command'))
77 self.assertThat(94 self.expectThat(
78 ssh_mock.connect,95 ssh_mock.connect,
79 MockCalledOnceWith(96 MockCalledOnceWith(
80 api.host, username=api.username, password=api.password))97 api.host, username=api.username, password=api.password))
81 self.assertThat(ssh_mock.close, MockCalledOnceWith())98 self.expectThat(ssh_mock.close, MockCalledOnceWith())
8299
83 def test_closes_when_exception_raised(self):100 def test_run_cli_command_closes_when_exception_raised(self):
84 api = make_mscm_api()101 api = make_mscm_api()
85 ssh_mock = self.patch(api, '_ssh')102 ssh_mock = self.patch(api, '_ssh')
86103
@@ -90,11 +107,7 @@
90 ssh_mock.exec_command = Mock(side_effect=fail)107 ssh_mock.exec_command = Mock(side_effect=fail)
91 command = factory.make_name('command')108 command = factory.make_name('command')
92 self.assertRaises(Exception, api._run_cli_command, command)109 self.assertRaises(Exception, api._run_cli_command, command)
93 self.assertThat(ssh_mock.close, MockCalledOnceWith())110 self.expectThat(ssh_mock.close, MockCalledOnceWith())
94
95
96class TestDiscoverNodes(MAASTestCase):
97 """Tests for ``MSCM_CLI_API.discover_nodes``."""
98111
99 def test_discover_nodes(self):112 def test_discover_nodes(self):
100 api = make_mscm_api()113 api = make_mscm_api()
@@ -106,10 +119,6 @@
106 output = api.discover_nodes()119 output = api.discover_nodes()
107 self.assertEqual(expected, output)120 self.assertEqual(expected, output)
108121
109
110class TestNodeMACAddress(MAASTestCase):
111 """Tests for ``MSCM_CLI_API.get_node_macaddr``."""
112
113 def test_get_node_macaddr(self):122 def test_get_node_macaddr(self):
114 api = make_mscm_api()123 api = make_mscm_api()
115 expected = make_show_node_macaddr()124 expected = make_show_node_macaddr()
@@ -120,10 +129,6 @@
120 self.assertEqual(re.findall(r':'.join(['[0-9a-f]{2}'] * 6),129 self.assertEqual(re.findall(r':'.join(['[0-9a-f]{2}'] * 6),
121 expected), output)130 expected), output)
122131
123
124class TestNodeArch(MAASTestCase):
125 """Tests for ``MSCM_CLI_API.get_node_arch``."""
126
127 def test_get_node_arch(self):132 def test_get_node_arch(self):
128 api = make_mscm_api()133 api = make_mscm_api()
129 expected = '\r\n Product Name: ProLiant Moonshot Cartridge\r\n'134 expected = '\r\n Product Name: ProLiant Moonshot Cartridge\r\n'
@@ -134,36 +139,17 @@
134 key = expected.split('Product Name: ')[1].splitlines()[0]139 key = expected.split('Product Name: ')[1].splitlines()[0]
135 self.assertEqual(cartridge_mapping[key], output)140 self.assertEqual(cartridge_mapping[key], output)
136141
137142 def test_get_node_power_state(self):
138class TestGetNodePowerStatus(MAASTestCase):
139 """Tests for ``MSCM_CLI_API.get_node_power_status``."""
140
141 def test_get_node_power_status(self):
142 api = make_mscm_api()143 api = make_mscm_api()
143 expected = '\r\n Node #1\r\n Power State: On\r\n'144 expected = '\r\n Node #1\r\n Power State: On\r\n'
144 cli_mock = self.patch(api, '_run_cli_command')145 cli_mock = self.patch(api, '_run_cli_command')
145 cli_mock.return_value = expected146 cli_mock.return_value = expected
146 node_id = make_node_id()147 node_id = make_node_id()
147 output = api.get_node_power_status(node_id)148 output = api.get_node_power_state(node_id)
148 self.assertEqual(expected.split('Power State: ')[1].splitlines()[0],149 self.assertEqual(expected.split('Power State: ')[1].splitlines()[0],
149 output)150 output)
150151
151152 def test_power_and_configure_node_returns_expected_outout(self):
152class TestPowerAndConfigureNode(MAASTestCase):
153 """Tests for ``MSCM_CLI_API.configure_node_bootonce_pxe,
154 MSCM_CLI_API.power_node_on, and MSCM_CLI_API.power_node_off``.
155 """
156
157 scenarios = [
158 ('power_node_on()',
159 dict(method='power_node_on')),
160 ('power_node_off()',
161 dict(method='power_node_off')),
162 ('configure_node_bootonce_pxe()',
163 dict(method='configure_node_bootonce_pxe')),
164 ]
165
166 def test_returns_expected_outout(self):
167 api = make_mscm_api()153 api = make_mscm_api()
168 ssh_mock = self.patch(api, '_ssh')154 ssh_mock = self.patch(api, '_ssh')
169 expected = factory.make_name('output')155 expected = factory.make_name('output')
@@ -174,60 +160,8 @@
174 self.assertEqual(expected, output)160 self.assertEqual(expected, output)
175161
176162
177class TestPowerControlMSCM(MAASTestCase):163class TestMSCMProbeAndEnlist(MAASTestCase):
178 """Tests for ``power_control_ucsm``."""164 """Tests for `probe_and_enlist_mscm`."""
179
180 def test_power_control_mscm_on_on(self):
181 # power_change and power_status are both 'on'
182 host = factory.make_hostname('mscm')
183 username = factory.make_name('user')
184 password = factory.make_name('password')
185 node_id = make_node_id()
186 bootonce_mock = self.patch(MSCM_CLI_API, 'configure_node_bootonce_pxe')
187 power_status_mock = self.patch(MSCM_CLI_API, 'get_node_power_status')
188 power_status_mock.return_value = 'On'
189 power_node_on_mock = self.patch(MSCM_CLI_API, 'power_node_on')
190 power_node_off_mock = self.patch(MSCM_CLI_API, 'power_node_off')
191
192 power_control_mscm(host, username, password, node_id,
193 power_change='on')
194 self.assertThat(bootonce_mock, MockCalledOnceWith(node_id))
195 self.assertThat(power_node_off_mock, MockCalledOnceWith(node_id))
196 self.assertThat(power_node_on_mock, MockCalledOnceWith(node_id))
197
198 def test_power_control_mscm_on_off(self):
199 # power_change is 'on' and power_status is 'off'
200 host = factory.make_hostname('mscm')
201 username = factory.make_name('user')
202 password = factory.make_name('password')
203 node_id = make_node_id()
204 bootonce_mock = self.patch(MSCM_CLI_API, 'configure_node_bootonce_pxe')
205 power_status_mock = self.patch(MSCM_CLI_API, 'get_node_power_status')
206 power_status_mock.return_value = 'Off'
207 power_node_on_mock = self.patch(MSCM_CLI_API, 'power_node_on')
208
209 power_control_mscm(host, username, password, node_id,
210 power_change='on')
211 self.assertThat(bootonce_mock, MockCalledOnceWith(node_id))
212 self.assertThat(power_node_on_mock, MockCalledOnceWith(node_id))
213
214 def test_power_control_mscm_off_on(self):
215 # power_change is 'off' and power_status is 'on'
216 host = factory.make_hostname('mscm')
217 username = factory.make_name('user')
218 password = factory.make_name('password')
219 node_id = make_node_id()
220 power_status_mock = self.patch(MSCM_CLI_API, 'get_node_power_status')
221 power_status_mock.return_value = 'On'
222 power_node_off_mock = self.patch(MSCM_CLI_API, 'power_node_off')
223
224 power_control_mscm(host, username, password, node_id,
225 power_change='off')
226 self.assertThat(power_node_off_mock, MockCalledOnceWith(node_id))
227
228
229class TestProbeAndEnlistMSCM(MAASTestCase):
230 """Tests for ``probe_and_enlist_mscm``."""
231165
232 def test_probe_and_enlist(self):166 def test_probe_and_enlist(self):
233 host = factory.make_hostname('mscm')167 host = factory.make_hostname('mscm')
@@ -244,16 +178,134 @@
244 node_macs_mock = self.patch(MSCM_CLI_API, 'get_node_macaddr')178 node_macs_mock = self.patch(MSCM_CLI_API, 'get_node_macaddr')
245 node_macs_mock.return_value = macs179 node_macs_mock.return_value = macs
246 create_node_mock = self.patch(utils, 'create_node')180 create_node_mock = self.patch(utils, 'create_node')
247 probe_and_enlist_mscm(host, username, password)
248 self.assertThat(discover_nodes_mock, MockCalledOnceWith())
249 self.assertThat(boot_m2_mock, MockCalledOnceWith(node_id))
250 self.assertThat(node_arch_mock, MockCalledOnceWith(node_id))
251 self.assertThat(node_macs_mock, MockCalledOnceWith(node_id))
252 params = {181 params = {
253 'power_address': host,182 'power_address': host,
254 'power_user': username,183 'power_user': username,
255 'power_pass': password,184 'power_pass': password,
256 'node_id': node_id,185 'node_id': node_id,
257 }186 }
258 self.assertThat(create_node_mock,187
188 probe_and_enlist_mscm(host, username, password)
189 self.expectThat(discover_nodes_mock, MockAnyCall())
190 self.expectThat(boot_m2_mock, MockCalledWith(node_id))
191 self.expectThat(node_arch_mock, MockCalledOnceWith(node_id))
192 self.expectThat(node_macs_mock, MockCalledOnceWith(node_id))
193 self.expectThat(create_node_mock,
259 MockCalledOnceWith(macs, arch, 'mscm', params))194 MockCalledOnceWith(macs, arch, 'mscm', params))
195
196 def test_probe_and_enlist_discover_nodes_failure(self):
197 host = factory.make_hostname('mscm')
198 username = factory.make_name('user')
199 password = factory.make_name('password')
200 discover_nodes_mock = self.patch(MSCM_CLI_API, 'discover_nodes')
201 discover_nodes_mock.side_effect = MSCMError('error')
202 self.assertRaises(
203 MSCMError, probe_and_enlist_mscm, host, username, password)
204
205
206class TestMSCMPowerControl(MAASTestCase):
207 """Tests for `power_control_mscm`."""
208
209 def test_power_control_error_on_unknown_power_change(self):
210 host = factory.make_hostname('mscm')
211 username = factory.make_name('user')
212 password = factory.make_name('password')
213 node_id = make_node_id()
214 power_change = factory.make_name('error')
215 self.assertRaises(
216 MSCMError, power_control_mscm, host,
217 username, password, node_id, power_change)
218
219 def test_power_control_power_change_on_power_state_on(self):
220 # power_change and current power_state are both 'on'
221 host = factory.make_hostname('mscm')
222 username = factory.make_name('user')
223 password = factory.make_name('password')
224 node_id = make_node_id()
225 power_state_mock = self.patch(MSCM_CLI_API, 'get_node_power_state')
226 power_state_mock.return_value = MSCMState.ON
227 power_node_off_mock = self.patch(MSCM_CLI_API, 'power_node_off')
228 bootonce_mock = self.patch(MSCM_CLI_API, 'configure_node_bootonce_pxe')
229 power_node_on_mock = self.patch(MSCM_CLI_API, 'power_node_on')
230
231 power_control_mscm(host, username, password, node_id,
232 power_change='on')
233 self.expectThat(power_state_mock, MockCalledOnceWith(node_id))
234 self.expectThat(power_node_off_mock, MockCalledOnceWith(node_id))
235 self.expectThat(bootonce_mock, MockCalledOnceWith(node_id))
236 self.expectThat(power_node_on_mock, MockCalledOnceWith(node_id))
237
238 def test_power_control_power_change_on_power_state_off(self):
239 # power_change is 'on' and current power_state is 'off'
240 host = factory.make_hostname('mscm')
241 username = factory.make_name('user')
242 password = factory.make_name('password')
243 node_id = make_node_id()
244 power_state_mock = self.patch(MSCM_CLI_API, 'get_node_power_state')
245 power_state_mock.return_value = MSCMState.OFF
246 bootonce_mock = self.patch(MSCM_CLI_API, 'configure_node_bootonce_pxe')
247 power_node_on_mock = self.patch(MSCM_CLI_API, 'power_node_on')
248
249 power_control_mscm(host, username, password, node_id,
250 power_change='on')
251 self.expectThat(power_state_mock, MockCalledOnceWith(node_id))
252 self.expectThat(bootonce_mock, MockCalledOnceWith(node_id))
253 self.expectThat(power_node_on_mock, MockCalledOnceWith(node_id))
254
255 def test_power_control_power_change_off_power_state_on(self):
256 # power_change is 'off' and current power_state is 'on'
257 host = factory.make_hostname('mscm')
258 username = factory.make_name('user')
259 password = factory.make_name('password')
260 node_id = make_node_id()
261 power_node_off_mock = self.patch(MSCM_CLI_API, 'power_node_off')
262
263 power_control_mscm(host, username, password, node_id,
264 power_change='off')
265 self.expectThat(power_node_off_mock, MockCalledOnceWith(node_id))
266
267
268class TestMSCMPowerState(MAASTestCase):
269 """Tests for `power_state_mscm`."""
270
271 def test_power_state_failed_to_get_state(self):
272 host = factory.make_hostname('mscm')
273 username = factory.make_name('user')
274 password = factory.make_name('password')
275 node_id = make_node_id()
276 power_state_mock = self.patch(MSCM_CLI_API, 'get_node_power_state')
277 power_state_mock.side_effect = MSCMError('error')
278 self.assertRaises(
279 MSCMError, power_state_mscm, host, username, password, node_id)
280
281 def test_power_state_get_off(self):
282 host = factory.make_hostname('mscm')
283 username = factory.make_name('user')
284 password = factory.make_name('password')
285 node_id = make_node_id()
286 power_state_mock = self.patch(MSCM_CLI_API, 'get_node_power_state')
287 power_state_mock.return_value = MSCMState.OFF
288 self.assertThat(
289 power_state_mscm(host, username, password, node_id),
290 Equals('off'))
291
292 def test_power_state_get_on(self):
293 host = factory.make_hostname('mscm')
294 username = factory.make_name('user')
295 password = factory.make_name('password')
296 node_id = make_node_id()
297 power_state_mock = self.patch(MSCM_CLI_API, 'get_node_power_state')
298 power_state_mock.return_value = MSCMState.ON
299 self.assertThat(
300 power_state_mscm(host, username, password, node_id),
301 Equals('on'))
302
303 def test_power_state_error_on_unknown_state(self):
304 host = factory.make_hostname('mscm')
305 username = factory.make_name('user')
306 password = factory.make_name('password')
307 node_id = make_node_id()
308 power_state_mock = self.patch(MSCM_CLI_API, 'get_node_power_state')
309 power_state_mock.return_value = factory.make_name('error')
310 self.assertRaises(
311 MSCMError, power_state_mscm, host, username, password, node_id)
260312
=== modified file 'src/provisioningserver/rpc/power.py'
--- src/provisioningserver/rpc/power.py 2014-10-27 11:56:50 +0000
+++ src/provisioningserver/rpc/power.py 2014-10-30 20:06:36 +0000
@@ -61,7 +61,7 @@
61# state for these power types.61# state for these power types.
62# This is meant to be temporary until all the power types support62# This is meant to be temporary until all the power types support
63# querying the power state of a node.63# querying the power state of a node.
64QUERY_POWER_TYPES = ['amt', 'ipmi', 'virsh']64QUERY_POWER_TYPES = ['amt', 'ipmi', 'mscm', 'virsh']
6565
6666
67# Timeout for change_power_state(). We set it to 2 minutes by default,67# Timeout for change_power_state(). We set it to 2 minutes by default,