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 chroot_dir = None 104 if self.options.existing_chroot: 105 distro.set_chroot_dir(self.options.existing_chroot) 106 distro.call_hooks('preflight_check') 107 else: 108 chroot_dir = util.tmpdir() 109 distro.set_chroot_dir(chroot_dir) 110 distro.build_chroot() 111 112 if self.options.only_chroot: 113 print 'Chroot can be found in %s' % distro.chroot_dir 114 sys.exit(0) 115 116 self.set_disk_layout(hypervisor) 117 hypervisor.install_os() 118 119 os.mkdir(destdir) 120 self.fix_ownership(destdir) 121 hypervisor.finalise(destdir) 122 # If chroot_dir is not None, it means we created it, 123 # and if we reach here, it means the user didn't pass 124 # --only-chroot. Hence, we need to remove it to clean 125 # up after ourselves. 126 if chroot_dir: 127 util.run_cmd('rm', '-rf', '--one-file-system', chroot_dir) 128 except VMBuilderException, e: 129 logging.error(e) 130 raise 131 sys.exit(1)
132
133 - def fix_ownership(self, filename):
134 """ 135 Change ownership of file to $SUDO_USER. 136 137 @type path: string 138 @param path: file or directory to give to $SUDO_USER 139 """ 140 if 'SUDO_USER' in os.environ: 141 logging.debug('Changing ownership of %s to %s' % (filename, os.environ['SUDO_USER'])) 142 (uid, gid) = pwd.getpwnam(os.environ['SUDO_USER'])[2:4] 143 os.chown(filename, uid, gid)
144
145 - def add_settings_from_context(self, optparser, context):
146 setting_groups = set([setting.setting_group for setting in context._config.values()]) 147 for setting_group in setting_groups: 148 optgroup = optparse.OptionGroup(optparser, setting_group.name) 149 for setting in setting_group._settings: 150 args = ['--%s' % setting.name] 151 args += setting.extra_args 152 kwargs = {} 153 if setting.help: 154 kwargs['help'] = setting.help 155 if len(setting.extra_args) > 0: 156 setting.help += " Config option: %s" % setting.name 157 if setting.metavar: 158 kwargs['metavar'] = setting.metavar 159 if setting.get_default(): 160 kwargs['default'] = setting.get_default() 161 if type(setting) == VMBuilder.plugins.Plugin.BooleanSetting: 162 kwargs['action'] = 'store_true' 163 if type(setting) == VMBuilder.plugins.Plugin.ListSetting: 164 kwargs['action'] = 'append' 165 optgroup.add_option(*args, **kwargs) 166 optparser.add_option_group(optgroup)
167
168 - def versioninfo(self, option, opt, value, parser):
169 print '%(major)d.%(minor)d.%(micro)s.r%(revno)d' % VMBuilder.get_version_info() 170 sys.exit(0)
171
172 - def set_usage(self, optparser):
173 optparser.set_usage('%prog hypervisor distro [options]')
174 # optparser.arg_help = (('hypervisor', vm.hypervisor_help), ('distro', vm.distro_help)) 175
176 - def handle_args(self, optparser, args):
177 if len(args) < 2: 178 optparser.error("You need to specify at least the hypervisor type and the distro") 179 distro = VMBuilder.get_distro(args[1])() 180 hypervisor = VMBuilder.get_hypervisor(args[0])(distro) 181 return hypervisor, distro
182
183 - def set_verbosity(self, option, opt_str, value, parser):
184 if opt_str == '--debug': 185 VMBuilder.set_console_loglevel(logging.DEBUG) 186 elif opt_str == '--verbose': 187 VMBuilder.set_console_loglevel(logging.INFO) 188 elif opt_str == '--quiet': 189 VMBuilder.set_console_loglevel(logging.CRITICAL)
190
191 - def set_disk_layout(self, hypervisor):
192 default_filesystem = hypervisor.distro.preferred_filesystem() 193 if not self.options.part: 194 rootsize = parse_size(self.options.rootsize) 195 swapsize = parse_size(self.options.swapsize) 196 optsize = parse_size(self.options.optsize) 197 if hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE: 198 tmpfile = util.tmpfile(keep=False) 199 hypervisor.add_filesystem(filename=tmpfile, size='%dM' % rootsize, type='ext3', mntpnt='/') 200 tmpfile = util.tmpfile(keep=False) 201 hypervisor.add_filesystem(filename=tmpfile, size='%dM' % swapsize, type='swap', mntpnt=None) 202 if optsize > 0: 203 tmpfile = util.tmpfile(keep=False) 204 hypervisor.add_filesystem(filename=tmpfile, size='%dM' % optsize, type='ext3', mntpnt='/opt') 205 else: 206 if self.options.raw: 207 disk = hypervisor.add_disk(filename=self.options.raw) 208 else: 209 size = rootsize + swapsize + optsize 210 tmpfile = util.tmpfile(keep=False) 211 disk = hypervisor.add_disk(tmpfile, size='%dM' % size) 212 offset = 0 213 disk.add_part(offset, rootsize, default_filesystem, '/') 214 offset += rootsize 215 disk.add_part(offset, swapsize, 'swap', 'swap') 216 offset += swapsize 217 if optsize > 0: 218 disk.add_part(offset, optsize, default_filesystem, '/opt') 219 else: 220 # We need to parse the file specified 221 if hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE: 222 try: 223 for line in file(self.options.part): 224 elements = line.strip().split(' ') 225 tmpfile = util.tmpfile(keep=False) 226 if elements[0] == 'root': 227 hypervisor.add_filesystem(elements[1], default_filesystem, filename=tmpfile, mntpnt='/') 228 elif elements[0] == 'swap': 229 hypervisor.add_filesystem(elements[1], type='swap', filename=tmpfile, mntpnt=None) 230 elif elements[0] == '---': 231 # We just ignore the user's attempt to specify multiple disks 232 pass 233 elif len(elements) == 3: 234 hypervisor.add_filesystem(elements[1], type=default_filesystem, filename=tmpfile, mntpnt=elements[0], devletter='', device=elements[2], dummy=(int(elements[1]) == 0)) 235 else: 236 hypervisor.add_filesystem(elements[1], type=default_filesystem, filename=tmpfile, mntpnt=elements[0]) 237 238 except IOError, (errno, strerror): 239 self.optparser.error("%s parsing --part option: %s" % (errno, strerror)) 240 else: 241 try: 242 curdisk = list() 243 size = 0 244 for line in file(self.options.part): 245 pair = line.strip().split(' ',1) 246 if pair[0] == '---': 247 self.do_disk(hypervisor, curdisk, size) 248 curdisk = list() 249 size = 0 250 elif pair[0] != '': 251 logging.debug("part: %s, size: %d" % (pair[0], int(pair[1]))) 252 curdisk.append((pair[0], pair[1])) 253 size += int(pair[1]) 254 255 self.do_disk(hypervisor, curdisk, size) 256 257 except IOError, (errno, strerror): 258 hypervisor.optparser.error("%s parsing --part option: %s" % (errno, strerror))
259
260 - def do_disk(self, hypervisor, curdisk, size):
261 default_filesystem = hypervisor.distro.preferred_filesystem() 262 disk = hypervisor.add_disk(util.tmpfile(keep=False), size+1) 263 logging.debug("do_disk - size: %d" % size) 264 offset = 0 265 for pair in curdisk: 266 logging.debug("do_disk - part: %s, size: %s, offset: %d" % (pair[0], pair[1], offset)) 267 if pair[0] == 'root': 268 disk.add_part(offset, int(pair[1]), default_filesystem, '/') 269 elif pair[0] == 'swap': 270 disk.add_part(offset, int(pair[1]), pair[0], pair[0]) 271 else: 272 disk.add_part(offset, int(pair[1]), default_filesystem, pair[0]) 273 offset += int(pair[1])
274
275 -class UVB(CLI):
276 arg = 'ubuntu-vm-builder' 277
278 - def set_usage(self, optparser):
279 optparser.set_usage('%prog hypervisor suite [options]')
280 # optparser.arg_help = (('hypervisor', vm.hypervisor_help), ('suite', self.suite_help)) 281
282 - def suite_help(self):
283 return 'Suite. Valid options: %s' % " ".join(VMBuilder.plugins.ubuntu.distro.Ubuntu.suites)
284
285 - def handle_args(self, optparser, args):
286 if len(args) < 2: 287 optparser.error("You need to specify at least the hypervisor type and the series") 288 distro = VMBuilder.get_distro('ubuntu')() 289 hypervisor = VMBuilder.get_hypervisor(args[0])(distro) 290 distro.set_setting('suite', args[1]) 291 return hypervisor, distro
292