#!/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