Merge lp:~javier.collado/utah/readable-preseed into lp:utah

Proposed by Javier Collado
Status: Merged
Approved by: Javier Collado
Approved revision: 831
Merged at revision: 821
Proposed branch: lp:~javier.collado/utah/readable-preseed
Merge into: lp:utah
Diff against target: 345 lines (+113/-96)
11 files modified
debian/utah.install (+1/-0)
templates/50-utahdefault.conf.jinja2 (+13/-0)
templates/casper-preseed-script.jinja2 (+4/-0)
templates/check-locks-command.jinja2 (+9/-0)
templates/install-deb-command.jinja2 (+2/-0)
templates/preseed-install-commands.jinja2 (+5/-0)
templates/preseed-postinstall-commands.jinja2 (+4/-0)
templates/preseed-success-command.jinja2 (+8/-0)
templates/utah-latecommand.jinja2 (+18/-0)
utah/config.py (+2/-0)
utah/provisioning/provisioning.py (+47/-96)
To merge this branch: bzr merge lp:~javier.collado/utah/readable-preseed
Reviewer Review Type Date Requested Status
Javier Collado (community) Approve
Review via email: mp+149664@code.launchpad.net

Description of the change

The changes in this branch are intended to improve the readability of the
generated preseed once it's rewritten.

To do this, it replaces the templates that were include in the code with other
ones in separate files using jinja2 template library. Some of the files aren't
really templates because they don't have any substitution variable, but I've
moved them to a file to keep a better separatation between the code and the
data that is used in the provisioned machines. I could replace the template
rendering for them with just a file copy if you find this doesn't make much
sense.

An example of a fragment of a the preseed for a desktop would be as follows:

ubiquity ubiquity/success_command string \
    sh utah-latecommand; \
    in-target sh -c '\
        while (fuser /var/lib/dpkg/lock \
                     /var/cache/apt/archives/lock \
                     /var/lib/apt/lists/lock \
               >/dev/null 2>&1); \
        do \
            echo "Waiting for dpkg lock to become available"; \
            sleep 10; \
        done; \
        apt-get install -y --force-yes openssh-server >>/var/log/utah-install 2>&1; \
        while (fuser /var/lib/dpkg/lock \
                     /var/cache/apt/archives/lock \
                     /var/lib/apt/lists/lock \
               >/dev/null 2>&1); \
        do \
            echo "Waiting for dpkg lock to become available"; \
            sleep 10; \
        done; \
        apt-get install -y --force-yes gdebi >>/var/log/utah-install 2>&1; \
        sed -i -e '"'"'/^exit 0$/i\
            while (fuser /var/lib/dpkg/lock \
                         /var/cache/apt/archives/lock \
                         /var/lib/apt/lists/lock \
                   >/dev/null 2>&1); \
            do \
                echo "Waiting for dpkg lock to become available"; \
                sleep 10; \
            done; \
            apt-get install -y --force-yes openssh-server >>/var/log/utah-install 2>&1; \
            while (fuser /var/lib/dpkg/lock \
                         /var/cache/apt/archives/lock \
                         /var/lib/apt/lists/lock \
                   >/dev/null 2>&1); \
            do \
                echo "Waiting for dpkg lock to become available"; \
                sleep 10; \
            done; \
            apt-get install -y --force-yes gdebi >>/var/log/utah-install 2>&1; \
        '"'"'\
        /etc/rc.local;\
        '; [ "$?" -eq "0" ]

Note that this was all in a single line and now it's possible to take a look at
it if it's needed to troubleshoot a problem.

I've tested the changes with {desktop,server} {i386,amd64} images and didn't
fine any problem.

To post a comment you must log in.
Revision history for this message
Max Brustkern (nuclearbob) wrote :

This looks pretty great. I think it would be awesome if we also templated the default preseed, libvirt XML file, and maybe even stuff like the kernel command line options and the commands we pass to cobbler, but all of those would involve more work to keep them compatible with user input. I think this is a really good step in the direction of separation of code from configuration.

As far as the actual code, it all looks reasonable to me. If you've tested it, it should be fine. If I have some time, I'll try to test it as well.

Finally, if we merge this before the rsyslog stuff, we'll need to make sure that branch gets properly updated to take these changes into account, and vice versa.

Revision history for this message
Andy Doan (doanac) wrote :

> === added directory 'templates'
> === added file 'templates/50-utahdefault.conf.jinja2'
> --- templates/50-utahdefault.conf.jinja2 1970-01-01 00:00:00 +0000
> +++ templates/50-utahdefault.conf.jinja2 2013-02-20 19:07:27 +0000
> @@ -0,0 +1,18 @@
> +# Default rules for rsyslog.
> +# Minimal file provided for utah installation logging
> +# For more information see rsyslog.conf(5) and /etc/rsyslog.conf
> +auth,authpriv.* /var/log/auth.log
> +*.*;auth,authpriv.none -/dev/ttyS0
> +*.*;auth,authpriv.none -/var/log/syslog
> +kern.* -/var/log/kern.log
> +mail.* -/var/log/mail.log
> +mail.err /var/log/mail.err
> +news.crit /var/log/news/news.crit
> +news.err /var/log/news/news.err
> +news.notice -/var/log/news/news.notice
> +*.emerg *
> +daemon.*;mail.*;\
> + news.err;\
> + *.=debug;*.=info;\
> + *.=notice;*.=warn |/dev/xconsole

you can delete these last 4 lines. They just cause a warning in the
target. I did them in my syslog-install branch.

Revision history for this message
Andy Doan (doanac) wrote :

On 02/20, Max Brustkern wrote:
> This looks pretty great. I think it would be awesome if we also templated the default preseed, libvirt XML file, and maybe even stuff like the kernel command line options and the commands we pass to cobbler, but all of those would involve more work to keep them compatible with user input. I think this is a really good step in the direction of separation of code from configuration.
>
> As far as the actual code, it all looks reasonable to me. If you've tested it, it should be fine. If I have some time, I'll try to test it as well.
>
> Finally, if we merge this before the rsyslog stuff, we'll need to make sure that branch gets properly updated to take these changes into account, and vice versa.

Its okay if you want to merge this first. I'm taking Max's branch and
mine and rebasing them. With the new rsylogd support I'm adding its
become sufficiently different that dragging the original history around
isn't going to be helpful.

831. By Javier Collado

Removed lines that were causing a warning (following Andy's comment)

Revision history for this message
Javier Collado (javier.collado) wrote :

Both of you seem to agree with the changes, so I'm merging them.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/utah.install'
2--- debian/utah.install 2012-12-05 16:15:01 +0000
3+++ debian/utah.install 2013-02-21 08:48:18 +0000
4@@ -5,3 +5,4 @@
5 utah-client_*_all.deb usr/share/utah
6 utah-common_*_all.deb usr/share/utah
7 python-jsonschema_*_all.deb usr/share/utah
8+templates usr/share/utah
9
10=== added directory 'templates'
11=== added file 'templates/50-utahdefault.conf.jinja2'
12--- templates/50-utahdefault.conf.jinja2 1970-01-01 00:00:00 +0000
13+++ templates/50-utahdefault.conf.jinja2 2013-02-21 08:48:18 +0000
14@@ -0,0 +1,13 @@
15+# Default rules for rsyslog.
16+# Minimal file provided for utah installation logging
17+# For more information see rsyslog.conf(5) and /etc/rsyslog.conf
18+auth,authpriv.* /var/log/auth.log
19+*.*;auth,authpriv.none -/dev/ttyS0
20+*.*;auth,authpriv.none -/var/log/syslog
21+kern.* -/var/log/kern.log
22+mail.* -/var/log/mail.log
23+mail.err /var/log/mail.err
24+news.crit /var/log/news/news.crit
25+news.err /var/log/news/news.err
26+news.notice -/var/log/news/news.notice
27+*.emerg *
28
29=== added file 'templates/casper-preseed-script.jinja2'
30--- templates/casper-preseed-script.jinja2 1970-01-01 00:00:00 +0000
31+++ templates/casper-preseed-script.jinja2 2013-02-21 08:48:18 +0000
32@@ -0,0 +1,4 @@
33+#!/bin/sh
34+
35+cp preseed.cfg utah-ssh-key utah-latecommand /root
36+cp 50-utahdefault.conf /root/etc/rsyslog.d
37
38=== added file 'templates/check-locks-command.jinja2'
39--- templates/check-locks-command.jinja2 1970-01-01 00:00:00 +0000
40+++ templates/check-locks-command.jinja2 2013-02-21 08:48:18 +0000
41@@ -0,0 +1,9 @@
42+{# Check lock files before package installation -#}
43+while (fuser /var/lib/dpkg/lock \
44+ /var/cache/apt/archives/lock \
45+ /var/lib/apt/lists/lock \
46+ >/dev/null 2>&1); \
47+do \
48+ echo "Waiting for dpkg lock to become available"; \
49+ sleep 10; \
50+done; \
51
52=== added file 'templates/install-deb-command.jinja2'
53--- templates/install-deb-command.jinja2 1970-01-01 00:00:00 +0000
54+++ templates/install-deb-command.jinja2 2013-02-21 08:48:18 +0000
55@@ -0,0 +1,2 @@
56+{% include "check-locks-command.jinja2" %}
57+DEBIAN_FRONTEND=noninteractive gdebi -n -q {{deb}}
58
59=== added file 'templates/preseed-install-commands.jinja2'
60--- templates/preseed-install-commands.jinja2 1970-01-01 00:00:00 +0000
61+++ templates/preseed-install-commands.jinja2 2013-02-21 08:48:18 +0000
62@@ -0,0 +1,5 @@
63+{% for package_name in package_names -%}
64+{% include "check-locks-command.jinja2" %}
65+{# Install package -#}
66+apt-get install -y --force-yes {{package_name}} >>{{log_file}} 2>&1; \
67+{% endfor %}
68
69=== added file 'templates/preseed-postinstall-commands.jinja2'
70--- templates/preseed-postinstall-commands.jinja2 1970-01-01 00:00:00 +0000
71+++ templates/preseed-postinstall-commands.jinja2 2013-02-21 08:48:18 +0000
72@@ -0,0 +1,4 @@
73+sed -i -e '/^exit 0$/i\
74+ {{install_commands | indent}}
75+'\
76+/etc/rc.local;
77
78=== added file 'templates/preseed-success-command.jinja2'
79--- templates/preseed-success-command.jinja2 1970-01-01 00:00:00 +0000
80+++ templates/preseed-success-command.jinja2 2013-02-21 08:48:18 +0000
81@@ -0,0 +1,8 @@
82+{# Note that since the chroot command is passed to sh within single quotes, the
83+single quotes inside the chroot command have to be escaped using '"'"'.
84+For more information, please refer to:
85+http://stackoverflow.com/q/1250079/183066 -#}
86+\
87+ in-target sh -c '\
88+ {{commands | replace('\'', '\'"\'"\'') | indent(8)}}\
89+ ';
90
91=== added file 'templates/utah-latecommand.jinja2'
92--- templates/utah-latecommand.jinja2 1970-01-01 00:00:00 +0000
93+++ templates/utah-latecommand.jinja2 2013-02-21 08:48:18 +0000
94@@ -0,0 +1,18 @@
95+#!/bin/sh
96+
97+ROOTDIR=/target/root/.ssh
98+USERDIR=/target/home/{{user}}/.ssh
99+
100+for DIR in $ROOTDIR $USERDIR
101+do
102+ mkdir -p $DIR
103+ cp utah-ssh-key $DIR/authorized_keys
104+ chmod 700 $DIR
105+done
106+
107+chown -R root:root $ROOTDIR
108+chown -R 1000:1000 $USERDIR
109+
110+mkdir -p /target/etc/utah
111+echo "{{uuid}}" > /target/etc/utah/uuid
112+echo "{{user}}" >> /target/etc/utah/users
113
114=== modified file 'utah/config.py'
115--- utah/config.py 2013-01-24 15:56:24 +0000
116+++ utah/config.py 2013-02-21 08:48:18 +0000
117@@ -140,6 +140,8 @@
118 # sqlite database connection timeout
119 # a value higher than the default is used to avoid db locking problems
120 sqlite3_db_connection_timeout=30,
121+ # location of the jinja2 templates used by the provisionig module
122+ template_dir=os.path.join('/', 'usr', 'share', 'utah', 'templates')
123 )
124
125 # These depend on the local user/path, and need to be filtered out
126
127=== modified file 'utah/provisioning/provisioning.py'
128--- utah/provisioning/provisioning.py 2013-02-13 15:43:27 +0000
129+++ utah/provisioning/provisioning.py 2013-02-21 08:48:18 +0000
130@@ -33,6 +33,8 @@
131
132 from glob import glob
133
134+from jinja2 import Environment, FileSystemLoader
135+
136 import utah.timeout
137
138 from utah import config
139@@ -62,16 +64,6 @@
140 * stop, uploadfiles, downloadfiles, run
141 (these must be implemented separately.)
142 """
143- # Used in installation commands to make sure
144- # files aren't locked
145- CHECK_LOCK_COMMAND = (
146- 'while (fuser /var/lib/dpkg/lock /var/cache/apt/archives/lock '
147- '/var/lib/apt/lists/lock >/dev/null 2>&1); '
148- 'do '
149- 'echo "Waiting for dpkg lock to become available"; '
150- 'sleep 10; '
151- 'done; ')
152-
153 def __init__(self, arch=None, boot=None, clean=None, debug=False,
154 directory=None, image=None, dlpercentincrement=1,
155 initrd=None, installtype=None, kernel=None, machineid=None,
156@@ -214,6 +206,9 @@
157
158 self.finalpreseed = self.preseed
159
160+ self.template_env = \
161+ Environment(loader=FileSystemLoader(config.template_dir))
162+
163 self.logger.debug('Machine init finished')
164
165 def _namesetup(self, name=None):
166@@ -401,11 +396,9 @@
167 raise err
168
169 remote_deb = os.path.join(tmppath, os.path.basename(deb))
170- install_command = (
171- '{}'
172- 'DEBIAN_FRONTEND=noninteractive gdebi -n -q {}'
173- .format(self.CHECK_LOCK_COMMAND,
174- remote_deb))
175+ template = self.template_env.get_template(
176+ 'install-deb-command.jinja2')
177+ install_command = template.render(deb=remote_deb)
178 returncode, _stdout, stderr = self.run(install_command, root=True)
179 if (returncode != 0 or
180 re.search(r'script returned error exit status \d+',
181@@ -787,28 +780,12 @@
182 os.path.join(tmpdir, 'initrd.d', 'utah-ssh-key'))
183
184 self.logger.info('Creating latecommand script')
185+ template = self.template_env.get_template('utah-latecommand.jinja2')
186+ latecommand = template.render(user=config.user,
187+ uuid=self.uuid)
188 filename = os.path.join(tmpdir, 'initrd.d', 'utah-latecommand')
189- latecommand = open(filename, 'w')
190- latecommand.write("""#!/bin/sh
191-
192-ROOTDIR=/target/root/.ssh
193-USERDIR=/target/home/{user}/.ssh
194-
195-for DIR in $ROOTDIR $USERDIR
196-do
197- mkdir -p $DIR
198- cp utah-ssh-key $DIR/authorized_keys
199- chmod 700 $DIR
200-done
201-
202-chown -R root:root $ROOTDIR
203-chown -R 1000:1000 $USERDIR
204-
205-mkdir -p /target/etc/utah
206-echo "{uuid}" > /target/etc/utah/uuid
207-echo "{user}" >> /target/etc/utah/users
208-""".format(user=config.user, uuid=self.uuid))
209- latecommand.close()
210+ with open(filename, 'w') as f:
211+ f.write(latecommand)
212
213 def _setuppreseed(self, tmpdir=None):
214 """
215@@ -864,29 +841,26 @@
216 question.qname = 'ubiquity/success_command'
217 log_file = '/var/log/utah-install'
218
219- install_commands = (
220- ' '.join(['{}'
221- 'apt-get install -y --force-yes {} >>{} 2>&1; '
222- .format(self.CHECK_LOCK_COMMAND, pkg_name, log_file)
223- for pkg_name in config.installpackages]))
224- postinstall_commands = (
225- 'sed -i -e \'/^exit 0$/i{}\' /etc/rc.local;'
226- .format(install_commands)
227- )
228- chroot_command = ' '.join([install_commands, postinstall_commands])
229- # Note that since the chroot command is passed to sh within single
230- # quotes, the single quotes inside the chroot command have to be
231- # escaped using '"'"'
232- # For more information, please refer to:
233- # http://stackoverflow.com/q/1250079/183066
234- question.value.prepend(
235- 'in-target sh -c \'{}\'; '
236- .format(chroot_command.replace('\'', '\'"\'"\'')))
237+ template = self.template_env.get_template(
238+ 'preseed-install-commands.jinja2')
239+ install_commands = template.render(
240+ package_names=config.installpackages,
241+ log_file=log_file)
242+ template = self.template_env.get_template(
243+ 'preseed-postinstall-commands.jinja2')
244+ postinstall_commands = template.render(
245+ install_commands=install_commands)
246+ template = self.template_env.get_template(
247+ 'preseed-success-command.jinja2')
248+ chroot_command = template.render(
249+ commands=''.join([install_commands,
250+ postinstall_commands]))
251+ question.value.prepend(chroot_command)
252 question.prepend("ubiquity ubiquity/summary note")
253 question.prepend("ubiquity ubiquity/reboot boolean true")
254 else:
255 self.logger.info('Prepending latecommand')
256- question.value.prepend('sh utah-latecommand ; ')
257+ question.value.prepend('\\\n sh utah-latecommand; ')
258
259 def _rewrite_success_command(self, preseed):
260 """
261@@ -895,7 +869,7 @@
262 """
263 self.logger.info('Prepending success_command')
264 question = preseed['ubiquity/success_command']
265- question.value.prepend('sh utah-latecommand ; ')
266+ question.value.prepend('\\\n sh utah-latecommand; ')
267
268 def _rewrite_pkgsel_include(self, preseed):
269 """
270@@ -934,30 +908,22 @@
271 self.logger.info('Inserting preseed into casper')
272 if tmpdir is None:
273 tmpdir = self.tmpdir
274- preseedscript = os.path.join(tmpdir, 'initrd.d', 'scripts',
275- 'casper-bottom', 'utah')
276- open(preseedscript, 'w').write("""#!/bin/sh
277-
278-cp preseed.cfg utah-ssh-key utah-latecommand /root
279-cp 50-utahdefault.conf /root/etc/rsyslog.d
280-""")
281- os.chmod(preseedscript, 0755)
282+ template = self.template_env.get_template(
283+ 'casper-preseed-script.jinja2')
284+ preseedscript = template.render()
285 casper_dir = os.path.join(tmpdir, 'initrd.d', 'scripts',
286 'casper-bottom')
287- tmpfilename = os.path.join(casper_dir, 'ORDER.tmp')
288- tmpfile = open(tmpfilename, 'w')
289+ filename = os.path.join(casper_dir, 'utah')
290+ with open(filename, 'w') as f:
291+ f.write(preseedscript)
292+ os.chmod(filename, 0755)
293+
294 orderfilename = os.path.join(casper_dir, 'ORDER')
295- orderfile = open(orderfilename, 'r')
296- tmpfile.write("""/scripts/casper-bottom/utah
297-[ -e /conf/param.conf ] && . /conf/param.conf
298-""")
299- tmpfile.flush()
300- for line in orderfile:
301- tmpfile.write(line)
302- tmpfile.flush()
303- tmpfile.close()
304- orderfile.close()
305- os.rename(tmpfilename, orderfilename)
306+ self._runargs(['sed', '-i',
307+ '1i/scripts/casper-bottom/'
308+ 'utah\\n'
309+ '[ -e /conf/param.conf ] && . /conf/param.conf',
310+ orderfilename])
311
312 def _setuplogging(self, tmpdir=None):
313 """
314@@ -976,27 +942,12 @@
315 "-f /var/log/syslog \n")
316 else:
317 self.logger.info('No inittab found, creating rsyslog config file')
318+ template = self.template_env.get_template(
319+ '50-utahdefault.conf.jinja2')
320 conffilename = os.path.join(tmpdir, 'initrd.d',
321 '50-utahdefault.conf')
322- open(conffilename, 'w').write("""
323-# Default rules for rsyslog.
324-# Minimal file provided for utah installation logging
325-# For more information see rsyslog.conf(5) and /etc/rsyslog.conf
326-auth,authpriv.* /var/log/auth.log
327-*.*;auth,authpriv.none -/dev/ttyS0
328-*.*;auth,authpriv.none -/var/log/syslog
329-kern.* -/var/log/kern.log
330-mail.* -/var/log/mail.log
331-mail.err /var/log/mail.err
332-news.crit /var/log/news/news.crit
333-news.err /var/log/news/news.err
334-news.notice -/var/log/news/news.notice
335-*.emerg *
336-daemon.*;mail.*;\
337- news.err;\
338- *.=debug;*.=info;\
339- *.=notice;*.=warn |/dev/xconsole
340-""")
341+ with open(conffilename, 'w') as f:
342+ f.write(template.render())
343
344 def _repackinitrd(self, tmpdir=None):
345 """

Subscribers

People subscribed via source and target branches