Merge lp:~corey.bryant/curtin/trunk into lp:~curtin-dev/curtin/trunk

Proposed by Corey Bryant
Status: Superseded
Proposed branch: lp:~corey.bryant/curtin/trunk
Merge into: lp:~curtin-dev/curtin/trunk
Diff against target: 84 lines (+60/-0)
1 file modified
curtin/commands/install.py (+60/-0)
To merge this branch: bzr merge lp:~corey.bryant/curtin/trunk
Reviewer Review Type Date Requested Status
curtin developers Pending
Review via email: mp+205447@code.launchpad.net

This proposal has been superseded by a proposal from 2014-02-14.

Description of the change

Add kexec support and a minor update to example launch command

Sample usage: curtin install --set "power_state/mode=kexec" ...

To post a comment you must log in.
Revision history for this message
Scott Moser (smoser) wrote :

Corey,
  Thanks for the merge request.

 * The 'opt_map' fix seems reasonable. Not the way I had thoght of implementing it, but that should be fine.
   The other option is to just not bother rebooting, but have curtin call 'kexec' itself.
   As I'm thinking... maybe that would be better. As if you reboot, kexec-tools will load the kernel by reading /boot/grub (or attempt to) in its root filesystem. However, we want to load the one that is in the *installed* OS's filesystem.

 * when you use subp, best to not run through 'sh' unless necessary. Ie:
   - util.subp(args=['sh', '-c', 'apt-get install kexec-tools -qy'])
   + util.subp(args=['apt-get', 'install', '-qy', 'kexec-tools'])

 * I generally prefer long format arguments to programs as they're more self documenting:
   + util.subp(args=['apt-get', 'install', '--quiet', '--assume-yes', 'kexec-tools'])

Thanks!

Revision history for this message
Corey Bryant (corey.bryant) wrote :

> Corey,
> Thanks for the merge request.
>

Thanks for reviewing!

> * The 'opt_map' fix seems reasonable. Not the way I had thoght of
> implementing it, but that should be fine.
> The other option is to just not bother rebooting, but have curtin call
> 'kexec' itself.

The reason I took the reboot approach is because I wanted to make sure proper
shutdown occurred before exec'ing the new kernel. From the looks of it you might
be able to get the same result by calling kexec directly without an option parameter.
But I don't think a simple 'kexec -e' does proper shutdown. I'll look into it.

> As I'm thinking... maybe that would be better. As if you reboot, kexec-
> tools will load the kernel by reading /boot/grub (or attempt to) in its root
> filesystem. However, we want to load the one that is in the *installed* OS's
> filesystem.

I think you're right. I'm currently running kexec-load in the root fs and it's
looking at the wrong /boot dir. Another approach is to run kexec-load while
chroot'ed into /tmp/.../target. Then it should look at the right /boot dir.

Which takes me to a somewhat related question that I haven't figured out. When
I use launch with a normal non-kexec reboot, and it reboots into the new OS, the
grub menu is not the one from /tmp/.../target/boot/grub/grub.cfg. However once
booted, the new root fs is the new system (/dev/vdc) and contains the updated
grub.cfg. Shouldn't the grub menu reflect what's in
/tmp/.../target/boot/grub/grub.cfg?

>
>
> * when you use subp, best to not run through 'sh' unless necessary. Ie:
> - util.subp(args=['sh', '-c', 'apt-get install kexec-tools -qy'])
> + util.subp(args=['apt-get', 'install', '-qy', 'kexec-tools'])

Ok

>
> * I generally prefer long format arguments to programs as they're more self
> documenting:
> + util.subp(args=['apt-get', 'install', '--quiet', '--assume-yes', 'kexec-
> tools'])

Yep, makes sense.

>
>
> Thanks!

lp:~corey.bryant/curtin/trunk updated
98. By Scott Moser

curthooks: always update grub linux default entry

Previously we only modified GRUB_CMDLINE_LINUX_DEFAULT in /etc/default/grub
if there were new kernel command line parameters found.

The images that were built from cloud images would have baked into them
'console=ttyS0'. The result was serial console output even if the user
didn't request it (or didn't have a serial console).

99. By Scott Moser

write_files: avoid writing a file if no path is given

if the user provides an entry in 'write_files' that did not have a 'path'
then this would warn, and then stack trace. better to just warn.

100. By Scott Moser

write_files: read 'permissions' or 'perms' to specify mode

cloud-init uses 'permissions' for the permission key in a write_files
input. this just makes it more forgiving.

101. By Scott Moser

decode_perms: fix error if permissions was not an int

isinstance(thing, None) is not valid, and that was throwing
an error, causing us down the return default path.

102. By Scott Moser

support source as a local tar file (not only a url)

103. By Scott Moser

partition: default to 'mbr' format

this will probably have to change with UEFI support, but for now, partition
default to 'mbr'

104. By Corey Bryant

curtin/commands/install.py: Add kexec support

This allows for a faster alternative to the existing reboot power_state mode.
Sample usage: curtin install --set "kexec/mode=on"

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'curtin/commands/install.py'
2--- curtin/commands/install.py 2013-09-19 21:01:27 +0000
3+++ curtin/commands/install.py 2014-02-14 15:32:12 +0000
4@@ -19,6 +19,7 @@
5 import json
6 import os
7 import re
8+import shlex
9 import shutil
10 import tempfile
11
12@@ -158,6 +159,61 @@
13
14 return (['sh', '-c', shcmd, 'curtin-poweroff', delay] + args)
15
16+def apply_kexec(kexec, target):
17+ # load kexec kernel from target directory, similar to /etc/init.d/kexec-load
18+ # kexec:
19+ # mode: on
20+ if kexec is None or kexec.get("mode") != "on":
21+ return False
22+
23+ if not isinstance(kexec, dict):
24+ raise TypeError("kexec is not a dict.")
25+
26+ util.subp(args=['apt-get', 'install', 'kexec-tools', '--assume-yes',
27+ '--quiet'])
28+
29+ with open(target + "/boot/grub/grub.cfg", "r") as fp:
30+ default = 0
31+ menu_lines = []
32+
33+ # get the default grub boot entry number and menu entry line numbers
34+ for line_num, line in enumerate(fp, 1):
35+ if re.search(r"set default=\"[0-9]+\"", line):
36+ default = int(re.sub(r"[^0-9]", '', line))
37+ if re.match(r"menuentry", line):
38+ menu_lines.append(line_num)
39+
40+ if not menu_lines:
41+ LOG.error("grub config file does not have a menuentry\n")
42+ return False
43+
44+ # get the begin and end line numbers for default menuentry section
45+ begin = menu_lines[default]
46+ if begin != menu_lines[-1]:
47+ end = menu_lines[default + 1] - 1
48+ else:
49+ end = line_num
50+
51+ fp.seek(0)
52+ lines=fp.readlines()
53+ kernel = append = initrd = ""
54+
55+ for i in range(begin, end):
56+ if 'vmlinuz' in lines[i]:
57+ split_line = shlex.split(lines[i])
58+ kernel = target + split_line[1]
59+ append = "--append=" + ' '.join(split_line[2:])
60+ if 'initrd' in lines[i]:
61+ split_line = shlex.split(lines[i])
62+ initrd = "--initrd=" + target + split_line[1]
63+
64+ if not kernel:
65+ LOG.error("grub config file does not have a kernel\n")
66+ return False
67+
68+ LOG.debug("kexec -l %s %s %s" % (kernel, append, initrd))
69+ util.subp(args=['kexec', '-l', kernel, append, initrd])
70+ return True
71
72 def cmd_install(args):
73 cfg = CONFIG_BUILTIN
74@@ -191,6 +247,10 @@
75 stage = Stage(name, cfg.get(commands_name, {}), env)
76 stage.run()
77
78+ if apply_kexec(cfg.get('kexec'), workingd.target):
79+ cfg['power_state'] = {'mode': 'reboot', 'delay': 'now',
80+ 'message': "'rebooting with kexec'"}
81+
82 finally:
83 for d in ('sys', 'dev', 'proc'):
84 util.do_umount(os.path.join(workingd.target, d))

Subscribers

People subscribed via source and target branches