Package VMBuilder :: Package contrib :: Module cli
[frames] | no frames]

Source Code for Module VMBuilder.contrib.cli

  1  #    Uncomplicated VM Builder 
  2  #    Copyright (C) 2007-2009 Canonical Ltd. 
  3  # 
  4  #    See AUTHORS for list of contributors 
  5  # 
  6  #    This program is free software: you can redistribute it and/or modify 
  7  #    it under the terms of the GNU General Public License version 3, as 
  8  #    published by the Free Software Foundation. 
  9  # 
 10  #    This program is distributed in the hope that it will be useful, 
 11  #    but WITHOUT ANY WARRANTY; without even the implied warranty of 
 12  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  #    GNU General Public License for more details. 
 14  # 
 15  #    You should have received a copy of the GNU General Public License 
 16  #    along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 17  # 
 18  #    CLI plugin 
 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   
31 -class CLI(object):
32 arg = 'cli' 33
34 - def main(self):
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
126 - def fix_ownership(self, filename):
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
161 - def versioninfo(self, option, opt, value, parser):
162 print '%(major)d.%(minor)d.%(micro)s.r%(revno)d' % VMBuilder.get_version_info() 163 sys.exit(0)
164
165 - def set_usage(self, optparser):
166 optparser.set_usage('%prog hypervisor distro [options]')
167 # optparser.arg_help = (('hypervisor', vm.hypervisor_help), ('distro', vm.distro_help)) 168
169 - def handle_args(self, optparser, args):
170 if len(args) < 2: 171 optparser.error("You need to specify at least the hypervisor type and the distro") 172 distro = VMBuilder.get_distro(args[1])() 173 hypervisor = VMBuilder.get_hypervisor(args[0])(distro) 174 return hypervisor, distro
175
176 - def set_verbosity(self, option, opt_str, value, parser):
177 if opt_str == '--debug': 178 VMBuilder.set_console_loglevel(logging.DEBUG) 179 elif opt_str == '--verbose': 180 VMBuilder.set_console_loglevel(logging.INFO) 181 elif opt_str == '--quiet': 182 VMBuilder.set_console_loglevel(logging.CRITICAL)
183
184 - def set_disk_layout(self, hypervisor):
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 # We need to parse the file specified 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 # We just ignore the user's attempt to specify multiple disks 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
267 -class UVB(CLI):
268 arg = 'ubuntu-vm-builder' 269
270 - def set_usage(self, optparser):
271 optparser.set_usage('%prog hypervisor suite [options]')
272 # optparser.arg_help = (('hypervisor', vm.hypervisor_help), ('suite', self.suite_help)) 273
274 - def suite_help(self):
275 return 'Suite. Valid options: %s' % " ".join(VMBuilder.plugins.ubuntu.distro.Ubuntu.suites)
276
277 - def handle_args(self, optparser, args):
278 if len(args) < 2: 279 optparser.error("You need to specify at least the hypervisor type and the series") 280 distro = VMBuilder.get_distro('ubuntu')() 281 hypervisor = VMBuilder.get_hypervisor(args[0])(distro) 282 distro.set_setting('suite', args[1]) 283 return hypervisor, distro
284