#! /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";; (*) if wget -qO- http://download.opensuse.org/distribution/${VERSION}; then echo "http://download.opensuse.org/distribution/${VERSION}/repo/oss/suse" else echo "http://download.opensuse.org/distribution/leap/${VERSION}/repo/oss/suse" fi;; 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} < ${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" ################################################################################