Files
suse-chroots/scripts/susebootstrap.sh
Marc Wäckerlin ddcc670662 initial takeover
2015-11-05 15:34:13 +00:00

537 lines
19 KiB
Bash
Executable File

#! /bin/bash -e
function error() {
echo "**** ERROR aborted. Status of last operation: $?" 1>&2
exit 1
}
trap error HUP INT QUIT TERM ERR
# log LEVEL "Text"
# LEVEL: 0=normal 1=verbose 2=more-verbose
function echon() {
if test "$1" == "-n"; then
shift
echo -n "$*"
else
echo "$*"
fi
}
function log() {
l=$1
shift
if test "$1" == "-n"; then
shift
n="-n"
else
n=""
fi
if test $q -eq 1; then
return
elif test $l -eq 0 -o $l -eq 1 -a $v -eq 1 -o $l -eq 2 -a $vv -eq 1; then
if test $l -gt 0; then
echon $n " $l$*"
else
echon $n "$*"
fi
fi
}
################################################################################
# Arguments
################################################################################
q=0
v=0
vv=0
while test $# -gt 0; do
case "$1" in
(-q) q=1; v=0; vv=0;;
(-v) q=0; v=1; vv=0;;
(-vv) q=0; v=1; vv=1;;
(-h|--help)
echo "SYNOPSIS: $0 [-q|-v|-vv]"
echo " -q quiet"
echo " -v verbose"
echo " -vv more verbose"
exit 0;;
esac
shift
done
################################################################################
################################################################################
# CONFIGURATION you can overwrite any of the variables when you start the script
# e.g. HW="x86_64 noarch" VERSION=11.4 sudo susebootstrap.sh
# Setup OS sources
#
# OS: name of the OS, used for chroot pathname
OS=${OS:-"opensuse"}
log 2 "OS=$OS"
#
# VERSION: see e.g. http://download.opensuse.org/distribution/
VERSION=${VERSION:-$(
case "$OS" in
opensuse) echo "openSUSE-current";;
fedora) echo "$(wget -O- http://mirror.switch.ch/ftp/mirror/fedora/linux/releases 2>/dev/null | html2 | sed -n 's,.*/a/@href=\([0-9][0-9]*\)/,\1,gp' | uniq | tail -1)";;
centos) echo "$(wget -O- http://mirror.switch.ch/ftp/mirror/centos 2>/dev/null | sed -n 's,.*href="\([0-9][0-9]*\)/".*,\1,pg' | uniq | tail -1)"
esac)}
log 2 "VERSION=$VERSION"
#
# HW: list of hardware subdirs in openSUSE, e.g. "x86_64 noarch"
HW=${HW:-$(
case "$OS" in
opensuse) echo "i586 noarch";;
fedora) echo "i686 noarch";;
centos) echo "x86_64 noarch";;
esac)}
log 2 "HW=$HW"
#
# BASEARCH: Base architecture, e.g. for i686 and i566 BASEARCH is i386
BASEARCH=${BASEARCH:-$(
case "${HW%% *}" in
i?86) echo "i386";;
*) echo "${HW%% *}";;
esac)}
log 2 "BASEARCH=$BASEARCH"
#
# URL: where to download packages from
URL=${URL:-$(
case "$OS" in
opensuse)
case "$VERSION" in
(tumbleweed) echo "http://download.opensuse.org/tumbleweed/repo/oss/suse";;
(*) echo "http://download.opensuse.org/distribution/${VERSION}/repo/oss/suse";;
esac;;
fedora)
if test "$VERSION" -gt 20; then
echo "http://mirror.switch.ch/ftp/mirror/fedora/linux/releases/${VERSION}/Server/${BASEARCH}/os"
else
echo "http://mirror.switch.ch/ftp/mirror/fedora/linux/releases/${VERSION}/Fedora/${BASEARCH}/os"
fi;;
centos) echo "http://mirror.switch.ch/ftp/mirror/centos/${VERSION}/os/${BASEARCH}";;
esac)}
log 2 "URL=$URL"
# Setup installation pathes
#
# BASE: Base path to the chroots on your system
BASE=${BASE:-/var/chroot}
log 2 "BASE=$BASE"
#
# SCHROOTCONF: Configurationfile for schroot
SCHROOTCONF=${SCHROOTCONF:-${OS}-${VERSION}_${BASEARCH}}
log 2 "SCHROOTCONF=$SCHROOTCONF"
#
# ROOT: Full path to the chroot directory
ROOT=${ROOT:-${BASE}/${SCHROOTCONF}}
log 2 "ROOT=$ROOT"
#
# PACKAGES: Where to store package lists path+filename-prefix
PACKAGES=${PACKAGES:-${ROOT}/var/tmp/packagelist}
log 2 "PACKAGES=$PACKAGES"
#
# PKGDIR: Where to store downloaded packages, relative to ${ROOT}
PKGDIR=${PKGDIR:-/var/tmp/packages}
log 2 "PKGDIR=$PKGDIR"
#
# SCHROOTUSER: Name of user or list of user that will use schroot
SCHROOTUSER=${SCHROOTUSER:-${USER}}
log 2 "SCHROOTUSER=$SCHROOTUSER"
#
# CHROOT: Command for starting chroot, more possibilities, see below
CHROOT="schroot -c ${SCHROOTCONF} -d / -u root"
log 2 "CHROOT=$CHROOT"
#
# YUM: Set Fedora / CentOS repository tool
if test "$OS" = "fedora" && test "${VERSION}" -gt "21"; then
YUM=${YUM:-"dnf"}
else
YUM=${YUM:-"yum"}
fi
log 2 "YUM=$YUM"
#
# PKGS: Base packages to install for minimal system
PKGS=${PKGS:-$(
case "$OS" in
opensuse) echo "bash rpm zypper";;
fedora)
echo "bash rpm fedora-release"
if test "${VERSION}" -gt "21"; then
echo "dnf"
else
echo "yum"
fi
;;
centos)
echo "bash rpm yum centos-release"
;;
esac)}
log 2 "PKGS=$PKGS"
#
#
if [ -z "${CHROOT}" ]; then
echo "**** ERROR: Variable CHROOT must be set." 1>&2
exit 1
fi
# ADDITIONAL_DEFINITIONS: Add additional definitions to /etc/schroot/chroot.d
# Example: ADDITIONAL_DEFINITIONS="setup.fstab=jenkins/fstab"
ADDITIONAL_DEFINITIONS=${ADDITIONAL_DEFINITIONS:-}
log 2 "ADDITIONAL_DEFINITIONS=$ADDITIONAL_DEFINITIONS"
################################################################################
################################################################################
# Main Part
################################################################################
# 1. Download basic packages
# 2. Unpack them into a chroot-path
# 3. Tweak the minimal system
# 4. Setup basic /dev
# 5. Properly install all the packages within chroot
# 6. configure basic system
# 7. Done, now chroot to the path and install whatever you need
################################################################################
log 0 "Install ${OS} ${VERSION} for ${BASEARCH} in ${ROOT}"
################################################################################
# Preparation of path for chroot and packages
test -d ${ROOT}${PKGDIR} || mkdir -p ${ROOT}${PKGDIR}
################################################################################
################################################################################
# 0. Setup schroot configuration
cat > /etc/schroot/chroot.d/${SCHROOTCONF} <<EOF
[${SCHROOTCONF}]
description=${OS}-${VERSION} ${BASEARCH}
directory=${ROOT}
users=${SCHROOTUSER}
root-groups=root
root-users=${SCHROOTUSER}
type=directory
${ADDITIONAL_DEFINITIONS}
EOF
################################################################################
################################################################################
# 0. Search for dependencies to install
# requires: rpm xml2 schroot
log 0 " ... read repository meta data"
test -d ${PACKAGES} || mkdir -p ${PACKAGES}
test -f ${PACKAGES}/repomd.xml || \
wget -q -O ${PACKAGES}/repomd.xml ${URL}/repodata/repomd.xml
datapath=$(xml2 < ${PACKAGES}/repomd.xml \
| awk -F= 'BEGIN {x=0}
x==1 && $1=="/repomd/data/location/@href" {print $2; exit}
$1=="/repomd/data/@type" && $2=="primary" {x=1}')
dataname=${PACKAGES}/${datapath##*/}
log 2 "dataname=${dataname} from ${URL}/${datapath}"
log 0 " ... read repository details"
test -f ${dataname} || \
wget -q -O ${dataname} ${URL}/${datapath}
log 0 " ... recursively extract dependencies"
oldPKGS=""
if [ ! -f ${PACKAGES}/packages ]; then
test ! -f ${PACKAGES}/install || rm ${PACKAGES}/install
while [ "$PKGS" != "$oldPKGS" ]; do
oldPKGS=$PKGS
log 0 " ... extract dependencies: scan $(echo "$PKGS" | wc -w)" \
"packages"
log 0 " ... extract dependencies: find requirements"
PKGS=${PKGS% }
chkinstpkgs=$(echo $PKGS | sed -e 's/[^-A-Za-z0-9_ ]/./g' | tr ' ' '|')
deps=$(
(
echo "$PKGS" | tr ' ' '\n';
zcat $dataname | xml2 | awk -F= '
BEGIN {
x=0
}
x==1 &&
( $1=="/metadata/package/format/rpm:requires/rpm:entry/@name" ||
( $1=="/metadata/package/format/rpm:provides/rpm:entry/@name" &&
$2~/^('${chkinstpkgs}')$/ ) ) {
print $2
}
$1=="/metadata/package/name" && $2~/^('${chkinstpkgs}')$/ {
x=1
}
$1=="/metadata/package/name" && $2!~/^('${chkinstpkgs}')$/ {
x=0
}
$1=="/metadata/package/arch" && $2!~/^('${HW// /|}')$/ {
x=0
}'
) | \
sed -e 's/[^-A-Za-z0-9_]/./g' | \
sort | uniq | tr '\n ' '||' | \
sed -e 's/^|//' -e 's/|$//'
)
log 0 " ... extract dependencies: extend packagelist by providers"
PKGS=$(
zcat $dataname | xml2 | awk -F= '
BEGIN {
matcher="^('${deps}')$" #(|\\(.*\\))$"
}
$1=="/metadata/package/name" && $2~matcher {
name=$2
tmp=$2
gsub(/[^-A-Za-z0-9_]/, ".", tmp)
sub("\\|" tmp "\\|", "|", matcher)
sub("^" tmp ")\\|", "", matcher)
sub("\\|" tmp "$", "", matcher)
print name
}
$1=="/metadata/package/name" && $2!~matcher {
name=$2
}
( $1=="/metadata/package/format/rpm:provides/rpm:entry/@name" ||
$1=="/metadata/package/format/file" ) &&
$2~matcher {
tmp=$2
gsub(/[^-A-Za-z0-9_]/, ".", tmp)
sub("\\|" tmp "\\|", "|", matcher)
sub("^" tmp ")\\|", "", matcher)
sub("\\|" tmp "$", "", matcher)
print name
}
END {
}' | sort | uniq | tr '\n' ' '
)
((++pkgcnt)) ###
log 2 "temp packages: $PKGS"
log 2 "temp dependencies: $deps"
done
else
log 2 "packages already evaluated"
PKGS=$(<${PACKAGES}/packages)
fi
PKGS=${PKGS% }
echo ${PKGS} > ${PACKAGES}/packages
log 1 "final packages: $PKGS"
log 0 " ... extract dependencies: find files to download and install"
if [ -f ${PACKAGES}/install ]; then
log 2 "installations already evaluated"
INSTALL=$(<${PACKAGES}/install)
else
chkinstpkgs=$(echo $PKGS | sed -e 's/[^-A-Za-z0-9_ ]/./g' | tr ' ' '|')
INSTALL=$(
zcat $dataname | xml2 | awk -F= '
BEGIN {
x=0
}
x==1 && $1=="/metadata/package/location/@href" {
print $2
}
$1=="/metadata/package/name" && $2~/^('${chkinstpkgs}')$/ {
x=1
}
$1=="/metadata/package/name" && $2!~/^('${chkinstpkgs}')$/ {
x=0
}
$1=="/metadata/package/arch" && $2!~/^('${HW// /|}')$/ {
x=0
}' | sort | uniq | tr '\n' ' '
)
echo $INSTALL > ${PACKAGES}/install
fi
log 1 "installations: ${INSTALL}"
log 0 " ... download and install $(echo ${INSTALL} | wc -w) files"
################################################################################
################################################################################
# 1. Download basic packages
# We know the logical package names, find matching package files
# on server
# INST: Will be filled with a list of package files to download and
# install
for p in $INSTALL; do # for all packages to install
log 0 " ... download $p"
test -f ${ROOT}${PKGDIR}/${p##*/} || \
wget -q -O ${ROOT}${PKGDIR}/${p##*/} ${URL}/$p
INST="$INST ${p##*/}"
done
################################################################################
################################################################################
# 2. Unpack them into a chroot-path
# Extract all downloaded packages in the chroot directory
cd ${ROOT}
for p in $INST; do # for all downloaded packages
# just extract the file structure withing the package without running
# pre-/post-install scripts
# this is necessary for a minimal basic system to chroot in
log 0 " ... unpack $p"
rpm2cpio ${ROOT}${PKGDIR}/$p | cpio -dim --quiet 2> /dev/null
done
cd - > /dev/null
################################################################################
################################################################################
# 3. Tweak the minimal system
log 0 " ... setup system"
#
# Do some system setup tweaks
#
# Create minimal /etc/passwd and /etc/group with user "root"
test -e ${ROOT}/etc/passwd || \
echo 'root:x:0:0:root:/root:/bin/bash' > ${ROOT}/etc/passwd
test -e ${ROOT}/etc/group || \
( \
echo 'root:x:0:'; \
echo 'utmp:x:0:' \
) > ${ROOT}/etc/group
test -e ${ROOT}/etc/shadow || touch ${ROOT}/etc/shadow
test -e ${ROOT}/etc/gshadow || touch ${ROOT}/etc/gshadow
test -e ${ROOT}/etc/fstab || touch ${ROOT}/etc/fstab
#
# copy /etc/resolv.conf into chroot to be able to access internet
test -e ${ROOT}/etc/resolv.conf || \
cp /etc/resolv.conf ${ROOT}/etc/
################################################################################
# 4. Setup basic /dev
log 0 " ... setup prepare minimal /dev with /dev/null and /dev/zero"
if [ -n "${CHROOT//*schroot*/}" ]; then
# only if chroot is not schroot, schroot creates /dev
test -d ${ROOT}/dev || ${CHROOT} mkdir ${ROOT}/dev
test -e ${ROOT}/dev/null || \
( \
${CHROOT} mknod -m 666 /dev/null c 1 3 && \
${CHROOT} chown root:root /dev/null
)
test -e ${ROOT}/dev/zero || \
( \
${CHROOT} mknod -m 666 /dev/zero c 1 5 && \
${CHROOT} chown root:root /dev/zero \
)
fi
################################################################################
################################################################################
# 5. Properly install all the package packages within chroot
# now chroot into the new system and properly install all downloaded packages,
# this executes triggers and maintains package database
log 0 " ... install all packages"
all_success=1
if ! ${CHROOT} -- rpm -i --nodeps --force ${PKGDIR}/*.rpm > /dev/null 2> /dev/null; then
for p in ${ROOT}${PKGDIR}/*.rpm; do
log 0 -n " ... install ${p#${ROOT}}"
if ${CHROOT} -- rpm -i --nodeps --force ${p#${ROOT}} \
> /dev/null 2> /dev/null; then
log 0 " success"
else
all_success=0
log 0 " error"
fi
done
fi
################################################################################
################################################################################
# System Dependent Part
################################################################################
case "$OS" in
(opensuse)
########################################################################
# 6. Add an archive source to package manager
# add installation source as repository
log 0 " ... setup package manager"
${CHROOT} -- zypper -q ar ${URL} repo-oss
#
# setup hardware architecture in zypper, necessary different from host
${CHROOT} -- perl -pi \
-e 's#^\#? *arch = .*$#arch = '${HW%% *}'#g' \
/etc/zypp/zypp.conf
#
# basic initialisation, first update - bug with key in 12.2
log 0 " ... basic initialisation of package manager"
${CHROOT} -- zypper -q -n --gpg-auto-import-keys update || \
${CHROOT} -- zypper -q -n --no-gpg-checks update
${CHROOT} -- zypper -q -n --gpg-auto-import-keys dist-upgrade || \
${CHROOT} -- zypper -q -n --no-gpg-checks dist-upgrade
#
# install some basic packages
log 0 " ... install more basic packages"
${CHROOT} -- zypper -q -n --gpg-auto-import-keys \
install openSUSE-release
########################################################################
;;
(fedora)
########################################################################
# 6. Install basic packages
log 0 " ... setup package manager using $YUM"
test -d ${ROOT}/etc/rpm || mkdir -p ${ROOT}/etc/rpm
sed -i 's,$basearch,'${BASEARCH}',g' \
$(grep -lr '$basearch' ${ROOT}/etc/yum.repos.d)
echo "${HW%% *}-${OS}-linux" > ${ROOT}/etc/rpm/platform
if test "${VERSION}" -gt "16"; then # hack for fedora 17 and above
log 0 " ... convert fedora 17+ filesystem"
${0%/*}/convertfs-fedora-17.sh ${ROOT}
fi
log 0 " ... upgrade base system"
${CHROOT} -- ${YUM} -y -q upgrade || \
( ${CHROOT} -- bash -c 'sed -i "s|^#baseurl|baseurl| ; s|^mirrorlist|#mirrorlist|" /etc/yum.repos.d/*' && \
${CHROOT} -- ${YUM} -y -q upgrade )
log 0 " ... install more basic packages"
for g in "Base" "Minimal Install"; do
if ${CHROOT} -- ${YUM} -y -q grouplist | grep -q "$g"; then
log 2 "install $g"
case "$VERSION" in
(*-Fedora)
${CHROOT} -- ${YUM} -y -q groups mark install "$g"
;;
(*)
${CHROOT} -- ${YUM} -y -q groupupdate "$g"
;;
esac
fi
done
########################################################################
;;
(centos)
########################################################################
# 6. Install basic packages
log 0 " ... setup package manager using $YUM"
${CHROOT} -- ln -s /sbin/chkconfig /usr/sbin/chkconfig
test -d ${ROOT}/etc/rpm || mkdir -p ${ROOT}/etc/rpm
echo "${HW%% *}-${OS}-linux" > ${ROOT}/etc/rpm/platform
if test "${VERSION}" -gt "6"; then # hack for fedora 17 and above
log 0 " ... convert fedora 17+ filesystem"
${0%/*}/convertfs-fedora-17.sh ${ROOT}
fi
log 0 " ... upgrade base system"
${CHROOT} -- ${YUM} -y -q upgrade || \
( ${CHROOT} -- bash -c 'sed -i "s|^#baseurl|baseurl| ; s|^mirrorlist|#mirrorlist|" /etc/yum.repos.d/*' && \
${CHROOT} -- ${YUM} -y -q upgrade )
log 0 " ... install more basic packages"
for g in "Base" "Minimal Install"; do
if ${CHROOT} -- ${YUM} -y -q grouplist | grep -q "$g"; then
log 2 "install $g"
${CHROOT} -- ${YUM} -y -q groups mark install "$g"
${CHROOT} -- ${YUM} -y -q upgrade
log 2 "update $g"
${CHROOT} -- ${YUM} -y -q groupupdate "$g"
fi
done
########################################################################
;;
esac
################################################################################
################################################################################
# 7. Done - use your chroot to work or install more packages
log 0 "**** SUCCESS done."
log 0
log 0 "########################################################################"
log 0 "Use your new chroot:"
log 0 " > ${CHROOT} -- bash"
log 0 " > [... work in your chroot ...]"
log 0 " > exit"
log 0 "########################################################################"
log 0 " ... cleanup chroot"
################################################################################