Merge ~ltrager/maas:lp1701694_2.2 into maas:2.2
- Git
- lp:~ltrager/maas
- lp1701694_2.2
- Merge into 2.2
Status: | Merged |
---|---|
Approved by: | Lee Trager |
Approved revision: | c262efce2849c532e1373662b12354f5d5e0eea5 |
Merge reported by: | Lee Trager |
Merged at revision: | c262efce2849c532e1373662b12354f5d5e0eea5 |
Proposed branch: | ~ltrager/maas:lp1701694_2.2 |
Merge into: | maas:2.2 |
Diff against target: |
727 lines (+186/-138) 22 files modified
src/maasserver/bootresources.py (+3/-3) src/maasserver/forms/__init__.py (+11/-13) src/maasserver/forms/tests/test_bootresource.py (+45/-2) src/maasserver/models/bootresource.py (+12/-3) src/maasserver/models/tests/test_bootresource.py (+21/-0) src/maasserver/tests/test_bootresources.py (+3/-3) src/maasserver/utils/osystems.py (+4/-5) src/maasserver/utils/tests/test_osystems.py (+25/-0) src/provisioningserver/drivers/osystem/__init__.py (+6/-5) src/provisioningserver/drivers/osystem/bootloader.py (+0/-4) src/provisioningserver/drivers/osystem/centos.py (+28/-24) src/provisioningserver/drivers/osystem/custom.py (+0/-5) src/provisioningserver/drivers/osystem/tests/test_base.py (+10/-1) src/provisioningserver/drivers/osystem/tests/test_bootloader.py (+0/-5) src/provisioningserver/drivers/osystem/tests/test_centos.py (+5/-19) src/provisioningserver/drivers/osystem/tests/test_custom.py (+0/-9) src/provisioningserver/drivers/osystem/tests/test_ubuntu.py (+11/-6) src/provisioningserver/drivers/osystem/tests/test_ubuntucore.py (+0/-9) src/provisioningserver/drivers/osystem/ubuntu.py (+1/-9) src/provisioningserver/drivers/osystem/ubuntucore.py (+0/-5) src/provisioningserver/drivers/osystem/windows.py (+1/-5) src/provisioningserver/testing/os.py (+0/-3) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Blake Rouse (community) | Approve | ||
Review via email: mp+327753@code.launchpad.net |
Description of the change
This is a backport of https:/
MAAS Lander (maas-lander) wrote : | # |
LANDING
-b lp1701694_2.2 lp:~ltrager/maas into -b 2.2 lp:~maas-committers/maas
STATUS: FAILED BUILD
LOG: http://
MAAS Lander (maas-lander) wrote : | # |
LANDING
-b lp1701694_2.2 lp:~ltrager/maas into -b 2.2 lp:~maas-committers/maas
STATUS: FAILED BUILD
LOG: http://
MAAS Lander (maas-lander) wrote : | # |
LANDING
-b lp1701694_2.2 lp:~ltrager/maas into -b 2.2 lp:~maas-committers/maas
STATUS: FAILED BUILD
LOG: http://
MAAS Lander (maas-lander) wrote : | # |
LANDING
-b lp1701694_2.2 lp:~ltrager/maas into -b 2.2 lp:~maas-committers/maas
STATUS: FAILED MERGE
LOG: http://
Preview Diff
1 | diff --git a/src/maasserver/bootresources.py b/src/maasserver/bootresources.py |
2 | index 996a6a0..f3c3824 100644 |
3 | --- a/src/maasserver/bootresources.py |
4 | +++ b/src/maasserver/bootresources.py |
5 | @@ -224,11 +224,11 @@ class SimpleStreamsHandler: |
6 | def get_boot_resource_identifiers(self, resource): |
7 | """Return tuple (os, arch, subarch, series) for the given resource.""" |
8 | arch, subarch = resource.split_arch() |
9 | - if resource.rtype == BOOT_RESOURCE_TYPE.UPLOADED: |
10 | + if '/' in resource.name: |
11 | + os, series = resource.name.split('/') |
12 | + else: |
13 | os = 'custom' |
14 | series = resource.name |
15 | - else: |
16 | - os, series = resource.name.split('/') |
17 | return (os, arch, subarch, series) |
18 | |
19 | def get_product_name(self, resource): |
20 | diff --git a/src/maasserver/forms/__init__.py b/src/maasserver/forms/__init__.py |
21 | index c03cc54..e6384c8 100644 |
22 | --- a/src/maasserver/forms/__init__.py |
23 | +++ b/src/maasserver/forms/__init__.py |
24 | @@ -2237,11 +2237,19 @@ class BootResourceForm(MAASModelForm): |
25 | If the passed resource already has a match in the database then that |
26 | resource is returned. If not then the passed resource is returned. |
27 | """ |
28 | + if resource.rtype == BOOT_RESOURCE_TYPE.UPLOADED: |
29 | + # Uploaded BootResources were previously generated, now they're |
30 | + # uploaded. Search for both to convert. |
31 | + rtypes = [ |
32 | + BOOT_RESOURCE_TYPE.UPLOADED, BOOT_RESOURCE_TYPE.GENERATED] |
33 | + else: |
34 | + rtypes = [resource.type] |
35 | existing_resource = get_one( |
36 | BootResource.objects.filter( |
37 | - rtype=resource.rtype, |
38 | + rtype__in=rtypes, |
39 | name=resource.name, architecture=resource.architecture)) |
40 | if existing_resource is not None: |
41 | + existing_resource.rtype = resource.rtype |
42 | return existing_resource |
43 | return resource |
44 | |
45 | @@ -2289,24 +2297,14 @@ class BootResourceForm(MAASModelForm): |
46 | This implementation of `save` does not support the `commit` argument. |
47 | """ |
48 | resource = super(BootResourceForm, self).save(commit=False) |
49 | - |
50 | - # XXX blake_r 2014-09-22 bug=1361370: Temporarily support the ability |
51 | - # to upload a generated image. This should only exist while CentOS and |
52 | - # Windows images need to be uploaded, rather than synced or generated. |
53 | - if '/' not in resource.name: |
54 | - label = 'uploaded' |
55 | - resource.rtype = BOOT_RESOURCE_TYPE.UPLOADED |
56 | - else: |
57 | - label = 'generated' |
58 | - resource.rtype = BOOT_RESOURCE_TYPE.GENERATED |
59 | - |
60 | + resource.rtype = BOOT_RESOURCE_TYPE.UPLOADED |
61 | resource = self.get_existing_resource(resource) |
62 | resource.extra = {'subarches': resource.architecture.split('/')[1]} |
63 | if 'title' in self.cleaned_data: |
64 | resource.extra['title'] = self.cleaned_data['title'] |
65 | |
66 | resource.save() |
67 | - resource_set = self.create_resource_set(resource, label) |
68 | + resource_set = self.create_resource_set(resource, 'uploaded') |
69 | self.create_resource_file( |
70 | resource_set, self.cleaned_data) |
71 | return resource |
72 | diff --git a/src/maasserver/forms/tests/test_bootresource.py b/src/maasserver/forms/tests/test_bootresource.py |
73 | index be7845a..5fb843f 100644 |
74 | --- a/src/maasserver/forms/tests/test_bootresource.py |
75 | +++ b/src/maasserver/forms/tests/test_bootresource.py |
76 | @@ -8,6 +8,7 @@ __all__ = [] |
77 | import random |
78 | |
79 | from django.core.files.uploadedfile import SimpleUploadedFile |
80 | +from maasserver.clusterrpc import osystems |
81 | from maasserver.enum import ( |
82 | BOOT_RESOURCE_FILE_TYPE, |
83 | BOOT_RESOURCE_TYPE, |
84 | @@ -99,8 +100,11 @@ class TestBootResourceForm(MAASServerTestCase): |
85 | written_content = stream.read() |
86 | self.assertEqual(content, written_content) |
87 | |
88 | - def test_creates_boot_resoures_with_generated_rtype(self): |
89 | + def test_creates_boot_resoures_with_uploaded_rtype(self): |
90 | os = factory.make_name('os') |
91 | + self.patch( |
92 | + osystems, 'gen_all_known_operating_systems').return_value = [ |
93 | + {'name': os}] |
94 | series = factory.make_name('series') |
95 | name = '%s/%s' % (os, series) |
96 | architecture = make_usable_architecture(self) |
97 | @@ -118,7 +122,7 @@ class TestBootResourceForm(MAASServerTestCase): |
98 | self.assertTrue(form.is_valid(), form._errors) |
99 | form.save() |
100 | resource = BootResource.objects.get( |
101 | - rtype=BOOT_RESOURCE_TYPE.GENERATED, |
102 | + rtype=BOOT_RESOURCE_TYPE.UPLOADED, |
103 | name=name, architecture=architecture) |
104 | resource_set = resource.sets.first() |
105 | rfile = resource_set.files.first() |
106 | @@ -131,6 +135,9 @@ class TestBootResourceForm(MAASServerTestCase): |
107 | |
108 | def test_adds_boot_resource_set_to_existing_generated_boot_resource(self): |
109 | os = factory.make_name('os') |
110 | + self.patch( |
111 | + osystems, 'gen_all_known_operating_systems').return_value = [ |
112 | + {'name': os}] |
113 | series = factory.make_name('series') |
114 | name = '%s/%s' % (os, series) |
115 | architecture = make_usable_architecture(self) |
116 | @@ -159,6 +166,42 @@ class TestBootResourceForm(MAASServerTestCase): |
117 | with rfile.largefile.content.open('rb') as stream: |
118 | written_content = stream.read() |
119 | self.assertEqual(content, written_content) |
120 | + self.assertEqual(resource.rtype, BOOT_RESOURCE_TYPE.UPLOADED) |
121 | + |
122 | + def test_adds_boot_resource_set_to_existing_uploaded_boot_resource(self): |
123 | + os = factory.make_name('os') |
124 | + self.patch( |
125 | + osystems, 'gen_all_known_operating_systems').return_value = [ |
126 | + {'name': os}] |
127 | + series = factory.make_name('series') |
128 | + name = '%s/%s' % (os, series) |
129 | + architecture = make_usable_architecture(self) |
130 | + resource = factory.make_usable_boot_resource( |
131 | + rtype=BOOT_RESOURCE_TYPE.UPLOADED, |
132 | + name=name, architecture=architecture) |
133 | + upload_type, filetype = self.pick_filetype() |
134 | + size = random.randint(1024, 2048) |
135 | + content = factory.make_string(size).encode('utf-8') |
136 | + upload_name = factory.make_name('filename') |
137 | + uploaded_file = SimpleUploadedFile(content=content, name=upload_name) |
138 | + data = { |
139 | + 'name': name, |
140 | + 'architecture': architecture, |
141 | + 'filetype': upload_type, |
142 | + } |
143 | + form = BootResourceForm(data=data, files={'content': uploaded_file}) |
144 | + self.assertTrue(form.is_valid(), form._errors) |
145 | + form.save() |
146 | + resource = reload_object(resource) |
147 | + resource_set = resource.sets.order_by('id').last() |
148 | + rfile = resource_set.files.first() |
149 | + self.assertTrue(filetype, rfile.filetype) |
150 | + self.assertTrue(filetype, rfile.filename) |
151 | + self.assertTrue(size, rfile.largefile.total_size) |
152 | + with rfile.largefile.content.open('rb') as stream: |
153 | + written_content = stream.read() |
154 | + self.assertEqual(content, written_content) |
155 | + self.assertEqual(resource.rtype, BOOT_RESOURCE_TYPE.UPLOADED) |
156 | |
157 | def test_requires_fields(self): |
158 | form = BootResourceForm(data={}) |
159 | diff --git a/src/maasserver/models/bootresource.py b/src/maasserver/models/bootresource.py |
160 | index 905e675..5af3eee 100644 |
161 | --- a/src/maasserver/models/bootresource.py |
162 | +++ b/src/maasserver/models/bootresource.py |
163 | @@ -187,6 +187,7 @@ class BootResourceManager(Manager): |
164 | rtypes = [ |
165 | BOOT_RESOURCE_TYPE.SYNCED, |
166 | BOOT_RESOURCE_TYPE.GENERATED, |
167 | + BOOT_RESOURCE_TYPE.UPLOADED, |
168 | ] |
169 | name = '%s/%s' % (image['osystem'], image['release']) |
170 | else: |
171 | @@ -442,9 +443,17 @@ class BootResource(CleanSave, TimestampedModel): |
172 | """ |
173 | if self.rtype == BOOT_RESOURCE_TYPE.UPLOADED: |
174 | if '/' in self.name: |
175 | - raise ValidationError( |
176 | - "%s boot resource cannot contain a '/' in it's name." % ( |
177 | - self.display_rtype)) |
178 | + # Avoid circular dependency |
179 | + from maasserver.clusterrpc.osystems import ( |
180 | + gen_all_known_operating_systems, |
181 | + ) |
182 | + osystem = self.name.split('/')[0] |
183 | + if osystem not in { |
184 | + i['name'] for i in gen_all_known_operating_systems()}: |
185 | + raise ValidationError( |
186 | + "%s boot resource cannot contain a '/' in it's name " |
187 | + "unless it starts with a supported operating system." |
188 | + % (self.display_rtype)) |
189 | elif self.rtype in RTYPE_REQUIRING_OS_SERIES_NAME: |
190 | if '/' not in self.name: |
191 | raise ValidationError( |
192 | diff --git a/src/maasserver/models/tests/test_bootresource.py b/src/maasserver/models/tests/test_bootresource.py |
193 | index 2efb4fc..59c3ac2 100644 |
194 | --- a/src/maasserver/models/tests/test_bootresource.py |
195 | +++ b/src/maasserver/models/tests/test_bootresource.py |
196 | @@ -10,6 +10,7 @@ from datetime import datetime |
197 | import random |
198 | |
199 | from django.core.exceptions import ValidationError |
200 | +from maasserver.clusterrpc import osystems |
201 | from maasserver.clusterrpc.testing.boot_images import make_rpc_boot_image |
202 | from maasserver.enum import ( |
203 | BOOT_RESOURCE_FILE_TYPE, |
204 | @@ -771,6 +772,26 @@ class TestBootResource(MAASServerTestCase): |
205 | self.assertRaises( |
206 | ValidationError, resource.save) |
207 | |
208 | + def test_validation_allows_any_uploaded_name_slash_with_supported_os(self): |
209 | + osystem = factory.make_name('osystem') |
210 | + self.patch( |
211 | + osystems, 'gen_all_known_operating_systems').return_value = [ |
212 | + {'name': osystem}] |
213 | + name = '%s/%s' % (osystem, factory.make_name('release')) |
214 | + arch = '%s/%s' % ( |
215 | + factory.make_name('arch'), factory.make_name('subarch')) |
216 | + resource = BootResource( |
217 | + rtype=BOOT_RESOURCE_TYPE.UPLOADED, name=name, architecture=arch) |
218 | + resource.save() |
219 | + |
220 | + def test_validation_allows_any_uploaded_name_without_slash(self): |
221 | + name = factory.make_name('name') |
222 | + arch = '%s/%s' % ( |
223 | + factory.make_name('arch'), factory.make_name('subarch')) |
224 | + resource = BootResource( |
225 | + rtype=BOOT_RESOURCE_TYPE.UPLOADED, name=name, architecture=arch) |
226 | + resource.save() |
227 | + |
228 | def test_create_raises_error_on_not_unique(self): |
229 | name = '%s/%s' % ( |
230 | factory.make_name('os'), factory.make_name('series')) |
231 | diff --git a/src/maasserver/tests/test_bootresources.py b/src/maasserver/tests/test_bootresources.py |
232 | index 135715b..3c860e8 100644 |
233 | --- a/src/maasserver/tests/test_bootresources.py |
234 | +++ b/src/maasserver/tests/test_bootresources.py |
235 | @@ -200,11 +200,11 @@ class TestSimpleStreamsHandler(MAASServerTestCase): |
236 | |
237 | def get_product_name_for_resource(self, resource): |
238 | arch, subarch = resource.architecture.split('/') |
239 | - if resource.rtype == BOOT_RESOURCE_TYPE.UPLOADED: |
240 | + if '/' in resource.name: |
241 | + os, series = resource.name.split('/') |
242 | + else: |
243 | os = 'custom' |
244 | series = resource.name |
245 | - else: |
246 | - os, series = resource.name.split('/') |
247 | return 'maas:boot:%s:%s:%s:%s' % (os, arch, subarch, series) |
248 | |
249 | def make_usable_product_boot_resource( |
250 | diff --git a/src/maasserver/utils/osystems.py b/src/maasserver/utils/osystems.py |
251 | index d7ad380..2746d46 100644 |
252 | --- a/src/maasserver/utils/osystems.py |
253 | +++ b/src/maasserver/utils/osystems.py |
254 | @@ -25,7 +25,6 @@ from distro_info import UbuntuDistroInfo |
255 | from django.core.exceptions import ValidationError |
256 | from django.db.models import Q |
257 | from maasserver.clusterrpc.osystems import gen_all_known_operating_systems |
258 | -from maasserver.enum import BOOT_RESOURCE_TYPE |
259 | from maasserver.models import ( |
260 | BootResource, |
261 | BootSourceCache, |
262 | @@ -57,7 +56,7 @@ def list_osystem_choices(osystems, include_default=True): |
263 | (osystem['name'], osystem['title']) |
264 | for osystem in osystems |
265 | ] |
266 | - return choices |
267 | + return sorted(list(set(choices))) |
268 | |
269 | |
270 | def list_all_usable_releases(osystems): |
271 | @@ -75,11 +74,11 @@ def list_all_usable_releases(osystems): |
272 | # When custom images are returned by list_all_usable_osystems |
273 | # the osystem name is 'custom' and the release name to whatever |
274 | # the user specified. |
275 | - if resource.rtype == BOOT_RESOURCE_TYPE.UPLOADED: |
276 | + if '/' in resource.name: |
277 | + osystem, release = resource.name.split('/') |
278 | + else: |
279 | osystem = 'custom' |
280 | release = resource.name |
281 | - else: |
282 | - osystem, release = resource.name.split('/') |
283 | if osystem not in titles: |
284 | titles[osystem] = {} |
285 | titles[osystem][release] = resource.extra['title'] |
286 | diff --git a/src/maasserver/utils/tests/test_osystems.py b/src/maasserver/utils/tests/test_osystems.py |
287 | index e0d92a8..8ee6b92 100644 |
288 | --- a/src/maasserver/utils/tests/test_osystems.py |
289 | +++ b/src/maasserver/utils/tests/test_osystems.py |
290 | @@ -10,6 +10,7 @@ import random |
291 | |
292 | from distro_info import UbuntuDistroInfo |
293 | from django.core.exceptions import ValidationError |
294 | +from maasserver.clusterrpc import osystems |
295 | from maasserver.clusterrpc.testing.osystems import ( |
296 | make_rpc_osystem, |
297 | make_rpc_release, |
298 | @@ -95,6 +96,15 @@ class TestOsystems(MAASServerTestCase): |
299 | [(osystem['name'], osystem['title'])], |
300 | list_osystem_choices([osystem], include_default=False)) |
301 | |
302 | + def test_list_osystem_choices_doesnt_duplicate(self): |
303 | + self.assertEqual( |
304 | + [('custom', 'Custom')], |
305 | + list_osystem_choices( |
306 | + [ |
307 | + {'name': 'custom', 'title': 'Custom'}, |
308 | + {'name': 'custom', 'title': 'Custom'}, |
309 | + ], include_default=False)) |
310 | + |
311 | |
312 | class TestReleases(MAASServerTestCase): |
313 | |
314 | @@ -145,6 +155,21 @@ class TestReleases(MAASServerTestCase): |
315 | title, |
316 | list_all_usable_releases([osystem])[osystem['name']][0]['title']) |
317 | |
318 | + def test_list_all_usable_releases_finds_uploaded_with_osystem(self): |
319 | + release = make_rpc_release() |
320 | + osystem = make_rpc_osystem(releases=[release]) |
321 | + title = factory.make_name('title') |
322 | + self.patch( |
323 | + osystems, 'gen_all_known_operating_systems').return_value = [ |
324 | + {'name': osystem['name']}] |
325 | + factory.make_BootResource( |
326 | + rtype=BOOT_RESOURCE_TYPE.UPLOADED, |
327 | + name='%s/%s' % (osystem['name'], release['name']), |
328 | + extra={'title': title}) |
329 | + self.assertEquals( |
330 | + title, |
331 | + list_all_usable_releases([osystem])[osystem['name']][0]['title']) |
332 | + |
333 | def test_list_all_releases_requiring_keys(self): |
334 | releases = [ |
335 | make_rpc_release(requires_license_key=True) for _ in range(3)] |
336 | diff --git a/src/provisioningserver/drivers/osystem/__init__.py b/src/provisioningserver/drivers/osystem/__init__.py |
337 | index bdf6ff8..93a9f4b 100644 |
338 | --- a/src/provisioningserver/drivers/osystem/__init__.py |
339 | +++ b/src/provisioningserver/drivers/osystem/__init__.py |
340 | @@ -1,4 +1,4 @@ |
341 | -# Copyright 2014-2016 Canonical Ltd. This software is licensed under the |
342 | +# Copyright 2014-2017 Canonical Ltd. This software is licensed under the |
343 | # GNU Affero General Public License version 3 (see the file LICENSE). |
344 | |
345 | """Osystem Drivers.""" |
346 | @@ -67,10 +67,6 @@ class OperatingSystem(metaclass=ABCMeta): |
347 | """Title of the operating system.""" |
348 | |
349 | @abstractmethod |
350 | - def is_release_supported(self, release): |
351 | - """Return True when the release is supported, False otherwise.""" |
352 | - |
353 | - @abstractmethod |
354 | def get_default_release(self): |
355 | """Return the default release to use when none is specified. |
356 | |
357 | @@ -96,6 +92,11 @@ class OperatingSystem(metaclass=ABCMeta): |
358 | :return: list of supported purposes |
359 | """ |
360 | |
361 | + def is_release_supported(self, release): |
362 | + """Return True when the release is supported, False otherwise.""" |
363 | + # If the osystem matches assume all releases are supported. |
364 | + return True |
365 | + |
366 | def format_release_choices(self, releases): |
367 | """Format the release choices that are presented to the user. |
368 | |
369 | diff --git a/src/provisioningserver/drivers/osystem/bootloader.py b/src/provisioningserver/drivers/osystem/bootloader.py |
370 | index 6ada008..2811a82 100644 |
371 | --- a/src/provisioningserver/drivers/osystem/bootloader.py |
372 | +++ b/src/provisioningserver/drivers/osystem/bootloader.py |
373 | @@ -18,10 +18,6 @@ class BootLoaderOS(OperatingSystem): |
374 | name = 'bootloader' |
375 | title = 'Bootloader' |
376 | |
377 | - def is_release_supported(self, release): |
378 | - # All releases are supported, they're pulled from the Ubuntu archive. |
379 | - return True |
380 | - |
381 | def get_default_release(self): |
382 | # No Default bootloader as it depends on the arch. |
383 | return '' |
384 | diff --git a/src/provisioningserver/drivers/osystem/centos.py b/src/provisioningserver/drivers/osystem/centos.py |
385 | index aee813b..b9f2290 100644 |
386 | --- a/src/provisioningserver/drivers/osystem/centos.py |
387 | +++ b/src/provisioningserver/drivers/osystem/centos.py |
388 | @@ -1,4 +1,4 @@ |
389 | -# Copyright 2014-2015 Canonical Ltd. This software is licensed under the |
390 | +# Copyright 2014-2017 Canonical Ltd. This software is licensed under the |
391 | # GNU Affero General Public License version 3 (see the file LICENSE). |
392 | |
393 | """CentOS Operating System.""" |
394 | @@ -14,20 +14,20 @@ from provisioningserver.drivers.osystem import ( |
395 | OperatingSystem, |
396 | ) |
397 | |
398 | - |
399 | -DISTRO_SERIES_DEFAULT = 'centos65' |
400 | - |
401 | -# Regex matcher that is used to check if the release is supported. |
402 | -# It needs to match the name "centosXY". Where "X" is the major version |
403 | -# and "Y" is the minor version. |
404 | -DISTRO_MATCHER = re.compile("centos(?P<major>[0-9])(?P<minor>[0-9])?\Z") |
405 | +# Regex matcher that is used to check if the release is supported. The release |
406 | +# name just has to start with 'centos' to be supported but the major, minor, |
407 | +# and title are found if available to help format the title. |
408 | +DISTRO_MATCHER = re.compile( |
409 | + '^centos((?P<major>[0-9])(?P<minor>[0-9])?)?([\-\.]?(?P<title>.+))?$', |
410 | + re.I) |
411 | +DISTRO_SERIES_DEFAULT = 'centos70' |
412 | |
413 | |
414 | class CentOS(OperatingSystem): |
415 | """CentOS operating system.""" |
416 | |
417 | - name = "centos" |
418 | - title = "CentOS" |
419 | + name = 'centos' |
420 | + title = 'CentOS' |
421 | |
422 | def get_boot_image_purposes(self, arch, subarch, release, label): |
423 | """Gets the purpose of each boot image.""" |
424 | @@ -35,11 +35,6 @@ class CentOS(OperatingSystem): |
425 | BOOT_IMAGE_PURPOSE.XINSTALL |
426 | ] |
427 | |
428 | - def is_release_supported(self, release): |
429 | - """Return True when the release is supported, False otherwise.""" |
430 | - matched = DISTRO_MATCHER.match(release) |
431 | - return matched is not None |
432 | - |
433 | def get_default_release(self): |
434 | """Gets the default release to use when a release is not |
435 | explicit.""" |
436 | @@ -49,10 +44,14 @@ class CentOS(OperatingSystem): |
437 | """Return the title for the given release.""" |
438 | matched = DISTRO_MATCHER.match(release) |
439 | if matched is None: |
440 | - return None |
441 | - matched_dict = matched.groupdict() |
442 | - major = matched_dict['major'] |
443 | - minor = matched_dict['minor'] |
444 | + # This should never happen as is_release_supported will return |
445 | + # false but just in case it does... |
446 | + return "%s %s" % (self.title, release) |
447 | + |
448 | + ret = self.title |
449 | + major = matched.group('major') |
450 | + minor = matched.group('minor') |
451 | + title = matched.group('title') |
452 | # MAAS provided images via streams are not bound to a minor |
453 | # release version, which means we always provide the latest |
454 | # available release from CentOS 6 and CentOS 7. To address |
455 | @@ -65,9 +64,14 @@ class CentOS(OperatingSystem): |
456 | # from the stream and the minor version doesn't match to what |
457 | # we publish. As such, we ensure that we only return minor |
458 | # if we have any other version other that X.0, 7.0 and 6.6. |
459 | - if minor is None or minor == '0': |
460 | - return "CentOS %s" % major |
461 | + if major is not None and minor is None or minor == '0': |
462 | + ret = "%s %s" % (ret, major) |
463 | elif major == '6' and minor == '6': |
464 | - return "CentOS %s" % major |
465 | - else: |
466 | - return "CentOS %s.%s" % (major, minor) |
467 | + ret = "%s %s" % (ret, major) |
468 | + elif None not in (major, minor): |
469 | + ret = "%s %s.%s" % (ret, major, minor) |
470 | + |
471 | + if title is not None: |
472 | + ret = "%s %s" % (ret, title) |
473 | + |
474 | + return ret |
475 | diff --git a/src/provisioningserver/drivers/osystem/custom.py b/src/provisioningserver/drivers/osystem/custom.py |
476 | index 6e817e1..845c132 100644 |
477 | --- a/src/provisioningserver/drivers/osystem/custom.py |
478 | +++ b/src/provisioningserver/drivers/osystem/custom.py |
479 | @@ -27,11 +27,6 @@ class CustomOS(OperatingSystem): |
480 | # Custom images can only be used with XINSTALL. |
481 | return [BOOT_IMAGE_PURPOSE.XINSTALL] |
482 | |
483 | - def is_release_supported(self, release): |
484 | - """Return True when the release is supported, False otherwise.""" |
485 | - # All release are supported, since the user uploaded it. |
486 | - return True |
487 | - |
488 | def get_default_release(self): |
489 | """Gets the default release to use when a release is not |
490 | explicit.""" |
491 | diff --git a/src/provisioningserver/drivers/osystem/tests/test_base.py b/src/provisioningserver/drivers/osystem/tests/test_base.py |
492 | index 9c41dc4..1fa9ca1 100644 |
493 | --- a/src/provisioningserver/drivers/osystem/tests/test_base.py |
494 | +++ b/src/provisioningserver/drivers/osystem/tests/test_base.py |
495 | @@ -1,4 +1,4 @@ |
496 | -# Copyright 2014-2016 Canonical Ltd. This software is licensed under the |
497 | +# Copyright 2014-2017 Canonical Ltd. This software is licensed under the |
498 | # GNU Affero General Public License version 3 (see the file LICENSE). |
499 | |
500 | """Tests for `provisioningserver.drivers.osystem`.""" |
501 | @@ -42,6 +42,15 @@ class TestOperatingSystem(MAASTestCase): |
502 | osystem_module, 'list_boot_images_for').return_value = images |
503 | return images |
504 | |
505 | + def test_is_release_supported(self): |
506 | + osystem = self.make_usable_osystem() |
507 | + releases = [factory.make_name('release') for _ in range(3)] |
508 | + supported = [ |
509 | + osystem.is_release_supported(release) |
510 | + for release in releases |
511 | + ] |
512 | + self.assertEqual([True, True, True], supported) |
513 | + |
514 | def test_format_release_choices(self): |
515 | osystem = self.make_usable_osystem() |
516 | releases = osystem.get_supported_releases() |
517 | diff --git a/src/provisioningserver/drivers/osystem/tests/test_bootloader.py b/src/provisioningserver/drivers/osystem/tests/test_bootloader.py |
518 | index da0766e..9d89480 100644 |
519 | --- a/src/provisioningserver/drivers/osystem/tests/test_bootloader.py |
520 | +++ b/src/provisioningserver/drivers/osystem/tests/test_bootloader.py |
521 | @@ -13,11 +13,6 @@ from provisioningserver.drivers.osystem.bootloader import BootLoaderOS |
522 | |
523 | class TestCustomOS(MAASTestCase): |
524 | |
525 | - def test_is_release_supported(self): |
526 | - osystem = BootLoaderOS() |
527 | - self.assertTrue( |
528 | - osystem.is_release_supported(factory.make_name('release'))) |
529 | - |
530 | def test_get_default_release(self): |
531 | osystem = BootLoaderOS() |
532 | self.assertEquals("", osystem.get_default_release()) |
533 | diff --git a/src/provisioningserver/drivers/osystem/tests/test_centos.py b/src/provisioningserver/drivers/osystem/tests/test_centos.py |
534 | index 8b3dbb6..92f8be7 100644 |
535 | --- a/src/provisioningserver/drivers/osystem/tests/test_centos.py |
536 | +++ b/src/provisioningserver/drivers/osystem/tests/test_centos.py |
537 | @@ -1,4 +1,4 @@ |
538 | -# Copyright 2014-2015 Canonical Ltd. This software is licensed under the |
539 | +# Copyright 2014-2017 Canonical Ltd. This software is licensed under the |
540 | # GNU Affero General Public License version 3 (see the file LICENSE). |
541 | |
542 | """Tests for the CentOS module.""" |
543 | @@ -34,21 +34,6 @@ class TestCentOS(MAASTestCase): |
544 | BOOT_IMAGE_PURPOSE.XINSTALL, |
545 | ]) |
546 | |
547 | - def test_is_release_supported(self): |
548 | - name_supported = { |
549 | - "centos6": True, |
550 | - "centos65": True, |
551 | - "centos7": True, |
552 | - "centos71": True, |
553 | - "cent65": False, |
554 | - "cent": False, |
555 | - "centos711": False, |
556 | - } |
557 | - osystem = CentOS() |
558 | - for name, supported in name_supported.items(): |
559 | - self.expectThat( |
560 | - osystem.is_release_supported(name), Equals(supported)) |
561 | - |
562 | def test_get_default_release(self): |
563 | osystem = CentOS() |
564 | expected = osystem.get_default_release() |
565 | @@ -62,9 +47,10 @@ class TestCentOS(MAASTestCase): |
566 | "centos7": "CentOS 7", |
567 | "centos70": "CentOS 7", # See LP: #1654063 |
568 | "centos71": "CentOS 7.1", |
569 | - "cent65": None, |
570 | - "cent": None, |
571 | - "centos711": None, |
572 | + "centos65": "CentOS 6.5", |
573 | + "cent": "CentOS cent", |
574 | + "centos711": "CentOS 7.1 1", |
575 | + "centos71-custom": "CentOS 7.1 custom", |
576 | } |
577 | osystem = CentOS() |
578 | for name, title in name_titles.items(): |
579 | diff --git a/src/provisioningserver/drivers/osystem/tests/test_custom.py b/src/provisioningserver/drivers/osystem/tests/test_custom.py |
580 | index 1b7ff8e..80a6cce 100644 |
581 | --- a/src/provisioningserver/drivers/osystem/tests/test_custom.py |
582 | +++ b/src/provisioningserver/drivers/osystem/tests/test_custom.py |
583 | @@ -51,15 +51,6 @@ class TestCustomOS(MAASTestCase): |
584 | BOOT_IMAGE_PURPOSE.XINSTALL, |
585 | ]) |
586 | |
587 | - def test_is_release_supported(self): |
588 | - osystem = CustomOS() |
589 | - releases = [factory.make_name('release') for _ in range(3)] |
590 | - supported = [ |
591 | - osystem.is_release_supported(release) |
592 | - for release in releases |
593 | - ] |
594 | - self.assertEqual([True, True, True], supported) |
595 | - |
596 | def test_get_default_release(self): |
597 | osystem = CustomOS() |
598 | self.assertEqual("", osystem.get_default_release()) |
599 | diff --git a/src/provisioningserver/drivers/osystem/tests/test_ubuntu.py b/src/provisioningserver/drivers/osystem/tests/test_ubuntu.py |
600 | index d64faa9..f68f493 100644 |
601 | --- a/src/provisioningserver/drivers/osystem/tests/test_ubuntu.py |
602 | +++ b/src/provisioningserver/drivers/osystem/tests/test_ubuntu.py |
603 | @@ -19,12 +19,7 @@ from provisioningserver.drivers.osystem.ubuntu import UbuntuOS |
604 | class TestUbuntuOS(MAASTestCase): |
605 | |
606 | def get_lts_release(self): |
607 | - # XXX ltrager 2016-04-06 - python3-distro-info won't set the latest lts |
608 | - # to Xenial until its been released. So we can start testing MAAS 2.0 |
609 | - # with Xenial by default override it here. Once Xenial is released this |
610 | - # can be removed |
611 | - # return UbuntuDistroInfo().lts() |
612 | - return "xenial" |
613 | + return UbuntuDistroInfo().lts() |
614 | |
615 | def get_release_title(self, release): |
616 | info = UbuntuDistroInfo() |
617 | @@ -51,6 +46,16 @@ class TestUbuntuOS(MAASTestCase): |
618 | BOOT_IMAGE_PURPOSE.DISKLESS, |
619 | ]) |
620 | |
621 | + def test_is_release_supported(self): |
622 | + osystem = UbuntuOS() |
623 | + info = UbuntuDistroInfo() |
624 | + self.assertTrue(osystem.is_release_supported(random.choice(info.all))) |
625 | + |
626 | + def test_get_lts_release(self): |
627 | + # Canary so we know when the lts changes |
628 | + osystem = UbuntuOS() |
629 | + self.assertEquals('xenial', osystem.get_lts_release()) |
630 | + |
631 | def test_get_default_release(self): |
632 | osystem = UbuntuOS() |
633 | expected = osystem.get_default_release() |
634 | diff --git a/src/provisioningserver/drivers/osystem/tests/test_ubuntucore.py b/src/provisioningserver/drivers/osystem/tests/test_ubuntucore.py |
635 | index 591a7bf..c01ee28 100644 |
636 | --- a/src/provisioningserver/drivers/osystem/tests/test_ubuntucore.py |
637 | +++ b/src/provisioningserver/drivers/osystem/tests/test_ubuntucore.py |
638 | @@ -51,15 +51,6 @@ class TestUbuntuCoreOS(MAASTestCase): |
639 | BOOT_IMAGE_PURPOSE.XINSTALL, |
640 | ]) |
641 | |
642 | - def test_is_release_supported(self): |
643 | - osystem = UbuntuCoreOS() |
644 | - releases = [factory.make_name('release') for _ in range(3)] |
645 | - supported = [ |
646 | - osystem.is_release_supported(release) |
647 | - for release in releases |
648 | - ] |
649 | - self.assertEqual([True, True, True], supported) |
650 | - |
651 | def test_get_default_release(self): |
652 | osystem = UbuntuCoreOS() |
653 | self.assertEqual("16", osystem.get_default_release()) |
654 | diff --git a/src/provisioningserver/drivers/osystem/ubuntu.py b/src/provisioningserver/drivers/osystem/ubuntu.py |
655 | index 7490465..dd8d243 100644 |
656 | --- a/src/provisioningserver/drivers/osystem/ubuntu.py |
657 | +++ b/src/provisioningserver/drivers/osystem/ubuntu.py |
658 | @@ -42,15 +42,7 @@ class UbuntuOS(OperatingSystem): |
659 | |
660 | def get_lts_release(self): |
661 | """Return the latest Ubuntu LTS release.""" |
662 | - lts_release = self.ubuntu_distro_info.lts() |
663 | - # XXX ltrager 2016-04-06 - python3-distro-info won't set the latest lts |
664 | - # to Xenial until its been released. So we can start testing MAAS 2.0 |
665 | - # with Xenial by default override it here. Once Xenial is released this |
666 | - # can be removed |
667 | - if lts_release == "trusty": |
668 | - return "xenial" |
669 | - else: |
670 | - return lts_release |
671 | + return self.ubuntu_distro_info.lts() |
672 | |
673 | def get_default_release(self): |
674 | """Gets the default release to use when a release is not |
675 | diff --git a/src/provisioningserver/drivers/osystem/ubuntucore.py b/src/provisioningserver/drivers/osystem/ubuntucore.py |
676 | index 0a1ea45..1830da6 100644 |
677 | --- a/src/provisioningserver/drivers/osystem/ubuntucore.py |
678 | +++ b/src/provisioningserver/drivers/osystem/ubuntucore.py |
679 | @@ -27,11 +27,6 @@ class UbuntuCoreOS(OperatingSystem): |
680 | # Custom images can only be used with XINSTALL. |
681 | return [BOOT_IMAGE_PURPOSE.XINSTALL] |
682 | |
683 | - def is_release_supported(self, release): |
684 | - """Return True when the release is supported, False otherwise.""" |
685 | - # All release are supported, since the user uploaded it. |
686 | - return True |
687 | - |
688 | def get_default_release(self): |
689 | """Gets the default release to use when a release is not |
690 | explicit.""" |
691 | diff --git a/src/provisioningserver/drivers/osystem/windows.py b/src/provisioningserver/drivers/osystem/windows.py |
692 | index a3bc514..ad7391d 100644 |
693 | --- a/src/provisioningserver/drivers/osystem/windows.py |
694 | +++ b/src/provisioningserver/drivers/osystem/windows.py |
695 | @@ -55,10 +55,6 @@ class WindowsOS(OperatingSystem): |
696 | purposes.append(BOOT_IMAGE_PURPOSE.INSTALL) |
697 | return purposes |
698 | |
699 | - def is_release_supported(self, release): |
700 | - """Return True when the release is supported, False otherwise.""" |
701 | - return release in WINDOWS_CHOICES |
702 | - |
703 | def get_default_release(self): |
704 | """Gets the default release to use when a release is not |
705 | explicit.""" |
706 | @@ -66,7 +62,7 @@ class WindowsOS(OperatingSystem): |
707 | |
708 | def get_release_title(self, release): |
709 | """Return the title for the given release.""" |
710 | - return WINDOWS_CHOICES.get(release) |
711 | + return WINDOWS_CHOICES.get(release, release) |
712 | |
713 | def requires_license_key(self, release): |
714 | return release in REQUIRE_LICENSE_KEY |
715 | diff --git a/src/provisioningserver/testing/os.py b/src/provisioningserver/testing/os.py |
716 | index 5dd7538..9bc5626 100644 |
717 | --- a/src/provisioningserver/testing/os.py |
718 | +++ b/src/provisioningserver/testing/os.py |
719 | @@ -34,9 +34,6 @@ class FakeOS(OperatingSystem): |
720 | def get_boot_image_purposes(self, *args): |
721 | return self.purpose |
722 | |
723 | - def is_release_supported(self, release): |
724 | - return release in self.fake_list |
725 | - |
726 | def get_supported_releases(self): |
727 | return self.fake_list |
728 |
Looks good.