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