# Filename: /usr/share/ngcp-ngcpcfg/functions/main # Purpose: helper functions for ngcpcfg ################################################################################ # console output including timestamps {{{ timestamp_replacementchars='' # unset by default console_output() { if [ -z "${TIME_FORMAT:-}" ] ; then printf -- "$*" return 0 fi local timestamp="$(date "$TIME_FORMAT")" # indent depending on number of characters in date output timestamp_replacementchars="$(printf -- "%s: " "$timestamp" | sed 's/./ /g')" printf -- "$timestamp ${HNAME:-}: $*" } # }}} ## logging functions {{{ log_info() { logger -t ngcpcfg -- "$*" console_output "$*\n" } # info without ending newline log_info_n() { logger -t ngcpcfg -- "$*" console_output "$*" } log_warn() { logger -t ngcpcfg -- "Warning: $*" console_output "Warning: $*\n" } log_error() { logger -t ngcpcfg -- "Error: $*" console_output "Error: $*\n" >&2 } log_debug() { if [ -n "${DEBUG:-}" ] ; then logger -t ngcpcfg -- "Debug: $*" console_output "DEBUG: $*\n" >&2 fi } ## }}} hook_setup() { log_debug "hook_setup ${1:-}" if ! [ -d "${HOOKS}" ] ; then log_debug "Directory ${HOOKS} does not exist." return 0 fi local target_directory="$1" if [ -z "${1:-}" ] ; then log_error "Missing argument for target directory in hook_setup. Exiting." exit 1 fi if ! [ -d "$target_directory" ] ; then if [ "${NGCP_TESTSUITE:-false}" = "true" ]; then log_info "Hook target directory $target_directory not a directory. Creating it." mkdir -p "$target_directory" else log_error "Hook target directory $target_directory not a directory. Exiting." exit 1 fi fi for hook in "${HOOKS}"/* ; do [ -r "$hook" ] || continue log_debug "Creating symlink for $hook in $target_directory" ln -sf "$(readlink -f "$hook")" "$target_directory"/ done } compare_active_branch() { log_debug "get_active_branch ${1:-}" log_debug "cd $NGCPCTL_MAIN" cd "$NGCPCTL_MAIN" local current_branch current_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) log_debug "current_branch = $current_branch" echo "$current_branch" } get_branch_status() { log_debug "cd $NGCPCTL_MAIN" cd "$NGCPCTL_MAIN" log_debug "git rev-parse HEAD" local LOCAL=$(git rev-parse HEAD) log_debug "git rev-parse @{u}" local REMOTE=$(git rev-parse @{u}) log_debug "git merge-base HEAD @{u}" local BASE=$(git merge-base HEAD @{u}) if [ "$LOCAL" = "$REMOTE" ]; then # Up-to-date return 0 elif [ "$LOCAL" = "$BASE" ]; then # Need to pull return 1 elif [ "$REMOTE" = "$BASE" ]; then # Need to push return 2 else # Diverged return 3 fi } ## important variables we depend on to operate successfully {{{ # support test suite which requires system independent configuration if [ -r "${NGCPCFG:-}" ] ; then log_debug "sourcing configuration file ${NGCPCFG:-}" . "${NGCPCFG:-}" else if [ -r /etc/ngcp-config/ngcpcfg.cfg ] ; then . /etc/ngcp-config/ngcpcfg.cfg log_debug "sourced configuration file /etc/ngcp-config/ngcpcfg.cfg" if [ -d /etc/ngcp-config/ngcpcfg.d ] ; then for file in /etc/ngcp-config/ngcpcfg.d/*.cfg ; do if test -r $file ; then . $file log_debug "sourced configuration file $file" fi done fi elif [ -r /etc/ngcp-config-crypted.tgz.gpg ] ; then log_error "Configuration pool locked. Please contact your distributor. Exiting." exit 1 else log_error "Could not read configuration file /etc/ngcp-config/ngcpcfg.cfg. Exiting." exit 1 fi fi if ! [ -r "$NGCPCTL_CONFIG" ] ; then log_error "Configuration file ${NGCPCTL_CONFIG} does not exist (unconfigured?) - exiting." exit 1 fi if ! [ -r "$CONSTANTS_CONFIG" ] ; then log_error "Constants file ${CONSTANTS_CONFIG} does not exist (unconfigured?) - exiting." exit 1 fi if ! [ -n "${NETWORK_CONFIG:-}" ] ; then log_warn "NETWORK_CONFIG is not configured in $NGCPCTL_CONFIG - continuing anyway." elif ! [ -r "$NETWORK_CONFIG" ] ; then log_error "Constants file ${NETWORK_CONFIG} does not exist (unconfigured?) - exiting." exit 1 fi if ! [ -d "$TEMPLATE_POOL_BASE" ] ; then log_error "No template directory (${TEMPLATE_POOL_BASE}) found - exiting." exit 1 fi if [ -d "${EXTRA_CONFIG_DIR:-}" ] && ls ${EXTRA_CONFIG_DIR}/*.yml &>/dev/null ; then log_debug "EXTRA_CONFIG_DIR is configured and *.yml files are present, setting EXTRA_CONFIG_FILES" EXTRA_CONFIG_FILES=${EXTRA_CONFIG_DIR}/*.yml fi ## }}} ## environment variables {{{ export PN="ngcpcfg" export HNAME="$(hostname)" export NNAME="$(ngcp-nodename)" # avoid warnings by perl script complaining about locales export LANG=C export LC_ALL=C # make sure it's available in all helper scripts [ -n "${DEBUG:-}" ] && export DEBUG [ -n "${NO_DB_SYNC:-}" ] && export NO_DB_SYNC # export for access via build_config etc export CONFIG_POOL export HOST_CONFIG export LOCAL_CONFIG export NGCPCTL_CONFIG export CONSTANTS_CONFIG export NETWORK_CONFIG export EXTRA_CONFIG_DIR export EXTRA_CONFIG_FILES ## }}} ## HA / carrier features {{{ if [ -r /usr/share/ngcp-ngcpcfg/functions/ha_features ] ; then . /usr/share/ngcp-ngcpcfg/functions/ha_features set_ha_file # set $HA_FILE for usage in generate_template_list fi if [ -r /usr/share/ngcp-ngcpcfg/functions/carrier_features ] ; then . /usr/share/ngcp-ngcpcfg/functions/carrier_features set_host_and_pair_files # set $HOST_FILE + $PAIR_FILE for usage in generate_template_list fi ## }}} ## functions {{{ generate_template_list() { [ -n "$TEMPLATE_POOL_BASE" ] || return 1 local filelist_allfiles=$(mktemp) local filelist_prepared=$(mktemp) local filelist_final=$(mktemp) local filelist_sorted=$(mktemp) declare -a dirs_to_process=() for dir in ${CONFIG_POOL} ; do [ -n "${dir}" ] || ( echo "${dir} doesn't exist" >&2 ; continue ) dirs_to_process+=("$TEMPLATE_POOL_BASE/${dir}") done # find all files we should process find "${dirs_to_process[@]}" \ -name \*.tt2 \ -o -name \*.tt2"${HA_FILE:-}" \ -o -name \*.tt2"${HOST_FILE:-}" \ -o -name \*.tt2"${PAIR_FILE:-}" \ > "${filelist_allfiles}" # argument(s) (file list/pattern) provided via cmdline if [ -z "${1:-}" ] ; then cat "${filelist_allfiles}" >> "${filelist_prepared}" else # limit processing to requested file(s) only for arg in "$@"; do grep -- "${arg}" "${filelist_allfiles}" >> "${filelist_prepared}" done fi # remove all filenames where a preferred filename exists # foo.customtt.tt2.hostname > foo.customtt.tt2.pairname > foo.customtt.tt2.spX > foo.customtt.tt2 > foo.tt2.hostname > foo.tt2.pairname > foo.tt2.spX > foo.tt2 for line in $(cat ${filelist_prepared}); do # ignoring foo.patchtt.tt2.* completely (it is not a tt2 template to be built) if [[ "${line}" =~ .*\.patchtt\.tt2(.*)?$ ]]; then log_debug "Ignored patchtt file '${line}'" continue fi normalized_filename="$line" if [ -n "${HA_FILE:-}" ] ; then normalized_filename="${normalized_filename%${HA_FILE}}" fi if [ -n "${HOST_FILE:-}" ] ; then normalized_filename="${normalized_filename%${HOST_FILE}}" fi if [ -n "${PAIR_FILE:-}" ] ; then normalized_filename="${normalized_filename%${PAIR_FILE}}" fi normalized_filename="${normalized_filename%.customtt.tt2}" normalized_filename="${normalized_filename%.tt2}" # foo.custom.tt2.hostname if [ -n "${HOST_FILE:-}" ] ; then if grep -q -- "^${normalized_filename}.customtt.tt2${HOST_FILE}$" "${filelist_prepared}" ; then echo "${normalized_filename}.customtt.tt2${HOST_FILE}" >> "${filelist_final}" continue fi fi # foo.custom.tt2.pairname if [ -n "${PAIR_FILE:-}" ] ; then if grep -q -- "^${normalized_filename}.customtt.tt2${PAIR_FILE}$" "${filelist_prepared}" ; then echo "${normalized_filename}.customtt.tt2${PAIR_FILE}" >> "${filelist_final}" continue fi fi # foo.customtt.tt2.sp{1,2} if [ -n "${HA_FILE:-}" ] ; then if grep -q -- "^${normalized_filename}.customtt.tt2${HA_FILE:-}" "${filelist_prepared}" ; then echo "${normalized_filename}.customtt.tt2${HA_FILE:-}" >> "${filelist_final}" continue fi fi # foo.customtt.tt2 if grep -q -- "^${normalized_filename}.customtt.tt2$" "${filelist_prepared}" ; then echo "${normalized_filename}.customtt.tt2" >> "${filelist_final}" continue fi # foo.tt2.hostname if [ -n "${HOST_FILE:-}" ] ; then if grep -q -- "^${normalized_filename}.tt2${HOST_FILE}" "${filelist_prepared}" ; then echo "${normalized_filename}.tt2${HOST_FILE}" >> "${filelist_final}" continue fi fi # foo.tt2.pairname if [ -n "${HOST_FILE:-}" ] ; then if grep -q -- "^${normalized_filename}.tt2${PAIR_FILE}" "${filelist_prepared}" ; then echo "${normalized_filename}.tt2${PAIR_FILE}" >> "${filelist_final}" continue fi fi # foo.tt2.sp{1,2} if [ -n "${HA_FILE:-}" ] ; then if grep -q -- "^${normalized_filename}.tt2${HA_FILE}" "${filelist_prepared}" ; then echo "${normalized_filename}.tt2${HA_FILE}" >> "${filelist_final}" continue fi fi # another file not matching any previous checks echo "$line" >> "${filelist_final}" done sort -u ${filelist_final} >${filelist_sorted} # Output file list, make sure we provide the file names just once, and # special case the ngcp-service files, as they are a second stage source # of data required during configuration file building, which depends at # the same time on the main YAML files. grep ngcp-service ${filelist_sorted} || true grep -v ngcp-service ${filelist_sorted} || true if [ -n "${DEBUG:-}" ] ; then # send to stderr since stdout is used from outside log_debug "Not removing temporary filelist files since we are in debug mode:" >&2 log_debug " filelist_allfiles = ${filelist_allfiles}" >&2 log_debug " filelist_prepared = ${filelist_prepared}" >&2 log_debug " filelist_final = ${filelist_final}" >&2 log_debug " filelist_sorted = ${filelist_sorted}" >&2 else rm -f "${filelist_allfiles}" "${filelist_prepared}" "${filelist_final}" "${filelist_sorted}" fi unset filelist_allfiles filelist_prepared filelist_final dirs_to_process } record_commit_id() { log_debug "cd $NGCPCTL_MAIN" cd "$NGCPCTL_MAIN" log_debug "mkdir -p ${STATE_FILES_DIR}" mkdir -p "${STATE_FILES_DIR}" # if there are uncommitted changes then record it as such if git status --porcelain | grep -q . ; then echo "dirty" > "${STATE_FILES_DIR}/build" else local latest_commit=$(git log -1 --format="%H") log_debug "echo $latest_commit > ${STATE_FILES_DIR}/build" echo "$latest_commit" > "${STATE_FILES_DIR}/build" fi } is_git_clean() { log_debug "call 'git status --porcelain=v2'. it must have no output" if [ -z "$(git status --porcelain=v2)" ]; then return 0 else return 1 fi } ## }}} ## END OF FILE #################################################################