Add --lint flag for the 'deploy' action and a 'lint' action to validate the Docker compose/stack file

For this (optional) new feature, the 'docker-compose' tool must be installed,
see: https://docs.docker.com/compose/install/
This commit is contained in:
Tortue Torche 2019-08-11 02:30:47 -04:00 committed by Tortue Torche
parent a494dcbb79
commit c0a98d6505

58
psu
View File

@ -48,6 +48,7 @@ main() {
"masked-variables;-m;--masked-variables;In debug and/or verbose mode, the value of sensitive variables will be hidden, useful in CI to avoid leaking passwords/tokens in logs. Possible values: true|extended|false. Defaults to false"
"quiet;-q;--quiet;Display the minimum of information or nothing, UNIX/Linux friendly. Defaults to false"
"strict;-t;--strict;Never updates an existent stack nor removes an inexistent one, and instead exits with an error. Defaults to false"
"lint;-L;--lint;Validate the Docker compose/stack file before deploying the stack (only used when action=deploy). Defaults to false"
"help;-h;--help;Display help message. To display help of a given action, run: 'psu <action> --help'"
"version;-V;--version;Display the version of this program"
"secure;-s;--secure[=yes|no];DEPRECATED: Use the '--insecure' option instead. Enable or disable the host's SSL certificate verification. Defaults to 'yes'"
@ -56,7 +57,7 @@ main() {
ACTIONS_TABLE=(
# action_name;description[;required_option_key1|required_option_key2...][;optional_option_key1|optional_option_key2...]
"deploy;Deploy the stack;url|user|password|name|compose-file;auth-token|endpoint|env-file|prune|insecure|verbose|debug|masked-variables|strict"
"deploy;Deploy the stack;url|user|password|name|compose-file;auth-token|endpoint|lint|env-file|prune|insecure|verbose|debug|masked-variables|strict"
"undeploy;Undeploy/remove the stack;url|user|password|name;auth-token|endpoint|insecure|verbose|debug|masked-variables|strict"
"login;Log in to a Portainer instance;url|user|password;insecure|verbose|debug|masked-variables"
"list;Lists of the stacks already deployed;url|user|password;auth-token|endpoint|quiet|insecure|verbose|debug|masked-variables|help"
@ -67,14 +68,15 @@ main() {
"tasks;Lists tasks for the current stack;url|user|password|name;auth-token|endpoint|service|detect-job|timeout|quiet|insecure|verbose|debug|masked-variables"
"tasks:healthy;Lists tasks who are running correctly for the current stack;url|user|password|name;auth-token|endpoint|service|detect-job|timeout|quiet|insecure|verbose|debug|masked-variables"
"containers;Lists containers running for the current stack;url|user|password|name;auth-token|endpoint|service|quiet|insecure|verbose|debug|masked-variables"
"actions;Lists available actions of this program;;verbose|debug|masked-variables"
"lint;Validate the Docker compose/stack file;compose-file;verbose|debug"
"actions;Lists available actions of this program;;verbose|debug"
"help;Display help message"
"version;Display this program version"
)
# Special actions who display text only
# No HTTP requests are done
ACTIONS_TEXT_ONLY="actions help version"
# No HTTP requests will be made
ACTIONS_TEXT_ONLY="actions lint help version"
# Aliases of default actions
# NOTICE: This is an experimental feature
@ -325,6 +327,12 @@ main() {
exit 0
fi
# Lint the Docker compose/stack file
if [ $ACTION == "lint" ]; then
lint
exit 0
fi
# Get list of all actions who can be used for this program
if [ $ACTION == "actions" ]; then
echo "Portainer Stack Utils, version $VERSION"
@ -350,6 +358,7 @@ main() {
# PORTAINER_STACK_NAME #
# PORTAINER_SERVICE_NAME #
# DOCKER_COMPOSE_FILE #
# DOCKER_COMPOSE_LINT #
# ENVIRONMENT_VARIABLES_FILE #
# PORTAINER_ENDPOINT #
# PORTAINER_PRUNE #
@ -378,6 +387,7 @@ set_globals() {
PORTAINER_STACK_NAME=${PORTAINER_STACK_NAME}
PORTAINER_SERVICE_NAME=${PORTAINER_SERVICE_NAME}
DOCKER_COMPOSE_FILE=${DOCKER_COMPOSE_FILE}
DOCKER_COMPOSE_LINT=${DOCKER_COMPOSE_LINT:-"false"}
ENVIRONMENT_VARIABLES_FILE=${ENVIRONMENT_VARIABLES_FILE}
PORTAINER_ENDPOINT=${PORTAINER_ENDPOINT:-"1"}
PORTAINER_PRUNE=${PORTAINER_PRUNE:-"false"}
@ -402,6 +412,7 @@ set_globals() {
echo_debug "PORTAINER_STACK_NAME -> $PORTAINER_STACK_NAME"
echo_debug "PORTAINER_SERVICE_NAME -> $PORTAINER_SERVICE_NAME"
echo_debug "DOCKER_COMPOSE_FILE -> $DOCKER_COMPOSE_FILE"
echo_debug "DOCKER_COMPOSE_LINT -> $DOCKER_COMPOSE_LINT"
echo_debug "ENVIRONMENT_VARIABLES_FILE -> $ENVIRONMENT_VARIABLES_FILE"
echo_debug "PORTAINER_ENDPOINT -> $PORTAINER_ENDPOINT"
echo_debug "PORTAINER_PRUNE -> $PORTAINER_PRUNE"
@ -423,8 +434,8 @@ set_globals() {
fi
check_argument "$PORTAINER_URL" "portainer url" "PORTAINER_URL" "l" "url"
fi
if [ "$ACTION" == "deploy" ]; then
check_argument "$DOCKER_COMPOSE_FILE" "docker stack file" "DOCKER_COMPOSE_FILE" "f" "stack-file"
if [ "$ACTION" == "deploy" ] || [ "$ACTION" == "lint" ]; then
check_argument "$DOCKER_COMPOSE_FILE" "docker compose file" "DOCKER_COMPOSE_FILE" "c" "compose-file"
if [ -n "$ENVIRONMENT_VARIABLES_FILE" ] && [[ ! -f "$ENVIRONMENT_VARIABLES_FILE" ]]; then
echo_error "Error: File path \"$ENVIRONMENT_VARIABLES_FILE\" not found for \"ENVIRONMENT_VARIABLES_FILE\" environment variable or the \"-g\" flag or the \"--env-file\" option."
exit 1
@ -488,6 +499,13 @@ inputs() {
shift
fi
;;
-L|--lint|-L=*|--lint=*)
DOCKER_COMPOSE_LINT=$(input_flag "$1" "$2")
if [ -n "$2" ] && [[ ! $2 =~ ^-.+$ ]] ; then
# When the second argument is the value of the current option
shift
fi
;;
-g=*|--env-file=*|-g|--env-file)
ENVIRONMENT_VARIABLES_FILE=$(input_option "$1" "$2")
if [ -n "$2" ] && [[ ! $2 =~ ^-.+$ ]] ; then
@ -910,6 +928,7 @@ mask_variables() {
# Globals: #
# STACK #
# DOCKER_COMPOSE_FILE #
# DOCKER_COMPOSE_LINT #
# PORTAINER_STACK_NAME #
# PORTAINER_URL #
# ENVIRONMENT_VARIABLES_FILE #
@ -922,6 +941,10 @@ mask_variables() {
# None #
################################
deploy() {
# Lint docker-compose file if --lint option is "true"
if [ "$DOCKER_COMPOSE_LINT" == "true" ]; then
lint
fi
# Read docker-compose file content
local docker_compose_file_content
docker_compose_file_content="$( jq -Rscjr '{StackFileContent: . }' $DOCKER_COMPOSE_FILE | tail -c +2 | head -c -1 )"
@ -1236,6 +1259,29 @@ containers() {
echo "$containers"
}
lint() {
local docker_stack_error
local docker_stack_validation
if [ -x "$(command -v docker-compose)" ]; then
echo_verbose "Linting Docker compose/stack file..."
docker_stack_error="error_docker_stack_is_invalid"
docker_stack_validation=$(docker-compose -f "$DOCKER_COMPOSE_FILE" config -q > docker_stack_validation_report 2>&1 || echo $docker_stack_error)
if [[ $docker_stack_validation =~ $docker_stack_error$ ]]; then
echo_error "Error: The '$DOCKER_COMPOSE_FILE' Docker compose/stack file is invalid:"
echo_error "$(cat docker_stack_validation_report)"
rm -f docker_stack_validation_report
exit 1
else
echo "[OK]"
echo_verbose "The '$DOCKER_COMPOSE_FILE' Docker compose/stack file is valid"
fi
else
echo "WARNING: Cannot validate '$DOCKER_COMPOSE_FILE' file, 'docker-compose' is not installed or not executable."
echo_verbose "For more informations, see: https://docs.docker.com/compose/install/"
fi || true
}
display_options_message() {
echo "Options:"
local table