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 tempfile
26 import VMBuilder
27 import VMBuilder.util as util
28 from VMBuilder.disk import parse_size
29 import VMBuilder.hypervisor
30 from VMBuilder.exception import VMBuilderUserError, VMBuilderException
31
33 arg = 'cli'
34
36 tmpfs_mount_point = None
37 try:
38 optparser = optparse.OptionParser()
39
40 self.set_usage(optparser)
41
42 optparser.add_option('--version', action='callback', callback=self.versioninfo, help='Show version information')
43
44 group = optparse.OptionGroup(optparser, 'Build options')
45 group.add_option('--debug', action='callback', callback=self.set_verbosity, help='Show debug information')
46 group.add_option('--verbose', '-v', action='callback', callback=self.set_verbosity, help='Show progress information')
47 group.add_option('--quiet', '-q', action='callback', callback=self.set_verbosity, help='Silent operation')
48 group.add_option('--overwrite', '-o', action='store_true', help='Configuration file')
49 group.add_option('--config', '-c', type='str', help='Configuration file')
50 group.add_option('--templates', metavar='DIR', help='Prepend DIR to template search path.')
51 group.add_option('--destdir', '-d', type='str', help='Destination directory')
52 group.add_option('--only-chroot', action='store_true', help="Only build the chroot. Don't install it on disk images or anything.")
53 group.add_option('--existing-chroot', help="Use existing chroot.")
54 group.add_option('--tmp',
55 '-t',
56 metavar='DIR',
57 dest='tmp_root',
58 default=tempfile.gettempdir(),
59 help=('Use TMP as temporary working space for '
60 'image generation. Defaults to $TMPDIR if '
61 'it is defined or /tmp otherwise. '
62 '[default: %default]'))
63 group.add_option('--tmpfs',
64 metavar="SIZE",
65 help=('Use a tmpfs as the working directory, '
66 'specifying its size or "-" to use tmpfs '
67 'default (suid,dev,size=1G).'))
68
69 optparser.add_option_group(group)
70
71 group = optparse.OptionGroup(optparser, 'Disk')
72 group.add_option('--rootsize', metavar='SIZE', default=4096, help='Size (in MB) of the root filesystem [default: %default]')
73 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.')
74 group.add_option('--swapsize', metavar='SIZE', default=1024, help='Size (in MB) of the swap partition [default: %default]')
75 group.add_option('--raw', metavar='PATH', type='str', help="Specify a file (or block device) to as first disk image.")
76 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")
77 optparser.add_option_group(group)
78
79 hypervisor, distro = self.handle_args(optparser, sys.argv[1:])
80
81 self.add_settings_from_context(optparser, distro)
82 self.add_settings_from_context(optparser, hypervisor)
83
84 hypervisor.register_hook('fix_ownership', self.fix_ownership)
85
86 config_files = ['/etc/vmbuilder.cfg', os.path.expanduser('~/.vmbuilder.cfg')]
87 (self.options, args) = optparser.parse_args(sys.argv[2:])
88
89 if os.geteuid() != 0:
90 raise VMBuilderUserError('Must run as root')
91
92 destdir = self.options.destdir or ('%s-%s' % (distro.arg, hypervisor.arg))
93 if os.path.exists(destdir):
94 if self.options.overwrite:
95 logging.debug('%s existed, but -o was specified. Nuking it.' % destdir)
96 shutil.rmtree(destdir)
97 else:
98 raise VMBuilderUserError('%s already exists' % destdir)
99
100 if self.options.config:
101 config_files.append(self.options.config)
102 util.apply_config_files_to_context(config_files, distro)
103 util.apply_config_files_to_context(config_files, hypervisor)
104
105 if self.options.templates:
106 distro.template_dirs.insert(0,'%s/%%s' % self.options.templates)
107 hypervisor.template_dirs.insert(0,'%s/%%s' % self.options.templates)
108
109 for option in dir(self.options):
110 if option.startswith('_') or option in ['ensure_value', 'read_module', 'read_file']:
111 continue
112 val = getattr(self.options, option)
113 option = option.replace('_', '-')
114 if val:
115 if distro.has_setting(option) and distro.get_setting_default(option) != val:
116 distro.set_setting_fuzzy(option, val)
117 elif hypervisor.has_setting(option) and hypervisor.get_setting_default(option) != val:
118 hypervisor.set_setting_fuzzy(option, val)
119
120 chroot_dir = None
121 if self.options.existing_chroot:
122 distro.set_chroot_dir(self.options.existing_chroot)
123 distro.call_hooks('preflight_check')
124 else:
125 if self.options.tmpfs is not None:
126 if str(self.options.tmpfs) == '-':
127 tmpfs_size = 1024
128 else:
129 tmpfs_size = int(self.options.tmpfs)
130 tmpfs_mount_point = util.set_up_tmpfs(
131 tmp_root=self.options.tmp_root, size=tmpfs_size)
132 chroot_dir = tmpfs_mount_point
133 else:
134 chroot_dir = util.tmpdir(tmp_root=self.options.tmp_root)
135
136 distro.set_chroot_dir(chroot_dir)
137 distro.build_chroot()
138
139 if self.options.only_chroot:
140 print 'Chroot can be found in %s' % distro.chroot_dir
141 sys.exit(0)
142
143 self.set_disk_layout(hypervisor)
144 hypervisor.install_os()
145
146 os.mkdir(destdir)
147 self.fix_ownership(destdir)
148 hypervisor.finalise(destdir)
149
150
151
152
153 if chroot_dir is not None and tmpfs_mount_point is None:
154 util.run_cmd('rm', '-rf', '--one-file-system', chroot_dir)
155 except VMBuilderException, e:
156 logging.error(e)
157 raise
158 finally:
159 if tmpfs_mount_point is not None:
160 util.clean_up_tmpfs(tmpfs_mount_point)
161 util.run_cmd('rmdir', tmpfs_mount_point)
162
164 """
165 Change ownership of file to $SUDO_USER.
166
167 @type path: string
168 @param path: file or directory to give to $SUDO_USER
169 """
170 if 'SUDO_USER' in os.environ:
171 logging.debug('Changing ownership of %s to %s' % (filename, os.environ['SUDO_USER']))
172 (uid, gid) = pwd.getpwnam(os.environ['SUDO_USER'])[2:4]
173 os.chown(filename, uid, gid)
174
175 - def add_settings_from_context(self, optparser, context):
176 setting_groups = set([setting.setting_group for setting in context._config.values()])
177 for setting_group in setting_groups:
178 optgroup = optparse.OptionGroup(optparser, setting_group.name)
179 for setting in setting_group._settings:
180 args = ['--%s' % setting.name]
181 args += setting.extra_args
182 kwargs = {}
183 if setting.help:
184 kwargs['help'] = setting.help
185 if len(setting.extra_args) > 0:
186 setting.help += " Config option: %s" % setting.name
187 if setting.metavar:
188 kwargs['metavar'] = setting.metavar
189 if setting.get_default():
190 kwargs['default'] = setting.get_default()
191 if type(setting) == VMBuilder.plugins.Plugin.BooleanSetting:
192 kwargs['action'] = 'store_true'
193 if type(setting) == VMBuilder.plugins.Plugin.ListSetting:
194 kwargs['action'] = 'append'
195 optgroup.add_option(*args, **kwargs)
196 optparser.add_option_group(optgroup)
197
201
203 optparser.set_usage('%prog hypervisor distro [options]')
204
205
212
220
222 default_filesystem = hypervisor.distro.preferred_filesystem()
223 if not self.options.part:
224 rootsize = parse_size(self.options.rootsize)
225 swapsize = parse_size(self.options.swapsize)
226 optsize = parse_size(self.options.optsize)
227 if hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE:
228 tmpfile = util.tmp_filename(tmp_root=self.options.tmp_root)
229 hypervisor.add_filesystem(filename=tmpfile,
230 size='%dM' % rootsize,
231 type='ext3',
232 mntpnt='/')
233 if swapsize > 0:
234 tmpfile = util.tmp_filename(tmp_root=self.options.tmp_root)
235 hypervisor.add_filesystem(filename=tmpfile,
236 size='%dM' % swapsize,
237 type='swap',
238 mntpnt=None)
239 if optsize > 0:
240 tmpfile = util.tmp_filename(tmp_root=self.options.tmp_root)
241 hypervisor.add_filesystem(filename=tmpfile,
242 size='%dM' % optsize,
243 type='ext3',
244 mntpnt='/opt')
245 else:
246 if self.options.raw:
247 for raw_disk in self.options.raw:
248 hypervisor.add_disk(filename=raw_disk)
249 disk = hypervisor.disks[0]
250 else:
251 size = rootsize + swapsize + optsize
252 tmpfile = util.tmp_filename(tmp_root=self.options.tmp_root)
253 disk = hypervisor.add_disk(tmpfile, size='%dM' % size)
254 offset = 0
255 disk.add_part(offset, rootsize, default_filesystem, '/')
256 offset += rootsize
257 if swapsize > 0:
258 disk.add_part(offset, swapsize, 'swap', 'swap')
259 offset += swapsize
260 if optsize > 0:
261 disk.add_part(offset, optsize, default_filesystem, '/opt')
262 else:
263
264 if hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE:
265 try:
266 for line in file(self.options.part):
267 elements = line.strip().split(' ')
268 tmpfile = util.tmp_filename(
269 tmp_root=self.options.tmp_root)
270 if elements[0] == 'root':
271 hypervisor.add_filesystem(elements[1], default_filesystem, filename=tmpfile, mntpnt='/')
272 elif elements[0] == 'swap':
273 hypervisor.add_filesystem(elements[1], type='swap', filename=tmpfile, mntpnt=None)
274 elif elements[0] == '---':
275
276 pass
277 elif len(elements) == 3:
278 hypervisor.add_filesystem(elements[1], type=default_filesystem, filename=tmpfile, mntpnt=elements[0], devletter='', device=elements[2], dummy=(int(elements[1]) == 0))
279 else:
280 hypervisor.add_filesystem(elements[1], type=default_filesystem, filename=tmpfile, mntpnt=elements[0])
281
282 except IOError, (errno, strerror):
283 self.optparser.error("%s parsing --part option: %s" % (errno, strerror))
284 else:
285 try:
286 curdisk = list()
287 size = 0
288 for line in file(self.options.part):
289 pair = line.strip().split(' ',1)
290 if pair[0] == '---':
291 self.do_disk(hypervisor, curdisk, size)
292 curdisk = list()
293 size = 0
294 elif pair[0] != '':
295 logging.debug("part: %s, size: %d" % (pair[0], int(pair[1])))
296 curdisk.append((pair[0], pair[1]))
297 size += int(pair[1])
298
299 self.do_disk(hypervisor, curdisk, size)
300
301 except IOError, (errno, strerror):
302 hypervisor.optparser.error("%s parsing --part option: %s" % (errno, strerror))
303
304 - def do_disk(self, hypervisor, curdisk, size):
305 default_filesystem = hypervisor.distro.preferred_filesystem()
306 disk = hypervisor.add_disk(util.tmpfile(keep=False), size+1)
307 if self.options.raw:
308 disk = hypervisor.add_disk(filename=self.options.raw[disk_idx])
309 else:
310 disk = hypervisor.add_disk(
311 util.tmp_filename(tmp_root=self.options.tmp_root),
312 size+1)
313 logging.debug("do_disk - size: %d" % size)
314 offset = 0
315 for pair in curdisk:
316 logging.debug("do_disk - part: %s, size: %s, offset: %d" % (pair[0], pair[1], offset))
317 if pair[0] == 'root':
318 disk.add_part(offset, int(pair[1]), default_filesystem, '/')
319 elif pair[0] == 'swap':
320 disk.add_part(offset, int(pair[1]), pair[0], pair[0])
321 else:
322 disk.add_part(offset, int(pair[1]), default_filesystem, pair[0])
323 offset += int(pair[1])
324
326 arg = 'ubuntu-vm-builder'
327
329 optparser.set_usage('%prog hypervisor suite [options]')
330
331
334
342