~ubuntu-branches/ubuntu/maverick/vm-builder/maverick-updates

« back to all changes in this revision

Viewing changes to VMBuilder/plugins/ubuntu/distro.py

  • Committer: Bazaar Package Importer
  • Author(s): Soren Hansen
  • Date: 2010-02-22 13:56:18 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20100222135618-la13e3mu397rg0m1
Tags: 0.12.0-0ubuntu1
* New upstream release. (FFe: LP: #525741)
  - All patches incorporated upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#
2
2
#    Uncomplicated VM Builder
3
 
#    Copyright (C) 2007-2009 Canonical Ltd.
4
 
#    
 
3
#    Copyright (C) 2007-2010 Canonical Ltd.
 
4
#
5
5
#    See AUTHORS for list of contributors
6
6
#
7
7
#    This program is free software: you can redistribute it and/or modify
29
29
class Ubuntu(Distro):
30
30
    name = 'Ubuntu'
31
31
    arg = 'ubuntu'
32
 
    suites = ['dapper', 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic']
 
32
    suites = ['dapper', 'gutsy', 'hardy', 'intrepid', 'jaunty', 'karmic', 'lucid']
33
33
    
34
34
    # Maps host arch to valid guest archs
35
35
    valid_archs = { 'amd64' : ['amd64', 'i386', 'lpia' ],
39
39
    xen_kernel = ''
40
40
 
41
41
    def register_options(self):
42
 
        group = self.vm.setting_group('Package options')
43
 
        group.add_option('--addpkg', action='append', metavar='PKG', help='Install PKG into the guest (can be specfied multiple times).')
44
 
        group.add_option('--removepkg', action='append', metavar='PKG', help='Remove PKG from the guest (can be specfied multiple times)')
45
 
        self.vm.register_setting_group(group)
 
42
        group = self.setting_group('Package options')
 
43
        group.add_setting('addpkg', type='list', metavar='PKG', help='Install PKG into the guest (can be specfied multiple times).')
 
44
        group.add_setting('removepkg', type='list', metavar='PKG', help='Remove PKG from the guest (can be specfied multiple times)')
46
45
 
47
 
        group = self.vm.setting_group('General OS options')
 
46
        group = self.setting_group('General OS options')
48
47
        self.host_arch = run_cmd('dpkg', '--print-architecture').rstrip()
49
 
        group.add_option('-a', '--arch', default=self.host_arch, help='Specify the target architecture.  Valid options: amd64 i386 lpia (defaults to host arch)')
50
 
        group.add_option('--hostname', default='ubuntu', help='Set NAME as the hostname of the guest. Default: ubuntu. Also uses this name as the VM name.')
51
 
        self.vm.register_setting_group(group)
52
 
 
53
 
        group = self.vm.setting_group('Installation options')
54
 
        group.add_option('--suite', default='jaunty', help='Suite to install. Valid options: %s [default: %%default]' % ' '.join(self.suites))
55
 
        group.add_option('--flavour', '--kernel-flavour', help='Kernel flavour to use. Default and valid options depend on architecture and suite')
56
 
        group.add_option('--variant', metavar='VARIANT', help='Passed to debootstrap --variant flag; use minbase, buildd, or fakechroot.')
57
 
        group.add_option('--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.')
58
 
        group.add_option('--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')
59
 
        group.add_option('--proxy', metavar='URL', help='Use proxy at URL for cached packages')
60
 
        group.add_option('--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')
61
 
        group.add_option('--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.')
62
 
        group.add_option('--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')
63
 
        group.add_option('--components', metavar='COMPS', help='A comma seperated list of distro components to include (e.g. main,universe).')
64
 
        group.add_option('--ppa', metavar='PPA', action='append', help='Add ppa belonging to PPA to the vm\'s sources.list.')
65
 
        group.add_option('--lang', metavar='LANG', default=self.get_locale(), help='Set the locale to LANG [default: %default]')
66
 
        group.add_option('--timezone', metavar='TZ', default='UTC', help='Set the timezone to TZ in the vm. [default: %default]')
67
 
        self.vm.register_setting_group(group)
68
 
 
69
 
        group = self.vm.setting_group('Settings for the initial user')
70
 
        group.add_option('--user', default='ubuntu', help='Username of initial user [default: %default]')
71
 
        group.add_option('--name', default='Ubuntu', help='Full name of initial user [default: %default]')
72
 
        group.add_option('--pass', default='ubuntu', help='Password of initial user [default: %default]')
73
 
        group.add_option('--rootpass', help='Initial root password (WARNING: this has strong security implications).')
74
 
        group.add_option('--uid', help='Initial UID value.')
75
 
        group.add_option('--gid', help='Initial GID value.')
76
 
        group.add_option('--lock-user', action='store_true', help='Lock the initial user [default %default]')
77
 
        self.vm.register_setting_group(group)
78
 
 
79
 
        group = self.vm.setting_group('Other options')
80
 
        group.add_option('--ssh-key', metavar='PATH', help='Add PATH to root\'s ~/.ssh/authorized_keys (WARNING: this has strong security implications).')
81
 
        group.add_option('--ssh-user-key', help='Add PATH to the user\'s ~/.ssh/authorized_keys.')
82
 
        group.add_option('--manifest', metavar='PATH', help='If passed, a manifest will be written to PATH')
83
 
        self.vm.register_setting_group(group)
 
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')
84
79
 
85
80
    def set_defaults(self):
86
 
        if not self.vm.mirror:
87
 
            if self.vm.arch == 'lpia':
88
 
                self.vm.mirror = 'http://ports.ubuntu.com/ubuntu-ports'
89
 
            else:
90
 
                self.vm.mirror = 'http://archive.ubuntu.com/ubuntu'
91
 
 
92
 
        if not self.vm.security_mirror:
93
 
            if self.vm.arch == 'lpia':
94
 
                self.vm.security_mirror = 'http://ports.ubuntu.com/ubuntu-ports'
95
 
            else:
96
 
                self.vm.security_mirror = 'http://security.ubuntu.com/ubuntu'
97
 
 
98
 
        if not self.vm.components:
99
 
            self.vm.components = ['main', 'restricted', 'universe']
 
81
        mirror = self.get_setting('mirror')
 
82
        security_mirror = self.get_setting('security-mirror')
 
83
        arch = self.get_setting('arch')
 
84
        components = self.get_setting('components')
 
85
 
 
86
        if not mirror:
 
87
            if arch == 'lpia':
 
88
                self.set_setting_default('mirror', 'http://ports.ubuntu.com/ubuntu-ports')
 
89
            else:
 
90
                self.set_setting_default('mirror', 'http://archive.ubuntu.com/ubuntu')
 
91
 
 
92
        if not security_mirror:
 
93
            if arch == 'lpia':
 
94
                self.set_setting_default('security-mirror', 'http://ports.ubuntu.com/ubuntu-ports')
 
95
            else:
 
96
                self.set_setting_default('security-mirror', 'http://security.ubuntu.com/ubuntu')
 
97
 
 
98
        if not components:
 
99
            self.set_setting_default('components',  ['main', 'restricted', 'universe'])
100
100
        else:
101
 
            self.vm.components = self.vm.components.split(',')
 
101
            self.set_setting_default('components',  components.split(','))
102
102
 
103
103
    def get_locale(self):
104
104
        return os.getenv('LANG')
108
108
        lead to failure, and since we can check them before we start setting up disk
109
109
        and whatnot, we might as well go ahead an do this now."""
110
110
 
111
 
        if not self.vm.suite in self.suites:
112
 
            raise VMBuilderUserError('Invalid suite. Valid suites are: %s' % ' '.join(self.suites))
 
111
        suite = self.get_setting('suite') 
 
112
        if not suite in self.suites:
 
113
            raise VMBuilderUserError('Invalid suite: "%s". Valid suites are: %s' % (suite, ' '.join(self.suites)))
113
114
        
114
 
        modname = 'VMBuilder.plugins.ubuntu.%s' % (self.vm.suite, )
115
 
        mod = __import__(modname, fromlist=[self.vm.suite])
116
 
        self.suite = getattr(mod, self.vm.suite.capitalize())(self.vm)
 
115
        modname = 'VMBuilder.plugins.ubuntu.%s' % (suite, )
 
116
        mod = __import__(modname, fromlist=[suite])
 
117
        self.suite = getattr(mod, suite.capitalize())(self)
117
118
 
118
 
        if self.vm.arch not in self.valid_archs[self.host_arch] or  \
119
 
            not self.suite.check_arch_validity(self.vm.arch):
120
 
            raise VMBuilderUserError('%s is not a valid architecture. Valid architectures are: %s' % (self.vm.arch, 
 
119
        arch = self.get_setting('arch') 
 
120
        if arch not in self.valid_archs[self.host_arch] or  \
 
121
            not self.suite.check_arch_validity(arch):
 
122
            raise VMBuilderUserError('%s is not a valid architecture. Valid architectures are: %s' % (arch,
121
123
                                                                                                      ' '.join(self.valid_archs[self.host_arch])))
122
124
 
123
 
        if not self.vm.components:
124
 
            self.vm.components = ['main', 'restricted', 'universe']
 
125
        components = self.get_setting('components')
 
126
        if not components:
 
127
            self.set_config_value_list = ['main', 'restricted', 'universe']
125
128
        else:
126
 
            if type(self.vm.components) is str:
 
129
            if type(components) is str:
127
130
                self.vm.components = self.vm.components.split(',')
128
131
 
129
 
        if self.vm.hypervisor.name == 'Xen':
130
 
            logging.info('Xen kernel default: linux-image-%s %s', self.suite.xen_kernel_flavour, self.xen_kernel_version())
131
 
 
132
 
        self.vm.virtio_net = self.use_virtio_net()
133
 
 
134
 
        if self.vm.lang:
 
132
        self.context.virtio_net = self.use_virtio_net()
 
133
 
 
134
        lang = self.get_setting('lang')
 
135
        if lang:
135
136
            try:
136
 
                run_cmd('locale-gen', '%s' % self.vm.lang)
 
137
                run_cmd('locale-gen', '%s' % lang)
137
138
            except VMBuilderException, e:
138
 
                msg = "locale-gen does not recognize your locale '%s'" % self.vm.lang
139
 
                raise VMBuilderUserError(msg)
140
 
 
141
 
        if getattr(self.vm, 'ec2', False):
142
 
            self.get_ec2_kernel()
143
 
            self.get_ec2_ramdisk()
144
 
            self.apply_ec2_settings()
 
139
                raise VMBuilderUserError("Unrecognised locale: '%s'" % (lang, ))
 
140
 
 
141
# FIXME
 
142
#        if getattr(self.vm, 'ec2', False):
 
143
#            self.get_ec2_kernel()
 
144
#            self.get_ec2_ramdisk()
 
145
#            self.apply_ec2_settings()
 
146
 
 
147
    def bootstrap(self):
 
148
        self.suite.debootstrap()
 
149
        self.suite.pre_install()
 
150
 
 
151
    def configure_os(self):
 
152
        self.suite.install_sources_list()
 
153
        self.suite.install_apt_proxy()
 
154
        self.suite.create_devices()
 
155
        self.suite.prevent_daemons_starting()
 
156
        self.suite.mount_dev_proc()
 
157
        self.suite.install_extras()
 
158
        self.suite.create_initial_user()
 
159
        self.suite.install_authorized_keys()
 
160
        self.suite.config_host_and_domainname()
 
161
        self.suite.set_timezone()
 
162
        self.suite.update()
 
163
        self.suite.install_sources_list(final=True)
 
164
        self.suite.run_in_target('apt-get', 'clean');
 
165
        self.suite.unmount_volatile()
 
166
        self.suite.unmount_proc()
 
167
        self.suite.unmount_dev_pts()
 
168
        self.suite.unmount_dev()
 
169
        self.suite.unprevent_daemons_starting()
 
170
        self.suite.create_manifest()
 
171
 
 
172
    def configure_networking(self, nics):
 
173
        self.suite.config_interfaces(nics)
 
174
 
 
175
    def configure_mounting(self, disks, filesystems):
 
176
        self.suite.install_fstab(disks, filesystems)
145
177
 
146
178
    def install(self, destdir):
147
179
        self.destdir = destdir
156
188
    def use_virtio_net(self):
157
189
        return self.suite.virtio_net
158
190
 
159
 
    def install_bootloader_cleanup(self):
160
 
        self.vm.cancel_cleanup(self.install_bootloader_cleanup)
161
 
        tmpdir = '%s/tmp/vmbuilder-grub' % self.destdir
 
191
    def install_bootloader_cleanup(self, chroot_dir):
 
192
        self.context.cancel_cleanup(self.install_bootloader_cleanup)
 
193
        tmpdir = '%s/tmp/vmbuilder-grub' % chroot_dir
162
194
        for disk in os.listdir(tmpdir):
163
195
            if disk != 'device.map':
164
196
                run_cmd('umount', os.path.join(tmpdir, disk))
165
197
        shutil.rmtree(tmpdir)
166
198
 
167
 
    def install_bootloader(self):
 
199
    def install_kernel(self, destdir):
 
200
        self.suite.install_kernel(destdir)
 
201
 
 
202
    def install_bootloader(self, chroot_dir, disks):
168
203
        tmpdir = '/tmp/vmbuilder-grub'
169
 
        os.makedirs('%s%s' % (self.destdir, tmpdir))
170
 
        self.vm.add_clean_cb(self.install_bootloader_cleanup)
 
204
        os.makedirs('%s%s' % (chroot_dir, tmpdir))
 
205
        self.context.add_clean_cb(self.install_bootloader_cleanup)
171
206
        devmapfile = os.path.join(tmpdir, 'device.map')
172
 
        devmap = open('%s%s' % (self.destdir, devmapfile), 'w')
173
 
        for (disk, id) in zip(self.vm.disks, range(len(self.vm.disks))):
 
207
        devmap = open('%s%s' % (chroot_dir, devmapfile), 'w')
 
208
        for (disk, id) in zip(disks, range(len(disks))):
174
209
            new_filename = os.path.join(tmpdir, os.path.basename(disk.filename))
175
 
            open('%s%s' % (self.destdir, new_filename), 'w').close()
176
 
            run_cmd('mount', '--bind', disk.filename, '%s%s' % (self.destdir, new_filename))
 
210
            open('%s%s' % (chroot_dir, new_filename), 'w').close()
 
211
            run_cmd('mount', '--bind', disk.filename, '%s%s' % (chroot_dir, new_filename))
177
212
            devmap.write("(hd%d) %s\n" % (id, new_filename))
178
213
        devmap.close()
 
214
        self.suite.install_grub(chroot_dir)
179
215
        self.run_in_target('grub', '--device-map=%s' % devmapfile, '--batch',  stdin='''root (hd0,0)
180
216
setup (hd0)
181
 
EOT''')
182
 
        self.install_bootloader_cleanup()
 
217
EOT''') 
 
218
        self.suite.install_menu_lst(disks)
 
219
        self.install_bootloader_cleanup(chroot_dir)
183
220
 
184
221
    def xen_kernel_version(self):
185
222
        if self.suite.xen_kernel_flavour:
 
223
            # if this is ec2, do not call rmadison.
 
224
            # this could be replaced with a method to get most recent
 
225
            # stable kernel, but really, this is not used at all for ec2
 
226
            if hasattr(self.vm, 'ec2') and self.context.ec2:
 
227
                logging.debug("selecting ec2 kernel")
 
228
                self.xen_kernel = "2.6.ec2-kernel"
 
229
                return self.xen_kernel
186
230
            if not self.xen_kernel:
187
231
                rmad = run_cmd('rmadison', 'linux-image-%s' % self.suite.xen_kernel_flavour)
188
232
                version = ['0', '0','0', '0']
190
234
                for line in rmad.splitlines():
191
235
                    sline = line.split('|')
192
236
                    
193
 
                    if sline[2].strip().startswith(self.vm.suite):
 
237
                    if sline[2].strip().startswith(self.context.suite):
194
238
                        vt = sline[1].strip().split('.')
195
239
                        for i in range(4):
196
240
                            if int(vt[i]) > int(version[i]):
198
242
                                break
199
243
 
200
244
                if version[0] == '0':
201
 
                    raise VMBuilderException('Something is wrong, no valid xen kernel for the suite %s found by rmadison' % self.vm.suite)
 
245
                    raise VMBuilderException('Something is wrong, no valid xen kernel for the suite %s found by rmadison' % self.context.suite)
202
246
                
203
247
                self.xen_kernel = '%s.%s.%s-%s' % (version[0],version[1],version[2],version[3])
204
248
            return self.xen_kernel
217
261
 
218
262
    def get_ec2_kernel(self):
219
263
        if self.suite.ec2_kernel_info:
220
 
            return self.suite.ec2_kernel_info[self.vm.arch]
 
264
            return self.suite.ec2_kernel_info[self.context.arch]
221
265
        else:
222
266
            raise VMBuilderUserError('EC2 is not supported for the suite selected')
223
267
 
224
268
    def get_ec2_ramdisk(self):
225
269
        if self.suite.ec2_ramdisk_info:
226
 
            return self.suite.ec2_ramdisk_info[self.vm.arch]
 
270
            return self.suite.ec2_ramdisk_info[self.context.arch]
227
271
        else:
228
272
            raise VMBuilderUserError('EC2 is not supported for the suite selected')
229
273
 
233
277
    def apply_ec2_settings(self):
234
278
        return self.suite.apply_ec2_settings()
235
279
 
 
280
    def has_256_bit_inode_ext3_support(self):
 
281
        return self.suite.has_256_bit_inode_ext3_support()
 
282
 
 
283
    def preferred_filesystem(self):
 
284
        return self.suite.preferred_filesystem
 
285
 
236
286
register_distro(Ubuntu)