Package VMBuilder :: Package plugins :: Package debian :: Module distro
[frames] | no frames]

Source Code for Module VMBuilder.plugins.debian.distro

  1  # 
  2  #    Uncomplicated VM Builder 
  3  #    Copyright (C) 2007-2010 Canonical Ltd. 
  4  # 
  5  #    See AUTHORS for list of contributors 
  6  # 
  7  #    This program is free software: you can redistribute it and/or modify 
  8  #    it under the terms of the GNU General Public License version 3, as 
  9  #    published by the Free Software Foundation. 
 10  # 
 11  #    This program is distributed in the hope that it will be useful, 
 12  #    but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 14  #    GNU General Public License for more details. 
 15  # 
 16  #    You should have received a copy of the GNU General Public License 
 17  #    along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 18  # 
 19  import logging 
 20  import os 
 21  import shutil 
 22  import stat 
 23  import VMBuilder 
 24  from   VMBuilder           import register_distro, Distro 
 25  from   VMBuilder.util      import run_cmd 
 26  from   VMBuilder.exception import VMBuilderUserError, VMBuilderException 
 27   
28 -class Debian(Distro):
29 name = 'Debian' 30 arg = 'debian' 31 suites = ['potato', 'woody', 'sarge', 'etch', 'lenny', 32 'squeeze', 'wheezy', 'jessie', 'stretch' ] 33 34 # Maps host arch to valid guest archs 35 valid_archs = { 'amd64' : ['amd64', 'i386' ], 36 'i386' : [ 'i386' ] } 37 38 xen_kernel = '' 39
40 - def register_options(self):
41 group = self.setting_group('Package options') 42 group.add_setting('addpkg', type='list', metavar='PKG', help='Install PKG into the guest (can be specified multiple times).') 43 group.add_setting('removepkg', type='list', metavar='PKG', help='Remove PKG from the guest (can be specified multiple times)') 44 group.add_setting('seedfile', metavar="SEEDFILE", help='Seed the debconf database with the contents of this seed file before installing packages') 45 46 group = self.setting_group('General OS options') 47 self.host_arch = run_cmd('dpkg', '--print-architecture').rstrip() 48 group.add_setting('arch', extra_args=['-a'], default=self.host_arch, help='Specify the target architecture. Valid options: amd64 i386 (defaults to host arch)') 49 group.add_setting('hostname', default='debian', help='Set NAME as the hostname of the guest. Default: debian. Also uses this name as the VM name.') 50 51 group = self.setting_group('Installation options') 52 group.add_setting('suite', default='jessie', help='Suite to install. Valid options: %s [default: %%default]' % ' '.join(self.suites)) 53 group.add_setting('flavour', extra_args=['--kernel-flavour'], help='Kernel flavour to use. Default and valid options depend on architecture and suite') 54 group.add_setting('variant', metavar='VARIANT', help='Passed to debootstrap --variant flag; use minbase, buildd, or fakechroot.') 55 group.add_setting('debootstrap-tarball', metavar='FILE', help='Passed to debootstrap --unpack-tarball flag.') 56 group.add_setting('iso', metavar='PATH', help='Use an iso image as the source for installation of file. Full path to the iso must be provided. If --mirror is also provided, it will be used in the final sources.list of the vm. This requires suite and kernel parameter to match what is available on the iso, obviously.') 57 group.add_setting('mirror', metavar='URL', help='Use Debian mirror at URL instead of the default, which is http://ftp.debian.org/debian for official arches and http://ports.ubuntu.com/ubuntu-ports otherwise') 58 group.add_setting('proxy', metavar='URL', help='Use proxy at URL for cached packages') 59 group.add_setting('install-mirror', metavar='URL', help='Use Debian mirror at URL for the installation only. Apt\'s sources.list will still use default or URL set by --mirror') 60 group.add_setting('security-mirror', metavar='URL', help='Use Debian security mirror at URL instead of the default, which is http://security.debian.org/debian-security.') 61 group.add_setting('install-security-mirror', metavar='URL', help='Use the security mirror at URL for installation only. Apt\'s sources.list will still use default or URL set by --security-mirror') 62 group.add_setting('components', type='list', metavar='COMPS', help='A comma seperated list of distro components to include (e.g. main,universe).') 63 group.add_setting('lang', metavar='LANG', default=get_locale(), help='Set the locale to LANG [default: %default]') 64 group.add_setting('timezone', metavar='TZ', default='UTC', help='Set the timezone to TZ in the vm. [default: %default]') 65 66 group = self.setting_group('Settings for the initial user') 67 group.add_setting('user', default='debian', help='Username of initial user [default: %default]') 68 group.add_setting('name', default='Debian', help='Full name of initial user [default: %default]') 69 group.add_setting('pass', default='debian', help='Password of initial user [default: %default]') 70 group.add_setting('rootpass', help='Initial root password (WARNING: this has strong security implications).') 71 group.add_setting('uid', type='int', help='Initial UID value.') 72 group.add_setting('gid', help='Initial GID value.') 73 group.add_setting('lock-user', type='bool', default=False, help='Lock the initial user [default: %default]') 74 75 group = self.setting_group('Other options') 76 group.add_setting('ssh-key', metavar='PATH', help='Add PATH to root\'s ~/.ssh/authorized_keys (WARNING: this has strong security implications).') 77 group.add_setting('ssh-user-key', help='Add PATH to the user\'s ~/.ssh/authorized_keys.') 78 group.add_setting('manifest', metavar='PATH', help='If passed, a manifest will be written to PATH')
79
80 - def set_defaults(self):
81 self.set_setting_default('mirror', 'http://ftp.debian.org/debian') 82 self.set_setting_default('security-mirror', 'http://security.debian.org/debian-security') 83 84 self.set_setting_default('components', ['main'])
85
86 - def preflight_check(self):
87 """While not all of these are strictly checks, their failure would inevitably 88 lead to failure, and since we can check them before we start setting up disk 89 and whatnot, we might as well go ahead an do this now.""" 90 91 suite = self.get_setting('suite') 92 if not suite in self.suites: 93 raise VMBuilderUserError('Invalid suite: "%s". Valid suites are: %s' % (suite, ' '.join(self.suites))) 94 95 modname = 'VMBuilder.plugins.debian.%s' % (suite, ) 96 mod = __import__(modname, fromlist=[suite]) 97 self.suite = getattr(mod, suite.capitalize())(self) 98 99 arch = self.get_setting('arch') 100 if arch not in self.valid_archs[self.host_arch] or \ 101 not self.suite.check_arch_validity(arch): 102 raise VMBuilderUserError('%s is not a valid architecture. Valid architectures are: %s' % (arch, 103 ' '.join(self.valid_archs[self.host_arch]))) 104 105 components = self.get_setting('components') 106 if not components: 107 self.set_config_value_list = ['main', 'contrib'] 108 else: 109 if type(components) is str: 110 self.vm.components = self.vm.components.split(',') 111 112 self.context.virtio_net = self.use_virtio_net() 113 114 # check if the seedfile exists if one is to be used 115 seedfile = self.context.get_setting('seedfile') 116 if seedfile and not os.path.exists(seedfile): 117 raise VMBuilderUserError("Seedfile '%s' does not exist" % seedfile) 118 119 lang = self.get_setting('lang')
120 121 # FIXME 122 # if getattr(self.vm, 'ec2', False): 123 # self.get_ec2_kernel() 124 # self.get_ec2_ramdisk() 125 # self.apply_ec2_settings() 126
127 - def bootstrap(self):
128 self.suite.debootstrap() 129 self.suite.pre_install()
130
131 - def configure_os(self):
132 self.suite.install_apt_proxy() 133 self.suite.install_sources_list() 134 self.suite.create_devices() 135 self.suite.prevent_daemons_starting() 136 self.suite.mount_dev_proc() 137 self.suite.install_extras() 138 self.suite.create_initial_user() 139 self.suite.install_authorized_keys() 140 self.suite.set_timezone() 141 self.suite.set_locale() 142 self.suite.update() 143 self.suite.install_sources_list(final=True) 144 self.suite.run_in_target('apt-get', 'clean'); 145 self.suite.unmount_volatile() 146 self.suite.unmount_proc() 147 self.suite.unmount_dev_pts() 148 self.suite.unmount_dev() 149 self.suite.unprevent_daemons_starting() 150 self.suite.create_manifest()
151
152 - def configure_networking(self, nics):
155
156 - def configure_mounting(self, disks, filesystems):
157 self.suite.install_fstab(disks, filesystems)
158
159 - def install(self, destdir):
160 self.destdir = destdir 161 self.suite.install(destdir)
162
163 - def install_vmbuilder_log(self, logfile, rootdir):
164 self.suite.install_vmbuilder_log(logfile, rootdir)
165
166 - def post_mount(self, fs):
167 self.suite.post_mount(fs)
168
169 - def use_virtio_net(self):
170 return self.suite.virtio_net
171
172 - def install_bootloader_cleanup(self, chroot_dir):
173 self.context.cancel_cleanup(self.install_bootloader_cleanup) 174 tmpdir = '%s/tmp/vmbuilder-grub' % chroot_dir 175 for disk in os.listdir(tmpdir): 176 if disk != 'device.map': 177 run_cmd('umount', os.path.join(tmpdir, disk)) 178 shutil.rmtree(tmpdir)
179
180 - def install_kernel(self, destdir):
181 self.suite.install_kernel(destdir)
182
183 - def install_bootloader(self, chroot_dir, disks):
184 root_dev = VMBuilder.disk.bootpart(disks).get_grub_id() 185 186 tmpdir = '/tmp/vmbuilder-grub' 187 os.makedirs('%s%s' % (chroot_dir, tmpdir)) 188 self.context.add_clean_cb(self.install_bootloader_cleanup) 189 devmapfile = os.path.join(tmpdir, 'device.map') 190 devmap = open('%s%s' % (chroot_dir, devmapfile), 'w') 191 for (disk, id) in zip(disks, range(len(disks))): 192 new_filename = os.path.join(tmpdir, os.path.basename(disk.filename)) 193 open('%s%s' % (chroot_dir, new_filename), 'w').close() 194 run_cmd('mount', '--bind', disk.filename, '%s%s' % (chroot_dir, new_filename)) 195 st = os.stat(disk.filename) 196 if stat.S_ISBLK(st.st_mode): 197 for (part, part_id) in zip(disk.partitions, range(len(disk.partitions))): 198 part_mountpnt = '%s%s%d' % (chroot_dir, new_filename, part_id+1) 199 open(part_mountpnt, 'w').close() 200 run_cmd('mount', '--bind', part.filename, part_mountpnt) 201 devmap.write("(hd%d) %s\n" % (id, new_filename)) 202 devmap.close() 203 run_cmd('cat', '%s%s' % (chroot_dir, devmapfile)) 204 self.suite.install_grub(chroot_dir) 205 self.run_in_target('grub', '--device-map=%s' % devmapfile, '--batch', stdin='''root %s 206 setup (hd0) 207 EOT''' % root_dev) 208 self.suite.install_menu_lst(disks) 209 self.install_bootloader_cleanup(chroot_dir)
210
211 - def xen_kernel_version(self):
212 if self.suite.xen_kernel_flavour: 213 # if this is ec2, do not call rmadison. 214 # this could be replaced with a method to get most recent 215 # stable kernel, but really, this is not used at all for ec2 216 if hasattr(self.context, 'ec2') and self.context.ec2: 217 logging.debug("selecting ec2 kernel") 218 self.xen_kernel = "2.6.ec2-kernel" 219 return self.xen_kernel 220 if not self.xen_kernel: 221 rmad = run_cmd('rmadison', 'linux-image-%s' % self.suite.xen_kernel_flavour) 222 version = ['0', '0','0', '0'] 223 224 for line in rmad.splitlines(): 225 sline = line.split('|') 226 227 if sline[2].strip().startswith(self.context.get_setting('suite')): 228 vt = sline[1].strip().split('.') 229 for i in range(4): 230 if int(vt[i]) > int(version[i]): 231 version = vt 232 break 233 234 if version[0] == '0': 235 raise VMBuilderException('Something is wrong, no valid xen kernel for the suite %s found by rmadison' % self.context.suite) 236 237 self.xen_kernel = '%s.%s.%s-%s' % (version[0],version[1],version[2],version[3]) 238 return self.xen_kernel 239 else: 240 raise VMBuilderUserError('There is no valid xen kernel for the suite selected.')
241
242 - def xen_kernel_initrd_path(self, which):
243 path = '/boot/%s-%s-%s' % (which, self.xen_kernel_version(), self.suite.xen_kernel_flavour) 244 return path
245
246 - def xen_kernel_path(self):
247 return self.xen_kernel_initrd_path('kernel')
248
249 - def xen_ramdisk_path(self):
250 return self.xen_kernel_initrd_path('ramdisk')
251
252 - def get_ec2_kernel(self):
253 if self.suite.ec2_kernel_info: 254 return self.suite.ec2_kernel_info[self.context.arch] 255 else: 256 raise VMBuilderUserError('EC2 is not supported for the suite selected')
257
258 - def get_ec2_ramdisk(self):
259 if self.suite.ec2_ramdisk_info: 260 return self.suite.ec2_ramdisk_info[self.context.arch] 261 else: 262 raise VMBuilderUserError('EC2 is not supported for the suite selected')
263
264 - def disable_hwclock_access(self):
265 return self.suite.disable_hwclock_access()
266
267 - def apply_ec2_settings(self):
268 return self.suite.apply_ec2_settings()
269 272
273 - def preferred_filesystem(self):
274 return self.suite.preferred_filesystem
275
276 -def get_locale():
277 lang = os.getenv('LANG') 278 if lang is None: 279 return 'C' 280 # People's $LANG looks different since lucid, but locale-gen still 281 # wants the old format. 282 if lang.endswith('utf8'): 283 return lang[:-4] + 'UTF-8' 284 return lang
285 286 register_distro(Debian) 287