~smoser/curtin/yakkety.lp1666986

« back to all changes in this revision

Viewing changes to curtin/commands/curthooks.py

  • Committer: Scott Moser
  • Date: 2016-08-05 20:47:14 UTC
  • mto: (58.1.1 pkg)
  • mto: This revision was merged to the branch mainline in revision 56.
  • Revision ID: smoser@ubuntu.com-20160805204714-f6j1k61cli5uf614
Tags: upstream-0.1.0~bzr415
ImportĀ upstreamĀ versionĀ 0.1.0~bzr415

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
#   along with Curtin.  If not, see <http://www.gnu.org/licenses/>.
17
17
 
18
18
import copy
19
 
import glob
20
19
import os
21
20
import platform
22
 
import re
23
21
import sys
24
22
import shutil
25
23
import textwrap
32
30
from curtin import util
33
31
from curtin import net
34
32
from curtin.reporter import events
 
33
from curtin.commands import apt_config
35
34
 
36
35
from . import populate_one_subcmd
37
36
 
90
89
                                         info.get('perms', "0644")))
91
90
 
92
91
 
93
 
def apt_config(cfg, target):
94
 
    # cfg['apt_proxy']
95
 
 
96
 
    proxy_cfg_path = os.path.sep.join(
97
 
        [target, '/etc/apt/apt.conf.d/90curtin-aptproxy'])
98
 
    if cfg.get('apt_proxy'):
99
 
        util.write_file(
100
 
            proxy_cfg_path,
101
 
            content='Acquire::HTTP::Proxy "%s";\n' % cfg['apt_proxy'])
 
92
def do_apt_config(cfg, target):
 
93
    cfg = apt_config.translate_old_apt_features(cfg)
 
94
    apt_cfg = cfg.get("apt")
 
95
    if apt_cfg is not None:
 
96
        LOG.info("curthooks handling apt to target %s with config %s",
 
97
                 target, apt_cfg)
 
98
        apt_config.handle_apt(apt_cfg, target)
102
99
    else:
103
 
        if os.path.isfile(proxy_cfg_path):
104
 
            os.unlink(proxy_cfg_path)
105
 
 
106
 
    # cfg['apt_mirrors']
107
 
    # apt_mirrors:
108
 
    #  ubuntu_archive: http://local.archive/ubuntu
109
 
    #  ubuntu_security: http://local.archive/ubuntu
110
 
    sources_list = os.path.sep.join([target, '/etc/apt/sources.list'])
111
 
    if (isinstance(cfg.get('apt_mirrors'), dict) and
112
 
            os.path.isfile(sources_list)):
113
 
        repls = [
114
 
            ('ubuntu_archive', r'http://\S*[.]*archive.ubuntu.com/\S*'),
115
 
            ('ubuntu_security', r'http://security.ubuntu.com/\S*'),
116
 
        ]
117
 
        content = None
118
 
        for name, regex in repls:
119
 
            mirror = cfg['apt_mirrors'].get(name)
120
 
            if not mirror:
121
 
                continue
122
 
 
123
 
            if content is None:
124
 
                with open(sources_list) as fp:
125
 
                    content = fp.read()
126
 
                util.write_file(sources_list + ".dist", content)
127
 
 
128
 
            content = re.sub(regex, mirror + " ", content)
129
 
 
130
 
        if content is not None:
131
 
            util.write_file(sources_list, content)
 
100
        LOG.info("No apt config provided, skipping")
132
101
 
133
102
 
134
103
def disable_overlayroot(cfg, target):
140
109
        shutil.move(local_conf, local_conf + ".old")
141
110
 
142
111
 
143
 
def clean_cloud_init(target):
144
 
    flist = glob.glob(
145
 
        os.path.sep.join([target, "/etc/cloud/cloud.cfg.d/*dpkg*"]))
146
 
 
147
 
    LOG.debug("cleaning cloud-init config from: %s" % flist)
148
 
    for dpkg_cfg in flist:
149
 
        os.unlink(dpkg_cfg)
150
 
 
151
 
 
152
112
def _maybe_remove_legacy_eth0(target,
153
113
                              path="/etc/network/interfaces.d/eth0.cfg"):
154
114
    """Ubuntu cloud images previously included a 'eth0.cfg' that had
232
192
def run_zipl(cfg, target):
233
193
    if platform.machine() != 's390x':
234
194
        return
235
 
    with util.RunInChroot(target) as in_chroot:
236
 
        in_chroot(['zipl'])
 
195
    with util.ChrootableTarget(target) as in_chroot:
 
196
        in_chroot.subp(['zipl'])
237
197
 
238
198
 
239
199
def install_kernel(cfg, target):
250
210
    mapping = copy.deepcopy(KERNEL_MAPPING)
251
211
    config.merge_config(mapping, kernel_cfg.get('mapping', {}))
252
212
 
253
 
    with util.RunInChroot(target) as in_chroot:
254
 
 
255
 
        if kernel_package:
256
 
            util.install_packages([kernel_package], target=target)
257
 
            return
258
 
 
259
 
        # uname[2] is kernel name (ie: 3.16.0-7-generic)
260
 
        # version gets X.Y.Z, flavor gets anything after second '-'.
261
 
        kernel = os.uname()[2]
262
 
        codename, err = in_chroot(['lsb_release', '--codename', '--short'],
263
 
                                  capture=True)
264
 
        codename = codename.strip()
265
 
        version, abi, flavor = kernel.split('-', 2)
266
 
 
267
 
        try:
268
 
            map_suffix = mapping[codename][version]
269
 
        except KeyError:
270
 
            LOG.warn("Couldn't detect kernel package to install for %s."
271
 
                     % kernel)
272
 
            if kernel_fallback is not None:
273
 
                util.install_packages([kernel_fallback], target=target)
274
 
            return
275
 
 
276
 
        package = "linux-{flavor}{map_suffix}".format(
277
 
            flavor=flavor, map_suffix=map_suffix)
278
 
 
279
 
        if util.has_pkg_available(package, target):
280
 
            if util.has_pkg_installed(package, target):
281
 
                LOG.debug("Kernel package '%s' already installed", package)
282
 
            else:
283
 
                LOG.debug("installing kernel package '%s'", package)
284
 
                util.install_packages([package], target=target)
285
 
        else:
286
 
            if kernel_fallback is not None:
287
 
                LOG.info("Kernel package '%s' not available.  "
288
 
                         "Installing fallback package '%s'.",
289
 
                         package, kernel_fallback)
290
 
                util.install_packages([kernel_fallback], target=target)
291
 
            else:
292
 
                LOG.warn("Kernel package '%s' not available and no fallback."
293
 
                         " System may not boot.", package)
294
 
 
295
 
 
296
 
def apply_debconf_selections(cfg, target):
297
 
    # debconf_selections:
298
 
    #  set1: |
299
 
    #   cloud-init cloud-init/datasources multiselect MAAS
300
 
    #  set2: pkg pkg/value string bar
301
 
    selsets = cfg.get('debconf_selections')
302
 
    if not selsets:
303
 
        LOG.debug("debconf_selections was not set in config")
304
 
        return
305
 
 
306
 
    # for each entry in selections, chroot and apply them.
307
 
    # keep a running total of packages we've seen.
308
 
    pkgs_cfgd = set()
309
 
    for key, content in selsets.items():
310
 
        LOG.debug("setting for %s, %s" % (key, content))
311
 
        util.subp(['chroot', target, 'debconf-set-selections'],
312
 
                  data=content.encode())
313
 
        for line in content.splitlines():
314
 
            if line.startswith("#"):
315
 
                continue
316
 
            pkg = re.sub(r"[:\s].*", "", line)
317
 
            pkgs_cfgd.add(pkg)
318
 
 
319
 
    pkgs_installed = get_installed_packages(target)
320
 
 
321
 
    LOG.debug("pkgs_cfgd: %s" % pkgs_cfgd)
322
 
    LOG.debug("pkgs_installed: %s" % pkgs_installed)
323
 
    need_reconfig = pkgs_cfgd.intersection(pkgs_installed)
324
 
 
325
 
    if len(need_reconfig) == 0:
326
 
        LOG.debug("no need for reconfig")
327
 
        return
328
 
 
329
 
    # For any packages that are already installed, but have preseed data
330
 
    # we populate the debconf database, but the filesystem configuration
331
 
    # would be preferred on a subsequent dpkg-reconfigure.
332
 
    # so, what we have to do is "know" information about certain packages
333
 
    # to unconfigure them.
334
 
    unhandled = []
335
 
    to_config = []
336
 
    for pkg in need_reconfig:
337
 
        if pkg in CONFIG_CLEANERS:
338
 
            LOG.debug("unconfiguring %s" % pkg)
339
 
            CONFIG_CLEANERS[pkg](target)
340
 
            to_config.append(pkg)
341
 
        else:
342
 
            unhandled.append(pkg)
343
 
 
344
 
    if len(unhandled):
345
 
        LOG.warn("The following packages were installed and preseeded, "
346
 
                 "but cannot be unconfigured: %s", unhandled)
347
 
 
348
 
    util.subp(['chroot', target, 'dpkg-reconfigure',
349
 
               '--frontend=noninteractive'] +
350
 
              list(to_config), data=None)
351
 
 
352
 
 
353
 
def get_installed_packages(target=None):
354
 
    cmd = []
355
 
    if target is not None:
356
 
        cmd = ['chroot', target]
357
 
    cmd.extend(['dpkg-query', '--list'])
358
 
 
359
 
    (out, _err) = util.subp(cmd, capture=True)
360
 
    if isinstance(out, bytes):
361
 
        out = out.decode()
362
 
 
363
 
    pkgs_inst = set()
364
 
    for line in out.splitlines():
365
 
        try:
366
 
            (state, pkg, other) = line.split(None, 2)
367
 
        except ValueError:
368
 
            continue
369
 
        if state.startswith("hi") or state.startswith("ii"):
370
 
            pkgs_inst.add(re.sub(":.*", "", pkg))
371
 
 
372
 
    return pkgs_inst
 
213
    if kernel_package:
 
214
        util.install_packages([kernel_package], target=target)
 
215
        return
 
216
 
 
217
    # uname[2] is kernel name (ie: 3.16.0-7-generic)
 
218
    # version gets X.Y.Z, flavor gets anything after second '-'.
 
219
    kernel = os.uname()[2]
 
220
    codename, _ = util.subp(['lsb_release', '--codename', '--short'],
 
221
                            capture=True, target=target)
 
222
    codename = codename.strip()
 
223
    version, abi, flavor = kernel.split('-', 2)
 
224
 
 
225
    try:
 
226
        map_suffix = mapping[codename][version]
 
227
    except KeyError:
 
228
        LOG.warn("Couldn't detect kernel package to install for %s."
 
229
                 % kernel)
 
230
        if kernel_fallback is not None:
 
231
            util.install_packages([kernel_fallback], target=target)
 
232
        return
 
233
 
 
234
    package = "linux-{flavor}{map_suffix}".format(
 
235
        flavor=flavor, map_suffix=map_suffix)
 
236
 
 
237
    if util.has_pkg_available(package, target):
 
238
        if util.has_pkg_installed(package, target):
 
239
            LOG.debug("Kernel package '%s' already installed", package)
 
240
        else:
 
241
            LOG.debug("installing kernel package '%s'", package)
 
242
            util.install_packages([package], target=target)
 
243
    else:
 
244
        if kernel_fallback is not None:
 
245
            LOG.info("Kernel package '%s' not available.  "
 
246
                     "Installing fallback package '%s'.",
 
247
                     package, kernel_fallback)
 
248
            util.install_packages([kernel_fallback], target=target)
 
249
        else:
 
250
            LOG.warn("Kernel package '%s' not available and no fallback."
 
251
                     " System may not boot.", package)
373
252
 
374
253
 
375
254
def setup_grub(cfg, target):
498
377
        util.subp(args + instdevs, env=env)
499
378
 
500
379
 
501
 
def update_initramfs(target, all_kernels=False):
 
380
def update_initramfs(target=None, all_kernels=False):
502
381
    cmd = ['update-initramfs', '-u']
503
382
    if all_kernels:
504
383
        cmd.extend(['-k', 'all'])
505
 
    with util.RunInChroot(target) as in_chroot:
506
 
        in_chroot(cmd)
 
384
    util.subp(cmd, target=target)
507
385
 
508
386
 
509
387
def copy_fstab(fstab, target):
704
582
 
705
583
        # FIXME: this assumes grub. need more generic way to update root=
706
584
        util.ensure_dir(os.path.sep.join([target, os.path.dirname(grub_dev)]))
707
 
        with util.RunInChroot(target) as in_chroot:
708
 
            in_chroot(['update-grub'])
 
585
        with util.ChrootableTarget(target) as in_chroot:
 
586
            in_chroot.subp(['update-grub'])
709
587
 
710
588
    else:
711
589
        LOG.warn("Not sure how this will boot")
740
618
    }
741
619
 
742
620
    needed_packages = []
743
 
    installed_packages = get_installed_packages(target)
 
621
    installed_packages = util.get_installed_packages(target)
744
622
    for cust_cfg, pkg_reqs in custom_configs.items():
745
623
        if cust_cfg not in cfg:
746
624
            continue
820
698
            name=stack_prefix, reporting_enabled=True, level="INFO",
821
699
            description="writing config files and configuring apt"):
822
700
        write_files(cfg, target)
823
 
        apt_config(cfg, target)
 
701
        do_apt_config(cfg, target)
824
702
        disable_overlayroot(cfg, target)
825
703
 
826
704
    # packages may be needed prior to installing kernel
834
712
        copy_mdadm_conf(mdadm_location, target)
835
713
        # as per https://bugs.launchpad.net/ubuntu/+source/mdadm/+bug/964052
836
714
        # reconfigure mdadm
837
 
        util.subp(['chroot', target, 'dpkg-reconfigure',
838
 
                   '--frontend=noninteractive', 'mdadm'], data=None)
 
715
        util.subp(['dpkg-reconfigure', '--frontend=noninteractive', 'mdadm'],
 
716
                  data=None, target=target)
839
717
 
840
718
    with events.ReportEventStack(
841
719
            name=stack_prefix, reporting_enabled=True, level="INFO",
843
721
        setup_zipl(cfg, target)
844
722
        install_kernel(cfg, target)
845
723
        run_zipl(cfg, target)
846
 
        apply_debconf_selections(cfg, target)
847
724
 
848
725
        restore_dist_interfaces(cfg, target)
849
726
 
906
783
    populate_one_subcmd(parser, CMD_ARGUMENTS, curthooks)
907
784
 
908
785
 
909
 
CONFIG_CLEANERS = {
910
 
    'cloud-init': clean_cloud_init,
911
 
}
912
 
 
913
786
# vi: ts=4 expandtab syntax=python