Current Path : /usr/bin/ |
Current File : //usr/bin/varnishreload |
#!/bin/sh # # Copyright (c) 2006-2021 Varnish Software AS # All rights reserved. # # Author: Dridi Boukelmoune <dridi.boukelmoune@gmail.com> # Author: Javier Bartley <javierbartley@yahoo.com> # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. set -e set -u MAXIMUM= VCL_FILE= VCL_LABEL= VCL_NAME= WARMUP= WORK_DIR= SCRIPT=$0 usage() { test $# -eq 1 && printf 'Error: %s.\n\n' "$1" cat <<-EOF Usage: $SCRIPT [-l <label>] [-m <max>] [-n <workdir>] [-p <prefix>] [-w <warmup>] [<file>] $SCRIPT -h Reload and use a VCL on a running Varnish instance. Available options: -h : show this help and exit -l <label> : name of the VCL label to reload -m <max> : maximum number of available reloads to leave behind -n <workdir> : specify the name or directory for the varnishd instance -p <prefix> : prefix for the name of the loaded and discarded VCLs -w <warmup> : the number of seconds between load and use operations When <label> is empty or missing, the active VCL is reloaded. If the reloaded VCL is a label, the underlying VCL program is reloaded, and the label is updated to reference the new program. When <prefix> is empty or missing, the names of the loaded and later discarded VCLs will start with 'reload'. When <file> is empty or missing, the selected VCL's file is used but reload will fail if it wasn't loaded from a file. The <file>, when specified, is passed as-is to the vcl.load command. Refer to the varnishd manual regarding the handling of absolute or relative paths. Upon success, the name of the loaded VCL is constructed from the prefix, current date and time, like for example: $(VCL_PREFIX=reload vcl_reload_name) Afterwards available VCLs created by this script are discarded until <max> are left, unless it was empty or undefined. VCLs referenced by a label aren't discarded. EOF exit $# } varnishadm() { if ! OUTPUT=$(command varnishadm -n "$WORK_DIR" -- "$@" 2>&1) then echo "Command: varnishadm -n '$WORK_DIR' -- $*" echo echo "$OUTPUT" echo return 1 fi >&2 echo "$OUTPUT" 2>/dev/null # silence "broken pipe" diagnostics } fail() { echo "Error: $*" >&2 exit 1 } vcl_reload_name() { # NB: The PID compensates the lack of sub-second resolution. # Varnish will vcl.list in chronological vcl.load order anyway. printf '%s_%s_%s' "$VCL_PREFIX" "$(date -u +%Y%m%d_%H%M%S)" $$ } awk_vcl_list() { printf '%s' "$VCL_LIST" | awk -F ' *|/' "$@" } active_vcl() { awk_vcl_list '$1 == "active" {print $5}' } find_label_ref() { awk_vcl_list '$5 == "'"$VCL_LABEL"'" && $6 == "->" {print $7}' } find_vcl_file() { varnishadm vcl.show -v "$VCL_NAME" | awk '$1 == "//" && $2 == "VCL.SHOW" {print; exit}' | { # all this ceremony to handle blanks in FILE read -r DELIM VCL_SHOW INDEX SIZE FILE && echo "$FILE" } || fail "failed to get the VCL file name" } find_vcl_reloads() { awk_vcl_list -v regex="^${VCL_PREFIX}_[0-9]+_[0-9]+_[0-9]+$" 'NF == 5 && $1 == "available" && $5 ~ regex {print $5}' } while getopts hl:m:n:p:w: OPT do case $OPT in h) usage ;; l) VCL_LABEL=$OPTARG ;; m) MAXIMUM=$OPTARG ;; n) WORK_DIR=$OPTARG ;; p) VCL_PREFIX=$OPTARG ;; w) WARMUP=$OPTARG ;; *) usage "wrong usage" >&2 ;; esac done shift $((OPTIND - 1)) test $# -gt 1 && usage "too many arguments" >&2 test $# -eq 1 && VCL_FILE=$1 VCL_LIST=$(varnishadm vcl.list) || fail "failed to get the VCL list" VCL_PREFIX=${VCL_PREFIX:-reload} VCL_PREFIX_CHK="$(printf '%s' "$VCL_PREFIX" | tr '[:space:]' :)" test "$VCL_PREFIX" = "$VCL_PREFIX_CHK" || fail "illegal character in VCL prefix ('\\n')" VCL_PREFIX_CHK="$(printf '%s' "$VCL_PREFIX" | tr -d A-Za-z0-9-_)" if [ -n "$VCL_PREFIX_CHK" ] then VCL_PREFIX_CHK="$(printf '%c' "$VCL_PREFIX_CHK")" fail "illegal character in VCL prefix ('$VCL_PREFIX_CHK')" fi VCL_PREFIX_CHK=$(printf '%c' "$VCL_PREFIX") test "$VCL_PREFIX_CHK" != _ || fail "illegal leading character in VCL prefix ('_')" if [ -z "$VCL_LABEL" ] then VCL_NAME=$(active_vcl) VCL_LABEL=$VCL_NAME VCL_REF=$(find_label_ref) if [ -n "$VCL_REF" ] then # active VCL is a label, swap VCL_LABEL=$VCL_NAME VCL_NAME=$VCL_REF else # not a label after all VCL_LABEL= fi else VCL_NAME=$(find_label_ref) fi test -n "$VCL_NAME" || fail "'$VCL_LABEL' is not a label" if [ -z "$VCL_FILE" ] then VCL_FILE=$(find_vcl_file) case $VCL_FILE in /*) ;; *) fail "VCL file not found for $VCL_NAME (got $VCL_FILE)" ;; esac fi RELOAD_NAME=$(vcl_reload_name) varnishadm vcl.load "$RELOAD_NAME" "\"$VCL_FILE\"" >/dev/null echo "VCL '$RELOAD_NAME' compiled" test -n "$WARMUP" && sleep "$WARMUP" if [ -n "$VCL_LABEL" ] then varnishadm vcl.label "$VCL_LABEL" "$RELOAD_NAME" >/dev/null echo "VCL label '$VCL_LABEL' references '$RELOAD_NAME'" fi if [ "$VCL_NAME" = "$(active_vcl)" ] then varnishadm vcl.use "$RELOAD_NAME" fi test -n "$MAXIMUM" || exit 0 test "$MAXIMUM" -ge 0 || exit 0 VCL_LIST=$(varnishadm vcl.list) || fail "failed to refresh the VCL list" AVAILABLE=$(find_vcl_reloads | wc -l) DISCARDED=$((AVAILABLE - MAXIMUM)) test "$DISCARDED" -gt 0 || exit 0 find_vcl_reloads | head -n "$DISCARDED" | while read -r DISCARD_NAME do varnishadm vcl.discard "$DISCARD_NAME" >/dev/null echo "VCL '$DISCARD_NAME' discarded" done