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

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