Merge lp:~andreserl/maas/distro_series_support into lp:maas/trunk

Proposed by Andres Rodriguez on 2012-09-18
Status: Merged
Approved by: Andres Rodriguez on 2012-09-19
Approved revision: 1025
Merged at revision: 1026
Proposed branch: lp:~andreserl/maas/distro_series_support
Merge into: lp:maas/trunk
Prerequisite: lp:~andreserl/maas/add_node_distro_series
Diff against target: 244 lines (+54/-20)
7 files modified
src/maasserver/api.py (+6/-3)
src/maasserver/forms.py (+13/-0)
src/maasserver/models/config.py (+6/-1)
src/maasserver/models/node.py (+11/-0)
src/maasserver/preseed.py (+12/-16)
src/maasserver/templates/maasserver/snippets.html (+4/-0)
src/maasserver/tests/test_forms.py (+2/-0)
To merge this branch: bzr merge lp:~andreserl/maas/distro_series_support
Reviewer Review Type Date Requested Status
Gavin Panella (community) Needs Fixing on 2012-09-19
John A Meinel 2012-09-18 Approve on 2012-09-19
Review via email: mp+125012@code.launchpad.net

Commit Message

Adds the UI changes for the Ubuntu Release, as well as the necessary support to deploy machine using the specified release.

To post a comment you must log in.
John A Meinel (jameinel) wrote :

maybe if the variable was 'release_series' it might be more obvious how it matches the 'release=' parameter? (In general, the fact that it is sometimes called distro_series, sometimes series, sometimes release is a bit confusing.)

def get_preseed_filenames(node, prefix='', release='', default=False):

Would it be better as 'release=None' ?

Or is that to handle: src/maasserver/templates/maasserver/snippets.html wanting to have a string there.

Otherwise it looks good to me.

review: Approve
Andres Rodriguez (andreserl) wrote :

Hi John,

Thanks for the review.

1. release parameter: I will address this in a different branch (I had planned to do it either way).

2. release='': It needs to be '' instead of None. We had agreed to default it that way as it requires a string eventually. (as you mention).

MAAS Lander (maas-lander) wrote :

Attempt to merge into lp:maas failed due to conflicts:

text conflict in src/maasserver/models/config.py

1025. By Andres Rodriguez on 2012-09-19

Resolve conflict on src/maasserver/models/config.py

Gavin Panella (allenap) wrote :
Download full text (3.8 KiB)

Looks good, thank you for taking this on. I have a lot of comments,
but they're all fairly minor. However, I think [1] and [8] must be
addressed before landing (well, everything ought to be, but those are
especially important) so Needs Fixing.

[1]

In src/maasserver/api.py:

+    if node is None or node.status == NODE_STATUS.COMMISSIONING:
+        series = Config.objects.get_config('commissioning_distro_series')
+    else:
+        series = node.get_distro_series()

In src/maasserver/models/node.py:

+    def get_distro_series(self):
+        """Return the distro series to install that node."""
+        if not self.distro_series or self.distro_series == DISTRO_SERIES.default:
+            return Config.objects.get_config('default_distro_series')
+        else:
+            return self.distro_series

There's two levels of overriding here: get_distro_series() can return
something other than node.distro_series, and then the code in the API
view can return something else again.

I suggest putting the logic that's in the API view into
get_distro_series, and renaming the method:

    def get_effective_distro_series(self):
        """Return the distro series to install that node."""
        if node is None or node.status == NODE_STATUS.COMMISSIONING:
            return Config.objects.get_config('commissioning_distro_series')
        elif not self.distro_series or self.distro_series == DISTRO_SERIES.default:
            return Config.objects.get_config('default_distro_series')
        else:
            return self.distro_series

[2]

     params = KernelParameters(
-        arch=arch, subarch=subarch, release=release, purpose=purpose,
+        arch=arch, subarch=subarch, release=series, purpose=purpose,

That release argument ought to be renamed. File a bug if it's too much
to do here.

[3]

Before landing, please run `make lint` and fix all warnings.

[4]

Also before landing, please run:

  utilities/format-new-and-modified-imports -r submit:

and commit the changes it makes.

[5]

+    distro_series = CharField(
+        max_length=10, choices=DISTRO_SERIES_CHOICES, null=True,
+        blank=True, default=None)

To avoid mix-ups between None and "", I think this should be defined
as:

    distro_series = CharField(
        max_length=10, choices=DISTRO_SERIES_CHOICES, null=False,
        blank=True, default="")

Also, a maximum length of 10 seems tight. As Django should be
selecting a VARCHAR type in PostgreSQL here, the storage will be the
same:

  The storage requirement for a short string (up to 126 bytes) is 1
  byte plus the actual string, ...

  http://www.postgresql.org/docs/9.1/interactive/datatype-character.html

Make it at least 20, because it's not going to make any difference to
storage or performance, and because having to change it later will be
a much bigger PITA.

[6]

+    <label for="id_distro_series">Release</label>
+    {{ node_form.distro_series }}

s/Release/Series/ ?

Also, how about showing the effective series?

[7]

+    distro_series = forms.ChoiceField(
+        choices=DISTRO_SERIES_CHOICES, required=False,
+        initial=DISTRO_SERIES.default,
+        label="Release",
+        error_messages={'invalid_choi...

Read more...

review: Needs Fixing

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/maasserver/api.py'
2--- src/maasserver/api.py 2012-09-18 16:00:45 +0000
3+++ src/maasserver/api.py 2012-09-19 14:12:24 +0000
4@@ -1353,14 +1353,17 @@
5 preseed_url = compose_preseed_url(node)
6 hostname = node.hostname
7
8- # XXX JeroenVermeulen 2012-08-06 bug=1013146: Stop hard-coding this.
9- release = 'precise'
10+ if node is None or node.status == NODE_STATUS.COMMISSIONING:
11+ series = Config.objects.get_config('commissioning_distro_series')
12+ else:
13+ series = node.get_distro_series()
14+
15 purpose = get_boot_purpose(node)
16 domain = 'local.lan' # TODO: This is probably not enough!
17 server_address = get_maas_facing_server_address()
18
19 params = KernelParameters(
20- arch=arch, subarch=subarch, release=release, purpose=purpose,
21+ arch=arch, subarch=subarch, release=series, purpose=purpose,
22 hostname=hostname, domain=domain, preseed_url=preseed_url,
23 log_host=server_address, fs_host=server_address)
24
25
26=== modified file 'src/maasserver/forms.py'
27--- src/maasserver/forms.py 2012-09-18 16:36:51 +0000
28+++ src/maasserver/forms.py 2012-09-19 14:12:24 +0000
29@@ -59,6 +59,8 @@
30 NODEGROUP_STATUS,
31 NODEGROUPINTERFACE_MANAGEMENT,
32 NODEGROUPINTERFACE_MANAGEMENT_CHOICES,
33+ DISTRO_SERIES,
34+ DISTRO_SERIES_CHOICES,
35 )
36 from maasserver.fields import MACAddressFormField
37 from maasserver.models import (
38@@ -97,6 +99,9 @@
39 INVALID_ARCHITECTURE_MESSAGE = compose_invalid_choice_text(
40 'architecture', ARCHITECTURE_CHOICES)
41
42+INVALID_DISTRO_SERIES_MESSAGE = compose_invalid_choice_text(
43+ 'distro_series', DISTRO_SERIES_CHOICES)
44+
45
46 class NodeForm(ModelForm):
47 after_commissioning_action = forms.TypedChoiceField(
48@@ -104,6 +109,12 @@
49 choices=NODE_AFTER_COMMISSIONING_ACTION_CHOICES, required=False,
50 empty_value=NODE_AFTER_COMMISSIONING_ACTION.DEFAULT)
51
52+ distro_series = forms.ChoiceField(
53+ choices=DISTRO_SERIES_CHOICES, required=False,
54+ initial=DISTRO_SERIES.default,
55+ label="Release",
56+ error_messages={'invalid_choice': INVALID_DISTRO_SERIES_MESSAGE})
57+
58 architecture = forms.ChoiceField(
59 choices=ARCHITECTURE_CHOICES, required=True,
60 initial=ARCHITECTURE.i386,
61@@ -115,6 +126,7 @@
62 'hostname',
63 'after_commissioning_action',
64 'architecture',
65+ 'distro_series',
66 )
67
68
69@@ -154,6 +166,7 @@
70 'hostname',
71 'after_commissioning_action',
72 'architecture',
73+ 'distro_series',
74 'power_type',
75 'power_parameters',
76 )
77
78=== modified file 'src/maasserver/models/config.py'
79--- src/maasserver/models/config.py 2012-09-18 16:36:51 +0000
80+++ src/maasserver/models/config.py 2012-09-19 14:12:24 +0000
81@@ -26,7 +26,10 @@
82 )
83 from django.db.models.signals import post_save
84 from maasserver import DefaultMeta
85-from maasserver.enum import NODE_AFTER_COMMISSIONING_ACTION
86+from maasserver.enum import (
87+ DISTRO_SERIES,
88+ NODE_AFTER_COMMISSIONING_ACTION,
89+ )
90 from maasserver.fields import JSONObjectField
91 from provisioningserver.enum import POWER_TYPE
92
93@@ -49,6 +52,8 @@
94 'maas_name': gethostname(),
95 'enlistment_domain': b'local',
96 ## /settings
97+ 'default_distro_series': DISTRO_SERIES.precise,
98+ 'commissioning_distro_series': DISTRO_SERIES.precise,
99 }
100
101
102
103=== modified file 'src/maasserver/models/node.py'
104--- src/maasserver/models/node.py 2012-09-18 17:58:14 +0000
105+++ src/maasserver/models/node.py 2012-09-19 14:12:24 +0000
106@@ -359,6 +359,10 @@
107 max_length=10, choices=DISTRO_SERIES_CHOICES, null=True,
108 blank=True, default='')
109
110+ distro_series = CharField(
111+ max_length=10, choices=DISTRO_SERIES_CHOICES, null=True,
112+ blank=True, default=None)
113+
114 architecture = CharField(
115 max_length=10, choices=ARCHITECTURE_CHOICES, blank=False,
116 default=ARCHITECTURE.i386)
117@@ -556,6 +560,13 @@
118 else:
119 return None
120
121+ def get_distro_series(self):
122+ """Return the distro series to install that node."""
123+ if not self.distro_series or self.distro_series == DISTRO_SERIES.default:
124+ return Config.objects.get_config('default_distro_series')
125+ else:
126+ return self.distro_series
127+
128 def get_effective_power_parameters(self):
129 """Return effective power parameters, including any defaults."""
130 if self.power_parameters:
131
132=== modified file 'src/maasserver/preseed.py'
133--- src/maasserver/preseed.py 2012-08-21 20:27:47 +0000
134+++ src/maasserver/preseed.py 2012-09-19 14:12:24 +0000
135@@ -30,6 +30,7 @@
136 )
137 from maasserver.server_address import get_maas_facing_server_host
138 from maasserver.utils import absolute_reverse
139+from maasserver.models import Config
140 import tempita
141
142
143@@ -54,28 +55,26 @@
144 return render_preseed(None, PRESEED_TYPE.ENLIST_USERDATA)
145
146
147-# XXX: rvb 2012-06-21 bug=1013146: 'precise' is hardcoded here.
148-def get_preseed(node, release="precise"):
149+def get_preseed(node):
150 """Return the preseed for a given node. Depending on the node's status
151 this will be a commissioning preseed (if the node is commissioning) or the
152 standard preseed (normal installation preseed).
153
154 :param node: The node to return preseed for.
155 :type node: :class:`maasserver.models.Node`
156- :param release: The Ubuntu release to be used.
157- :type release: basestring
158 :return: The rendered preseed string.
159 :rtype: basestring.
160 """
161 if node.status == NODE_STATUS.COMMISSIONING:
162 return render_preseed(
163- node, PRESEED_TYPE.COMMISSIONING, release=release)
164+ node, PRESEED_TYPE.COMMISSIONING,
165+ release=Config.objects.get_config('commissioning_distro_series'))
166 else:
167- return render_preseed(node, PRESEED_TYPE.DEFAULT, release=release)
168-
169-
170-# XXX: rvb 2012-06-14 bug=1013146: 'precise' is hardcoded here.
171-def get_preseed_filenames(node, prefix='', release='precise', default=False):
172+ return render_preseed(node, PRESEED_TYPE.DEFAULT,
173+ release=node.get_distro_series())
174+
175+
176+def get_preseed_filenames(node, prefix='', release='', default=False):
177 """List possible preseed template filenames for the given node.
178
179 :param node: The node to return template preseed filenames for.
180@@ -174,8 +173,7 @@
181 self.name = name
182
183
184-# XXX: rvb 2012-06-18 bug=1013146: 'precise' is hardcoded here.
185-def load_preseed_template(node, prefix, release="precise"):
186+def load_preseed_template(node, prefix, release=''):
187 """Find and load a `PreseedTemplate` for the given node.
188
189 :param node: See `get_preseed_filenames`.
190@@ -201,8 +199,7 @@
191 return get_template(prefix, None, default=True)
192
193
194-# XXX: rvb 2012-06-19 bug=1013146: 'precise' is hardcoded here.
195-def get_preseed_context(node, release="precise"):
196+def get_preseed_context(node, release=''):
197 """Return the context dictionary to be used to render preseed templates
198 for this node.
199
200@@ -236,8 +233,7 @@
201 return context
202
203
204-# XXX: rvb 2012-06-19 bug=1013146: 'precise' is hardcoded here.
205-def render_preseed(node, prefix, release="precise"):
206+def render_preseed(node, prefix, release=''):
207 """Find and load a `PreseedTemplate` for the given node.
208
209 :param node: See `get_preseed_filenames`.
210
211=== modified file 'src/maasserver/templates/maasserver/snippets.html'
212--- src/maasserver/templates/maasserver/snippets.html 2012-06-11 12:25:37 +0000
213+++ src/maasserver/templates/maasserver/snippets.html 2012-09-19 14:12:24 +0000
214@@ -20,6 +20,10 @@
215 {{ node_form.after_commissioning_action }}
216 </p>
217 <p>
218+ <label for="id_distro_series">Release</label>
219+ {{ node_form.distro_series }}
220+ </p>
221+ <p>
222 <label for="id_architecture">Architecture</label>
223 {{ node_form.architecture }}
224 </p>
225
226=== modified file 'src/maasserver/tests/test_forms.py'
227--- src/maasserver/tests/test_forms.py 2012-09-18 07:51:29 +0000
228+++ src/maasserver/tests/test_forms.py 2012-09-19 14:12:24 +0000
229@@ -226,6 +226,7 @@
230 'hostname',
231 'after_commissioning_action',
232 'architecture',
233+ 'distro_series',
234 ], list(form.fields))
235
236 def test_NodeForm_changes_node(self):
237@@ -256,6 +257,7 @@
238 'hostname',
239 'after_commissioning_action',
240 'architecture',
241+ 'distro_series',
242 'power_type',
243 'power_parameters',
244 ],