diskimage-builder/elements/yum-minimal/root.d/08-yum-chroot
Ian Wienand 5f3855f6f5 yum-minimal: leave behind dummy /etc/resolv.conf
As described in the comment, systemd will create a broken
/etc/resolv.conf link if there is no file in the base-image (as you
can read in the bug, it is debated if this is a bug or a feature).

The solution is to leave a dummy /etc/resolv.conf file in the image.
Whatever network manager you choose (NetworkManager, glean,
cloud-config, etc) will overwrite this anyway.

It's just that some tools, such as dhclient, get confused with the
broken symlink.  This affects you if you're using glean to configure
the network in a DHCP situation, for example -- dhclient won't
configure nameservers and everything goes to heck.

Change-Id: I734834d03e7fdb13f9ab2e86f877b07bf4a84ff9
2015-12-21 15:28:52 +11:00

203 lines
7.7 KiB
Bash
Executable file

#!/bin/bash
#
# Copyright 2015 Hewlett-Packard Development Company, L.P.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
if [ "${DIB_DEBUG_TRACE:-0}" -gt 0 ]; then
set -x
fi
set -eu
set -o pipefail
if [ -f ${TARGET_ROOT}/.extra_settings ] ; then
. ${TARGET_ROOT}/.extra_settings
fi
ARCH=${ARCH:-x86_64}
if [ $ARCH = amd64 ]; then
ARCH=x86_64
fi
# Calling elements will need to set DISTRO_NAME and DIB_RELEASE
DIB_YUMCHROOT_EXTRA_ARGS=${DIB_YUMCHROOT_EXTRA_ARGS:-}
YUMCHROOT_TARBALL=$DIB_IMAGE_CACHE/yumchroot-${DISTRO_NAME}-${DIB_RELEASE}-${ARCH}.tar.gz
# TODO Maybe deal with DIB_DISTRIBUTION_MIRROR
http_proxy=${http_proxy:-}
YUM=${YUM:-yum}
WORKING=$(mktemp --tmpdir=${TMP_DIR:-/tmp} -d)
EACTION="rm -r $WORKING"
trap "$EACTION" EXIT
YUM_CACHE=$DIB_IMAGE_CACHE/yum
mkdir -p $YUM_CACHE
# Note, on Debian/Ubuntu, %_dbpath is set in the RPM macros as
# ${HOME}/.rpmdb/ -- this makes sense as RPM isn't the system
# packager. This path is relative to the "--root" argument
_RPM="rpm --dbpath=/var/lib/rpm"
# install the [fedora|centos]-[release|repo] packages inside the
# chroot, which are needed to bootstrap yum/dnf
#
# note this runs outside the chroot, where we're assuming the platform
# has yum/yumdownloader
function _install_repos {
yumdownloader \
--releasever=$DIB_RELEASE \
--setopt=reposdir=$TMP_HOOKS_PATH/yum.repos.d \
--destdir=$WORKING \
${DISTRO_NAME}-release
# after fedora21, this is split into into a separate -repos
# package
if [ $DISTRO_NAME = fedora ] ; then
yumdownloader \
--releasever=$DIB_RELEASE \
--setopt=reposdir=$TMP_HOOKS_PATH/yum.repos.d \
--destdir=$WORKING \
${DISTRO_NAME}-repos
fi
# --nodeps works around these wanting /bin/sh in some fedora
# releases, see rhbz#1265873
sudo $_RPM --root $TARGET_ROOT --nodeps -ivh $WORKING/*rpm
}
# _install_pkg_manager packages...
#
# install the package manager packages. This is done outside the chroot
# and with yum from the build system.
# TODO: one day build systems will be dnf only, but we don't handle
# that right now
function _install_pkg_manager {
# Install into the chroot, using the gpg keys from the release
# rpm's installed in the chroot
sudo sed -i "s,/etc/pki/rpm-gpg,$TARGET_ROOT/etc/pki/rpm-gpg,g" \
$TARGET_ROOT/etc/yum.repos.d/*repo
# See notes on $_RPM variable -- we need to override the
# $HOME-based dbpath set on debian/ubuntu here. Unfortunately,
# yum does not have a way to override rpm macros from the command
# line. So we modify the user's ~/.rpmmacros to set %_dbpath back
# to "/var/lib/rpm" (note, this is taken relative to the
# --installroot).
#
# Also note, we only want this done around this call -- this is
# the only place we are using yum outside the chroot, and hence
# picking up the base-system's default rpm macros. For example,
# the yumdownloader calls above in _install_repos want to use
# ~/.rpmdb/ ... there is nothing in the build-system /var/lib/rpm!
#
# Another issue we hit is having to set --releasedir here. yum
# determines $releasevar based on (more or less) "rpm -q
# --whatprovides $distroverpkg". By default, this is
# "redhat-release" (fedora-release provides redhat-release) but
# some platforms like CentOS override it in /etc/yum.conf (to
# centos-release in their case). You can't override this (see
# [1]), but setting --releasever works around this.
#
# [1] https://bugzilla.redhat.com/show_bug.cgi?id=1287333
(
flock -w 1200 9 || die "Can not lock .rpmmacros"
echo "%_dbpath /var/lib/rpm" >> $HOME/.rpmmacros
sudo -E yum -y \
--setopt=cachedir=$YUM_CACHE/$ARCH/$DIB_RELEASE \
--setopt=reposdir=$TARGET_ROOT/etc/yum.repos.d \
--releasever=$DIB_RELEASE \
--installroot $TARGET_ROOT \
install $@
sed -i '$ d' $HOME/.rpmmacros
) 9>$HOME/.rpmmacros.dib.lock
rm $HOME/.rpmmacros.dib.lock
# Set gpg path back because subsequent actions will take place in
# the chroot
sudo sed -i "s,$TARGET_ROOT/etc/pki/rpm-gpg,/etc/pki/rpm-gpg,g" \
$TARGET_ROOT/etc/yum.repos.d/*repo
}
if [ -n "$DIB_OFFLINE" -o -n "${DIB_YUMCHROOT_USE_CACHE:-}" ] && [ -f $YUMCHROOT_TARBALL ] ; then
echo $YUMCHROOT_TARBALL found in cache. Using.
sudo tar -C $TARGET_ROOT --numeric-owner -xzf $YUMCHROOT_TARBALL
else
# Note this is not usually done for root.d elements (see
# lib/common-functions:mount_proc_dev_sys) but it's important that
# we have things like /dev/urandom around inside the chroot for
# the rpm [pre|post]inst scripts within the packages.
sudo mkdir -p $TARGET_ROOT/proc $TARGET_ROOT/dev $TARGET_ROOT/sys
sudo mount -t proc none $TARGET_ROOT/proc
sudo mount --bind /dev $TARGET_ROOT/dev
sudo mount --bind /dev/pts $TARGET_ROOT/dev/pts
sudo mount -t sysfs none $TARGET_ROOT/sys
# initalize rpmdb
sudo mkdir -p $TARGET_ROOT/var/lib/rpm
sudo $_RPM --root $TARGET_ROOT --initdb
# this makes sure that running yum/dnf in the chroot it can get
# out to download stuff
sudo mkdir $TARGET_ROOT/etc
sudo cp /etc/resolv.conf $TARGET_ROOT/etc/resolv.conf
# Bind mount the external yum cache inside the chroot. Same logic
# as in the yum element to provide for yum caching copied here
# because the sequencing is wrong otherwise
sudo mkdir -p $TMP_MOUNT_PATH/tmp/yum
sudo mount --bind $YUM_CACHE $TMP_MOUNT_PATH/tmp/yum
_install_repos
if [ $DIB_RELEASE -ge 22 ]; then
# install dnf for >= f22
_install_pkg_manager dnf dnf-plugins-core yum
else
_install_pkg_manager yum
fi
# bootstrap the environment within the chroot
sudo -E chroot $TARGET_ROOT ${YUM} makecache
sudo -E chroot $TARGET_ROOT ${YUM} -y \
--setopt=cachedir=/tmp/yum/$ARCH/$DIB_RELEASE \
install passwd findutils sudo util-linux-ng
# Put in a dummy /etc/resolv.conf over the temporary one we used
# to bootstrap. systemd has a bug/feature [1] that it will assume
# you want systemd-networkd as the network manager and create a
# broken symlink to /run/... if the base image doesn't have one.
# This broken link confuses things like dhclient.
# [1] https://bugzilla.redhat.com/show_bug.cgi?id=1197204
echo -e "# This file intentionally left blank\n" | \
sudo tee $TARGET_ROOT/etc/resolv.conf
# cleanup
# TODO : move this into a exit trap; and reconsider how
# this integrates with the global exit cleanup path.
sudo umount $TMP_MOUNT_PATH/tmp/yum
sudo umount $TARGET_ROOT/proc
sudo umount $TARGET_ROOT/dev/pts
sudo umount $TARGET_ROOT/dev
sudo umount $TARGET_ROOT/sys
# RPM doesn't know whether files have been changed since install
# At this point though, we know for certain that we have changed no
# config files, so anything marked .rpmnew is just a bug.
for newfile in $(sudo find $TARGET_ROOT -type f -name '*rpmnew') ; do
sudo mv $newfile $(echo $newfile | sed 's/.rpmnew$//')
done
echo Caching result in $YUMCHROOT_TARBALL
sudo tar --numeric-owner \
-C $TARGET_ROOT \
-zcf $YUMCHROOT_TARBALL --exclude='./tmp/*' .
fi
sudo rm -f ${TARGET_ROOT}/.extra_settings