#!/bin/bash # Purpose: check/validate YAML config files (syntax, encoding, ...) ################################################################################ set -e set -u # support testsuite FUNCTIONS="${FUNCTIONS:-/usr/share/ngcp-ngcpcfg/functions/}" HELPER="${HELPER:-/usr/share/ngcp-ngcpcfg/helper/}" SCRIPTS="${SCRIPTS:-/usr/share/ngcp-ngcpcfg/scripts/}" if ! [ -r "${FUNCTIONS}"/main ] ; then printf "Error: %s/main could not be read. Exiting.\n" "${FUNCTIONS}" >&2 exit 1 fi # shellcheck disable=SC1090 . "${FUNCTIONS}"/main usage() { printf "ngcpcfg build -- supported command line options: --ignore-branch-check - do not fail build if branch doesn't match 'master' --ignore-shared-storage-check - skip check of shared storage\n\n" } CHECK_BRANCH=true CHECK_SHARED_STORAGE=true while [ -n "${1:-}" ] ; do case "$1" in *--ignore-branch-check*) CHECK_BRANCH=false ; shift ;; *--ignore-shared-storage-check*) CHECK_SHARED_STORAGE=false ; shift ;; *--help*) usage ; exit 0 ;; *) break ;; esac done check_branch() { if ! $CHECK_BRANCH ; then log_info "Option --ignore-branch-check is enabled, not checking for branch 'master'." return 0 fi local current_branch current_branch=$(compare_active_branch 'master') if [ "$current_branch" = 'master' ] ; then log_debug "Current branch is 'master', continuing." else log_error "branch '$current_branch' in '$NGCPCTL_MAIN' active - please switch to branch 'master' before continuing." exit 1 fi } check_origin() { if ! type -p execute_check_shared_storage &>/dev/null ; then log_debug "Skipping check_origin, does not look like PRO/CARRIER system." return 0 fi if [ "${NO_CHECK_ORIGIN:-}" = "1" ] ; then log_debug "Skipping check_origin (NO_CHECK_ORIGIN=1)." return 0 fi log_debug "check_origin" log_debug "cd ${NGCPCTL_MAIN}" cd "${NGCPCTL_MAIN}" local mgmtnode mgmtnode="$(cat /etc/ngcp_mgmt_node)" local expected_origin="${mgmtnode}:/mnt/glusterfs/ngcpcfg-share" if [ -n "${NGCPCTL_SHARE:-}" ] ; then expected_origin="${mgmtnode}:${NGCPCTL_SHARE}" log_debug "NGCPCTL_SHARE is set, using it for expected_origin ['${expected_origin}']" else log_debug "NGCPCTL_SHARE is unset, using default ['${expected_origin}'] setting for expected_origin" fi local actual_origin actual_origin="$(git remote get-url origin)" if [ "${actual_origin}" = "${expected_origin}" ] ; then log_debug "Current remote origin looks as expected [${expected_origin}]." else log_error "Remote origin of ngcpcfg is '$actual_origin', expected: '${expected_origin}'." log_error "NOTE: execute \`cd $NGCPCTL_MAIN ; git remote set-url origin '${expected_origin}'\` to adjust setting." log_error "NOTE: perform \`ngcpcfg clean --all\` to recreate local master branch from remote." exit 1 fi } check_config_encoding() { log_debug "Checking encoding for $config_files" for f in $config_files ; do if [ -r "$f" ] && ! file -L "$f" | grep -qe "UTF-8" -qe "ASCII" ; then log_error "Encoding check of ${f} fails: neither ASCII nor UTF-8." log_error "Please convert ${f} to UTF-8." log_info log_info "NOTE:" log_info "* Check encoding via:" log_info " # file ${f}" log_info "* To convert ISO-8859/latin1 to UTF-8 execute:" log_info " # iconv -f latin1 -t utf8 < ${f} > ${f}.tmp && mv ${f}.tmp ${f}" exit 1 fi done } check_config_syntax() { log_debug "Checking for valid YAML syntax for $config_files" for f in $config_files ; do if [ -r "$f" ] ; then # use YAML::XS for checking log_debug "Validating main YAML syntax of ${f}" if ! "${HELPER}/validate-yml" "${f}" 2>/dev/null ; then log_error "Invalid file syntax in ${f}:" "${HELPER}/validate-yml" "${f}" exit 1 fi fi done } check_configs() { check_config_encoding check_config_syntax } validate_config() { local rc=0 log_debug "Validating schema for main YAML files" for f in $config_files ; do local name name="$(basename "${f}")" if [ "$name" = 'network.yml' ]; then if ! ngcp-network-validator "$f"; then log_error "Invalid schema detected for ${f}" rc=1 fi else local schema schema="/usr/share/ngcp-cfg-schema/validate/${name}" if ! [ -f "${schema}" ] ; then continue fi local config_type config_type=$(basename "${name}" .yml) local c local c_cleanup=false case "${config_type}" in config|constants) c_cleanup=true c="$(mktemp -t "ngcpcfg-check-${config_type}.XXXXXXXXXX.yml")" "${SCRIPTS}/cat" "${config_type}" >"$c" ;; *) c="$f" ;; esac if ! pkwalify -s -m 'YAML::XS' -f "${schema}" "$c" >/dev/null 2>&1 ; then log_error "Invalid schema detected for $c" pkwalify -m 'YAML::XS' -f "${schema}" "$c" >&2 || true rc=1 fi if ${c_cleanup}; then rm -f "$c" fi fi done if [ "$rc" = "0" ] ; then log_info "yml configs were validated successfully" else if [ -n "${NO_VALIDATE:-}" ] ; then log_info "DANGEROUS ZONE: invalid configs detected, continue anyway due to option '--no-validate'" else log_error "Aborted, please fix issue(s) above and repeat." exit 1 fi fi } check_configs_conflicts() { log_debug "Checking merge conflicts in ngcp configs:" if grep -rP --exclude-dir='.git' --exclude='*.dpkg-*' \ '^>>>>>>> [0-9a-fA-F]+' /etc/ngcp-config/ >/dev/null 2>&1 then log_error "ERROR: ngcp configs with Git merge conflicts found:" grep -rP --exclude-dir='.git' --exclude='*.dpkg-*' \ '^>>>>>>> [0-9a-fA-F]+' /etc/ngcp-config/ >&2 exit 1 else log_debug "No ngcp configs with merge conflicts found." fi } check_shared_storage() { if ! ${CHECK_SHARED_STORAGE} ; then log_info "Option --ignore-shared-storage-check is enabled, skipping." return 0 fi # ensure there are no outstanding pull actions, # unless --no-action-failure is used (ignore then) if ! type -p execute_check_shared_storage &>/dev/null ; then log_debug "execute_check_shared_storage not available" return 0 fi log_debug "execute_check_shared_storage function, action pull" if [ "${NO_ACTION_FAILURE:-}" = "1" ] ; then if execute_check_shared_storage pull ; then log_debug "No outstanding pull actions identified (NO_ACTION_FAILURE=1)." else log_info "Ignoring outstanding pull actions as --no-action-failure option is enabled." fi return 0 fi execute_check_shared_storage pull && RC=0 || RC=$? if [ "$RC" = "0" ] ; then log_debug "No outstanding pull actions identified (NO_ACTION_FAILURE unset)." else log_info "Outstanding pull actions have been identified (see ACTION_NEEDED), exiting." log_info "TIP: '--no-action-failure' forces execution within 'apply' anyway (use with care!)." return $RC fi } if [ "$*" = "" ] ; then config_files="${NGCPCTL_CONFIG:-} ${NODE_CONFIG:-} ${PAIR_CONFIG:-} ${HOST_CONFIG:-} ${LOCAL_CONFIG:-} ${NETWORK_CONFIG:-} ${EXTRA_CONFIG_FILES[*]} ${CONSTANTS_CONFIG:-}" else config_files="$*" fi check_branch check_origin check_configs if "${VALIDATE_SCHEMA:-false}" || [ "${VALIDATE:-0}" = "1" ] ; then validate_config fi check_configs_conflicts check_shared_storage || exit $? log_info "configs were checked successfully" exit 0 ## END OF FILE #################################################################