← Back to team overview

cloud-init-dev team mailing list archive

[Merge] ~smoser/cloud-init:feature/run-opensuse into cloud-init:master

 

Scott Moser has proposed merging ~smoser/cloud-init:feature/run-opensuse into cloud-init:master.

Requested reviews:
  cloud-init commiters (cloud-init-dev)

For more details, see:
https://code.launchpad.net/~smoser/cloud-init/+git/cloud-init/+merge/329650
-- 
Your team cloud-init commiters is requested to review the proposed merge of ~smoser/cloud-init:feature/run-opensuse into cloud-init:master.
diff --git a/tools/read-dependencies b/tools/read-dependencies
index 2a64868..08ef3bf 100755
--- a/tools/read-dependencies
+++ b/tools/read-dependencies
@@ -35,7 +35,7 @@ DISTRO_INSTALL_PKG_CMD = {
     'redhat': ['yum', 'install', '--assumeyes'],
     'debian': ['apt', 'install', '-y'],
     'ubuntu': ['apt', 'install', '-y'],
-    'opensuse': ['zypper', 'install'],
+    'opensuse': ['zypper', '--non-interactive', 'install'],
     'suse': ['zypper', 'install']
 }
 
diff --git a/tools/run-opensuse b/tools/run-opensuse
new file mode 100755
index 0000000..e974f8c
--- /dev/null
+++ b/tools/run-opensuse
@@ -0,0 +1,273 @@
+#!/bin/bash
+# This file is part of cloud-init. See LICENSE file for license information.
+
+set -u
+
+VERBOSITY=0
+TEMP_D=""
+KEEP=false
+CONTAINER=""
+
+error() { echo "$@" 1>&2; }
+fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
+errorrc() { local r=$?; error "$@" "ret=$r"; return $r; }
+
+Usage() {
+    cat <<EOF
+Usage: ${0##*/} [ options ] version
+
+    This utility can makes it easier to run tests, build rpm and source rpm
+        generation inside a LXC of the specified version of OpenSuSE
+
+    version is major release number (42.3)
+
+    options:
+      -a | --artifact keep .rpm artifacts
+      -k | --keep     keep container after tests
+      -r | --rpm      build .rpm
+      -s | --srpm     build .src.rpm
+      -u | --unittest run unit tests
+
+    Example:
+      * ${0##*/} --rpm --srpm --unittest 42.3
+EOF
+}
+
+bad_Usage() { Usage 1>&2; [ $# -eq 0 ] || error "$@"; return 1; }
+cleanup() {
+    if [ -n "$CONTAINER" -a "$KEEP" = "false" ]; then
+        delete_container "$CONTAINER"
+    fi
+    [ -z "${TEMP_D}" -o ! -d "${TEMP_D}" ] || rm -Rf "${TEMP_D}"
+}
+
+debug() {
+    local level=${1}; shift;
+    [ "${level}" -gt "${VERBOSITY}" ] && return
+    error "${@}"
+}
+
+
+inside_as() {
+    # inside_as(container_name, user, cmd[, args])
+    # executes cmd with args inside container as user in users home dir.
+    local name="$1" user="$2"
+    shift 2
+    if [ "$user" = "root" ]; then
+        inside "$name" "$@"
+        return
+    fi
+    local stuffed="" b64=""
+    stuffed=$(getopt --shell sh --options "" -- -- "$@")
+    stuffed=${stuffed# -- }
+    b64=$(printf "%s\n" "$stuffed" | base64 --wrap=0)
+    inside "$name" su "$user" -c \
+        'cd; eval set -- "$(echo '$b64' | base64 --decode)" && exec "$@"'
+}
+
+inside_as_cd() {
+    local name="$1" user="$2" dir="$3"
+    shift 3
+    inside_as "$name" "$user" sh -c 'cd "$0" && exec "$@"' "$dir" "$@"
+}
+
+inside() {
+    local name="$1"
+    shift
+    echo "$name": "$@" 1>&2
+    lxc exec "$name" -- "$@"
+}
+
+inject_cloud_init(){
+    # take current cloud-init git dir and put it inside $name at
+    # ~$user/cloud-init.
+    local name="$1" user="$2" top_d="" dname="" pstat=""
+    top_d=$(git rev-parse --show-toplevel) || {
+        errorrc "Failed to get git top level in $PWD";
+        return
+    }
+    dname=$(basename "${top_d}") || return
+    debug 1 "collecting ${top_d} ($dname) into user $user in $name."
+    tar -C "${top_d}/.." -cpf - "$dname" |
+        inside_as "$name" "$user" sh -ec '
+            dname=$1
+            rm -Rf "$dname"
+            tar -xpf -
+            [ "$dname" = "cloud-init" ] || mv "$dname" cloud-init' \
+            extract "$dname"
+    [ "${PIPESTATUS[*]}" = "0 0" ] || {
+        error "Failed to push tarball of '$top_d' into $name" \
+            " for user $user (dname=$dname)"
+        return 1
+    }
+    return 0
+}
+
+prep() {
+    # we need some very basic things not present in the container.
+    #  - git
+    #  - tar (CentOS 6 lxc container does not have it)
+    #  - python-argparse (or python3)
+    local needed="" pair="" pkg="" cmd="" needed=""
+    for pair in tar:tar git:git; do
+        pkg=${pair#*:}
+        cmd=${pair%%:*}
+        command -v $cmd >/dev/null 2>&1 || needed="${needed} $pkg"
+    done
+    if ! command -v python3; then
+        python -c "import argparse" >/dev/null 2>&1 ||
+            needed="${needed} python-argparse"
+    fi
+    needed=${needed# }
+    if [ -z "$needed" ]; then
+        error "No prep packages needed"
+        return 0
+    fi
+    error "Installing prep packages: ${needed}"
+    zypper --non-interactive --gpg-auto-import-keys install \
+        --auto-agree-with-licenses ${needed}
+}
+
+start_container() {
+    local src="$1" name="$2"
+    debug 1 "starting container $name from '$src'"
+    lxc launch "$src" "$name" || {
+        errorrc "Failed to start container '$name' from '$src'";
+        return
+    }
+    CONTAINER=$name
+
+    local out="" ret=""
+    debug 1 "waiting for networking"
+    out=$(inside "$name" sh -c '
+        i=0
+        while [ $i -lt 60 ]; do
+            getent hosts opensuse.org && exit 0
+            sleep 2
+        done' 2>&1)
+    ret=$?
+    if [ $ret -ne 0 ]; then
+        error "Waiting for network in container '$name' failed. [$ret]"
+        error "$out"
+        return $ret
+    fi
+
+    #if [ ! -z "${http_proxy-}" ]; then
+        #debug 1 "configuring proxy ${http_proxy}"
+        #inside "$name" sh -c "echo proxy=$http_proxy >> /etc/yum.conf"
+    #fi
+}
+
+delete_container() {
+    debug 1 "removing container $1 [--keep to keep]"
+    lxc delete --force "$1"
+}
+
+main() {
+    local short_opts="ahkrsuv"
+    local long_opts="artifact,help,keep,rpm,srpm,unittest,verbose"
+    local getopt_out=""
+    getopt_out=$(getopt --name "${0##*/}" \
+        --options "${short_opts}" --long "${long_opts}" -- "$@") &&
+        eval set -- "${getopt_out}" ||
+        { bad_Usage; return; }
+
+    local cur="" next=""
+    local artifact="" keep="" rpm="" srpm="" unittest="" version=""
+
+    while [ $# -ne 0 ]; do
+        cur="${1:-}"; next="${2:-}";
+        case "$cur" in
+            -a|--artifact) artifact=1;;
+            -h|--help) Usage ; exit 0;;
+            -k|--keep) KEEP=true;;
+            -r|--rpm) rpm=1;;
+            -s|--srpm) srpm=1;;
+            -u|--unittest) unittest=1;;
+            -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));;
+            --) shift; break;;
+        esac
+        shift;
+    done
+
+    [ $# -eq 1 ] || { bad_Usage "ERROR: Must provide version!"; return; }
+    version="$1"
+    case "$version" in
+        42.*) version="42.3";;
+        *) error "Expected version of 42.*, not '$version'"; return;;
+    esac
+
+    TEMP_D=$(mktemp -d "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") ||
+        fail "failed to make tempdir"
+    trap cleanup EXIT
+
+    # program starts here
+    local uuid="" name="" user="ci-test" cdir=""
+    cdir="/home/$user/cloud-init"
+    uuid=$(uuidgen -t) || { error "no uuidgen"; return 1; }
+    name="cloud-init-opensuse-${uuid%%-*}"
+
+    start_container "images:opensuse/$version" "$name"
+
+    # prep the container (install very basic dependencies)
+    inside "$name" bash -s prep <"$0" ||
+        { errorrc "Failed to prep container $name"; return; }
+
+    # add the user
+    inside "$name" useradd --create-home "$user"
+
+    debug 1 "inserting cloud-init"
+    inject_cloud_init "$name" "$user" || {
+        errorrc "FAIL: injecting cloud-init into $name failed."
+        return
+    }
+
+    inside_as_cd "$name" root "$cdir" \
+        ./tools/read-dependencies --distro=opensuse --test-distro || {
+        errorrc "FAIL: failed to install dependencies with read-dependencies"
+        return
+    }
+
+    local errors=0
+    inside_as_cd "$name" "$user" "$cdir" \
+        sh -ec "git checkout .; git status" ||
+            { errorrc "git checkout failed."; errors=$(($errors+1)); }
+
+    if [ -n "$unittest" ]; then
+        debug 1 "running unit tests."
+        inside_as_cd "$name" "$user" "$cdir" nosetests tests/unittests ||
+            { errorrc "nosetests failed."; errors=$(($errors+1)); }
+    fi
+
+    if [ -n "$srpm" ]; then
+        debug 1 "building srpm."
+        inside_as_cd "$name" "$user" "$cdir" ./packages/brpm --srpm ||
+            { errorrc "brpm --srpm."; errors=$(($errors+1)); }
+    fi
+
+    if [ -n "$rpm" ]; then
+        debug 1 "building rpm."
+        inside_as_cd "$name" "$user" "$cdir" ./packages/brpm ||
+            { errorrc "brpm failed."; errors=$(($errors+1)); }
+    fi
+
+    if [ -n "$artifact" ]; then
+        for built_rpm in $(inside "$name" sh -c "echo $cdir/*.rpm"); do
+            lxc file pull "$name/$built_rpm" .
+        done
+    fi
+
+    if [ "$errors" != "0" ]; then
+        error "there were $errors errors."
+        return 1
+    fi
+    return 0
+}
+
+if [ "${1:-}" = "prep" ]; then
+    shift
+    prep "$@"
+else
+    main "$@"
+fi
+# vi: ts=4 expandtab

Follow ups