Merge ~ltrager/maas:hmcz_power_driver into maas:master
- Git
- lp:~ltrager/maas
- hmcz_power_driver
- Merge into master
Status: | Merged |
---|---|
Approved by: | Adam Collard |
Approved revision: | 7647dadd034c38d584cdd104d2d5916e2db003a7 |
Merge reported by: | MAAS Lander |
Merged at revision: | not available |
Proposed branch: | ~ltrager/maas:hmcz_power_driver |
Merge into: | maas:master |
Diff against target: |
483 lines (+385/-2) 8 files modified
debian/control (+1/-0) required-packages/base (+1/-0) snap/snapcraft.yaml (+1/-0) src/provisioningserver/drivers/power/hmc.py (+2/-2) src/provisioningserver/drivers/power/hmcz.py (+121/-0) src/provisioningserver/drivers/power/registry.py (+2/-0) src/provisioningserver/drivers/power/tests/test_hmcz.py (+255/-0) utilities/check-imports (+2/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
MAAS Lander | Approve | ||
Adam Collard (community) | Approve | ||
Review via email: mp+398036@code.launchpad.net |
Commit message
Add the HMC power driver for IBM Z
Description of the change
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b hmcz_power_driver lp:~ltrager/maas/+git/maas into -b master lp:~maas-committers/maas
STATUS: FAILED
LOG: http://
COMMIT: 8dd73384509b457
Adam Collard (adam-collard) wrote : | # |
Urgh, failure in import linting
src/provisionin
denied: zhmcclient.Client
denied: zhmcclient.NotFound
denied: zhmcclient.Session
src/provisioni
denied: zhmcclient_
19788 imported names were ALLOWED.
4 imported names were DENIED.
Adam Collard (adam-collard) wrote : | # |
nit pick
- 0270acc... by Lee Trager
-
Allow zhmcclient to be imported
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b hmcz_power_driver lp:~ltrager/maas/+git/maas into -b master lp:~maas-committers/maas
STATUS: SUCCESS
COMMIT: 0270acc9c0542b8
- 04b9203... by Lee Trager
-
Merge branch 'master' into hmcz_power_driver
- 7647dad... by Lee Trager
-
adam-collard fix
Lee Trager (ltrager) wrote : | # |
Thanks for the review, updated as suggested.
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b hmcz_power_driver lp:~ltrager/maas/+git/maas into -b master lp:~maas-committers/maas
STATUS: FAILED
LOG: http://
COMMIT: 7647dadd034c38d
Adam Collard (adam-collard) wrote : | # |
jenkins: !test
Adam Collard (adam-collard) : | # |
MAAS Lander (maas-lander) wrote : | # |
UNIT TESTS
-b hmcz_power_driver lp:~ltrager/maas/+git/maas into -b master lp:~maas-committers/maas
STATUS: SUCCESS
COMMIT: 7647dadd034c38d
Preview Diff
1 | diff --git a/debian/control b/debian/control | |||
2 | index f83bbad..5e7c67e 100644 | |||
3 | --- a/debian/control | |||
4 | +++ b/debian/control | |||
5 | @@ -154,6 +154,7 @@ Depends: lshw, | |||
6 | 154 | iproute2, | 154 | iproute2, |
7 | 155 | ${misc:Depends}, | 155 | ${misc:Depends}, |
8 | 156 | ${python3:Depends} | 156 | ${python3:Depends} |
9 | 157 | Suggests: python3-zhmcclient (>= 0.22.0-0ubuntu1) | ||
10 | 157 | Description: MAAS server provisioning libraries (Python 3) | 158 | Description: MAAS server provisioning libraries (Python 3) |
11 | 158 | This package provides the MAAS provisioning server python libraries. | 159 | This package provides the MAAS provisioning server python libraries. |
12 | 159 | . | 160 | . |
13 | diff --git a/required-packages/base b/required-packages/base | |||
14 | index 7a7f382..4426319 100644 | |||
15 | --- a/required-packages/base | |||
16 | +++ b/required-packages/base | |||
17 | @@ -60,6 +60,7 @@ python3-tz | |||
18 | 60 | python3-uvloop | 60 | python3-uvloop |
19 | 61 | python3-venv | 61 | python3-venv |
20 | 62 | python3-yaml | 62 | python3-yaml |
21 | 63 | python3-zhmcclient | ||
22 | 63 | python3-zope.interface | 64 | python3-zope.interface |
23 | 64 | syslinux-common | 65 | syslinux-common |
24 | 65 | ubuntu-keyring | 66 | ubuntu-keyring |
25 | diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml | |||
26 | index 5d3eef9..1a34213 100644 | |||
27 | --- a/snap/snapcraft.yaml | |||
28 | +++ b/snap/snapcraft.yaml | |||
29 | @@ -149,6 +149,7 @@ parts: | |||
30 | 149 | - python3-txtftp | 149 | - python3-txtftp |
31 | 150 | - python3-urllib3 # for macaroonbakery | 150 | - python3-urllib3 # for macaroonbakery |
32 | 151 | - python3-yaml | 151 | - python3-yaml |
33 | 152 | - python3-zhmcclient | ||
34 | 152 | - python3-zope.interface | 153 | - python3-zope.interface |
35 | 153 | - rsyslog | 154 | - rsyslog |
36 | 154 | - snmp # APC | 155 | - snmp # APC |
37 | diff --git a/src/provisioningserver/drivers/power/hmc.py b/src/provisioningserver/drivers/power/hmc.py | |||
38 | index 49cb729..0358a69 100644 | |||
39 | --- a/src/provisioningserver/drivers/power/hmc.py | |||
40 | +++ b/src/provisioningserver/drivers/power/hmc.py | |||
41 | @@ -1,4 +1,4 @@ | |||
43 | 1 | # Copyright 2015-2016 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2015-2021 Canonical Ltd. This software is licensed under the |
44 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
45 | 3 | 3 | ||
46 | 4 | """HMC Power Driver. | 4 | """HMC Power Driver. |
47 | @@ -35,7 +35,7 @@ class HMCPowerDriver(PowerDriver): | |||
48 | 35 | name = "hmc" | 35 | name = "hmc" |
49 | 36 | chassis = True | 36 | chassis = True |
50 | 37 | can_probe = False | 37 | can_probe = False |
52 | 38 | description = "IBM Hardware Management Console (HMC)" | 38 | description = "IBM Hardware Management Console (HMC) for PowerPC" |
53 | 39 | settings = [ | 39 | settings = [ |
54 | 40 | make_setting_field("power_address", "IP for HMC", required=True), | 40 | make_setting_field("power_address", "IP for HMC", required=True), |
55 | 41 | make_setting_field("power_user", "HMC username"), | 41 | make_setting_field("power_user", "HMC username"), |
56 | diff --git a/src/provisioningserver/drivers/power/hmcz.py b/src/provisioningserver/drivers/power/hmcz.py | |||
57 | 42 | new file mode 100644 | 42 | new file mode 100644 |
58 | index 0000000..0f16af1 | |||
59 | --- /dev/null | |||
60 | +++ b/src/provisioningserver/drivers/power/hmcz.py | |||
61 | @@ -0,0 +1,121 @@ | |||
62 | 1 | # Copyright 2021 Canonical Ltd. This software is licensed under the | ||
63 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
64 | 3 | |||
65 | 4 | """HMC Z Driver. | ||
66 | 5 | |||
67 | 6 | Support for managing DPM partitions via the IBM Hardware Management Console | ||
68 | 7 | for Z. The HMC for IBM Z has a different API than the HMC for IBM Power, thus | ||
69 | 8 | two different power drivers. See | ||
70 | 9 | https://github.com/zhmcclient/python-zhmcclient/issues/494 | ||
71 | 10 | """ | ||
72 | 11 | |||
73 | 12 | import contextlib | ||
74 | 13 | |||
75 | 14 | from provisioningserver.drivers import ( | ||
76 | 15 | make_ip_extractor, | ||
77 | 16 | make_setting_field, | ||
78 | 17 | SETTING_SCOPE, | ||
79 | 18 | ) | ||
80 | 19 | from provisioningserver.drivers.power import PowerActionError, PowerDriver | ||
81 | 20 | from provisioningserver.logger import get_maas_logger | ||
82 | 21 | from provisioningserver.utils import typed | ||
83 | 22 | from provisioningserver.utils.twisted import asynchronous, threadDeferred | ||
84 | 23 | |||
85 | 24 | try: | ||
86 | 25 | from zhmcclient import Client, NotFound, Session | ||
87 | 26 | except ImportError: | ||
88 | 27 | no_zhmcclient = True | ||
89 | 28 | else: | ||
90 | 29 | no_zhmcclient = False | ||
91 | 30 | |||
92 | 31 | maaslog = get_maas_logger("drivers.power.hmcz") | ||
93 | 32 | |||
94 | 33 | |||
95 | 34 | class HMCZPowerDriver(PowerDriver): | ||
96 | 35 | |||
97 | 36 | name = "hmcz" | ||
98 | 37 | chassis = False | ||
99 | 38 | can_probe = False | ||
100 | 39 | description = "IBM Hardware Management Console (HMC) for Z" | ||
101 | 40 | settings = [ | ||
102 | 41 | make_setting_field("power_address", "HMC Address", required=True), | ||
103 | 42 | make_setting_field("power_user", "HMC username", required=True), | ||
104 | 43 | make_setting_field( | ||
105 | 44 | "power_pass", "HMC password", field_type="password", required=True | ||
106 | 45 | ), | ||
107 | 46 | make_setting_field( | ||
108 | 47 | "power_partition_name", | ||
109 | 48 | "HMC partition name", | ||
110 | 49 | scope=SETTING_SCOPE.NODE, | ||
111 | 50 | required=True, | ||
112 | 51 | ), | ||
113 | 52 | ] | ||
114 | 53 | ip_extractor = make_ip_extractor("power_address") | ||
115 | 54 | |||
116 | 55 | def detect_missing_packages(self): | ||
117 | 56 | if no_zhmcclient: | ||
118 | 57 | return ["python3-zhmcclient"] | ||
119 | 58 | else: | ||
120 | 59 | return [] | ||
121 | 60 | |||
122 | 61 | @typed | ||
123 | 62 | def _get_partition(self, context: dict): | ||
124 | 63 | session = Session( | ||
125 | 64 | context["power_address"], | ||
126 | 65 | context["power_user"], | ||
127 | 66 | context["power_pass"], | ||
128 | 67 | ) | ||
129 | 68 | partition_name = context["power_partition_name"] | ||
130 | 69 | client = Client(session) | ||
131 | 70 | # Each HMC manages one or more CPCs(Central Processor Complex). To find | ||
132 | 71 | # a partition MAAS must iterate over all CPCs. | ||
133 | 72 | for cpc in client.cpcs.list(): | ||
134 | 73 | if not cpc.dpm_enabled: | ||
135 | 74 | maaslog.warning( | ||
136 | 75 | f"DPM is not enabled on '{cpc.get_property('name')}', " | ||
137 | 76 | "skipping" | ||
138 | 77 | ) | ||
139 | 78 | continue | ||
140 | 79 | with contextlib.suppress(NotFound): | ||
141 | 80 | return cpc.partitions.find(name=partition_name) | ||
142 | 81 | raise PowerActionError(f"Unable to find '{partition_name}' on HMC!") | ||
143 | 82 | |||
144 | 83 | # IBM Z partitions can take awhile to start/stop. Don't wait for completion | ||
145 | 84 | # so power actions don't consume a thread. | ||
146 | 85 | |||
147 | 86 | @typed | ||
148 | 87 | @asynchronous | ||
149 | 88 | @threadDeferred | ||
150 | 89 | def power_on(self, system_id: str, context: dict): | ||
151 | 90 | """Power on IBM Z DPM.""" | ||
152 | 91 | partition = self._get_partition(context) | ||
153 | 92 | partition.start(wait_for_completion=False) | ||
154 | 93 | |||
155 | 94 | @typed | ||
156 | 95 | @asynchronous | ||
157 | 96 | @threadDeferred | ||
158 | 97 | def power_off(self, system_id: str, context: dict): | ||
159 | 98 | """Power off IBM Z DPM.""" | ||
160 | 99 | partition = self._get_partition(context) | ||
161 | 100 | partition.stop(wait_for_completion=False) | ||
162 | 101 | |||
163 | 102 | @typed | ||
164 | 103 | @asynchronous | ||
165 | 104 | @threadDeferred | ||
166 | 105 | def power_query(self, system_id: str, context: dict): | ||
167 | 106 | """Power on IBM Z DPM.""" | ||
168 | 107 | partition = self._get_partition(context) | ||
169 | 108 | status = partition.get_property("status") | ||
170 | 109 | # IBM Z takes time to start or stop a partition. It returns a | ||
171 | 110 | # transitional state during this time. Associate the transitional | ||
172 | 111 | # state with on or off so MAAS doesn't repeatedly issue a power | ||
173 | 112 | # on or off command. | ||
174 | 113 | if status in {"starting", "active"}: | ||
175 | 114 | # When a partition is starting it can go into a "paused" state. | ||
176 | 115 | # This isn't on or off, just that the partition isn't currently | ||
177 | 116 | # executing instructions. | ||
178 | 117 | return "on" | ||
179 | 118 | elif status in {"stopping", "stopped"}: | ||
180 | 119 | return "off" | ||
181 | 120 | else: | ||
182 | 121 | return "unknown" | ||
183 | diff --git a/src/provisioningserver/drivers/power/registry.py b/src/provisioningserver/drivers/power/registry.py | |||
184 | index 5eb0b66..ca742a5 100644 | |||
185 | --- a/src/provisioningserver/drivers/power/registry.py | |||
186 | +++ b/src/provisioningserver/drivers/power/registry.py | |||
187 | @@ -13,6 +13,7 @@ from provisioningserver.drivers.power.apc import APCPowerDriver | |||
188 | 13 | from provisioningserver.drivers.power.dli import DLIPowerDriver | 13 | from provisioningserver.drivers.power.dli import DLIPowerDriver |
189 | 14 | from provisioningserver.drivers.power.eaton import EatonPowerDriver | 14 | from provisioningserver.drivers.power.eaton import EatonPowerDriver |
190 | 15 | from provisioningserver.drivers.power.hmc import HMCPowerDriver | 15 | from provisioningserver.drivers.power.hmc import HMCPowerDriver |
191 | 16 | from provisioningserver.drivers.power.hmcz import HMCZPowerDriver | ||
192 | 16 | from provisioningserver.drivers.power.ipmi import IPMIPowerDriver | 17 | from provisioningserver.drivers.power.ipmi import IPMIPowerDriver |
193 | 17 | from provisioningserver.drivers.power.manual import ManualPowerDriver | 18 | from provisioningserver.drivers.power.manual import ManualPowerDriver |
194 | 18 | from provisioningserver.drivers.power.moonshot import MoonshotIPMIPowerDriver | 19 | from provisioningserver.drivers.power.moonshot import MoonshotIPMIPowerDriver |
195 | @@ -55,6 +56,7 @@ power_drivers = [ | |||
196 | 55 | DLIPowerDriver(), | 56 | DLIPowerDriver(), |
197 | 56 | EatonPowerDriver(), | 57 | EatonPowerDriver(), |
198 | 57 | HMCPowerDriver(), | 58 | HMCPowerDriver(), |
199 | 59 | HMCZPowerDriver(), | ||
200 | 58 | IPMIPowerDriver(), | 60 | IPMIPowerDriver(), |
201 | 59 | ManualPowerDriver(), | 61 | ManualPowerDriver(), |
202 | 60 | MoonshotIPMIPowerDriver(), | 62 | MoonshotIPMIPowerDriver(), |
203 | diff --git a/src/provisioningserver/drivers/power/tests/test_hmcz.py b/src/provisioningserver/drivers/power/tests/test_hmcz.py | |||
204 | 61 | new file mode 100644 | 63 | new file mode 100644 |
205 | index 0000000..abaf15c | |||
206 | --- /dev/null | |||
207 | +++ b/src/provisioningserver/drivers/power/tests/test_hmcz.py | |||
208 | @@ -0,0 +1,255 @@ | |||
209 | 1 | # Copyright 2021 Canonical Ltd. This software is licensed under the | ||
210 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
211 | 3 | |||
212 | 4 | """Tests for `provisioningserver.drivers.power.hmcz`.""" | ||
213 | 5 | |||
214 | 6 | from twisted.internet.defer import inlineCallbacks | ||
215 | 7 | from zhmcclient_mock import FakedSession | ||
216 | 8 | |||
217 | 9 | from maastesting.factory import factory | ||
218 | 10 | from maastesting.matchers import MockCalledOnce, MockCalledOnceWith | ||
219 | 11 | from maastesting.testcase import MAASTestCase, MAASTwistedRunTest | ||
220 | 12 | from provisioningserver.drivers.power import hmcz as hmcz_module | ||
221 | 13 | from provisioningserver.drivers.power import PowerActionError | ||
222 | 14 | |||
223 | 15 | |||
224 | 16 | class TestHMCZPowerDriver(MAASTestCase): | ||
225 | 17 | |||
226 | 18 | run_tests_with = MAASTwistedRunTest.make_factory(timeout=5) | ||
227 | 19 | |||
228 | 20 | def setUp(self): | ||
229 | 21 | super().setUp() | ||
230 | 22 | self.power_address = factory.make_ip_address() | ||
231 | 23 | self.fake_session = FakedSession( | ||
232 | 24 | self.power_address, | ||
233 | 25 | factory.make_name("hmc_name"), | ||
234 | 26 | # The version and API version below were taken from | ||
235 | 27 | # the test environment given by IBM. | ||
236 | 28 | "2.14.1", | ||
237 | 29 | "2.40", | ||
238 | 30 | ) | ||
239 | 31 | self.patch(hmcz_module, "Session").return_value = self.fake_session | ||
240 | 32 | self.hmcz = hmcz_module.HMCZPowerDriver() | ||
241 | 33 | |||
242 | 34 | def make_context(self, power_partition_name=None): | ||
243 | 35 | if power_partition_name is None: | ||
244 | 36 | power_partition_name = factory.make_name("power_partition_name") | ||
245 | 37 | return { | ||
246 | 38 | "power_address": self.power_address, | ||
247 | 39 | "power_user": factory.make_name("power_user"), | ||
248 | 40 | "power_pass": factory.make_name("power_pass"), | ||
249 | 41 | "power_partition_name": power_partition_name, | ||
250 | 42 | } | ||
251 | 43 | |||
252 | 44 | def test_detect_missing_packages(self): | ||
253 | 45 | hmcz_module.no_zhmcclient = False | ||
254 | 46 | self.assertEqual([], self.hmcz.detect_missing_packages()) | ||
255 | 47 | |||
256 | 48 | def test_detect_missing_packages_missing(self): | ||
257 | 49 | hmcz_module.no_zhmcclient = True | ||
258 | 50 | self.assertEqual( | ||
259 | 51 | ["python3-zhmcclient"], self.hmcz.detect_missing_packages() | ||
260 | 52 | ) | ||
261 | 53 | |||
262 | 54 | def test_get_partition(self): | ||
263 | 55 | power_partition_name = factory.make_name("power_partition_name") | ||
264 | 56 | cpc = self.fake_session.hmc.cpcs.add( | ||
265 | 57 | { | ||
266 | 58 | "name": factory.make_name("cpc"), | ||
267 | 59 | "dpm-enabled": True, | ||
268 | 60 | } | ||
269 | 61 | ) | ||
270 | 62 | cpc.partitions.add({"name": power_partition_name}) | ||
271 | 63 | |||
272 | 64 | self.assertEqual( | ||
273 | 65 | power_partition_name, | ||
274 | 66 | self.hmcz._get_partition( | ||
275 | 67 | self.make_context(power_partition_name) | ||
276 | 68 | ).get_property("name"), | ||
277 | 69 | ) | ||
278 | 70 | |||
279 | 71 | def test_get_partition_ignores_cpcs_with_no_dpm(self): | ||
280 | 72 | mock_logger = self.patch(hmcz_module.maaslog, "warning") | ||
281 | 73 | power_partition_name = factory.make_name("power_partition_name") | ||
282 | 74 | self.fake_session.hmc.cpcs.add( | ||
283 | 75 | { | ||
284 | 76 | "name": factory.make_name("cpc"), | ||
285 | 77 | "dpm-enabled": False, | ||
286 | 78 | } | ||
287 | 79 | ) | ||
288 | 80 | cpc = self.fake_session.hmc.cpcs.add({"dpm-enabled": True}) | ||
289 | 81 | cpc.partitions.add({"name": power_partition_name}) | ||
290 | 82 | |||
291 | 83 | self.assertEqual( | ||
292 | 84 | power_partition_name, | ||
293 | 85 | self.hmcz._get_partition( | ||
294 | 86 | self.make_context(power_partition_name) | ||
295 | 87 | ).get_property("name"), | ||
296 | 88 | ) | ||
297 | 89 | self.assertThat(mock_logger, MockCalledOnce()) | ||
298 | 90 | |||
299 | 91 | def test_get_partition_doesnt_find_partition(self): | ||
300 | 92 | cpc = self.fake_session.hmc.cpcs.add( | ||
301 | 93 | { | ||
302 | 94 | "name": factory.make_name("cpc"), | ||
303 | 95 | "dpm-enabled": True, | ||
304 | 96 | } | ||
305 | 97 | ) | ||
306 | 98 | cpc.partitions.add({"name": factory.make_name("power_partition_name")}) | ||
307 | 99 | |||
308 | 100 | self.assertRaises( | ||
309 | 101 | PowerActionError, self.hmcz._get_partition, self.make_context() | ||
310 | 102 | ) | ||
311 | 103 | |||
312 | 104 | # zhmcclient_mock doesn't currently support async so MagicMock | ||
313 | 105 | # must be used for power on/off | ||
314 | 106 | |||
315 | 107 | @inlineCallbacks | ||
316 | 108 | def test_power_on(self): | ||
317 | 109 | mock_get_partition = self.patch(self.hmcz, "_get_partition") | ||
318 | 110 | yield self.hmcz.power_on(None, self.make_context()) | ||
319 | 111 | self.assertThat( | ||
320 | 112 | mock_get_partition.return_value.start, | ||
321 | 113 | MockCalledOnceWith(wait_for_completion=False), | ||
322 | 114 | ) | ||
323 | 115 | |||
324 | 116 | @inlineCallbacks | ||
325 | 117 | def test_power_off(self): | ||
326 | 118 | mock_get_partition = self.patch(self.hmcz, "_get_partition") | ||
327 | 119 | yield self.hmcz.power_off(None, self.make_context()) | ||
328 | 120 | self.assertThat( | ||
329 | 121 | mock_get_partition.return_value.stop, | ||
330 | 122 | MockCalledOnceWith(wait_for_completion=False), | ||
331 | 123 | ) | ||
332 | 124 | |||
333 | 125 | @inlineCallbacks | ||
334 | 126 | def test_power_query_starting(self): | ||
335 | 127 | power_partition_name = factory.make_name("power_partition_name") | ||
336 | 128 | cpc = self.fake_session.hmc.cpcs.add( | ||
337 | 129 | { | ||
338 | 130 | "name": factory.make_name("cpc"), | ||
339 | 131 | "dpm-enabled": True, | ||
340 | 132 | } | ||
341 | 133 | ) | ||
342 | 134 | cpc.partitions.add( | ||
343 | 135 | { | ||
344 | 136 | "name": power_partition_name, | ||
345 | 137 | "status": "starting", | ||
346 | 138 | } | ||
347 | 139 | ) | ||
348 | 140 | |||
349 | 141 | status = yield self.hmcz.power_query( | ||
350 | 142 | None, self.make_context(power_partition_name) | ||
351 | 143 | ) | ||
352 | 144 | |||
353 | 145 | self.assertEqual("on", status) | ||
354 | 146 | |||
355 | 147 | @inlineCallbacks | ||
356 | 148 | def test_power_query_active(self): | ||
357 | 149 | power_partition_name = factory.make_name("power_partition_name") | ||
358 | 150 | cpc = self.fake_session.hmc.cpcs.add( | ||
359 | 151 | { | ||
360 | 152 | "name": factory.make_name("cpc"), | ||
361 | 153 | "dpm-enabled": True, | ||
362 | 154 | } | ||
363 | 155 | ) | ||
364 | 156 | cpc.partitions.add( | ||
365 | 157 | { | ||
366 | 158 | "name": power_partition_name, | ||
367 | 159 | "status": "active", | ||
368 | 160 | } | ||
369 | 161 | ) | ||
370 | 162 | |||
371 | 163 | status = yield self.hmcz.power_query( | ||
372 | 164 | None, self.make_context(power_partition_name) | ||
373 | 165 | ) | ||
374 | 166 | |||
375 | 167 | self.assertEqual("on", status) | ||
376 | 168 | |||
377 | 169 | @inlineCallbacks | ||
378 | 170 | def test_power_query_stopping(self): | ||
379 | 171 | power_partition_name = factory.make_name("power_partition_name") | ||
380 | 172 | cpc = self.fake_session.hmc.cpcs.add( | ||
381 | 173 | { | ||
382 | 174 | "name": factory.make_name("cpc"), | ||
383 | 175 | "dpm-enabled": True, | ||
384 | 176 | } | ||
385 | 177 | ) | ||
386 | 178 | cpc.partitions.add( | ||
387 | 179 | { | ||
388 | 180 | "name": power_partition_name, | ||
389 | 181 | "status": "stopping", | ||
390 | 182 | } | ||
391 | 183 | ) | ||
392 | 184 | |||
393 | 185 | status = yield self.hmcz.power_query( | ||
394 | 186 | None, self.make_context(power_partition_name) | ||
395 | 187 | ) | ||
396 | 188 | |||
397 | 189 | self.assertEqual("off", status) | ||
398 | 190 | |||
399 | 191 | @inlineCallbacks | ||
400 | 192 | def test_power_query_stopped(self): | ||
401 | 193 | power_partition_name = factory.make_name("power_partition_name") | ||
402 | 194 | cpc = self.fake_session.hmc.cpcs.add( | ||
403 | 195 | { | ||
404 | 196 | "name": factory.make_name("cpc"), | ||
405 | 197 | "dpm-enabled": True, | ||
406 | 198 | } | ||
407 | 199 | ) | ||
408 | 200 | cpc.partitions.add( | ||
409 | 201 | { | ||
410 | 202 | "name": power_partition_name, | ||
411 | 203 | "status": "stopped", | ||
412 | 204 | } | ||
413 | 205 | ) | ||
414 | 206 | |||
415 | 207 | status = yield self.hmcz.power_query( | ||
416 | 208 | None, self.make_context(power_partition_name) | ||
417 | 209 | ) | ||
418 | 210 | |||
419 | 211 | self.assertEqual("off", status) | ||
420 | 212 | |||
421 | 213 | @inlineCallbacks | ||
422 | 214 | def test_power_query_paused(self): | ||
423 | 215 | power_partition_name = factory.make_name("power_partition_name") | ||
424 | 216 | cpc = self.fake_session.hmc.cpcs.add( | ||
425 | 217 | { | ||
426 | 218 | "name": factory.make_name("cpc"), | ||
427 | 219 | "dpm-enabled": True, | ||
428 | 220 | } | ||
429 | 221 | ) | ||
430 | 222 | cpc.partitions.add( | ||
431 | 223 | { | ||
432 | 224 | "name": power_partition_name, | ||
433 | 225 | "status": "paused", | ||
434 | 226 | } | ||
435 | 227 | ) | ||
436 | 228 | |||
437 | 229 | status = yield self.hmcz.power_query( | ||
438 | 230 | None, self.make_context(power_partition_name) | ||
439 | 231 | ) | ||
440 | 232 | |||
441 | 233 | self.assertEqual("unknown", status) | ||
442 | 234 | |||
443 | 235 | @inlineCallbacks | ||
444 | 236 | def test_power_query_other(self): | ||
445 | 237 | power_partition_name = factory.make_name("power_partition_name") | ||
446 | 238 | cpc = self.fake_session.hmc.cpcs.add( | ||
447 | 239 | { | ||
448 | 240 | "name": factory.make_name("cpc"), | ||
449 | 241 | "dpm-enabled": True, | ||
450 | 242 | } | ||
451 | 243 | ) | ||
452 | 244 | cpc.partitions.add( | ||
453 | 245 | { | ||
454 | 246 | "name": power_partition_name, | ||
455 | 247 | "status": factory.make_name("status"), | ||
456 | 248 | } | ||
457 | 249 | ) | ||
458 | 250 | |||
459 | 251 | status = yield self.hmcz.power_query( | ||
460 | 252 | None, self.make_context(power_partition_name) | ||
461 | 253 | ) | ||
462 | 254 | |||
463 | 255 | self.assertEqual("unknown", status) | ||
464 | diff --git a/utilities/check-imports b/utilities/check-imports | |||
465 | index ac9a3a7..dc7b496 100755 | |||
466 | --- a/utilities/check-imports | |||
467 | +++ b/utilities/check-imports | |||
468 | @@ -164,6 +164,7 @@ TestingLibraries = Pattern( | |||
469 | 164 | "testresources|testresources.**", | 164 | "testresources|testresources.**", |
470 | 165 | "testscenarios|testscenarios.**", | 165 | "testscenarios|testscenarios.**", |
471 | 166 | "testtools|testtools.**", | 166 | "testtools|testtools.**", |
472 | 167 | "zhmcclient_mock.**", | ||
473 | 167 | ) | 168 | ) |
474 | 168 | 169 | ||
475 | 169 | 170 | ||
476 | @@ -235,6 +236,7 @@ RackControllerRule = Rule( | |||
477 | 235 | Allow("urllib3|urllib3.**"), | 236 | Allow("urllib3|urllib3.**"), |
478 | 236 | Allow("uvloop"), | 237 | Allow("uvloop"), |
479 | 237 | Allow("yaml"), | 238 | Allow("yaml"), |
480 | 239 | Allow("zhmcclient.**"), | ||
481 | 238 | Allow("zope.interface|zope.interface.**"), | 240 | Allow("zope.interface|zope.interface.**"), |
482 | 239 | Allow(StandardLibraries), | 241 | Allow(StandardLibraries), |
483 | 240 | ) | 242 | ) |
UNIT TESTS
-b hmcz_power_driver lp:~ltrager/maas/+git/maas into -b master lp:~maas-committers/maas
STATUS: FAILED maas-ci. internal: 8080/job/ maas/job/ branch- tester/ 9211/console 73be918b852fabf 2a617c6151
LOG: http://
COMMIT: 3da16a58b7f1932