| Ivan Berezovskiy | 3895982 | 2019-09-26 16:29:51 +0400 | [diff] [blame^] | 1 | #!/usr/bin/env bash | 
|  | 2 |  | 
|  | 3 | set -e | 
|  | 4 | [ -n "$DEBUG" ] && set -x | 
|  | 5 |  | 
|  | 6 | CURDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | 
|  | 7 | METADATA=${CURDIR}/../metadata.yml | 
|  | 8 | FORMULA_NAME=$(cat $METADATA | python -c "import sys,yaml; print yaml.load(sys.stdin)['name']") | 
|  | 9 | FORMULA_META_DIR=${CURDIR}/../${FORMULA_NAME}/meta | 
|  | 10 |  | 
|  | 11 | ## Overrideable parameters | 
|  | 12 | PILLARDIR=${PILLARDIR:-${CURDIR}/pillar} | 
|  | 13 | BUILDDIR=${BUILDDIR:-${CURDIR}/build} | 
|  | 14 | VENV_DIR=${VENV_DIR:-${BUILDDIR}/virtualenv} | 
|  | 15 | MOCK_BIN_DIR=${MOCK_BIN_DIR:-${CURDIR}/mock_bin} | 
|  | 16 | DEPSDIR=${BUILDDIR}/deps | 
|  | 17 |  | 
|  | 18 | SALT_FILE_DIR=${SALT_FILE_DIR:-${BUILDDIR}/file_root} | 
|  | 19 | SALT_PILLAR_DIR=${SALT_PILLAR_DIR:-${BUILDDIR}/pillar_root} | 
|  | 20 | SALT_CONFIG_DIR=${SALT_CONFIG_DIR:-${BUILDDIR}/salt} | 
|  | 21 | SALT_CACHE_DIR=${SALT_CACHE_DIR:-${SALT_CONFIG_DIR}/cache} | 
|  | 22 |  | 
|  | 23 | SALT_OPTS="${SALT_OPTS} --retcode-passthrough --local -c ${SALT_CONFIG_DIR} --log-file=/dev/null" | 
|  | 24 |  | 
|  | 25 | if [ "x${SALT_VERSION}" != "x" ]; then | 
|  | 26 | PIP_SALT_VERSION="==${SALT_VERSION}" | 
|  | 27 | fi | 
|  | 28 |  | 
|  | 29 | ## Functions | 
|  | 30 | log_info() { | 
|  | 31 | echo "[INFO] $*" | 
|  | 32 | } | 
|  | 33 |  | 
|  | 34 | log_err() { | 
|  | 35 | echo "[ERROR] $*" >&2 | 
|  | 36 | } | 
|  | 37 |  | 
|  | 38 | setup_virtualenv() { | 
|  | 39 | log_info "Setting up Python virtualenv" | 
|  | 40 | virtualenv $VENV_DIR | 
|  | 41 | source ${VENV_DIR}/bin/activate | 
|  | 42 | pip install salt${PIP_SALT_VERSION} | 
|  | 43 | } | 
|  | 44 |  | 
|  | 45 | setup_mock_bin() { | 
|  | 46 | # If some state requires a binary, a lightweight replacement for | 
|  | 47 | # such binary can be put into MOCK_BIN_DIR for test purposes | 
|  | 48 | if [ -d "${MOCK_BIN_DIR}" ]; then | 
|  | 49 | PATH="${MOCK_BIN_DIR}:$PATH" | 
|  | 50 | export PATH | 
|  | 51 | fi | 
|  | 52 | } | 
|  | 53 |  | 
|  | 54 | setup_pillar() { | 
|  | 55 | [ ! -d ${SALT_PILLAR_DIR} ] && mkdir -p ${SALT_PILLAR_DIR} | 
|  | 56 | echo "base:" > ${SALT_PILLAR_DIR}/top.sls | 
|  | 57 | for pillar in ${PILLARDIR}/*; do | 
|  | 58 | grep ${FORMULA_NAME}: ${pillar} &>/dev/null || continue | 
|  | 59 | state_name=$(basename ${pillar%.sls}) | 
|  | 60 | echo -e "  ${state_name}:\n    - ${state_name}" >> ${SALT_PILLAR_DIR}/top.sls | 
|  | 61 | done | 
|  | 62 | } | 
|  | 63 |  | 
|  | 64 | setup_salt() { | 
|  | 65 | [ ! -d ${SALT_FILE_DIR} ] && mkdir -p ${SALT_FILE_DIR} | 
|  | 66 | [ ! -d ${SALT_CONFIG_DIR} ] && mkdir -p ${SALT_CONFIG_DIR} | 
|  | 67 | [ ! -d ${SALT_CACHE_DIR} ] && mkdir -p ${SALT_CACHE_DIR} | 
|  | 68 |  | 
|  | 69 | echo "base:" > ${SALT_FILE_DIR}/top.sls | 
|  | 70 | for pillar in ${PILLARDIR}/*.sls; do | 
|  | 71 | grep ${FORMULA_NAME}: ${pillar} &>/dev/null || continue | 
|  | 72 | state_name=$(basename ${pillar%.sls}) | 
|  | 73 | echo -e "  ${state_name}:\n    - ${FORMULA_NAME}" >> ${SALT_FILE_DIR}/top.sls | 
|  | 74 | done | 
|  | 75 |  | 
|  | 76 | cat << EOF > ${SALT_CONFIG_DIR}/minion | 
|  | 77 | file_client: local | 
|  | 78 | cachedir: ${SALT_CACHE_DIR} | 
|  | 79 | verify_env: False | 
|  | 80 | minion_id_caching: False | 
|  | 81 |  | 
|  | 82 | file_roots: | 
|  | 83 | base: | 
|  | 84 | - ${SALT_FILE_DIR} | 
|  | 85 | - ${CURDIR}/.. | 
|  | 86 | - /usr/share/salt-formulas/env | 
|  | 87 |  | 
|  | 88 | pillar_roots: | 
|  | 89 | base: | 
|  | 90 | - ${SALT_PILLAR_DIR} | 
|  | 91 | - ${PILLARDIR} | 
|  | 92 | EOF | 
|  | 93 | } | 
|  | 94 |  | 
|  | 95 | fetch_dependency() { | 
|  | 96 | dep_name="$(echo $1|cut -d : -f 1)" | 
|  | 97 | dep_source="$(echo $1|cut -d : -f 2-)" | 
|  | 98 | dep_root="${DEPSDIR}/$(basename $dep_source .git)" | 
|  | 99 | dep_metadata="${dep_root}/metadata.yml" | 
|  | 100 |  | 
|  | 101 | [ -d /usr/share/salt-formulas/env/${dep_name} ] && log_info "Dependency $dep_name already present in system-wide salt env" && return 0 | 
|  | 102 | [ -d $dep_root ] && log_info "Dependency $dep_name already fetched" && return 0 | 
|  | 103 |  | 
|  | 104 | log_info "Fetching dependency $dep_name" | 
|  | 105 | [ ! -d ${DEPSDIR} ] && mkdir -p ${DEPSDIR} | 
|  | 106 | git clone $dep_source ${DEPSDIR}/$(basename $dep_source .git) | 
|  | 107 | ln -s ${dep_root}/${dep_name} ${SALT_FILE_DIR}/${dep_name} | 
|  | 108 |  | 
|  | 109 | METADATA="${dep_metadata}" install_dependencies | 
|  | 110 | } | 
|  | 111 |  | 
|  | 112 | install_dependencies() { | 
|  | 113 | grep -E "^dependencies:" ${METADATA} >/dev/null || return 0 | 
|  | 114 | (python - | while read dep; do fetch_dependency "$dep"; done) << EOF | 
|  | 115 | import sys,yaml | 
|  | 116 | for dep in yaml.load(open('${METADATA}', 'ro'))['dependencies']: | 
|  | 117 | print '%s:%s' % (dep["name"], dep["source"]) | 
|  | 118 | EOF | 
|  | 119 | } | 
|  | 120 |  | 
|  | 121 | clean() { | 
|  | 122 | log_info "Cleaning up ${BUILDDIR}" | 
|  | 123 | [ -d ${BUILDDIR} ] && rm -rf ${BUILDDIR} || exit 0 | 
|  | 124 | } | 
|  | 125 |  | 
|  | 126 | salt_run() { | 
|  | 127 | [ -e ${VEN_DIR}/bin/activate ] && source ${VENV_DIR}/bin/activate | 
|  | 128 | salt-call ${SALT_OPTS} $* | 
|  | 129 | } | 
|  | 130 |  | 
|  | 131 | prepare() { | 
|  | 132 | [ -d ${BUILDDIR} ] && mkdir -p ${BUILDDIR} | 
|  | 133 |  | 
|  | 134 | which salt-call || setup_virtualenv | 
|  | 135 | setup_mock_bin | 
|  | 136 | setup_pillar | 
|  | 137 | setup_salt | 
|  | 138 | install_dependencies | 
|  | 139 | } | 
|  | 140 |  | 
|  | 141 | run() { | 
|  | 142 | for pillar in ${PILLARDIR}/*.sls; do | 
|  | 143 | grep ${FORMULA_NAME}: ${pillar} &>/dev/null || continue | 
|  | 144 | state_name=$(basename ${pillar%.sls}) | 
|  | 145 | salt_run grains.set 'noservices' False force=True | 
|  | 146 |  | 
|  | 147 | echo "Checking state ${FORMULA_NAME}.${state_name} ..." | 
|  | 148 | salt_run --id=${state_name} state.show_sls ${FORMULA_NAME} || (log_err "Execution of ${FORMULA_NAME}.${state_name} failed"; exit 1) | 
|  | 149 |  | 
|  | 150 | # Check that all files in 'meta' folder can be rendered using any valid pillar | 
|  | 151 | for meta in `find ${FORMULA_META_DIR} -type f`; do | 
|  | 152 | meta_name=$(basename ${meta}) | 
|  | 153 | echo "Checking meta ${meta_name} ..." | 
|  | 154 | salt_run --out=quiet --id=${state_name} cp.get_template ${meta} ${SALT_CACHE_DIR}/${meta_name} \ | 
|  | 155 | || (log_err "Failed to render meta ${meta} using pillar ${FORMULA_NAME}.${state_name}"; exit 1) | 
|  | 156 | cat ${SALT_CACHE_DIR}/${meta_name} | 
|  | 157 | done | 
|  | 158 | done | 
|  | 159 | } | 
|  | 160 |  | 
|  | 161 | real_run() { | 
|  | 162 | for pillar in ${PILLARDIR}/*.sls; do | 
|  | 163 | state_name=$(basename ${pillar%.sls}) | 
|  | 164 | salt_run --id=${state_name} state.sls ${FORMULA_NAME} || (log_err "Execution of ${FORMULA_NAME}.${state_name} failed"; exit 1) | 
|  | 165 | done | 
|  | 166 | } | 
|  | 167 |  | 
|  | 168 | _atexit() { | 
|  | 169 | RETVAL=$? | 
|  | 170 | trap true INT TERM EXIT | 
|  | 171 |  | 
|  | 172 | if [ $RETVAL -ne 0 ]; then | 
|  | 173 | log_err "Execution failed" | 
|  | 174 | else | 
|  | 175 | log_info "Execution successful" | 
|  | 176 | fi | 
|  | 177 | return $RETVAL | 
|  | 178 | } | 
|  | 179 |  | 
|  | 180 | ## Main | 
|  | 181 | trap _atexit INT TERM EXIT | 
|  | 182 |  | 
|  | 183 | case $1 in | 
|  | 184 | clean) | 
|  | 185 | clean | 
|  | 186 | ;; | 
|  | 187 | prepare) | 
|  | 188 | prepare | 
|  | 189 | ;; | 
|  | 190 | run) | 
|  | 191 | run | 
|  | 192 | ;; | 
|  | 193 | real-run) | 
|  | 194 | real_run | 
|  | 195 | ;; | 
|  | 196 | *) | 
|  | 197 | prepare | 
|  | 198 | run | 
|  | 199 | ;; | 
|  | 200 | esac |