Merge lp:~andreserl/maas/lp1664248_webui into lp:~maas-committers/maas/trunk

Proposed by Andres Rodriguez
Status: Superseded
Proposed branch: lp:~andreserl/maas/lp1664248_webui
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 801 lines (+384/-75)
18 files modified
src/maasserver/api/packagerepositories.py (+11/-2)
src/maasserver/api/tests/test_packagerepositories.py (+136/-21)
src/maasserver/compose_preseed.py (+40/-24)
src/maasserver/forms/packagerepository.py (+48/-0)
src/maasserver/forms/tests/test_packagerepository.py (+38/-16)
src/maasserver/migrations/builtin/maasserver/0116_add_disabled_components_for_mirrors.py (+20/-0)
src/maasserver/models/packagerepository.py (+8/-0)
src/maasserver/models/tests/test_packagerepository.py (+5/-0)
src/maasserver/static/js/angular/controllers/settings.js (+2/-0)
src/maasserver/static/js/angular/controllers/tests/test_settings.js (+2/-0)
src/maasserver/static/js/angular/factories/general.js (+7/-0)
src/maasserver/static/js/angular/factories/tests/test_general.js (+16/-3)
src/maasserver/static/partials/settings.html (+5/-0)
src/maasserver/testing/factory.py (+4/-2)
src/maasserver/tests/test_preseed.py (+30/-7)
src/maasserver/websockets/handlers/general.py (+5/-0)
src/maasserver/websockets/handlers/tests/test_general.py (+6/-0)
src/maasserver/websockets/handlers/tests/test_packagerepository.py (+1/-0)
To merge this branch: bzr merge lp:~andreserl/maas/lp1664248_webui
Reviewer Review Type Date Requested Status
MAAS Maintainers Pending
Review via email: mp+320124@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/api/packagerepositories.py'
2--- src/maasserver/api/packagerepositories.py 2017-02-17 14:23:04 +0000
3+++ src/maasserver/api/packagerepositories.py 2017-03-16 22:02:44 +0000
4@@ -22,6 +22,7 @@
5 'url',
6 'distributions',
7 'disabled_pockets',
8+ 'disabled_components',
9 'components',
10 'arches',
11 'key',
12@@ -70,7 +71,11 @@
13
14 :param disabled_pockets: The list of pockets to disable.
15
16- :param components: The list of components to enable.
17+ :param disabled_components: The list of components to disable. Only
18+ applicable to the default Ubuntu repositories.
19+
20+ :param components: The list of components to enable. Only applicable
21+ to custom repositories.
22
23 :param arches: The list of supported architectures.
24
25@@ -129,7 +134,11 @@
26
27 :param disabled_pockets: The list of pockets to disable.
28
29- :param components: The list of components to enable.
30+ :param disabled_components: The list of components to disable. Only
31+ applicable to the default Ubuntu repositories.
32+
33+ :param components: The list of components to enable. Only applicable
34+ to custom repositories.
35
36 :param arches: The list of supported architectures.
37
38
39=== modified file 'src/maasserver/api/tests/test_packagerepositories.py'
40--- src/maasserver/api/tests/test_packagerepositories.py 2017-01-28 00:51:47 +0000
41+++ src/maasserver/api/tests/test_packagerepositories.py 2017-03-16 22:02:44 +0000
42@@ -72,27 +72,142 @@
43 self.assertEqual(
44 http.client.NOT_FOUND, response.status_code, response.content)
45
46- def test_update(self):
47- self.become_admin()
48- package_repository = factory.make_PackageRepository()
49- new_values = {
50- 'url': factory.make_url(scheme='http'),
51- 'distributions': [
52- factory.make_name("distribution%d" % i) for i in range(3)],
53- 'disabled_pockets': [
54- factory.make_name("disabled_pocket%d" % i) for i in range(1)],
55- 'components': [factory.make_name("comp%d" % i) for i in range(4)],
56- 'arches': [
57- random.choice(PackageRepository.KNOWN_ARCHES),
58- random.choice(PackageRepository.KNOWN_ARCHES),
59- ]
60- }
61- response = self.client.put(
62- self.get_package_repository_uri(package_repository), new_values)
63- self.assertEqual(
64- http.client.OK, response.status_code, response.content)
65- package_repository = reload_object(package_repository)
66- self.assertAttributes(package_repository, new_values)
67+ def test_update_custom_repository(self):
68+ """Updates a custom repository"""
69+ self.become_admin()
70+ # Creates a repository which is not 'default'.
71+ package_repository = factory.make_PackageRepository()
72+ new_values = {
73+ 'url': factory.make_url(scheme='http'),
74+ 'distributions': [
75+ factory.make_name("distribution%d" % i) for i in range(3)],
76+ 'components': [factory.make_name("comp%d" % i) for i in range(4)],
77+ 'arches': [
78+ random.choice(PackageRepository.KNOWN_ARCHES),
79+ random.choice(PackageRepository.KNOWN_ARCHES),
80+ ]
81+ }
82+ response = self.client.put(
83+ self.get_package_repository_uri(package_repository), new_values)
84+ self.assertEqual(
85+ http.client.OK, response.status_code, response.content)
86+ package_repository = reload_object(package_repository)
87+ self.assertAttributes(package_repository, new_values)
88+
89+ def test_update_custom_repository_fails_if_disabled_components(self):
90+ """Test that updating a custom repository fails if specifying
91+ 'disabled_components'. This is only needed when the repository
92+ is an Ubuntu repository"""
93+ self.become_admin()
94+ # Creates a repository which is not 'default'.
95+ package_repository = factory.make_PackageRepository()
96+ new_values = {
97+ 'url': factory.make_url(scheme='http'),
98+ 'distributions': [
99+ factory.make_name("distribution%d" % i) for i in range(3)],
100+ 'components': [factory.make_name("comp%d" % i) for i in range(4)],
101+ 'disabled_components': [
102+ factory.make_name("comp%d" % i) for i in range(4)],
103+ 'arches': [
104+ random.choice(PackageRepository.KNOWN_ARCHES),
105+ random.choice(PackageRepository.KNOWN_ARCHES),
106+ ]
107+ }
108+ response = self.client.put(
109+ self.get_package_repository_uri(package_repository), new_values)
110+ self.assertEqual(
111+ http.client.BAD_REQUEST, response.status_code, response.content)
112+
113+ def test_update_ubuntu_mirror(self):
114+ """Updates a Ubuntu mirror"""
115+ self.become_admin()
116+ # Create an Ubuntu mirror without components
117+ package_repository = factory.make_PackageRepository(
118+ default=True, components=[])
119+ new_values = {
120+ 'url': factory.make_url(scheme='http'),
121+ 'distributions': [
122+ factory.make_name("distribution%d" % i) for i in range(3)],
123+ 'disabled_pockets': ["updates", "security"],
124+ 'disabled_components': ["universe", "multiverse"],
125+ 'arches': [
126+ random.choice(PackageRepository.KNOWN_ARCHES),
127+ random.choice(PackageRepository.KNOWN_ARCHES),
128+ ]
129+ }
130+ response = self.client.put(
131+ self.get_package_repository_uri(package_repository), new_values)
132+ self.assertEqual(
133+ http.client.OK, response.status_code, response.content)
134+ package_repository = reload_object(package_repository)
135+ self.assertAttributes(package_repository, new_values)
136+
137+ def test_update_ubuntu_mirror_fail_with_invalid_disabled_pockets(self):
138+ """Test that updating an Ubuntu mirror with invalid pockets fails"""
139+ self.become_admin()
140+ # Create an Ubuntu mirror without components
141+ package_repository = factory.make_PackageRepository(
142+ default=True, components=[])
143+ new_values = {
144+ 'url': factory.make_url(scheme='http'),
145+ 'distributions': [
146+ factory.make_name("distribution%d" % i) for i in range(3)],
147+ 'disabled_pockets': ["updateses"],
148+ 'arches': [
149+ random.choice(PackageRepository.KNOWN_ARCHES),
150+ random.choice(PackageRepository.KNOWN_ARCHES),
151+ ]
152+ }
153+ response = self.client.put(
154+ self.get_package_repository_uri(package_repository), new_values)
155+ self.assertEqual(
156+ http.client.BAD_REQUEST, response.status_code, response.content)
157+
158+ def test_update_ubuntu_mirror_fail_with_invalid_disabled_components(self):
159+ """Test that updating an Ubuntu mirror with invalid components fails"""
160+ self.become_admin()
161+ # Create an Ubuntu mirror without components
162+ package_repository = factory.make_PackageRepository(
163+ default=True, components=[])
164+ new_values = {
165+ 'url': factory.make_url(scheme='http'),
166+ 'distributions': [
167+ factory.make_name("distribution%d" % i) for i in range(3)],
168+ 'disabled_components': ['universes'],
169+ 'arches': [
170+ random.choice(PackageRepository.KNOWN_ARCHES),
171+ random.choice(PackageRepository.KNOWN_ARCHES),
172+ ]
173+ }
174+ response = self.client.put(
175+ self.get_package_repository_uri(package_repository), new_values)
176+ self.assertEqual(
177+ http.client.BAD_REQUEST, response.status_code, response.content)
178+
179+ def test_update_ubuntu_mirror_fails_if_components_are_passed(self):
180+ """Test that updating a Ubuntu mirror fails if specifying
181+ 'components'. This is only needed when the repository is not
182+ an Ubuntu repository"""
183+ self.become_admin()
184+ # Create an Ubuntu mirror without components
185+ package_repository = factory.make_PackageRepository(
186+ default=True, components=[])
187+ new_values = {
188+ 'url': factory.make_url(scheme='http'),
189+ 'distributions': [
190+ factory.make_name("distribution%d" % i) for i in range(3)],
191+ 'components': [factory.make_name("comp%d" % i) for i in range(4)],
192+ 'disabled_components': [
193+ factory.make_name("comp%d" % i) for i in range(4)],
194+ 'arches': [
195+ random.choice(PackageRepository.KNOWN_ARCHES),
196+ random.choice(PackageRepository.KNOWN_ARCHES),
197+ ]
198+ }
199+ response = self.client.put(
200+ self.get_package_repository_uri(package_repository), new_values)
201+ self.assertEqual(
202+ http.client.BAD_REQUEST, response.status_code, response.content)
203
204 def test_update_admin_only(self):
205 package_repository = factory.make_PackageRepository()
206
207=== modified file 'src/maasserver/compose_preseed.py'
208--- src/maasserver/compose_preseed.py 2017-02-17 14:23:04 +0000
209+++ src/maasserver/compose_preseed.py 2017-03-16 22:02:44 +0000
210@@ -61,25 +61,41 @@
211 apt_proxy = get_apt_proxy_for_node(node)
212
213 # Process the default Ubuntu Archives or Mirror.
214- archives = {
215- 'apt': {
216- 'preserve_sources_list': preserve_sources,
217- 'primary': [
218- {
219- 'arches': ['default'],
220- 'uri': archive.url
221- },
222- ],
223- 'security': [
224- {
225- 'arches': ['default'],
226- 'uri': archive.url
227- },
228- ],
229- },
230- }
231- if archive.disabled_pockets:
232- archives['apt']['disable_suites'] = archive.disabled_pockets
233+ archives = {}
234+ archives['apt'] = {}
235+ archives['apt']['preserve_sources_list'] = preserve_sources
236+ # If disabled_components exist, build a custom list of repositories
237+ if archive.disabled_components:
238+ urls = ''
239+ components = archive.KNOWN_COMPONENTS[:]
240+
241+ for comp in archive.COMPONENTS_TO_DISABLE:
242+ if comp in archive.disabled_components:
243+ components.remove(comp)
244+ urls += 'deb %s $RELEASE %s\n' % (
245+ archive.url, ' '.join(components))
246+
247+ for pocket in archive.POCKETS_TO_DISABLE:
248+ if pocket not in archive.disabled_pockets:
249+ urls += 'deb %s $RELEASE-%s %s\n' % (
250+ archive.url, pocket, ' '.join(components))
251+
252+ archives['apt']['sources_list'] = urls
253+ else:
254+ archives['apt']['primary'] = [
255+ {
256+ 'arches': ['default'],
257+ 'uri': archive.url
258+ }
259+ ]
260+ archives['apt']['security'] = [
261+ {
262+ 'arches': ['default'],
263+ 'uri': archive.url
264+ }
265+ ]
266+ if archive.disabled_pockets:
267+ archives['apt']['disable_suites'] = archive.disabled_pockets
268 if apt_proxy:
269 archives['apt']['proxy'] = apt_proxy
270 if archive.key:
271@@ -94,7 +110,7 @@
272 if repo.url.startswith('ppa:'):
273 url = repo.url
274 elif 'ppa.launchpad.net' in repo.url:
275- url = 'deb %s %s main' % (repo.url, node.distro_series)
276+ url = 'deb %s $RELEASE main' % (repo.url)
277 else:
278 components = ''
279 if not repo.components:
280@@ -105,8 +121,8 @@
281 components = components.strip()
282
283 if not repo.distributions:
284- url = 'deb %s %s %s' % (
285- repo.url, node.distro_series, components)
286+ url = 'deb %s $RELEASE %s' % (
287+ repo.url, components)
288 else:
289 url = ''
290 for dist in repo.distributions:
291@@ -120,11 +136,11 @@
292 if repo.key:
293 archives['apt']['sources'][repo_name] = {
294 'key': repo.key,
295- 'source': url
296+ 'source': url.strip()
297 }
298 else:
299 archives['apt']['sources'][repo_name] = {
300- 'source': url
301+ 'source': url.strip()
302 }
303
304 return archives
305
306=== modified file 'src/maasserver/forms/packagerepository.py'
307--- src/maasserver/forms/packagerepository.py 2017-02-17 14:23:04 +0000
308+++ src/maasserver/forms/packagerepository.py 2017-03-16 22:02:44 +0000
309@@ -27,6 +27,7 @@
310 'url',
311 'distributions',
312 'disabled_pockets',
313+ 'disabled_components',
314 'components',
315 'arches',
316 'key',
317@@ -50,6 +51,9 @@
318 disabled_pockets = UnconstrainedMultipleChoiceField(
319 label="Disabled Pocket list")
320
321+ disabled_components = UnconstrainedMultipleChoiceField(
322+ label="Disabled Component list")
323+
324 components = UnconstrainedMultipleChoiceField(label="Component list")
325
326 arches = UnconstrainedMultipleChoiceField(label="Architecture list")
327@@ -99,10 +103,54 @@
328 values = []
329 for value in self.cleaned_data.get('disabled_pockets', []):
330 values.extend([s.strip() for s in value.split(',')])
331+ # This allows to reset the values of disabled_pockets if one of the
332+ # following is passed over the API:
333+ # disabled_pockets=
334+ # disabled_pockets=''
335+ # disabled_pockets=None
336+ # disabled_pockets=[]
337+ if values == [''] or values == ['None'] or values == ['[]']:
338+ return []
339+ # Check that a valid pocket is being disable.
340+ for pocket in values:
341+ if pocket not in PackageRepository.POCKETS_TO_DISABLE:
342+ raise ValidationError(
343+ "'%s' is not a valid Ubuntu archive pocket. You "
344+ "can only disable %s." % (
345+ pocket, PackageRepository.POCKETS_TO_DISABLE))
346+ return values
347+
348+ def clean_disabled_components(self):
349+ values = []
350+ for value in self.cleaned_data.get('disabled_components', []):
351+ values.extend([s.strip() for s in value.split(',')])
352+ # This allows to reset the values of disabled_components if one of the
353+ # following is passed over the API:
354+ # disabled_components=
355+ # disabled_components=''
356+ # disabled_components=None
357+ # disabled_components=[]
358+ if values == [''] or values == ['None'] or values == ['[]']:
359+ return []
360+ if self.instance is not None and not self.instance.default and values:
361+ raise ValidationError(
362+ "This is a custom repository. Please update 'components' "
363+ "instead.")
364+ # Check that a valid component is being passed.
365+ for component in values:
366+ if component not in PackageRepository.COMPONENTS_TO_DISABLE:
367+ raise ValidationError(
368+ "'%s' is not a valid Ubuntu archive component. You "
369+ "can only disable %s." % (
370+ component, PackageRepository.COMPONENTS_TO_DISABLE))
371 return values
372
373 def clean_components(self):
374 values = []
375 for value in self.cleaned_data.get('components', []):
376 values.extend([s.strip() for s in value.split(',')])
377+ if self.instance is not None and self.instance.default and values:
378+ raise ValidationError(
379+ "This is a default Ubuntu repository. Please update "
380+ "'disabled_components' instead.")
381 return values
382
383=== modified file 'src/maasserver/forms/tests/test_packagerepository.py'
384--- src/maasserver/forms/tests/test_packagerepository.py 2017-02-17 14:23:04 +0000
385+++ src/maasserver/forms/tests/test_packagerepository.py 2017-03-16 22:02:44 +0000
386@@ -27,10 +27,10 @@
387 arch2 = random.choice(PackageRepository.KNOWN_ARCHES)
388 dist1 = factory.make_name('dist')
389 dist2 = factory.make_name('dist')
390- pock1 = factory.make_name('pock')
391- pock2 = factory.make_name('pock')
392- comp1 = factory.make_name('comp')
393- comp2 = factory.make_name('comp')
394+ pock1 = 'updates'
395+ pock2 = 'backports'
396+ comp1 = 'universe'
397+ comp2 = 'multiverse'
398 enabled = factory.pick_bool()
399 params = {
400 'name': name,
401@@ -195,18 +195,40 @@
402 package_repository = factory.make_PackageRepository()
403 form = PackageRepositoryForm(
404 instance=package_repository,
405- data={'disabled_pockets': ['val1,val2']})
406- repo = form.save()
407- self.assertItemsEqual(['val1', 'val2'], repo.disabled_pockets)
408- form = PackageRepositoryForm(
409- instance=package_repository,
410- data={'disabled_pockets': ['val1, val2']})
411- repo = form.save()
412- self.assertItemsEqual(['val1', 'val2'], repo.disabled_pockets)
413- form = PackageRepositoryForm(
414- instance=package_repository, data={'disabled_pockets': ['val1']})
415- repo = form.save()
416- self.assertItemsEqual(['val1'], repo.disabled_pockets)
417+ data={'disabled_pockets': ['updates,backports']})
418+ repo = form.save()
419+ self.assertItemsEqual(['updates', 'backports'], repo.disabled_pockets)
420+ form = PackageRepositoryForm(
421+ instance=package_repository,
422+ data={'disabled_pockets': ['updates, backports']})
423+ repo = form.save()
424+ self.assertItemsEqual(['updates', 'backports'], repo.disabled_pockets)
425+ form = PackageRepositoryForm(
426+ instance=package_repository,
427+ data={'disabled_pockets': ['updates']})
428+ repo = form.save()
429+ self.assertItemsEqual(['updates'], repo.disabled_pockets)
430+
431+ def test__disabled_component_comma_cleaning(self):
432+ package_repository = factory.make_PackageRepository(
433+ default=True, components=[])
434+ form = PackageRepositoryForm(
435+ instance=package_repository,
436+ data={'disabled_components': ['universe,multiverse']})
437+ repo = form.save()
438+ self.assertItemsEqual(
439+ ['universe', 'multiverse'], repo.disabled_components)
440+ form = PackageRepositoryForm(
441+ instance=package_repository,
442+ data={'disabled_components': ['universe, multiverse']})
443+ repo = form.save()
444+ self.assertItemsEqual(
445+ ['universe', 'multiverse'], repo.disabled_components)
446+ form = PackageRepositoryForm(
447+ instance=package_repository,
448+ data={'disabled_components': ['universe']})
449+ repo = form.save()
450+ self.assertItemsEqual(['universe'], repo.disabled_components)
451
452 def test__component_comma_cleaning(self):
453 package_repository = factory.make_PackageRepository()
454
455=== added file 'src/maasserver/migrations/builtin/maasserver/0116_add_disabled_components_for_mirrors.py'
456--- src/maasserver/migrations/builtin/maasserver/0116_add_disabled_components_for_mirrors.py 1970-01-01 00:00:00 +0000
457+++ src/maasserver/migrations/builtin/maasserver/0116_add_disabled_components_for_mirrors.py 2017-03-16 22:02:44 +0000
458@@ -0,0 +1,20 @@
459+# -*- coding: utf-8 -*-
460+from __future__ import unicode_literals
461+
462+from django.db import migrations, models
463+import django.contrib.postgres.fields
464+
465+
466+class Migration(migrations.Migration):
467+
468+ dependencies = [
469+ ('maasserver', '0115_additional_boot_resource_filetypes'),
470+ ]
471+
472+ operations = [
473+ migrations.AddField(
474+ model_name='packagerepository',
475+ name='disabled_components',
476+ field=django.contrib.postgres.fields.ArrayField(base_field=models.TextField(), size=None, default=list, blank=True, null=True),
477+ ),
478+ ]
479
480=== modified file 'src/maasserver/models/packagerepository.py'
481--- src/maasserver/models/packagerepository.py 2016-09-01 13:12:15 +0000
482+++ src/maasserver/models/packagerepository.py 2017-03-16 22:02:44 +0000
483@@ -74,6 +74,9 @@
484 def get_pockets_to_disable(self):
485 return PackageRepository.POCKETS_TO_DISABLE
486
487+ def get_components_to_disable(self):
488+ return PackageRepository.COMPONENTS_TO_DISABLE
489+
490 def get_default_archive(self, arch):
491 return PackageRepository.objects.filter(
492 arches__contains=[arch],
493@@ -94,6 +97,8 @@
494 PORTS_ARCHES = ['armhf', 'arm64', 'ppc64el']
495 KNOWN_ARCHES = MAIN_ARCHES + PORTS_ARCHES
496 POCKETS_TO_DISABLE = ['updates', 'security', 'backports']
497+ COMPONENTS_TO_DISABLE = ['restricted', 'universe', 'multiverse']
498+ KNOWN_COMPONENTS = ['main', 'restricted', 'universe', 'multiverse']
499
500 class Meta(DefaultMeta):
501 """Needed for South to recognize this model."""
502@@ -111,6 +116,9 @@
503 disabled_pockets = ArrayField(
504 TextField(), blank=True, null=True, default=list)
505
506+ disabled_components = ArrayField(
507+ TextField(), blank=True, null=True, default=list)
508+
509 components = ArrayField(TextField(), blank=True, null=True, default=list)
510
511 arches = ArrayField(TextField(), blank=True, null=True, default=list)
512
513=== modified file 'src/maasserver/models/tests/test_packagerepository.py'
514--- src/maasserver/models/tests/test_packagerepository.py 2016-08-25 19:31:20 +0000
515+++ src/maasserver/models/tests/test_packagerepository.py 2017-03-16 22:02:44 +0000
516@@ -61,3 +61,8 @@
517 self.assertEqual(
518 PackageRepository.objects.get_pockets_to_disable(),
519 PackageRepository.POCKETS_TO_DISABLE)
520+
521+ def test_get_components_to_disable(self):
522+ self.assertEqual(
523+ PackageRepository.objects.get_components_to_disable(),
524+ PackageRepository.COMPONENTS_TO_DISABLE)
525
526=== modified file 'src/maasserver/static/js/angular/controllers/settings.js'
527--- src/maasserver/static/js/angular/controllers/settings.js 2016-09-21 14:49:23 +0000
528+++ src/maasserver/static/js/angular/controllers/settings.js 2017-03-16 22:02:44 +0000
529@@ -30,6 +30,8 @@
530 GeneralManager.getData("known_architectures");
531 $scope.pockets_to_disable =
532 GeneralManager.getData("pockets_to_disable");
533+ $scope.components_to_disable =
534+ GeneralManager.getData("components_to_disable");
535 $scope.packageRepositoriesManager = PackageRepositoriesManager;
536 $scope.repositories =
537 PackageRepositoriesManager.getItems();
538
539=== modified file 'src/maasserver/static/js/angular/controllers/tests/test_settings.js'
540--- src/maasserver/static/js/angular/controllers/tests/test_settings.js 2016-09-22 15:05:38 +0000
541+++ src/maasserver/static/js/angular/controllers/tests/test_settings.js 2017-03-16 22:02:44 +0000
542@@ -116,6 +116,8 @@
543 GeneralManager.getData("known_architectures"));
544 expect($scope.pockets_to_disable).toBe(
545 GeneralManager.getData("pockets_to_disable"));
546+ expect($scope.components_to_disable).toBe(
547+ GeneralManager.getData("components_to_disable"));
548 expect($scope.packageRepositoriesManager).toBe(
549 PackageRepositoriesManager);
550 expect($scope.repositories).toBe(
551
552=== modified file 'src/maasserver/static/js/angular/factories/general.js'
553--- src/maasserver/static/js/angular/factories/general.js 2016-09-22 15:05:38 +0000
554+++ src/maasserver/static/js/angular/factories/general.js 2017-03-16 22:02:44 +0000
555@@ -77,6 +77,13 @@
556 polling: false,
557 nextPromise: null
558 },
559+ components_to_disable: {
560+ method: "general.components_to_disable",
561+ data: [],
562+ loaded: false,
563+ polling: false,
564+ nextPromise: null
565+ },
566 hwe_kernels: {
567 method: "general.hwe_kernels",
568 data: [],
569
570=== modified file 'src/maasserver/static/js/angular/factories/tests/test_general.js'
571--- src/maasserver/static/js/angular/factories/tests/test_general.js 2016-08-22 04:10:43 +0000
572+++ src/maasserver/static/js/angular/factories/tests/test_general.js 2017-03-16 22:02:44 +0000
573@@ -53,9 +53,9 @@
574 ["machine_actions", "device_actions", "region_controller_actions",
575 "rack_controller_actions", "region_and_rack_controller_actions",
576 "architectures", "known_architectures", "pockets_to_disable",
577- "hwe_kernels", "min_hwe_kernels", "default_min_hwe_kernel",
578- "osinfo", "bond_options", "version", "power_types",
579- "release_options"]);
580+ "components_to_disable", "hwe_kernels", "min_hwe_kernels",
581+ "default_min_hwe_kernel", "osinfo", "bond_options",
582+ "version", "power_types", "release_options"]);
583 });
584
585 it("_data.machine_actions has correct data", function() {
586@@ -136,6 +136,15 @@
587 expect(ptd.nextPromise).toBeNull();
588 });
589
590+ it("_data.components_to_disable has correct data", function() {
591+ var ptd = GeneralManager._data.components_to_disable;
592+ expect(ptd.method).toBe("general.components_to_disable");
593+ expect(ptd.data).toEqual([]);
594+ expect(ptd.loaded).toBe(false);
595+ expect(ptd.polling).toBe(false);
596+ expect(ptd.nextPromise).toBeNull();
597+ });
598+
599 it("_data.hwe_kernels has correct data", function() {
600 var hwe_kernels = GeneralManager._data.hwe_kernels;
601 expect(hwe_kernels.method).toBe("general.hwe_kernels");
602@@ -302,6 +311,7 @@
603 GeneralManager._data.architectures.loaded = true;
604 GeneralManager._data.known_architectures.loaded = true;
605 GeneralManager._data.pockets_to_disable.loaded = true;
606+ GeneralManager._data.components_to_disable.loaded = true;
607 GeneralManager._data.hwe_kernels.loaded = true;
608 GeneralManager._data.osinfo.loaded = true;
609 GeneralManager._data.bond_options.loaded = true;
610@@ -321,6 +331,7 @@
611 GeneralManager._data.architectures.loaded = true;
612 GeneralManager._data.known_architectures.loaded = true;
613 GeneralManager._data.pockets_to_disable.loaded = true;
614+ GeneralManager._data.components_to_disable.loaded = true;
615 GeneralManager._data.hwe_kernels.loaded = true;
616 GeneralManager._data.min_hwe_kernels.loaded = true;
617 GeneralManager._data.default_min_hwe_kernel.loaded = true;
618@@ -353,6 +364,7 @@
619 GeneralManager._data.architectures.polling = false;
620 GeneralManager._data.known_architectures.polling = false;
621 GeneralManager._data.pockets_to_disable.polling = false;
622+ GeneralManager._data.components_to_disable.polling = false;
623 GeneralManager._data.hwe_kernels.polling = false;
624 GeneralManager._data.osinfo.polling = false;
625 expect(GeneralManager.isPolling()).toBe(true);
626@@ -363,6 +375,7 @@
627 GeneralManager._data.architectures.polling = true;
628 GeneralManager._data.known_architectures.polling = true;
629 GeneralManager._data.pockets_to_disable.polling = true;
630+ GeneralManager._data.components_to_disable.polling = true;
631 GeneralManager._data.hwe_kernels.polling = true;
632 GeneralManager._data.osinfo.polling = true;
633 expect(GeneralManager.isPolling()).toBe(true);
634
635=== modified file 'src/maasserver/static/partials/settings.html'
636--- src/maasserver/static/partials/settings.html 2017-02-17 14:23:04 +0000
637+++ src/maasserver/static/partials/settings.html 2017-03-16 22:02:44 +0000
638@@ -488,6 +488,11 @@
639 <maas-obj-field type="checkboxes" key="disabled_pockets" label="Disabled Pockets"
640 label-width="two" input-width="three" values="pockets_to_disable"></maas-obj-field>
641 </div>
642+ <div class="form__group u-align--left-mobile"
643+ data-ng-if="isMirror(editRepository) && !isPPA(editRepository)">
644+ <maas-obj-field type="checkboxes" key="disabled_components" label="Disabled Components"
645+ label-width="two" input-width="three" values="components_to_disable"></maas-obj-field>
646+ </div>
647 </div>
648 </div>
649 <div class="table__row is-active">
650
651=== modified file 'src/maasserver/testing/factory.py'
652--- src/maasserver/testing/factory.py 2017-03-15 16:40:59 +0000
653+++ src/maasserver/testing/factory.py 2017-03-16 22:02:44 +0000
654@@ -2037,7 +2037,8 @@
655
656 def make_PackageRepository(
657 self, name=None, url=None, arches=None, default=False, key=None,
658- distributions=None, components=None, disabled_pockets=None):
659+ distributions=None, components=None, disabled_pockets=None,
660+ disabled_components=None):
661 if name is None:
662 name = self.make_name("name")
663 if url is None:
664@@ -2051,7 +2052,8 @@
665 return PackageRepository.objects.create(
666 name=name, url=url,
667 distributions=distributions, disabled_pockets=disabled_pockets,
668- components=components, arches=arches, key=key, default=default)
669+ components=components, arches=arches, key=key, default=default,
670+ disabled_components=disabled_components)
671
672 def make_Notification(
673 self, message=None, *, ident=None, user=None, users=False,
674
675=== modified file 'src/maasserver/tests/test_preseed.py'
676--- src/maasserver/tests/test_preseed.py 2017-03-09 08:55:12 +0000
677+++ src/maasserver/tests/test_preseed.py 2017-03-16 22:02:44 +0000
678@@ -1230,6 +1230,31 @@
679 preseed['apt']['disable_suites'],
680 archive.disabled_pockets)
681
682+ def test_compose_curtin_archive_config_with_disabled_pockets(self):
683+ """Test that main archive has a configuration that includes
684+ disabled_pockets. If so, MAAS will create its own sources_list
685+ instead of letting curtin/cloud-init create it based on its own
686+ template"""
687+ PackageRepository.objects.all().delete()
688+ node = self.make_fastpath_node('amd64')
689+ node.osystem = 'ubuntu'
690+ node.distro_series = 'xenial'
691+ main_url = 'http://us.archive.ubuntu.com/ubuntu'
692+ factory.make_PackageRepository(
693+ url=main_url, default=True, arches=['i386', 'amd64'],
694+ disabled_pockets=['updates', 'backports'],
695+ disabled_components=['universe', 'multiverse'])
696+ self.configure_get_boot_images_for_node(node, 'xinstall')
697+ # compose_curtin_archive_config returns a list.
698+ userdata = compose_curtin_archive_config(node)
699+ preseed = yaml.safe_load(userdata[0])
700+ self.assertThat(
701+ preseed['apt']['sources_list'],
702+ Contains('$RELEASE main restricted'))
703+ self.assertThat(
704+ preseed['apt']['sources_list'],
705+ Contains('$RELEASE-security main restricted'))
706+
707 def test_compose_curtin_archive_config_has_ppa(self):
708 node = self.make_fastpath_node('i386')
709 node.osystem = 'ubuntu'
710@@ -1283,7 +1308,7 @@
711 )
712 self.assertThat(
713 preseed['apt']['sources'][ppa_name]['source'],
714- ContainsAll("deb %s %s main" % (ppa_first.url, node.distro_series))
715+ ContainsAll("deb %s $RELEASE main" % ppa_first.url)
716 )
717 # Clean up PPA name
718 ppa_name = make_clean_repo_name(ppa_second)
719@@ -1293,8 +1318,7 @@
720 )
721 self.assertThat(
722 preseed['apt']['sources'][ppa_name]['source'],
723- ContainsAll("deb %s %s main" % (
724- ppa_second.url, node.distro_series)))
725+ ContainsAll("deb %s $RELEASE main" % ppa_second.url))
726
727 def test_compose_curtin_archive_config_has_custom_repository(self):
728 node = self.make_fastpath_node('i386')
729@@ -1318,8 +1342,7 @@
730 )
731 self.assertThat(
732 preseed['apt']['sources'][repo_name]['source'],
733- ContainsAll("deb %s %s main" % (
734- repository.url, node.distro_series)))
735+ ContainsAll("deb %s $RELEASE main" % repository.url))
736
737 def test_compose_curtin_archive_config_custom_repo_with_components(self):
738 node = self.make_fastpath_node('i386')
739@@ -1348,8 +1371,8 @@
740 )
741 self.assertThat(
742 preseed['apt']['sources'][repo_name]['source'],
743- ContainsAll("deb %s %s %s" % (
744- repository.url, node.distro_series, components)))
745+ ContainsAll("deb %s $RELEASE %s" % (
746+ repository.url, components)))
747
748 def test_compose_curtin_archive_config_custom_repo_components_dists(self):
749 node = self.make_fastpath_node('i386')
750
751=== modified file 'src/maasserver/websockets/handlers/general.py'
752--- src/maasserver/websockets/handlers/general.py 2017-01-28 00:51:47 +0000
753+++ src/maasserver/websockets/handlers/general.py 2017-03-16 22:02:44 +0000
754@@ -46,6 +46,7 @@
755 'architectures',
756 'known_architectures',
757 'pockets_to_disable',
758+ 'components_to_disable',
759 'hwe_kernels',
760 'min_hwe_kernels',
761 'default_min_hwe_kernel',
762@@ -74,6 +75,10 @@
763 """Return pockets that can be disabled."""
764 return PackageRepository.objects.get_pockets_to_disable()
765
766+ def components_to_disable(self, params):
767+ "Return compoennts that can be disable for default Ubuntu archives"
768+ return PackageRepository.objects.get_components_to_disable()
769+
770 def hwe_kernels(self, params):
771 """Return all supported hwe_kernels."""
772 return list_hwe_kernel_choices(
773
774=== modified file 'src/maasserver/websockets/handlers/tests/test_general.py'
775--- src/maasserver/websockets/handlers/tests/test_general.py 2017-03-02 09:41:37 +0000
776+++ src/maasserver/websockets/handlers/tests/test_general.py 2017-03-16 22:02:44 +0000
777@@ -103,6 +103,12 @@
778 PackageRepository.objects.get_pockets_to_disable(),
779 handler.pockets_to_disable({}))
780
781+ def test_components_to_disable(self):
782+ handler = GeneralHandler(factory.make_User(), {})
783+ self.assertEqual(
784+ PackageRepository.objects.get_components_to_disable(),
785+ handler.components_to_disable({}))
786+
787 def test_hwe_kernels(self):
788 expected_output = self.make_boot_sources()
789 handler = GeneralHandler(factory.make_User(), {})
790
791=== modified file 'src/maasserver/websockets/handlers/tests/test_packagerepository.py'
792--- src/maasserver/websockets/handlers/tests/test_packagerepository.py 2017-02-17 14:23:04 +0000
793+++ src/maasserver/websockets/handlers/tests/test_packagerepository.py 2017-03-16 22:02:44 +0000
794@@ -34,6 +34,7 @@
795 'url': package_repository.url,
796 'distributions': package_repository.distributions,
797 'disabled_pockets': package_repository.disabled_pockets,
798+ 'disabled_components': package_repository.disabled_components,
799 'components': package_repository.components,
800 'arches': package_repository.arches,
801 'key': package_repository.key,