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