Merge lp:~ltrager/maas/rhel_driver into lp:~maas-committers/maas/trunk

Proposed by Lee Trager
Status: Merged
Approved by: Lee Trager
Approved revision: no longer in the source branch.
Merged at revision: 6091
Proposed branch: lp:~ltrager/maas/rhel_driver
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 332 lines (+190/-28)
7 files modified
src/maasserver/utils/osystems.py (+1/-1)
src/maasserver/utils/tests/test_osystems.py (+9/-0)
src/provisioningserver/drivers/osystem/__init__.py (+3/-1)
src/provisioningserver/drivers/osystem/centos.py (+28/-20)
src/provisioningserver/drivers/osystem/rhel.py (+67/-0)
src/provisioningserver/drivers/osystem/tests/test_centos.py (+9/-6)
src/provisioningserver/drivers/osystem/tests/test_rhel.py (+73/-0)
To merge this branch: bzr merge lp:~ltrager/maas/rhel_driver
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Review via email: mp+324909@code.launchpad.net

Commit message

Add RHEL driver and allow CentOS to be deployed using a custom name.

Description of the change

This adds the RHEL driver to MAAS. While testing I realized the CentOS driver only allowed images using the format centos<major><minor>, this branch fixes that making the RHEL and CentOS driver nearly identical. As a quick drive by I fixed 'custom' from being shown multiple times in the deploy drop down.

To post a comment you must log in.
Revision history for this message
Blake Rouse (blake-rouse) wrote :

Looks good.

review: Approve
Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (125.6 KiB)

The attempt to merge lp:~ltrager/maas/rhel_driver into lp:maas failed. Below is the output from the failed tests.

Hit:1 http://security.ubuntu.com/ubuntu xenial-security InRelease
Hit:2 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial InRelease
Hit:3 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-updates InRelease
Hit:4 http://prodstack-zone-2.clouds.archive.ubuntu.com/ubuntu xenial-backports InRelease
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
    --no-install-recommends install apache2 archdetect-deb authbind avahi-utils bash bind9 bind9utils build-essential bzr bzr-builddeb chromium-browser chromium-chromedriver curl daemontools debhelper dh-apport dh-systemd distro-info dnsutils firefox freeipmi-tools git gjs ipython isc-dhcp-common isc-dhcp-server libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libnss-wrapper libpq-dev make nodejs-legacy npm postgresql psmisc pxelinux python3-all python3-apt python3-attr python3-bson python3-convoy python3-crochet python3-cssselect python3-curtin python3-dev python3-distro-info python3-django python3-django-nose python3-django-piston3 python3-dnspython python3-docutils python3-formencode python3-hivex python3-httplib2 python3-jinja2 python3-jsonschema python3-lxml python3-netaddr python3-netifaces python3-novaclient python3-oauth python3-oauthlib python3-openssl python3-paramiko python3-petname python3-pexpect python3-psycopg2 python3-pyinotify python3-pyparsing python3-pyvmomi python3-requests python3-seamicroclient python3-setuptools python3-simplestreams python3-sphinx python3-tempita python3-twisted python3-txtftp python3-tz python3-yaml python3-zope.interface python-bson python-crochet python-django python-django-piston python-djorm-ext-pgarray python-formencode python-lxml python-netaddr python-netifaces python-pocket-lint python-psycopg2 python-simplejson python-tempita python-twisted python-yaml socat syslinux-common tgt ubuntu-cloudimage-keyring wget xvfb
Reading package lists...
Building dependency tree...
Reading state information...
authbind is already the newest version (2.1.1+nmu1).
avahi-utils is already the newest version (0.6.32~rc+dfsg-1ubuntu2).
build-essential is already the newest version (12.1ubuntu2).
debhelper is already the newest version (9.20160115ubuntu3).
distro-info is already the newest version (0.14build1).
libjs-angularjs is already the newest version (1.2.28-1ubuntu2).
libjs-jquery is already the newest version (1.11.3+dfsg-4).
libjs-yui3-full is already the newest version (3.5.1-1ubuntu3).
libjs-yui3-min is already the newest version (3.5.1-1ubuntu3).
make is already the newest version (4.1-6).
postgresql is already the newest version (9.5+173).
psmisc is already the newest version (22.21-2.1build1).
pxelinux is already the newest version (3:6.03+dfsg-11ubuntu1).
python-formencode is already the newest version (1.3.0-0ubuntu5).
python-lxml is already the newest version (3.5.0-1build1).
python-netaddr is already the newest version (0.7.18-1).
python-netifaces is already the newest version (0.10.4-0.1build2).
python-psycopg2 is already the newest version (2.6.1-1build2).
pytho...

Revision history for this message
MAAS Lander (maas-lander) wrote :
Download full text (2.0 MiB)

The attempt to merge lp:~ltrager/maas/rhel_driver into lp:maas failed. Below is the output from the failed tests.

Get:1 http://security.ubuntu.com/ubuntu xenial-security InRelease [102 kB]
Hit:2 http://archive.ubuntu.com/ubuntu xenial InRelease
Get:3 http://archive.ubuntu.com/ubuntu xenial-updates InRelease [102 kB]
Get:4 http://archive.ubuntu.com/ubuntu xenial-backports InRelease [102 kB]
Fetched 306 kB in 1s (261 kB/s)
Reading package lists...
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
    --no-install-recommends install apache2 archdetect-deb authbind avahi-utils bash bind9 bind9utils build-essential bzr bzr-builddeb chromium-browser chromium-chromedriver curl daemontools debhelper dh-apport dh-systemd distro-info dnsutils firefox freeipmi-tools git gjs ipython isc-dhcp-common isc-dhcp-server libjs-angularjs libjs-jquery libjs-jquery-hotkeys libjs-yui3-full libjs-yui3-min libnss-wrapper libpq-dev make nodejs-legacy npm postgresql psmisc pxelinux python3-all python3-apt python3-attr python3-bson python3-convoy python3-crochet python3-cssselect python3-curtin python3-dev python3-distro-info python3-django python3-django-nose python3-django-piston3 python3-dnspython python3-docutils python3-formencode python3-hivex python3-httplib2 python3-jinja2 python3-jsonschema python3-lxml python3-netaddr python3-netifaces python3-novaclient python3-oauth python3-oauthlib python3-openssl python3-paramiko python3-petname python3-pexpect python3-psycopg2 python3-pyinotify python3-pyparsing python3-pyvmomi python3-requests python3-seamicroclient python3-setuptools python3-simplestreams python3-sphinx python3-tempita python3-twisted python3-txtftp python3-tz python3-yaml python3-zope.interface python-bson python-crochet python-django python-django-piston python-djorm-ext-pgarray python-formencode python-lxml python-netaddr python-netifaces python-pocket-lint python-psycopg2 python-simplejson python-tempita python-twisted python-yaml socat syslinux-common tgt ubuntu-cloudimage-keyring wget xvfb
Reading package lists...
Building dependency tree...
Reading state information...
authbind is already the newest version (2.1.1+nmu1).
avahi-utils is already the newest version (0.6.32~rc+dfsg-1ubuntu2).
build-essential is already the newest version (12.1ubuntu2).
debhelper is already the newest version (9.20160115ubuntu3).
distro-info is already the newest version (0.14build1).
libjs-angularjs is already the newest version (1.2.28-1ubuntu2).
libjs-jquery is already the newest version (1.11.3+dfsg-4).
libjs-yui3-full is already the newest version (3.5.1-1ubuntu3).
libjs-yui3-min is already the newest version (3.5.1-1ubuntu3).
make is already the newest version (4.1-6).
postgresql is already the newest version (9.5+173).
psmisc is already the newest version (22.21-2.1build1).
pxelinux is already the newest version (3:6.03+dfsg-11ubuntu1).
python-formencode is already the newest version (1.3.0-0ubuntu5).
python-lxml is already the newest version (3.5.0-1build1).
python-netaddr is already the newest version (0.7.18-1).
python-netifaces is already the newest version (0.10.4-0.1build2).
python-psycopg2 is already the newest version (2.6.1-1build2).
python-simplejson ...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/utils/osystems.py'
2--- src/maasserver/utils/osystems.py 2017-05-05 22:08:46 +0000
3+++ src/maasserver/utils/osystems.py 2017-06-16 09:40:48 +0000
4@@ -57,7 +57,7 @@
5 (osystem['name'], osystem['title'])
6 for osystem in osystems
7 ]
8- return choices
9+ return sorted(list(set(choices)))
10
11
12 def list_all_usable_releases(osystems):
13
14=== modified file 'src/maasserver/utils/tests/test_osystems.py'
15--- src/maasserver/utils/tests/test_osystems.py 2017-05-05 22:08:46 +0000
16+++ src/maasserver/utils/tests/test_osystems.py 2017-06-16 09:40:48 +0000
17@@ -95,6 +95,15 @@
18 [(osystem['name'], osystem['title'])],
19 list_osystem_choices([osystem], include_default=False))
20
21+ def test_list_osystem_choices_doesnt_duplicate(self):
22+ self.assertEqual(
23+ [('custom', 'Custom')],
24+ list_osystem_choices(
25+ [
26+ {'name': 'custom', 'title': 'Custom'},
27+ {'name': 'custom', 'title': 'Custom'},
28+ ], include_default=False))
29+
30
31 class TestReleases(MAASServerTestCase):
32
33
34=== modified file 'src/provisioningserver/drivers/osystem/__init__.py'
35--- src/provisioningserver/drivers/osystem/__init__.py 2017-03-01 17:16:56 +0000
36+++ src/provisioningserver/drivers/osystem/__init__.py 2017-06-16 09:40:48 +0000
37@@ -1,4 +1,4 @@
38-# Copyright 2014-2016 Canonical Ltd. This software is licensed under the
39+# Copyright 2014-2017 Canonical Ltd. This software is licensed under the
40 # GNU Affero General Public License version 3 (see the file LICENSE).
41
42 """Osystem Drivers."""
43@@ -205,6 +205,7 @@
44 from provisioningserver.drivers.osystem.ubuntucore import UbuntuCoreOS
45 from provisioningserver.drivers.osystem.bootloader import BootLoaderOS
46 from provisioningserver.drivers.osystem.centos import CentOS
47+from provisioningserver.drivers.osystem.rhel import RHELOS
48 from provisioningserver.drivers.osystem.custom import CustomOS
49 from provisioningserver.drivers.osystem.windows import WindowsOS
50 from provisioningserver.drivers.osystem.suse import SUSEOS
51@@ -214,6 +215,7 @@
52 UbuntuCoreOS(),
53 BootLoaderOS(),
54 CentOS(),
55+ RHELOS(),
56 CustomOS(),
57 WindowsOS(),
58 SUSEOS(),
59
60=== modified file 'src/provisioningserver/drivers/osystem/centos.py'
61--- src/provisioningserver/drivers/osystem/centos.py 2017-04-25 20:44:56 +0000
62+++ src/provisioningserver/drivers/osystem/centos.py 2017-06-16 09:40:48 +0000
63@@ -1,4 +1,4 @@
64-# Copyright 2014-2015 Canonical Ltd. This software is licensed under the
65+# Copyright 2014-2017 Canonical Ltd. This software is licensed under the
66 # GNU Affero General Public License version 3 (see the file LICENSE).
67
68 """CentOS Operating System."""
69@@ -14,20 +14,20 @@
70 OperatingSystem,
71 )
72
73-
74-DISTRO_SERIES_DEFAULT = 'centos65'
75-
76-# Regex matcher that is used to check if the release is supported.
77-# It needs to match the name "centosXY". Where "X" is the major version
78-# and "Y" is the minor version.
79-DISTRO_MATCHER = re.compile("centos(?P<major>[0-9])(?P<minor>[0-9])?\Z")
80+# Regex matcher that is used to check if the release is supported. The release
81+# name just has to start with 'centos' to be supported but the major, minor,
82+# and title are found if available to help format the title.
83+DISTRO_MATCHER = re.compile(
84+ '^centos((?P<major>[0-9])(?P<minor>[0-9])?)?([\-\.]?(?P<title>.+))?$',
85+ re.I)
86+DISTRO_SERIES_DEFAULT = 'centos70'
87
88
89 class CentOS(OperatingSystem):
90 """CentOS operating system."""
91
92- name = "centos"
93- title = "CentOS"
94+ name = 'centos'
95+ title = 'CentOS'
96
97 def get_boot_image_purposes(self, arch, subarch, release, label):
98 """Gets the purpose of each boot image."""
99@@ -36,7 +36,6 @@
100 ]
101
102 def is_release_supported(self, release):
103- """Return True when the release is supported, False otherwise."""
104 matched = DISTRO_MATCHER.match(release)
105 return matched is not None
106
107@@ -49,10 +48,14 @@
108 """Return the title for the given release."""
109 matched = DISTRO_MATCHER.match(release)
110 if matched is None:
111- return None
112- matched_dict = matched.groupdict()
113- major = matched_dict['major']
114- minor = matched_dict['minor']
115+ # This should never happen as is_release_supported will return
116+ # false but just in case it does...
117+ return "%s %s" % (self.title, release)
118+
119+ ret = self.title
120+ major = matched.group('major')
121+ minor = matched.group('minor')
122+ title = matched.group('title')
123 # MAAS provided images via streams are not bound to a minor
124 # release version, which means we always provide the latest
125 # available release from CentOS 6 and CentOS 7. To address
126@@ -65,9 +68,14 @@
127 # from the stream and the minor version doesn't match to what
128 # we publish. As such, we ensure that we only return minor
129 # if we have any other version other that X.0, 7.0 and 6.6.
130- if minor is None or minor == '0':
131- return "CentOS %s" % major
132+ if major is not None and minor is None or minor == '0':
133+ ret = "%s %s" % (ret, major)
134 elif major == '6' and minor == '6':
135- return "CentOS %s" % major
136- else:
137- return "CentOS %s.%s" % (major, minor)
138+ ret = "%s %s" % (ret, major)
139+ elif None not in (major, minor):
140+ ret = "%s %s.%s" % (ret, major, minor)
141+
142+ if title is not None:
143+ ret = "%s %s" % (ret, title)
144+
145+ return ret
146
147=== added file 'src/provisioningserver/drivers/osystem/rhel.py'
148--- src/provisioningserver/drivers/osystem/rhel.py 1970-01-01 00:00:00 +0000
149+++ src/provisioningserver/drivers/osystem/rhel.py 2017-06-16 09:40:48 +0000
150@@ -0,0 +1,67 @@
151+# Copyright 2017 Canonical Ltd. This software is licensed under the
152+# GNU Affero General Public License version 3 (see the file LICENSE).
153+
154+"""RHELOS Operating System."""
155+
156+__all__ = [
157+ "RHELOS",
158+ ]
159+
160+import re
161+
162+from provisioningserver.drivers.osystem import (
163+ BOOT_IMAGE_PURPOSE,
164+ OperatingSystem,
165+)
166+
167+# Regex matcher that is used to check if the release is supported. The release
168+# name just has to start with 'rhel' to be supported but the major, minor,
169+# and title are found if available to help format the title.
170+DISTRO_MATCHER = re.compile(
171+ '^rhel((?P<major>[0-9])(?P<minor>[0-9])?)?([\-\.]?(?P<title>.+))?$',
172+ re.I)
173+DISTRO_SERIES_DEFAULT = 'rhel7'
174+
175+
176+class RHELOS(OperatingSystem):
177+ """RHELOS operating system."""
178+
179+ name = 'rhel'
180+ title = 'Redhat Enterprise Linux'
181+
182+ def get_boot_image_purposes(self, arch, subarch, release, label):
183+ """Gets the purpose of each boot image."""
184+ return [
185+ BOOT_IMAGE_PURPOSE.XINSTALL
186+ ]
187+
188+ def is_release_supported(self, release):
189+ matched = DISTRO_MATCHER.match(release)
190+ return matched is not None
191+
192+ def get_default_release(self):
193+ """Gets the default release to use when a release is not
194+ explicit."""
195+ return DISTRO_SERIES_DEFAULT
196+
197+ def get_release_title(self, release):
198+ """Return the title for the given release."""
199+ matched = DISTRO_MATCHER.match(release)
200+ if matched is None:
201+ # This should never happen as is_release_supported will return
202+ # false but just in case it does...
203+ return "%s %s" % (self.title, release)
204+
205+ ret = self.title
206+ major = matched.group('major')
207+ minor = matched.group('minor')
208+ title = matched.group('title')
209+ if None not in (major, minor):
210+ ret = "%s %s.%s" % (ret, major, minor)
211+ elif major is not None:
212+ ret = "%s %s" % (ret, major)
213+
214+ if title is not None:
215+ ret = "%s %s" % (ret, title)
216+
217+ return ret
218
219=== modified file 'src/provisioningserver/drivers/osystem/tests/test_centos.py'
220--- src/provisioningserver/drivers/osystem/tests/test_centos.py 2017-04-26 14:53:22 +0000
221+++ src/provisioningserver/drivers/osystem/tests/test_centos.py 2017-06-16 09:40:48 +0000
222@@ -1,4 +1,4 @@
223-# Copyright 2014-2015 Canonical Ltd. This software is licensed under the
224+# Copyright 2014-2017 Canonical Ltd. This software is licensed under the
225 # GNU Affero General Public License version 3 (see the file LICENSE).
226
227 """Tests for the CentOS module."""
228@@ -41,8 +41,10 @@
229 "centos7": True,
230 "centos71": True,
231 "cent65": False,
232- "cent": False,
233- "centos711": False,
234+ "centos711": True,
235+ "centos-title": True,
236+ "centos71.custom": True,
237+ factory.make_name("name"): False,
238 }
239 osystem = CentOS()
240 for name, supported in name_supported.items():
241@@ -62,9 +64,10 @@
242 "centos7": "CentOS 7",
243 "centos70": "CentOS 7", # See LP: #1654063
244 "centos71": "CentOS 7.1",
245- "cent65": None,
246- "cent": None,
247- "centos711": None,
248+ "centos65": "CentOS 6.5",
249+ "cent": "CentOS cent",
250+ "centos711": "CentOS 7.1 1",
251+ "centos71-custom": "CentOS 7.1 custom",
252 }
253 osystem = CentOS()
254 for name, title in name_titles.items():
255
256=== added file 'src/provisioningserver/drivers/osystem/tests/test_rhel.py'
257--- src/provisioningserver/drivers/osystem/tests/test_rhel.py 1970-01-01 00:00:00 +0000
258+++ src/provisioningserver/drivers/osystem/tests/test_rhel.py 2017-06-16 09:40:48 +0000
259@@ -0,0 +1,73 @@
260+# Copyright 2017 Canonical Ltd. This software is licensed under the
261+# GNU Affero General Public License version 3 (see the file LICENSE).
262+
263+"""Tests for the RHEL module."""
264+
265+__all__ = []
266+
267+from itertools import product
268+
269+from maastesting.factory import factory
270+from maastesting.testcase import MAASTestCase
271+from provisioningserver.drivers.osystem.rhel import (
272+ BOOT_IMAGE_PURPOSE,
273+ DISTRO_SERIES_DEFAULT,
274+ RHELOS,
275+)
276+from testtools.matchers import Equals
277+
278+
279+class TestRHEL(MAASTestCase):
280+
281+ def test_get_boot_image_purposes(self):
282+ osystem = RHELOS()
283+ archs = [factory.make_name('arch') for _ in range(2)]
284+ subarchs = [factory.make_name('subarch') for _ in range(2)]
285+ releases = [factory.make_name('release') for _ in range(2)]
286+ labels = [factory.make_name('label') for _ in range(2)]
287+ for arch, subarch, release, label in product(
288+ archs, subarchs, releases, labels):
289+ expected = osystem.get_boot_image_purposes(
290+ arch, subarchs, release, label)
291+ self.assertIsInstance(expected, list)
292+ self.assertEqual(expected, [
293+ BOOT_IMAGE_PURPOSE.XINSTALL,
294+ ])
295+
296+ def test_is_release_supported(self):
297+ name_supported = {
298+ "rhel6": True,
299+ "rhel65": True,
300+ "rhel7": True,
301+ "rhel71": True,
302+ "cent65": False,
303+ "rhel711": True,
304+ "rhel-title": True,
305+ "rhel71.custom": True,
306+ factory.make_name("name"): False,
307+ }
308+ osystem = RHELOS()
309+ for name, supported in name_supported.items():
310+ self.expectThat(
311+ osystem.is_release_supported(name), Equals(supported))
312+
313+ def test_get_default_release(self):
314+ osystem = RHELOS()
315+ expected = osystem.get_default_release()
316+ self.assertEqual(expected, DISTRO_SERIES_DEFAULT)
317+
318+ def test_get_release_title(self):
319+ name_titles = {
320+ "rhel6": "Redhat Enterprise Linux 6",
321+ "rhel65": "Redhat Enterprise Linux 6.5",
322+ "rhel7": "Redhat Enterprise Linux 7",
323+ "rhel71": "Redhat Enterprise Linux 7.1",
324+ "rhel65": "Redhat Enterprise Linux 6.5",
325+ "cent": "Redhat Enterprise Linux cent",
326+ "rhel711": "Redhat Enterprise Linux 7.1 1",
327+ "rhel71-custom": "Redhat Enterprise Linux 7.1 custom",
328+ }
329+ osystem = RHELOS()
330+ for name, title in name_titles.items():
331+ self.expectThat(
332+ osystem.get_release_title(name), Equals(title))