Merge maas:s390x-power-driver into maas:master

Proposed by Björn Tillenius
Status: Work in progress
Proposed branch: maas:s390x-power-driver
Merge into: maas:master
Diff against target: 211 lines (+164/-0)
5 files modified
snap/snapcraft.yaml (+2/-0)
src/provisioningserver/drivers/hardware/s390x.py (+48/-0)
src/provisioningserver/drivers/hardware/tests/test_s390x.py (+44/-0)
src/provisioningserver/drivers/power/registry.py (+3/-0)
src/provisioningserver/drivers/power/s390x.py (+67/-0)
Reviewer Review Type Date Requested Status
MAAS Maintainers Pending
Review via email: mp+348990@code.launchpad.net

Description of the change

Add a power driver for IBM Z LPARs. The power driver can connect to the HMC and turn on and off the LPARs.

Mostly complete, but might need another test or two.

Also, it currently depends on the Python zhmcclient library being used. For local testing I pip installed it, but it needs to be packaged before this branch can land.

To post a comment you must log in.
maas:s390x-power-driver updated
26fa215... by Lee Trager

Define chassis = False

Unmerged commits

26fa215... by Lee Trager

Define chassis = False

80cca4d... by Björn Tillenius

Add a S390X power driver that can turn on an off LPARs.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
2index c7b9ac3..1ee698a 100644
3--- a/snap/snapcraft.yaml
4+++ b/snap/snapcraft.yaml
5@@ -92,6 +92,8 @@ parts:
6 - squid
7 - tcpdump
8 - ubuntu-keyring
9+ python-packages:
10+ - zhmcclient
11 organize:
12 lib/python3.*/site-packages/etc/*: etc
13 lib/python3.*/site-packages/usr/bin/*: usr/bin
14diff --git a/src/provisioningserver/drivers/hardware/s390x.py b/src/provisioningserver/drivers/hardware/s390x.py
15new file mode 100644
16index 0000000..3f7b13a
17--- /dev/null
18+++ b/src/provisioningserver/drivers/hardware/s390x.py
19@@ -0,0 +1,48 @@
20+# Copyright 2018 Canonical Ltd. This software is licensed under the
21+# GNU Affero General Public License version 3 (see the file LICENSE).
22+
23+from zhmcclient import (
24+ Client,
25+ Session,
26+)
27+
28+from provisioningserver.logger import get_maas_logger
29+
30+
31+maaslog = get_maas_logger('drivers.s390x')
32+
33+
34+class S390XHMCClient:
35+
36+ def __init__(self, host, user, password):
37+ maaslog.info('Creating session')
38+ self.session = Session(host, user, password)
39+ maaslog.info('Creating client')
40+ self.client = Client(self.session)
41+
42+ def get_power_state(self, uuid):
43+ maaslog.info('Checking power state for {}'.format(uuid))
44+ partition = self._get_partition(uuid)
45+ return partition.properties['status']
46+
47+ def start_partition(self, uuid):
48+ partition = self._get_partition(uuid)
49+ partition.start(wait_for_completion=False)
50+
51+ def stop_partition(self, uuid):
52+ partition = self._get_partition(uuid)
53+ partition.stop(wait_for_completion=False)
54+
55+ def _get_partition(self, uuid):
56+ maaslog.info('Finding partition {}'.format(uuid))
57+ for cpc in self.client.cpcs.list():
58+ maaslog.info('Found a CPC')
59+ if not cpc.dpm_enabled:
60+ maaslog.info('DPM is not enabled')
61+ continue
62+ maaslog.info('Listing partitions')
63+ partitions = cpc.partitions.list(
64+ full_properties=True, filter_args={'object-id': uuid})
65+ if partitions:
66+ maaslog.info('Found partition')
67+ return partitions[0]
68diff --git a/src/provisioningserver/drivers/hardware/tests/test_s390x.py b/src/provisioningserver/drivers/hardware/tests/test_s390x.py
69new file mode 100644
70index 0000000..58d16b5
71--- /dev/null
72+++ b/src/provisioningserver/drivers/hardware/tests/test_s390x.py
73@@ -0,0 +1,44 @@
74+# Copyright 2018 Canonical Ltd. This software is licensed under the
75+# GNU Affero General Public License version 3 (see the file LICENSE).
76+
77+"""Tests for `provisioningserver.drivers.hardware.s390x`.
78+"""
79+
80+__all__ = []
81+
82+import zhmcclient
83+from zhmcclient_mock import FakedSession
84+
85+from maastesting.testcase import (
86+ MAASTestCase,
87+)
88+from provisioningserver.drivers.hardware import s390x
89+
90+
91+class TestS390XHMCClient(MAASTestCase):
92+ """Tests for `S390XHMCClient`."""
93+
94+ def setUp(self):
95+ super().setUp()
96+ self.session_mock = self.patch(s390x, 'Session')
97+ self.faked_session = FakedSession(
98+ 'example.com', 'hmc-test', '2.13.1', '1.8')
99+ self.session_mock.return_value = self.faked_session
100+ self.faked_session.hmc.cpcs.add(
101+ {'name': 'cpc-test',
102+ 'dpm-enabled': True,
103+ })
104+ client = zhmcclient.Client(self.faked_session)
105+ [cpc] = client.cpcs.list()
106+ self.part = cpc.partitions.create(
107+ {'name': 'test',
108+ 'status': 'active',
109+ 'object-id': 'some-uuid',
110+ 'initial-memory': 1024,
111+ 'maximum-memory': 2048})
112+
113+ def test_foo(self):
114+ client = s390x.S390XHMCClient('foo', 'bar', 'baz')
115+ self.assertEqual(
116+ 'active',
117+ client.get_power_state(self.part.properties['object-id']))
118diff --git a/src/provisioningserver/drivers/power/registry.py b/src/provisioningserver/drivers/power/registry.py
119index 14a1136..a37692c 100644
120--- a/src/provisioningserver/drivers/power/registry.py
121+++ b/src/provisioningserver/drivers/power/registry.py
122@@ -22,6 +22,7 @@ from provisioningserver.drivers.power.mscm import MSCMPowerDriver
123 from provisioningserver.drivers.power.msftocs import MicrosoftOCSPowerDriver
124 from provisioningserver.drivers.power.nova import NovaPowerDriver
125 from provisioningserver.drivers.power.recs import RECSPowerDriver
126+from provisioningserver.drivers.power.s390x import S390XPowerDriver
127 from provisioningserver.drivers.power.seamicro import SeaMicroPowerDriver
128 from provisioningserver.drivers.power.ucsm import UCSMPowerDriver
129 from provisioningserver.drivers.power.virsh import VirshPowerDriver
130@@ -61,6 +62,8 @@ power_drivers = [
131 MicrosoftOCSPowerDriver(),
132 NovaPowerDriver(),
133 RECSPowerDriver(),
134+ S390XPowerDriver(),
135+ SeaMicroPowerDriver(),
136 SeaMicroPowerDriver(),
137 UCSMPowerDriver(),
138 VirshPowerDriver(),
139diff --git a/src/provisioningserver/drivers/power/s390x.py b/src/provisioningserver/drivers/power/s390x.py
140new file mode 100644
141index 0000000..3da60ea
142--- /dev/null
143+++ b/src/provisioningserver/drivers/power/s390x.py
144@@ -0,0 +1,67 @@
145+# Copyright 2018 Canonical Ltd. This software is licensed under the
146+# GNU Affero General Public License version 3 (see the file LICENSE).
147+
148+"""s390x Power Driver."""
149+
150+__all__ = []
151+
152+from provisioningserver.drivers import (
153+ make_ip_extractor,
154+ make_setting_field,
155+ SETTING_SCOPE,
156+)
157+from provisioningserver.drivers.hardware.s390x import S390XHMCClient
158+from provisioningserver.drivers.power import PowerDriver
159+from provisioningserver.logger import get_maas_logger
160+
161+
162+maaslog = get_maas_logger('drivers.s390x')
163+
164+
165+def get_client(context):
166+ return S390XHMCClient(
167+ host=context['power_address'], user=context['power_user'],
168+ password=context['power_pass'])
169+
170+
171+class S390XPowerDriver(PowerDriver):
172+
173+ name = 's390x'
174+ chassis = False
175+ description = "IBM Z (s390x)"
176+ settings = [
177+ make_setting_field('power_address', "HMC host", required=True),
178+ make_setting_field('power_user', "HMC user", required=True),
179+ make_setting_field(
180+ 'power_pass', "HMC password",
181+ required=True, field_type='password'),
182+ make_setting_field(
183+ 'power_uuid', "Partition UUID", scope=SETTING_SCOPE.NODE,
184+ required=True),
185+ ]
186+
187+ ip_extractor = make_ip_extractor('power_address')
188+
189+ def detect_missing_packages(self):
190+ return []
191+
192+ def power_on(self, system_id, context):
193+ """Power on S390X partition."""
194+ client = get_client(context)
195+ client.start_partition(context['power_uuid'])
196+
197+ def power_off(self, system_id, context):
198+ """Power off Virsh node."""
199+ client = get_client(context)
200+ client.stop_partition(context['power_uuid'])
201+
202+ def power_query(self, system_id, context):
203+ """Power query Virsh node."""
204+ maaslog.info('Getting client')
205+ client = get_client(context)
206+ maaslog.info('Querying power state')
207+ state = client.get_power_state(context['power_uuid'])
208+ if state in ['starting', 'active', 'stopping', 'degraded']:
209+ return 'on'
210+ else:
211+ return 'off'

Subscribers

People subscribed via source and target branches