Merge lp:~blake-rouse/maas/fix-1581130 into lp:~maas-committers/maas/trunk

Proposed by Blake Rouse
Status: Merged
Approved by: Blake Rouse
Approved revision: no longer in the source branch.
Merged at revision: 5129
Proposed branch: lp:~blake-rouse/maas/fix-1581130
Merge into: lp:~maas-committers/maas/trunk
Diff against target: 183 lines (+74/-9)
8 files modified
src/maasserver/forms.py (+14/-0)
src/maasserver/migrations/builtin/maasserver/0065_larger_osystem_and_distro_series.py (+27/-0)
src/maasserver/models/node.py (+2/-2)
src/maasserver/node_action.py (+2/-2)
src/maasserver/tests/test_forms_bootresource.py (+1/-1)
src/maasserver/tests/test_node_action.py (+1/-1)
src/maasserver/utils/osystems.py (+7/-1)
src/maasserver/utils/tests/test_osystems.py (+20/-2)
To merge this branch: bzr merge lp:~blake-rouse/maas/fix-1581130
Reviewer Review Type Date Requested Status
Gavin Panella (community) Approve
Review via email: mp+297481@code.launchpad.net

Commit message

Fix uploading of custom image to strip "custom/" from the name. Fix distro_series and osystem to support longer names that match the same length of a boot resource. Fix issue with raising NodeActionError in the deploy action. Fix boot resources not having a title set falling back to the name of the boot resource.

To post a comment you must log in.
Revision history for this message
Gavin Panella (allenap) wrote :

This looks fine, but there's no explanation why much of it is necessary:

- Stripping "custom/" seems a fairly arbitrary thing to do. The clean_name method has a docstring and a comment which are both useful like "2 + 2 # add 2 and 2" is. There needs to be a proper explanation for future maintainers in the code.

- What was the issue with NodeActionError? One test has changed (for two distinct source changes...) and I can't tell how things are better now.

- How come boot resources don't have a title? Is that a bug in simplestreams?

+1, just explain in the code why these changes are necessary.

review: Approve
Revision history for this message
Blake Rouse (blake-rouse) wrote :

> This looks fine, but there's no explanation why much of it is necessary:
>
> - Stripping "custom/" seems a fairly arbitrary thing to do. The clean_name
> method has a docstring and a comment which are both useful like "2 + 2 # add
> 2 and 2" is. There needs to be a proper explanation for future maintainers in
> the code.

Add a better docstring to explain why.

>
> - What was the issue with NodeActionError? One test has changed (for two
> distinct source changes...) and I can't tell how things are better now.

The issue is that "message" attribute no longer exists on ValidationError in Django 1.8. The test was setting it up incorrect.

>
> - How come boot resources don't have a title? Is that a bug in simplestreams?

This is for uploaded images that do not come from simplestreams. A title on an uploaded image is optional. It is only used when the user wants to give it a nice title for the user to select in the WebUI.

>
> +1, just explain in the code why these changes are necessary.

Revision history for this message
Blake Rouse (blake-rouse) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/forms.py'
2--- src/maasserver/forms.py 2016-05-17 20:28:10 +0000
3+++ src/maasserver/forms.py 2016-06-16 15:17:48 +0000
4@@ -2139,6 +2139,20 @@
5 choices=choices, required=True, initial=default_arch,
6 error_messages={'invalid_choice': invalid_arch_message})
7
8+ def clean_name(self):
9+ """Clean the name field.
10+
11+ The 'custom/' is reserved for custom uploaded images and should not
12+ be present in the name field when uploaded. This allows users to
13+ provide 'custom/' where it will be removed and the image will be marked
14+ uploaded. Without this the image would be uploaded as Generated for
15+ a custom OS which is an invalid boot resource.
16+ """
17+ name = self.cleaned_data['name']
18+ if name.startswith('custom/'):
19+ name = name[7:]
20+ return name
21+
22 def get_existing_resource(self, resource):
23 """Return existing resource if avaliable.
24
25
26=== added file 'src/maasserver/migrations/builtin/maasserver/0065_larger_osystem_and_distro_series.py'
27--- src/maasserver/migrations/builtin/maasserver/0065_larger_osystem_and_distro_series.py 1970-01-01 00:00:00 +0000
28+++ src/maasserver/migrations/builtin/maasserver/0065_larger_osystem_and_distro_series.py 2016-06-16 15:17:48 +0000
29@@ -0,0 +1,27 @@
30+# -*- coding: utf-8 -*-
31+from __future__ import unicode_literals
32+
33+from django.db import (
34+ migrations,
35+ models,
36+)
37+
38+
39+class Migration(migrations.Migration):
40+
41+ dependencies = [
42+ ('maasserver', '0064_remove_unneeded_event_triggers'),
43+ ]
44+
45+ operations = [
46+ migrations.AlterField(
47+ model_name='node',
48+ name='distro_series',
49+ field=models.CharField(max_length=255, blank=True, default=''),
50+ ),
51+ migrations.AlterField(
52+ model_name='node',
53+ name='osystem',
54+ field=models.CharField(max_length=255, blank=True, default=''),
55+ ),
56+ ]
57
58=== modified file 'src/maasserver/models/node.py'
59--- src/maasserver/models/node.py 2016-06-16 01:30:23 +0000
60+++ src/maasserver/models/node.py 2016-06-16 15:17:48 +0000
61@@ -717,10 +717,10 @@
62 bios_boot_method = CharField(max_length=31, blank=True, null=True)
63
64 osystem = CharField(
65- max_length=20, blank=True, default='')
66+ max_length=255, blank=True, default='')
67
68 distro_series = CharField(
69- max_length=20, blank=True, default='')
70+ max_length=255, blank=True, default='')
71
72 architecture = CharField(max_length=31, blank=True, null=True)
73
74
75=== modified file 'src/maasserver/node_action.py'
76--- src/maasserver/node_action.py 2016-06-08 20:20:40 +0000
77+++ src/maasserver/node_action.py 2016-06-16 15:17:48 +0000
78@@ -301,7 +301,7 @@
79 validate_osystem_and_distro_series(osystem, distro_series))
80 self.node.save()
81 except ValidationError as e:
82- raise NodeActionError(e.message)
83+ raise NodeActionError(e)
84
85 try:
86 self.node.hwe_kernel = validate_hwe_kernel(
87@@ -310,7 +310,7 @@
88 self.node.distro_series)
89 self.node.save()
90 except ValidationError as e:
91- raise NodeActionError(e.message)
92+ raise NodeActionError(e)
93
94 try:
95 self.node.start(self.user)
96
97=== modified file 'src/maasserver/tests/test_forms_bootresource.py'
98--- src/maasserver/tests/test_forms_bootresource.py 2016-03-28 13:54:47 +0000
99+++ src/maasserver/tests/test_forms_bootresource.py 2016-06-16 15:17:48 +0000
100@@ -42,7 +42,7 @@
101 upload_name = factory.make_name('filename')
102 uploaded_file = SimpleUploadedFile(content=content, name=upload_name)
103 data = {
104- 'name': name,
105+ 'name': 'custom/' + name,
106 'title': title,
107 'architecture': architecture,
108 'filetype': upload_type,
109
110=== modified file 'src/maasserver/tests/test_node_action.py'
111--- src/maasserver/tests/test_node_action.py 2016-06-08 20:20:40 +0000
112+++ src/maasserver/tests/test_node_action.py 2016-06-16 15:17:48 +0000
113@@ -451,7 +451,7 @@
114 error = self.assertRaises(
115 NodeActionError, Deploy(node, user).execute, **extra)
116 self.assertEqual(
117- "%s is not a support operating system." % os_name,
118+ "['%s is not a support operating system.']" % os_name,
119 str(error))
120
121 def test_Deploy_sets_osystem_and_series(self):
122
123=== modified file 'src/maasserver/utils/osystems.py'
124--- src/maasserver/utils/osystems.py 2015-12-01 18:12:59 +0000
125+++ src/maasserver/utils/osystems.py 2016-06-16 15:17:48 +0000
126@@ -151,9 +151,15 @@
127 requires_key = get_release_requires_key(release)
128 else:
129 requires_key = ''
130+ title = release['title']
131+ if not title:
132+ # Uploaded boot resources are not required to have a title.
133+ # Fallback to the name of the release when the title is
134+ # missing.
135+ title = release['name']
136 choices.append((
137 '%s/%s%s' % (os_name, release['name'], requires_key),
138- release['title']
139+ title
140 ))
141 return choices
142
143
144=== modified file 'src/maasserver/utils/tests/test_osystems.py'
145--- src/maasserver/utils/tests/test_osystems.py 2016-05-13 12:01:58 +0000
146+++ src/maasserver/utils/tests/test_osystems.py 2016-06-16 15:17:48 +0000
147@@ -85,9 +85,12 @@
148
149 def make_release_choice(self, osystem, release, include_asterisk=False):
150 key = '%s/%s' % (osystem['name'], release['name'])
151+ title = release['title']
152+ if not title:
153+ title = release['name']
154 if include_asterisk:
155- return ('%s*' % key, release['title'])
156- return (key, release['title'])
157+ return ('%s*' % key, title)
158+ return (key, title)
159
160 def test_list_all_usable_releases(self):
161 releases = [make_rpc_release() for _ in range(3)]
162@@ -154,6 +157,21 @@
163 list_all_usable_releases([osystem]),
164 include_default=False))
165
166+ def test_list_release_choices_fallsback_to_name(self):
167+ releases = [make_rpc_release() for _ in range(3)]
168+ for release in releases:
169+ release['title'] = ""
170+ osystem = make_rpc_osystem(releases=releases)
171+ choices = [
172+ self.make_release_choice(osystem, release)
173+ for release in releases
174+ ]
175+ self.assertItemsEqual(
176+ choices,
177+ list_release_choices(
178+ list_all_usable_releases([osystem]),
179+ include_default=False))
180+
181 def test_list_release_choices_sorts(self):
182 releases = [make_rpc_release() for _ in range(3)]
183 osystem = make_rpc_osystem(releases=releases)