Merge lp:~javier.collado/utah/bug1050976 into lp:utah

Proposed by Javier Collado
Status: Merged
Approved by: Javier Collado
Approved revision: 710
Merged at revision: 707
Proposed branch: lp:~javier.collado/utah/bug1050976
Merge into: lp:utah
Diff against target: 90 lines (+20/-18)
4 files modified
utah/config.py (+3/-2)
utah/provisioning/provisioning.py (+14/-10)
utah/provisioning/vm/libvirtvm.py (+1/-1)
utah/run.py (+2/-5)
To merge this branch: bzr merge lp:~javier.collado/utah/bug1050976
Reviewer Review Type Date Requested Status
Max Brustkern (community) Approve
Javier Collado (community) Needs Resubmitting
Review via email: mp+128898@code.launchpad.net

Description of the change

This branch moves the "apt-get install" commands in the late command to etc/rc.local

This is to workaround the networking problems when executing the late command since
"apt-get install" and "apt-install" don't seem to be working.

In addition to this, this branch:
- removes the hardcoded ssh timeout of 3 seconds (config.checktimeout is used instead)
- changes bootimeout and checktimeout values in config to some values that work for me
- removes the check for the utah client return code

Regarding the update to the timeout values in the configuration, I think that boottimeout
is being used for multiple things at the same time. One problem I had with the old values
once the hardcoded ssh timeout was removed, was that if checktimeout was greater than
boottimeout, no more retry attempts were made. Hence, in the new values boottimeout (90)
is greater than checktimeout (15). I'm not sure if this might have an effect on some other
use cases, but I've tested this with 64bit desktop precise and quantal images and worked fine
(with the old values I got ssh timeout).

Regarding the utah client return code. The server was not writing the yaml file because the client
returns a failure code when some test case failed. To really fix this, it should be clear
which codes returns the client on a test case failure and on an internal failure. In the meantime
is preferable to write whatever the client prints to stdout to a yaml file.

To post a comment you must log in.
Revision history for this message
Javier Collado (javier.collado) wrote :

One thing that concerns me is that I think that the "apt-get install" commands in the late command install
the packages from the image itself (is that correct?), but after the move to /etc/rc.local, they need
a network connection to work fine, so this change will break the scenarios without network connection.

Revision history for this message
Max Brustkern (nuclearbob) wrote :

That's exactly what I was going to say. I almost think it might be good to have the option to do one or the other.

I definitely agree about a need to standardize client return codes and update the server accordingly. I still don't like that we return a failure code from the server if the client fails a tests with no errors, though, so we may have dissenting opinions on that.

Also, if you needed to update your timeouts to get things working, maybe we should make those the new defaults? I set things kind of aggressively low when first developing them because I wanted to see if things worked quickly, but for production use it's probably better to err on the high side.

lp:~javier.collado/utah/bug1050976 updated
708. By Javier Collado

Added sshserverinstall configuration variable to decide when to install the ssh server

Valid values are 'before reboot' and 'after reboot'

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

@Max

I've added a new configuration variable named sshserverinstall that can have two values: 'before reboot' and 'after reboot'. Based on this configuration variable value, the command to execute in the chroot is selected, that is, when 'before reboot' is set the apt-get install is executed directly and when 'after reboot' is set, the apt-get install is added to /etc/rc.local

The variable name isn't really very good because gdebi package is installed aside from openssh-server. If you've got a better name, please let me know. By the way, I don't like the configuration variables being words together without underscores or capital letters to separate them, but I decided to be consistent with the other ones.

With regard to the timeouts, they have been already updated in config.py.

review: Needs Resubmitting
Revision history for this message
Max Brustkern (nuclearbob) wrote :

I don't think there was any particular design decision making process in place to get the existing configuration variable names, so if we want to overhaul the rest of them to have underscores or something, that seems reasonable to me. I prefer configuration_option to ConfigurationOption myself, but I'm okay with either. As I'm thinking about it, I prefer functionName to function_name, so maybe my preferences aren't very consistent.

With regard to the option, I'm not crazy about the name and the specific values for the option. I don't think there's anything wrong with them, and they are solving a problem, so I don't want to slow down getting this merged, but I've been thinking more about it, and I think I'd almost favor generalizing it a little further. What I'm thinking is two lists, maybe something like install_packages and postinstall_packages, and the install_packages get installed by the latecommand and the postinstall_packages get installed by rc.local. It's definitely more work to implement, and I'm not sure there are important usecases for that flexibility, but when I think about the overall design, I like that idea better than what we have now.

That said, I don't want to derail this. It's a good solution to the problem we have right now, and if we do need more flexibility, we can always add it later. If we merge this, we can have quantal working, which is important, so I'm in favor of doing that.

review: Approve
lp:~javier.collado/utah/bug1050976 updated
709. By Javier Collado

Replaced sshserverinstall with installpackages and postinstallpackages

710. By Javier Collado

Removed postinstallpackages from configuration

Since for now what we really want is to install a list of packages,
installpackages is enough. What the latecommand tries to do now is just install
the given packages both before and after reboot (it doesn't matter which method
succeeds).

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

@Max

You're right, the implementation was ugly and shouldn't be committed to dev.

Following your advice, I've removed that sshserverinstall configuration added another
one called installpackages were a list of package names is expected in the configuration
file.

When the late command string is generated the apt-get install commands are attempted
both before reboot in the chroot and after reboot in the rc.local script.

I've tested that in precise and quantal images and looking into /var/log/utah-install
in the VM I've seen as expected that in precise the package installation succeeds in
the chroot and in quantal it does in the rc.local script.

Note that even in precise, the apt-get install command runs in rc.local, but when the packages
are already installed the commands quickly exits because the package is already installed.

review: Needs Resubmitting
Revision history for this message
Max Brustkern (nuclearbob) wrote :

That's a great idea. It'll work as long as we have a working network connection ever, and there's minimal overhead.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'utah/config.py'
2--- utah/config.py 2012-10-08 13:58:28 +0000
3+++ utah/config.py 2012-10-11 11:03:23 +0000
4@@ -27,14 +27,15 @@
5
6 DEFAULTS = dict(
7 arch='i386',
8- boottimeout=30,
9- checktimeout=180,
10+ boottimeout=90,
11+ checktimeout=15,
12 consoleloglevel=logging.WARNING,
13 debug=False,
14 fileloglevel=logging.INFO,
15 group='utah',
16 image=None,
17 initrd=None,
18+ installpackages=['openssh-server', 'gdebi'],
19 installtimeout=3600,
20 installtype='desktop',
21 kernel=None,
22
23=== modified file 'utah/provisioning/provisioning.py'
24--- utah/provisioning/provisioning.py 2012-10-09 14:01:08 +0000
25+++ utah/provisioning/provisioning.py 2012-10-11 11:03:23 +0000
26@@ -842,19 +842,23 @@
27 question = preseed['preseed/late_command']
28 if self.installtype == 'desktop':
29 self.logger.info('Changing d-i latecommand '
30- + 'to ubiquity success_command '
31- + 'and prepending ubiquity lines')
32+ 'to ubiquity success_command '
33+ 'and prepending ubiquity lines')
34 question.owner = 'ubiquity'
35 question.qname = 'ubiquity/success_command'
36- question.value.prepend(
37- 'chroot /target sh -c \'' # chroot start
38- 'export LOG_FILE=/var/log/utah-install; '
39- 'apt-get install -y --force-yes openssh-server '
40- '>>$LOG_FILE 2>&1 ; '
41- 'apt-get install -y --force-yes gdebi-core '
42- '>>$LOG_FILE 2>&1 ; '
43- '\'; ' # chroot end
44+ log_file = '/var/log/utah-install'
45+
46+ install_commands = (
47+ ' '.join(['apt-get install -y --force-yes {} '
48+ '>>{} 2>&1;'.format(pkg_name, log_file)
49+ for pkg_name in config.installpackages]))
50+ postinstall_commands = (
51+ 'sed -i -e "/^exit 0$/i{}" /etc/rc.local;'
52+ .format(install_commands)
53 )
54+ chroot_command = ' '.join([install_commands, postinstall_commands])
55+ question.value.prepend('chroot /target sh -c \'{}\'; '
56+ .format(chroot_command))
57 question.prepend("ubiquity ubiquity/summary note")
58 question.prepend("ubiquity ubiquity/reboot boolean true")
59 else:
60
61=== modified file 'utah/provisioning/vm/libvirtvm.py'
62--- utah/provisioning/vm/libvirtvm.py 2012-10-08 13:58:28 +0000
63+++ utah/provisioning/vm/libvirtvm.py 2012-10-11 11:03:23 +0000
64@@ -697,7 +697,7 @@
65 self.vm.create()
66 self.logger.info('Waiting ' + str(self.boottimeout) +
67 ' seconds to allow machine to boot')
68- self.sshpoll(self.boottimeout, 3)
69+ self.sshpoll(self.boottimeout)
70 self.active = True
71
72 def destroy(self, *args, **kw):
73
74=== modified file 'utah/run.py'
75--- utah/run.py 2012-08-29 19:32:22 +0000
76+++ utah/run.py 2012-10-11 11:03:23 +0000
77@@ -41,11 +41,8 @@
78 utah_command = 'utah' + extraopts + options
79 try:
80 returncode, stdout, stderr = machine.run(utah_command)
81- if returncode != 0:
82- machine.logger.error('utah failed with return code: {}\n'
83- .format(returncode))
84- exitstatus = 1
85- break
86+ # TODO: Decide which returncode means utah client failure
87+ # and which one means test case failure
88 except UTAHException as error:
89 machine.logger.error('Failed to run test: ' + str(error))
90 exitstatus = 1

Subscribers

People subscribed via source and target branches