1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import logging
20 import optparse
21 import os
22 import pwd
23 import shutil
24 import sys
25 import VMBuilder
26 import VMBuilder.util as util
27 from VMBuilder.disk import parse_size
28 import VMBuilder.hypervisor
29 from VMBuilder.exception import VMBuilderUserError, VMBuilderException
30
32 arg = 'cli'
33
35 try:
36 optparser = optparse.OptionParser()
37
38 self.set_usage(optparser)
39
40 optparser.add_option('--version', action='callback', callback=self.versioninfo, help='Show version information')
41
42 group = optparse.OptionGroup(optparser, 'Build options')
43 group.add_option('--debug', action='callback', callback=self.set_verbosity, help='Show debug information')
44 group.add_option('--verbose', '-v', action='callback', callback=self.set_verbosity, help='Show progress information')
45 group.add_option('--quiet', '-q', action='callback', callback=self.set_verbosity, help='Silent operation')
46 group.add_option('--overwrite', '-o', action='store_true', help='Configuration file')
47 group.add_option('--config', '-c', type='str', help='Configuration file')
48 group.add_option('--templates', metavar='DIR', help='Prepend DIR to template search path.')
49 group.add_option('--destdir', '-d', type='str', help='Destination directory')
50 group.add_option('--only-chroot', action='store_true', help="Only build the chroot. Don't install it on disk images or anything.")
51 group.add_option('--existing-chroot', help="Use existing chroot.")
52 optparser.add_option_group(group)
53
54 group = optparse.OptionGroup(optparser, 'Disk')
55 group.add_option('--rootsize', metavar='SIZE', default=4096, help='Size (in MB) of the root filesystem [default: %default]')
56 group.add_option('--optsize', metavar='SIZE', default=0, help='Size (in MB) of the /opt filesystem. If not set, no /opt filesystem will be added.')
57 group.add_option('--swapsize', metavar='SIZE', default=1024, help='Size (in MB) of the swap partition [default: %default]')
58 group.add_option('--raw', metavar='PATH', type='str', help="Specify a file (or block device) to as first disk image.")
59 group.add_option('--part', metavar='PATH', type='str', help="Allows to specify a partition table in PATH each line of partfile should specify (root first): \n mountpoint size \none per line, separated by space, where size is in megabytes. You can have up to 4 virtual disks, a new disk starts on a line containing only '---'. ie: \n root 2000 \n /boot 512 \n swap 1000 \n --- \n /var 8000 \n /var/log 2000")
60 optparser.add_option_group(group)
61
62 hypervisor, distro = self.handle_args(optparser, sys.argv[1:])
63
64 self.add_settings_from_context(optparser, distro)
65 self.add_settings_from_context(optparser, hypervisor)
66
67 hypervisor.register_hook('fix_ownership', self.fix_ownership)
68
69 config_files = ['/etc/vmbuilder.cfg', os.path.expanduser('~/.vmbuilder.cfg')]
70 (self.options, args) = optparser.parse_args(sys.argv[2:])
71
72 if os.geteuid() != 0:
73 raise VMBuilderUserError('Must run as root')
74
75 destdir = self.options.destdir or ('%s-%s' % (distro.arg, hypervisor.arg))
76 if os.path.exists(destdir):
77 if self.options.overwrite:
78 logging.debug('%s existed, but -o was specified. Nuking it.' % destdir)
79 shutil.rmtree(destdir)
80 else:
81 raise VMBuilderUserError('%s already exists' % destdir)
82
83 if self.options.config:
84 config_files.append(self.options.config)
85 util.apply_config_files_to_context(config_files, distro)
86 util.apply_config_files_to_context(config_files, hypervisor)
87
88 if self.options.templates:
89 distro.template_dirs.insert(0,'%s/%%s' % self.options.templates)
90 hypervisor.template_dirs.insert(0,'%s/%%s' % self.options.templates)
91
92 for option in dir(self.options):
93 if option.startswith('_') or option in ['ensure_value', 'read_module', 'read_file']:
94 continue
95 val = getattr(self.options, option)
96 option = option.replace('_', '-')
97 if val:
98 if distro.has_setting(option) and distro.get_setting_default(option) != val:
99 distro.set_setting_fuzzy(option, val)
100 elif hypervisor.has_setting(option) and hypervisor.get_setting_default(option) != val:
101 hypervisor.set_setting_fuzzy(option, val)
102
103 if self.options.existing_chroot:
104 distro.set_chroot_dir(self.options.existing_chroot)
105 distro.call_hooks('preflight_check')
106 else:
107 chroot_dir = util.tmpdir()
108 distro.set_chroot_dir(chroot_dir)
109 distro.build_chroot()
110
111 if self.options.only_chroot:
112 print 'Chroot can be found in %s' % distro.chroot_dir
113 sys.exit(0)
114
115 self.set_disk_layout(hypervisor)
116 hypervisor.install_os()
117
118 os.mkdir(destdir)
119 self.fix_ownership(destdir)
120 hypervisor.finalise(destdir)
121 except VMBuilderException, e:
122 logging.error(e)
123 raise
124 sys.exit(1)
125
127 """
128 Change ownership of file to $SUDO_USER.
129
130 @type path: string
131 @param path: file or directory to give to $SUDO_USER
132 """
133 if 'SUDO_USER' in os.environ:
134 logging.debug('Changing ownership of %s to %s' % (filename, os.environ['SUDO_USER']))
135 (uid, gid) = pwd.getpwnam(os.environ['SUDO_USER'])[2:4]
136 os.chown(filename, uid, gid)
137
138 - def add_settings_from_context(self, optparser, context):
139 setting_groups = set([setting.setting_group for setting in context._config.values()])
140 for setting_group in setting_groups:
141 optgroup = optparse.OptionGroup(optparser, setting_group.name)
142 for setting in setting_group._settings:
143 args = ['--%s' % setting.name]
144 args += setting.extra_args
145 kwargs = {}
146 if setting.help:
147 kwargs['help'] = setting.help
148 if len(setting.extra_args) > 0:
149 setting.help += " Config option: %s" % setting.name
150 if setting.metavar:
151 kwargs['metavar'] = setting.metavar
152 if setting.get_default():
153 kwargs['default'] = setting.get_default()
154 if type(setting) == VMBuilder.plugins.Plugin.BooleanSetting:
155 kwargs['action'] = 'store_true'
156 if type(setting) == VMBuilder.plugins.Plugin.ListSetting:
157 kwargs['action'] = 'append'
158 optgroup.add_option(*args, **kwargs)
159 optparser.add_option_group(optgroup)
160
164
166 optparser.set_usage('%prog hypervisor distro [options]')
167
168
175
183
185 default_filesystem = hypervisor.distro.preferred_filesystem()
186 if not self.options.part:
187 rootsize = parse_size(self.options.rootsize)
188 swapsize = parse_size(self.options.swapsize)
189 optsize = parse_size(self.options.optsize)
190 if hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE:
191 tmpfile = util.tmpfile(keep=False)
192 hypervisor.add_filesystem(filename=tmpfile, size='%dM' % rootsize, type='ext3', mntpnt='/')
193 tmpfile = util.tmpfile(keep=False)
194 hypervisor.add_filesystem(filename=tmpfile, size='%dM' % swapsize, type='swap', mntpnt=None)
195 if optsize > 0:
196 tmpfile = util.tmpfile(keep=False)
197 hypervisor.add_filesystem(filename=tmpfile, size='%dM' % optsize, type='ext3', mntpnt='/opt')
198 else:
199 if self.options.raw:
200 disk = hypervisor.add_disk(filename=self.options.raw)
201 else:
202 size = rootsize + swapsize + optsize
203 tmpfile = util.tmpfile(keep=False)
204 disk = hypervisor.add_disk(tmpfile, size='%dM' % size)
205 offset = 0
206 disk.add_part(offset, rootsize, default_filesystem, '/')
207 offset += rootsize
208 disk.add_part(offset, swapsize, 'swap', 'swap')
209 offset += swapsize
210 if optsize > 0:
211 disk.add_part(offset, optsize, default_filesystem, '/opt')
212 else:
213
214 if hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE:
215 try:
216 for line in file(self.options.part):
217 elements = line.strip().split(' ')
218 if elements[0] == 'root':
219 hypervisor.add_filesystem(elements[1], default_filesystem, mntpnt='/')
220 elif elements[0] == 'swap':
221 hypervisor.add_filesystem(elements[1], type='swap', mntpnt=None)
222 elif elements[0] == '---':
223
224 pass
225 elif len(elements) == 3:
226 hypervisor.add_filesystem(elements[1], type=default_filesystem, mntpnt=elements[0], devletter='', device=elements[2], dummy=(int(elements[1]) == 0))
227 else:
228 hypervisor.add_filesystem(elements[1], type=default_filesystem, mntpnt=elements[0])
229
230 except IOError, (errno, strerror):
231 self.optparser.error("%s parsing --part option: %s" % (errno, strerror))
232 else:
233 try:
234 curdisk = list()
235 size = 0
236 for line in file(self.options.part):
237 pair = line.strip().split(' ',1)
238 if pair[0] == '---':
239 self.do_disk(hypervisor, curdisk, size)
240 curdisk = list()
241 size = 0
242 elif pair[0] != '':
243 logging.debug("part: %s, size: %d" % (pair[0], int(pair[1])))
244 curdisk.append((pair[0], pair[1]))
245 size += int(pair[1])
246
247 self.do_disk(hypervisor, curdisk, size)
248
249 except IOError, (errno, strerror):
250 hypervisor.optparser.error("%s parsing --part option: %s" % (errno, strerror))
251
252 - def do_disk(self, hypervisor, curdisk, size):
253 default_filesystem = hypervisor.distro.preferred_filesystem()
254 disk = hypervisor.add_disk(util.tmpfile(keep=False), size+1)
255 logging.debug("do_disk - size: %d" % size)
256 offset = 0
257 for pair in curdisk:
258 logging.debug("do_disk - part: %s, size: %s, offset: %d" % (pair[0], pair[1], offset))
259 if pair[0] == 'root':
260 disk.add_part(offset, int(pair[1]), default_filesystem, '/')
261 elif pair[0] == 'swap':
262 disk.add_part(offset, int(pair[1]), pair[0], pair[0])
263 else:
264 disk.add_part(offset, int(pair[1]), default_filesystem, pair[0])
265 offset += int(pair[1])
266
268 arg = 'ubuntu-vm-builder'
269
271 optparser.set_usage('%prog hypervisor suite [options]')
272
273
276
284