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