1015 lines
34 KiB
Bash
Executable File
1015 lines
34 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
|
|
trap ctctl_exit INT
|
|
|
|
# Print current environnement
|
|
ctctl_current_env(){
|
|
if [ -z "${CTCTL_DOMAIN}" ]; then
|
|
echo "Unknown container domain"
|
|
ctctl_exit
|
|
fi
|
|
echo "Cluster: ${CTCTL_DOMAIN}"
|
|
if [ -z "${CTCTL_ENV}" ]; then
|
|
echo "Unknown container environment"
|
|
ctctl_exit
|
|
fi
|
|
echo "Namespace: ${CTCTL_ENV}"
|
|
}
|
|
|
|
ctctl_check_env() {
|
|
if [ -n "${CTCTL_DOMAIN}" -a -n "${CTCTL_ENV}" ]; then
|
|
echo 1
|
|
else
|
|
echo 0
|
|
fi
|
|
}
|
|
|
|
ctctl_load_config(){
|
|
if [ -n "${CTCTL_DOMAIN}" -a -n "${CTCTL_ENV}" ]; then
|
|
# Load env configuration
|
|
if [ -e ~/.ctctl/${TARGET_DOM}/${CTCTL_ENV}.conf ]; then
|
|
set -o allexport
|
|
source ~/.ctctl/${TARGET_DOM}/${CTCTL_ENV}.conf
|
|
set +o allexport
|
|
fi
|
|
|
|
# Load post login configuration
|
|
if [ -e ~/.ctctl/${CTCTL_DOMAIN}/ctctl.local.conf ]; then
|
|
set -o allexport
|
|
source ~/.ctctl/${CTCTL_DOMAIN}/ctctl.local.conf
|
|
set +o allexport
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Switch to a target environment (either from no current, or from another current env)
|
|
ctctl_switch_env(){
|
|
TARGET_DOM=$1
|
|
TARGET_NAMESPACE=$2
|
|
|
|
if [ -z "${TARGET_DOM}" ]; then
|
|
TARGET_DOM=$(ctctl_ls_env | fzf --header "Select the container install you want to work on")
|
|
fi
|
|
|
|
if [ ! -e ~/.ctctl/${TARGET_DOM}/ctctl.conf ]; then
|
|
echo "Env ${TARGET_DOM} doesn't exist"
|
|
ctctl_exit
|
|
fi
|
|
|
|
# Clear any variable
|
|
for VAR in $(printenv | grep -E '^(CTCTL|CONSUL|VAULT|NOMAD)_.*' | sed -E 's/^([^=]+)=.*/\1/'); do
|
|
unset ${VAR}
|
|
done
|
|
|
|
export CTCTL_DOMAIN=${TARGET_DOM}
|
|
|
|
# Load default config
|
|
set -o allexport
|
|
source ~/.ctctl/${CTCTL_DOMAIN}/ctctl.conf
|
|
set +o allexport
|
|
|
|
# Load pre login env configuration
|
|
if [ -e ~/.ctctl/${CTCTL_DOMAIN}/pre-login.conf ]; then
|
|
set -o allexport
|
|
source ~/.ctctl/${CTCTL_DOMAIN}/pre-login.conf
|
|
set +o allexport
|
|
fi
|
|
|
|
# Authenticate so we can list Nomad's namespaces
|
|
ctctl_auth_env
|
|
|
|
if [ -z "${TARGET_NAMESPACE}" ]; then
|
|
if [ $(ctctl_ls_namespace | wc -w) -eq 1 ]; then
|
|
TARGET_NAMESPACE=$(ctctl_ls_namespace)
|
|
else
|
|
TARGET_NAMESPACE=$(ctctl_ls_namespace | fzf --header "Select the namespace you are working in")
|
|
fi
|
|
fi
|
|
export CTCTL_ENV=${TARGET_NAMESPACE}
|
|
|
|
# TODO : decide if we keep NOMAD_VAR_env
|
|
export NOMAD_VAR_env=${TARGET_NAMESPACE}
|
|
export NOMAD_NAMESPACE=${TARGET_NAMESPACE}
|
|
}
|
|
|
|
# Check if we have a valid token for vault
|
|
ctctl_check_vault_token(){
|
|
vault token lookup > /dev/null 2>&1
|
|
if vault token lookup > /dev/null 2>&1; then
|
|
echo 1
|
|
else
|
|
echo 0
|
|
fi
|
|
}
|
|
|
|
# Check if we have a valid token for consul
|
|
ctctl_check_consul_token(){
|
|
CONSUL_TOKEN_VALID=0
|
|
if [ -n "${CONSUL_HTTP_TOKEN}" ]; then
|
|
consul acl token read -self > /dev/null 2>&1
|
|
if [ $? == 0 ]; then
|
|
echo 1
|
|
else
|
|
echo 0
|
|
fi
|
|
else
|
|
echo 0
|
|
fi
|
|
}
|
|
|
|
# Check if we have a valid token for nomad
|
|
ctctl_check_nomad_token(){
|
|
if [ -n "${NOMAD_TOKEN}" ]; then
|
|
nomad acl token self > /dev/null 2>&1
|
|
if [ $? == 0 ]; then
|
|
echo 1
|
|
else
|
|
echo 0
|
|
fi
|
|
else
|
|
echo 0
|
|
fi
|
|
}
|
|
|
|
# Auth on vault, consul and nomad on the current env
|
|
ctctl_auth_env(){
|
|
if [ -z "${CTCTL_DOMAIN}" ]; then
|
|
echo "Unknown environment"
|
|
ctctl_exit
|
|
fi
|
|
|
|
NEED_LOGIN=1
|
|
if [ "$(ctctl_check_vault_token)" != "1" ]; then
|
|
if [ -e ~/.vault-token ]; then
|
|
# If VAULT_TOKEN is defined, unset it and try again. This is because we might
|
|
# have a valid token in ~/.vault-token but an expired token is set in VAULT_TOKEN
|
|
# and is taking precedence
|
|
export VAULT_TOKEN=$(cat ~/.vault-token)
|
|
if [ "$(ctctl_check_vault_token)" != "1" ]; then
|
|
unset VAULT_TOKEN
|
|
else
|
|
NEED_LOGIN=0
|
|
fi
|
|
fi
|
|
else
|
|
NEED_LOGIN=0
|
|
fi
|
|
if [ "${NEED_LOGIN}" = "1" ]; then
|
|
echo "You're not connected on vault. Please enter your account password"
|
|
local CTCTL_VAULT_AUTH="vault login -field=token ${VAULT_AUTH_CONFIG:--method=ldap username=${CTCTL_USER:-$(whoami | sed -r 's/\@.*//')}}"
|
|
export VAULT_TOKEN=$(${CTCTL_VAULT_AUTH} || ctctl_exit)
|
|
echo "Logged on vault successfuly"
|
|
else
|
|
echo "Your vault token is valid"
|
|
vault token renew > /dev/null 2>&1
|
|
fi
|
|
unset NEED_LOGIN
|
|
|
|
VAULT_TOKEN_INFO=$(vault token lookup -format=json)
|
|
|
|
# TODO make the role selection more generic
|
|
if [ "$(echo $VAULT_TOKEN_INFO | jq '.data.policies | any(. == "admin-policy" or .== "admin")')" == "true" ]; then
|
|
NOMAD_ROLE=admin
|
|
CONSUL_ROLE=admin
|
|
else
|
|
NOMAD_ROLE=user
|
|
CONSUL_ROLE=user
|
|
fi
|
|
|
|
# Root CA
|
|
vault read -field certificate pki/root/cert/ca > ~/.ctctl/${CTCTL_DOMAIN}/root_ca.crt
|
|
|
|
# Consul certificate
|
|
# Get/renew cert if required.
|
|
# Note 1: as the template is using pkiCert, the cert won't be renewed, unless necessary
|
|
# Note 2: don't pass CONSUL_CLIENT_CERT CONSUL_CLIENT_KEY and CONSUL_CACERT because they would prevent consul-template from starting
|
|
# to get/renew the cert if they are absent, or expired
|
|
env -u CONSUL_CLIENT_CERT \
|
|
-u CONSUL_CLIENT_KEY \
|
|
-u CONSUL_CACERT \
|
|
consul-template -config ~/.ctctl/${CTCTL_DOMAIN}/consul/consul-template.hcl -once
|
|
|
|
# Get/renew cert for Nomad now
|
|
consul-template -config ~/.ctctl/${CTCTL_DOMAIN}/nomad/consul-template.hcl -once
|
|
|
|
# Check if we have a valid nomad token already
|
|
if [ "$(ctctl_check_nomad_token)" != "1" ]; then
|
|
echo "Fecthing a Nomad token from vault"
|
|
NOMAD_CREDS=$(vault read -format=json ${VAULT_PREFIX:-}nomad/creds/${NOMAD_ROLE})
|
|
export NOMAD_TOKEN=$(echo -n ${NOMAD_CREDS} | jq -r .data.secret_id)
|
|
export NOMAD_VAULT_LEASE=$(echo -n ${NOMAD_CREDS} | jq -r .lease_id)
|
|
unset NOMAD_CREDS
|
|
else
|
|
echo "Nomad token is valid, renewing lease"
|
|
vault lease renew ${NOMAD_VAULT_LEASE} >/dev/null
|
|
fi
|
|
# Check if we have a valid consul token already
|
|
if [ "$(ctctl_check_consul_token)" != "1" ]; then
|
|
echo "Fetching a Consul token from vault"
|
|
CONSUL_CREDS=$(vault read -format=json ${VAULT_PREFIX:-}consul/creds/${CONSUL_ROLE})
|
|
export CONSUL_HTTP_TOKEN=$(echo -n ${CONSUL_CREDS} | jq -r .data.token)
|
|
export CONSUL_VAULT_LEASE=$(echo -n ${CONSUL_CREDS} | jq -r .lease_id)
|
|
unset CONSUL_CREDS
|
|
else
|
|
echo "Consul token is valid, renewing lease"
|
|
vault lease renew ${CONSUL_VAULT_LEASE} >/dev/null
|
|
fi
|
|
|
|
ctctl_load_config
|
|
}
|
|
|
|
ctctl_renew_leases(){
|
|
# Renew vault token
|
|
([ -n "${VAULT_TOKEN}" ] && vault token renew >/dev/null &)
|
|
([ -n "${NOMAD_VAULT_LEASE}" ] && vault lease renew ${NOMAD_VAULT_LEASE} >/dev/null &)
|
|
([ -n "${CONSUL_VAULT_LEASE}" ] && vault lease renew ${CONSUL_VAULT_LEASE} >/dev/null &)
|
|
}
|
|
|
|
# Logout from the current env
|
|
ctctl_logout_env(){
|
|
if [ -z "${CTCTL_DOMAIN}" ]; then
|
|
echo "Unknown environment"
|
|
ctctl_exit
|
|
fi
|
|
echo "Disconecting from ${CTCTL_DOMAIN} environment"
|
|
vault token revoke -self
|
|
for VAR in $(printenv | grep -E '^(CTCTL|CONSUL|VAULT|NOMAD|LOKI)_' | sed -E 's/^((CTCTL|CONSUL|VAULT|NOMAD|LOKI)_[^=]+)=.*/\1/'); do
|
|
unset $VAR
|
|
done
|
|
rm -f ~/.vault-token
|
|
}
|
|
|
|
# List available env
|
|
ctctl_ls_env(){
|
|
find ~/.ctctl/ -name ctctl.conf | xargs dirname | xargs basename -a
|
|
}
|
|
|
|
# List available namespaces
|
|
ctctl_ls_namespace(){
|
|
nomad namespace list -json | jq -r ".[] | .Name"
|
|
}
|
|
|
|
# List buildable Docker images
|
|
ctctl_ls_build_docker_images(){
|
|
(for JOB in $(find . -maxdepth 1 \( -name \*.nomad -o -name \*.nomad.hcl \)); do
|
|
nomad run -output $JOB | jq '.Job.TaskGroups' | jq '.[] | .Tasks' | jq -r '.[] | .Config.image' 2>/dev/null
|
|
done) | grep -E "${CTCTL_DOCKER_BUILD_REPO_REGEX:-docker-repo.ehtrace.com}" | sort -u
|
|
}
|
|
|
|
# Load policies for vault, Consul and Nomad
|
|
ctctl_load_policies(){
|
|
if [ "$(ctctl_check_env)" = "0" ]; then
|
|
echo "Not currently in a valid env. Run ctctl (with no argument) and select your env first"
|
|
ctctl_exit
|
|
fi
|
|
|
|
for DIR in ./output .; do
|
|
if [ -d "${DIR}/vault/policies" ]; then
|
|
if [ "$(ctctl_check_vault_token)" != "1" ]; then
|
|
echo "No valid vault token. You have to authenticate first"
|
|
ctctl_exit
|
|
fi
|
|
for PFILE in $(ls ${DIR}/vault/policies/*.hcl 2>/dev/null); do
|
|
if [ "${DIR}" = "./output" -a -e "$(echo ${PFILE} | sed -E 's|^\./output/|./|')" ]; then
|
|
echo "Skiping ${PFILE} as $(echo ${PFILE} | sed -E 's|^\./output/|./|') will take precedence"
|
|
continue
|
|
elif [ \! -s "${PFILE}" ]; then
|
|
echo "Skiping empty file ${PFILE}"
|
|
continue
|
|
fi
|
|
PNAME=$(basename ${PFILE} .hcl)
|
|
echo "Loading vault policy ${PNAME}"
|
|
ctctl_replace_conf_var ${PFILE} | vault policy write ${PNAME} -
|
|
done
|
|
fi
|
|
if [ -d "${DIR}/consul/policies" ]; then
|
|
if [ "$(ctctl_check_consul_token)" != "1" ]; then
|
|
echo "No valid consul token. You have to authenticate first"
|
|
ctctl_exit
|
|
fi
|
|
CONSUL_CUR_POLICIES=$(consul acl policy list -format=json)
|
|
for PFILE in $(ls ${DIR}/consul/policies/*.hcl 2>/dev/null); do
|
|
PNAME=$(basename ${PFILE} .hcl)
|
|
if [ "${DIR}" = "./output" -a -e "$(echo ${PFILE} | sed -E 's|^\./output/|./|')" ]; then
|
|
echo "Skiping ${FILE} as $(echo ${PFILE} | sed -E 's|^\./output/|./|') will take precedence"
|
|
continue
|
|
elif [ \! -s "${PFILE}" ]; then
|
|
echo "Skiping empty file ${PFILE}"
|
|
continue
|
|
fi
|
|
# Consul do not use the same command to create a new policy and to update an existing one
|
|
# so we need to detect if the policy already exists
|
|
if [ "$(echo ${CONSUL_CUR_POLICIES} | jq -r '.[] | select(.Name=='\"${PNAME}\"') | .Name')" == "${PNAME}" ]; then
|
|
echo "Updating consul policy ${PNAME}"
|
|
ctctl_replace_conf_var ${PFILE} | consul acl policy update -name=${PNAME} -rules=-
|
|
else
|
|
echo "Adding new consul policy ${PNAME}"
|
|
ctctl_replace_conf_var ${PFILE} | consul acl policy create -name=${PNAME} -rules=-
|
|
fi
|
|
done
|
|
fi
|
|
if [ -d "${DIR}/nomad/policies" ]; then
|
|
if [ "$(ctctl_check_nomad_token)" != "1" ]; then
|
|
echo "No valid nomad token. You have to authenticate first"
|
|
ctctl_exit
|
|
fi
|
|
for PFILE in $(ls ${DIR}/nomad/policies/*.hcl 2>/dev/null); do
|
|
PNAME=$(basename ${PFILE} .hcl)
|
|
if [ "${DIR}" = "./output" -a -e "$(echo ${PFILE} | sed -E 's|^\./output/|./|')" ]; then
|
|
echo "Skiping ${PFILE} as $(echo ${PFILE} | sed -E 's|^\./output/|./|') will take precedence"
|
|
continue
|
|
elif [ \! -s "${PFILE}" ]; then
|
|
echo "Skiping empty file ${PFILE}"
|
|
continue
|
|
fi
|
|
echo "Loading Nomad policy ${PNAME}"
|
|
ctctl_replace_conf_var ${PFILE} | nomad acl policy apply ${PNAME} -
|
|
done
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Load consul config
|
|
ctctl_load_consul_conf(){
|
|
|
|
for DIR in ./output .; do
|
|
if [ -d "${DIR}/consul/config" ]; then
|
|
if [ "$(ctctl_check_consul_token)" != "1" ]; then
|
|
echo "No valid consul token. You have to authenticate first"
|
|
ctctl_exit
|
|
fi
|
|
# Note : service-defaults should be loaded before the others
|
|
# but that should be the case
|
|
for FILE in $(ls ${DIR}/consul/config/*.hcl 2>/dev/null); do
|
|
if [ "${DIR}" = "./output" -a -e "$(echo ${FILE} | sed -E 's|^\./output/|./|')" ]; then
|
|
echo "Skiping ${FILE} as $(echo ${FILE} | sed -E 's|^\./output/|./|') will take precedence"
|
|
continue
|
|
elif [ \! -s "${FILE}" ]; then
|
|
echo "Skiping empty file ${FILE}"
|
|
continue
|
|
fi
|
|
echo "Loading consul conf from ${FILE}"
|
|
TEMP=$(mktemp)
|
|
ctctl_replace_conf_var ${FILE} > ${TEMP}
|
|
consul config write ${TEMP}
|
|
rm -f ${TEMP}
|
|
done
|
|
|
|
# Support storing consul config in subdir eg consul/config/service-defaults/foo.hcl
|
|
# Or you can even omit service and use consul/config/defaults/bar.hcl, consul/config/intentions/bar.hcl
|
|
for KIND in service-defaults service-intentions service-router service-resolver proxy-defaults; do
|
|
if [ -d ${DIR}/consul/config/${KIND} ]; then
|
|
for FILE in $(ls ${DIR}/consul/config/${KIND}/*.hcl 2>/dev/null); do
|
|
if [ "${DIR}" = "./output" -a -e "$(echo ${FILE} | sed -E 's|^\./output/|./|')" ]; then
|
|
echo "Skiping ${FILE} as $(echo ${FILE} | sed -E 's|^\./output/|./|') will take precedence"
|
|
continue
|
|
elif [ \! -s "${FILE}" ]; then
|
|
echo "Skiping empty file ${FILE}"
|
|
continue
|
|
fi
|
|
echo "Loading consul conf from ${FILE}"
|
|
TEMP=$(mktemp)
|
|
ctctl_replace_conf_var ${FILE} > ${TEMP}
|
|
consul config write ${TEMP}
|
|
rm -f ${TEMP}
|
|
done
|
|
fi
|
|
done
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Build all images for the current project
|
|
ctctl_build_required_images(){
|
|
for DOCKER_IMAGE in $(ctctl_ls_build_docker_images); do
|
|
if ! docker manifest inspect ${DOCKER_IMAGE} > /dev/null 2>&1; then
|
|
ctctl_build_image ${DOCKER_IMAGE}
|
|
else
|
|
echo "Image ${DOCKER_IMAGE} already available"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Build selected images
|
|
ctctl_build_selected_images(){
|
|
local NO_CACHE=$1
|
|
for DOCKER_IMAGE in $(ctctl_ls_build_docker_images | fzf -m --header "Select images to build (space to select, then enter)"); do
|
|
ctctl_build_image "${DOCKER_IMAGE}" ${NO_CACHE}
|
|
done
|
|
}
|
|
|
|
# Build a single image
|
|
ctctl_build_image(){
|
|
local DOCKER_IMAGE=$1
|
|
local NO_CACHE=$2
|
|
|
|
echo "Building image ${DOCKER_IMAGE}"
|
|
# Extract the basename of the image, removing the repo and the tag
|
|
local IMAGE_NAME=$(echo -n ${DOCKER_IMAGE} | sed -E 's/.+\/([^\/]+):.*/\1/')
|
|
export DOCKER_IMAGE=${DOCKER_IMAGE}
|
|
local LATEST=$(echo ${DOCKER_IMAGE} | sed 's/:.*/:latest/')
|
|
if [ "${NO_CACHE}" != "" ]; then
|
|
NO_CACHE="--no-cache"
|
|
else
|
|
NO_CACHE=""
|
|
fi
|
|
|
|
local FOUND=0
|
|
for DIR in ./images ./output/images; do
|
|
if [ -d $DIR/${IMAGE_NAME} ]; then
|
|
DOCKER_BUILDKIT=1 BUILDKIT_PROGRESS=plain docker build ${NO_CACHE} -t ${DOCKER_IMAGE} -t ${LATEST} ${CTCTL_DOCKER_BUILD_OPTS:-} $DIR/${IMAGE_NAME} &&\
|
|
docker push ${DOCKER_IMAGE} &&\
|
|
docker push ${LATEST}
|
|
FOUND=1
|
|
break
|
|
fi
|
|
done
|
|
if [ "${FOUND}" = "0" ]; then
|
|
echo "Couldn't find Docker image directory"
|
|
ctctl_exit
|
|
fi
|
|
}
|
|
|
|
# Run all executable in the render.d directory
|
|
ctctl_handle_render_scripts(){
|
|
for DIR in ./output ./; do
|
|
if [ -d "${DIR}/render.d" ]; then
|
|
for H in $(find ${DIR}/render.d -type f -o -type l | sort); do
|
|
if [ -x "${H}" ]; then
|
|
echo "Running render script ${H}"
|
|
$H $1
|
|
else
|
|
echo "Skiping render script $H (not executable)"
|
|
fi
|
|
done
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Run all executable in the prep.d directory
|
|
ctctl_handle_prep_scripts(){
|
|
for DIR in ./output ./; do
|
|
if [ -d "${DIR}/prep.d" ]; then
|
|
for H in $(find ${DIR}/prep.d -type f -o -type l | sort); do
|
|
if [ -x "${H}" ]; then
|
|
echo "Running prep script ${H}"
|
|
$H $1
|
|
else
|
|
echo "Skiping prep script $H (not executable)"
|
|
fi
|
|
done
|
|
fi
|
|
done
|
|
}
|
|
|
|
ctctl_add_submodule(){
|
|
local NAME=$1
|
|
local MODULE=$2
|
|
local URL=$3
|
|
local BRANCH=$4
|
|
local DIR=$5
|
|
|
|
mkdir -p ${DIR}
|
|
if [ ! -d ${DIR}/${NAME} ]; then
|
|
echo "Adding ${MODULE} submodule from ${URL} (branch ${BRANCH})"
|
|
git submodule add --branch ${BRANCH} --name ${MODULE} --force ${URL} ${DIR}/${NAME}
|
|
else
|
|
echo "Updating ${MODULE} submodule from ${URL} (branch ${BRANCH})"
|
|
# Get the git top-level, then compare with $(pwd) to get the correct relative path of the bundle,
|
|
# from the git parent root point of view (not from $(pwd))
|
|
local GIT_ROOT=$(git rev-parse --show-toplevel)
|
|
local CURRENT_DIR=$(pwd)
|
|
local MODULE_REL_DIR=$(echo ${CURRENT_DIR} | sed -E "s|^${GIT_ROOT}/||")
|
|
git submodule set-branch --branch ${BRANCH} -- ${MODULE_REL_DIR}/${DIR}/${NAME}
|
|
fi
|
|
git submodule update --init --recursive --remote --merge ${DIR}/${NAME}
|
|
}
|
|
|
|
# Update ctctl bundles with git
|
|
ctctl_update_submodules(){
|
|
if [ -e "bundles.yml" ]; then
|
|
for BUNDLE in $(yq e -o=j -I=0 '.bundles[]' bundles.yml); do
|
|
local URL=$(echo ${BUNDLE} | jq -r .url)
|
|
local BRANCH=$(echo ${BUNDLE} | jq -r .branch)
|
|
local NAME=$(basename ${URL} .git)
|
|
local MODULE=$(basename $(pwd))_${NAME}
|
|
|
|
# If the branch is not defined, default to master
|
|
if [ "${BRANCH}" = "null" ]; then
|
|
BRANCH=master
|
|
fi
|
|
ctctl_add_submodule ${NAME} ${MODULE} ${URL} ${BRANCH} bundles
|
|
if [ -e "bundles/${NAME}/bundles.yml" ]; then
|
|
for DEP in $(yq e -o=j -I=0 '.dependencies[]' bundles/${NAME}/bundles.yml); do
|
|
local DEP_URL=$(echo ${DEP} | jq -r .url)
|
|
local DEP_BRANCH=$(echo ${DEP} | jq -r .branch)
|
|
local DEP_NAME="${NAME}_$(basename ${DEP_URL} .git)"
|
|
local DEP_MODULE="${MODULE}_$(basename ${DEP_URL} .git)"
|
|
|
|
# If the branch is not defined, assume the same as the parent bundle
|
|
if [ "${DEP_BRANCH}" = "null" ]; then
|
|
DEP_BRANCH=${BRANCH}
|
|
fi
|
|
|
|
# Handle relative URL for dependencies
|
|
if echo ${DEP_URL} | grep -qE '^\.\./'; then
|
|
DEP_URL=$(dirname ${URL})/$(echo ${DEP_URL} | sed -E 's|^\.\./||')
|
|
fi
|
|
ctctl_add_submodule ${DEP_NAME} ${DEP_MODULE} ${DEP_URL} ${DEP_BRANCH} bundles
|
|
done
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
# Render templates using gomplate (or levant for backward compat)
|
|
ctctl_render_templates(){
|
|
|
|
# If a bundles.yml file exist, use the new gomplate rendering method
|
|
if [ -e "bundles.yml" ]; then
|
|
mkdir -p bundles
|
|
|
|
export CTCTL_BUNDLE_CONFIG=$(mktemp -t tmp.XXXXXXXXX.yml)
|
|
# First, cleanup any previously rendered files
|
|
rm -rf output ./*.nomad ./*.nomad.hcl
|
|
|
|
for BUNDLE in $(yq e -o=j -I=0 '.bundles[]' bundles.yml); do
|
|
local URL=$(echo ${BUNDLE} | jq -r .url)
|
|
local BRANCH=$(echo ${BUNDLE} | jq -r .branch)
|
|
local NAME=$(basename ${URL} .git)
|
|
|
|
if [ "${BRANCH}" = "null" ]; then
|
|
BRANCH=master
|
|
fi
|
|
|
|
echo "Working on the ${NAME} bundle"
|
|
if [ ! -d bundles/${NAME} ]; then
|
|
ctctl_update_submodules
|
|
fi
|
|
|
|
# Use [[ and ]] so it won't clash with consul-template fragments
|
|
local GOMPLATE_COMMON_ARGS=(--left-delim '[[' --right-delim ']]')
|
|
# Setup a vault datasource
|
|
GOMPLATE_COMMON_ARGS+=(-d vault=vault:///)
|
|
# And another datasource for the config of the bundle
|
|
if [ -e "bundles/${NAME}/variables.yml" ]; then
|
|
GOMPLATE_COMMON_ARGS+=(-d bundle=./bundles/${NAME}/variables.yml)
|
|
elif [ -e "bundles/${NAME}/variables.yaml" ]; then
|
|
GOMPLATE_COMMON_ARGS+=(-d bundle=./bundles/${NAME}/variables.yaml)
|
|
fi
|
|
|
|
# Declare named, external templates
|
|
if [ -d "bundles/${NAME}/templates" ]; then
|
|
GOMPLATE_COMMON_ARGS+=(--template ${NAME}=bundles/${NAME}/templates)
|
|
for SUBFOLDER in $(find bundles/${NAME}/templates -mindepth 1 -maxdepth 2 -type d); do
|
|
GOMPLATE_COMMON_ARGS+=(--template ${NAME}/$(basename ${SUBFOLDER})=${SUBFOLDER})
|
|
done
|
|
fi
|
|
if [ -e "bundles/${NAME}/bundles.yml" ]; then
|
|
for DEP in $(yq e -o=j -I=0 '.dependencies[]' bundles/${NAME}/bundles.yml); do
|
|
local DEP_URL=$(echo $DEP | jq -r .url)
|
|
local DEP_NAME="$(basename ${DEP_URL} .git)"
|
|
if [ -d "bundles/${NAME}_${DEP_NAME}/templates" ]; then
|
|
GOMPLATE_COMMON_ARGS+=(--template ${DEP_NAME}=bundles/${NAME}_${DEP_NAME}/templates)
|
|
for SUBFOLDER in $(find bundles/${NAME}_${DEP_NAME}/templates -mindepth 1 -maxdepth 2 -type d); do
|
|
GOMPLATE_COMMON_ARGS+=(--template ${DEP_NAME}/$(basename ${SUBFOLDER})=${SUBFOLDER})
|
|
done
|
|
fi
|
|
done
|
|
fi
|
|
GOMPLATE_COMMON_ARGS+=(--exclude .git* --exclude ./**/*.swp)
|
|
|
|
local GOMPLATE_BUNDLE_ARGS=(--input-dir "bundles/${NAME}")
|
|
# Do not render templates from dependencies, variables files, optional files directory content and images (images will be handled later)
|
|
GOMPLATE_BUNDLE_ARGS+=(--exclude bundles.yml --exclude variables.yml --exclude images/** --exclude templates/** --exclude files/** --exclude example/**)
|
|
|
|
# Now, render the merged config in a temp file
|
|
|
|
# Build a list of configuration file to merge
|
|
# Files are in order of precedence (firsts win)
|
|
# Note : if we have a bundle named foobar, and another named anything-foobar-conf
|
|
# Then consider anything-foobar-conf just provides config to override the foobar one. So put those first in the list
|
|
# so they will take precedence
|
|
I=0
|
|
local VAR_FILES=""
|
|
for FILE in ${NAME}.yml \
|
|
${NAME}.yaml \
|
|
${NOMAD_NAMESPACE}.yml \
|
|
${NOMAD_NAMESPACE}.yaml \
|
|
variables.yml \
|
|
variables.yaml \
|
|
../${NOMAD_NAMESPACE}.yml \
|
|
../${NOMAD_NAMESPACE}.yaml \
|
|
../variables.yml \
|
|
../variables.yaml \
|
|
bundles/*-${NAME}-conf/${NAME}.yml \
|
|
bundles/*-${NAME}-conf/${NAME}.yaml \
|
|
bundles/*-${NAME}-conf/variables.yml \
|
|
bundles/*-${NAME}-conf/variables.yaml \
|
|
bundles/${NAME}/variables.yml \
|
|
bundles/${NAME}/variables.yaml \
|
|
bundles/*/${NAME}.yml \
|
|
bundles/*/${NAME}.yaml \
|
|
bundles/*/variables.yml \
|
|
bundles/*/variables.yaml; do
|
|
if [ -e ${FILE} ]; then
|
|
if [ $I -eq 0 ]; then
|
|
VAR_FILES+='.=merge:'
|
|
else
|
|
VAR_FILES+='|'
|
|
fi
|
|
VAR_FILES+="${FILE}"
|
|
I=$((I+1))
|
|
fi
|
|
done
|
|
gomplate "${GOMPLATE_COMMON_ARGS[@]}" --context "${VAR_FILES[@]}" -i "[[ . | toYAML ]]" -o ${CTCTL_BUNDLE_CONFIG}
|
|
# And render it again so we can replace any templated values in the config itself
|
|
# Render it as many time as needed until no [[ ]] are found
|
|
while grep -q '\[\[' ${CTCTL_BUNDLE_CONFIG}; do
|
|
gomplate "${GOMPLATE_COMMON_ARGS[@]}" --context ${VAR_FILES} -f ${CTCTL_BUNDLE_CONFIG} -o ${CTCTL_BUNDLE_CONFIG}
|
|
done
|
|
GOMPLATE_COMMON_ARGS+=(--context .=file://${CTCTL_BUNDLE_CONFIG})
|
|
|
|
# This is used for two things
|
|
# - Add the consul.suffix to every files (except job files). This allows ctctl to simply infer the policy name from the file name
|
|
# - Rename all files by replacing the default .instance with the configured one
|
|
# - Put job files in the current dir for conveniance, and everything else in the output dir
|
|
local GOMPLATE_OUT_ARGS=(--output-map)
|
|
GOMPLATE_OUT_ARGS+=('[[ if (regexp.Match ".*\\.nomad(\\.hcl)?" .in) ]][[ .in | regexp.Replace (ds "bundle").instance .ctx.instance ]][[ else ]]output/[[ .in | path.Dir ]]/[[ .in | path.Base | regexp.Replace (ds "bundle").instance .ctx.instance | regexp.Replace "^([^\\.]+)\\.(.*)$" (printf "%s%s.%s" "$1" .ctx.consul.suffix "$2") ]][[ end ]]')
|
|
|
|
echo "Redering bundles with gomplate ${GOMPLATE_COMMON_ARGS[@]} ${GOMPLATE_BUNDLE_ARGS[@]} ${GOMPLATE_OUT_ARGS[@]}"
|
|
|
|
# Now render the bundle files
|
|
gomplate "${GOMPLATE_COMMON_ARGS[@]}" "${GOMPLATE_BUNDLE_ARGS[@]}" "${GOMPLATE_OUT_ARGS[@]}"
|
|
|
|
for IMGDIR in $(find . -name images -type d | grep -vE '^(./output|./bundles/.+/example)'); do
|
|
for DOCKER_IMAGE in $(find ${IMGDIR} -mindepth 1 -maxdepth 1 -type d); do
|
|
echo "Redering Docker image $(basename ${DOCKER_IMAGE})"
|
|
gomplate "${GOMPLATE_COMMON_ARGS[@]}" --input-dir ${DOCKER_IMAGE} --exclude resources/** --exclude root/** --output-dir output/images/$(basename ${DOCKER_IMAGE})/
|
|
for ROOT in resources root; do
|
|
if [ -d "${DOCKER_IMAGE}/${ROOT}" ]; then
|
|
cp -r "${DOCKER_IMAGE}/${ROOT}" output/images/$(basename ${DOCKER_IMAGE})/
|
|
fi
|
|
done
|
|
done
|
|
done
|
|
|
|
echo
|
|
echo "Formating job files"
|
|
find ./ -maxdepth 1 -type f \( -name \*nomad.hcl -o -name \*.nomad \) -exec nomad fmt {} \;
|
|
|
|
# Run render.d scripts
|
|
ctctl_handle_render_scripts
|
|
|
|
# And now delete the merged config
|
|
rm -f ${CTCTL_BUNDLE_CONFIG}
|
|
|
|
if [ "$(echo ${BUNDLE} | jq -r '.render_example // "false"')" = "true" ]; then
|
|
echo "Rendering example job with bundle variables only"
|
|
|
|
I=0
|
|
local VAR_FILES=""
|
|
for FILE in bundles/${NAME}/variables.yml \
|
|
bundles/${NAME}/variables.yaml \
|
|
bundles/*/variables.yml \
|
|
bundles/*/variables.yaml; do
|
|
if [ -e ${FILE} ]; then
|
|
if [ $I -eq 0 ]; then
|
|
VAR_FILES+='.=merge:'
|
|
else
|
|
VAR_FILES+='|'
|
|
fi
|
|
VAR_FILES+="${FILE}"
|
|
I=$((I+1))
|
|
fi
|
|
done
|
|
gomplate "${GOMPLATE_COMMON_ARGS[@]}" --context "${VAR_FILES[@]}" -i "[[ . | toYAML ]]" -o ${CTCTL_BUNDLE_CONFIG}
|
|
# And render it again so we can replace any templated values in the config itself
|
|
while grep -q '\[\[' ${CTCTL_BUNDLE_CONFIG}; do
|
|
gomplate "${GOMPLATE_COMMON_ARGS[@]}" --context ${VAR_FILES} -f ${CTCTL_BUNDLE_CONFIG} -o ${CTCTL_BUNDLE_CONFIG}
|
|
done
|
|
|
|
# First, cleanup any previously rendered files
|
|
rm -rf bundles/${NAME}/example/*
|
|
|
|
# Now render the bundle files
|
|
gomplate "${GOMPLATE_COMMON_ARGS[@]}" "${GOMPLATE_BUNDLE_ARGS[@]}" --output-dir=bundles/${NAME}/example
|
|
|
|
if [ -d "bundles/${NAME}/images" ]; then
|
|
for DOCKER_IMAGE in $(find bundles/${NAME}/images -mindepth 1 -maxdepth 1 -type d); do
|
|
gomplate "${GOMPLATE_COMMON_ARGS[@]}" --input-dir ${DOCKER_IMAGE} --exclude resources/** --exclude root/** --output-dir bundles/${NAME}/example/images/$(basename ${DOCKER_IMAGE})/
|
|
for ROOT in resources root; do
|
|
if [ -d "${DOCKER_IMAGE}/${ROOT}" ]; then
|
|
cp -r "${DOCKER_IMAGE}/${ROOT}" bundles/${NAME}/example/images/$(basename ${DOCKER_IMAGE})/
|
|
fi
|
|
done
|
|
done
|
|
fi
|
|
|
|
# Format example job files
|
|
find ./bundles/${NAME}/example -maxdepth 1 -type f \( -name \*nomad.hcl -o -name \*.nomad \) -exec nomad fmt {} \;
|
|
fi
|
|
|
|
done
|
|
rm -f ${CTCTL_BUNDLE_CONFIG}
|
|
unset CTCTL_BUNDLE_CONFIG
|
|
else
|
|
# backward compatible, levant based rendering
|
|
MERGED_CONF=$(mktemp tmp.XXXXXXXX.yml)
|
|
ctctl_get_merged_conf > ${MERGED_CONF}
|
|
|
|
ctctl_handle_render_scripts ${MERGED_CONF}
|
|
|
|
for TEMPLATE in $(find . -type f -name \*.tpl ! -path "*templates/*"); do
|
|
local DIR=$(dirname ${TEMPLATE})
|
|
local FILE=$(basename ${TEMPLATE} .tpl)
|
|
local DEST=${DIR}/${FILE}
|
|
echo "Rendering ${TEMPLATE} into ${DEST}"
|
|
# Note: render twice, so included templates get rendered too
|
|
levant render -var-file ${MERGED_CONF} -log-level=WARN <(levant render -var-file ${MERGED_CONF} -log-level=WARN ${TEMPLATE}) > ${DEST}
|
|
nomad fmt ${DEST}
|
|
done
|
|
|
|
rm -f ${MERGED_CONF}
|
|
fi
|
|
}
|
|
|
|
# Print Consul and Nomad tokens (not vault, for security reasons)
|
|
ctctl_print_tokens(){
|
|
if [ "$(ctctl_check_nomad_token)" == "1" ]; then
|
|
echo "Nomad token: ${NOMAD_TOKEN}"
|
|
else
|
|
echo "No valid Nomad token, you should auth with ctctl auth"
|
|
fi
|
|
if [ "$(ctctl_check_consul_token)" == "1" ]; then
|
|
echo "Consul token: ${CONSUL_HTTP_TOKEN}"
|
|
else
|
|
echo "No valid Consul token, you should auth with ctctl auth"
|
|
fi
|
|
}
|
|
|
|
# Follow current jobs logs
|
|
ctctl_loki_logs(){
|
|
# Remove the first arg passed to ctctl, which is logs
|
|
shift
|
|
local SELECTOR
|
|
local LOGCLI_CMD
|
|
|
|
if [ -z "${LOKI_ADDR}" ]; then
|
|
echo "You need to configure loki first (LOKI_ADDR, LOKI_USERNAME and LOKI_PASSWORD or LOKI_PWD_CMD)"
|
|
ctctl_exit
|
|
fi
|
|
|
|
if [ -n "${LOKI_PWD_CMD}" ]; then
|
|
export LOKI_PASSWORD=$(eval ${LOKI_PWD_CMD})
|
|
fi
|
|
|
|
LOGCLI_CMD="logcli query --include-label=job --include-label=group --include-label=task --include-label=alloc"
|
|
|
|
echo -n "$*" | grep -qP '\{.+\}' >/dev/null 2>&1
|
|
# If a logcli filter was given, use it. Else, build one for jobs in the current dir
|
|
if [ $? == 0 ]; then
|
|
echo "Running ${LOGCLI_CMD} $@"
|
|
${LOGCLI_CMD} $@
|
|
else
|
|
# Exclude connect-proxy logs as it's often not wanted
|
|
SELECTOR='{job=~"'$(ctctl_ls_jobs | sed -zE 's/\n/|/g' | sed -E 's/\s+//' | sed -E 's/\|$//')'", task!~"'${LOKI_IGNORE_TASKS:-connect-proxy-.+|tls-proxy|metrics-proxy|pgbouncer}'"}'
|
|
echo "Running ${LOGCLI_CMD} $@ ${SELECTOR}"
|
|
${LOGCLI_CMD} $@ "${SELECTOR}"
|
|
fi
|
|
unset LOKI_PASSWORD
|
|
}
|
|
|
|
### Helpers ###
|
|
|
|
# Merge the configuration files for the current env and return the result (as string)
|
|
ctctl_get_merged_conf() {
|
|
CONF_FILES=""
|
|
if [ -e "./vars/defaults.yml" ]; then
|
|
CONF_FILES="./vars/defaults.yml"
|
|
fi
|
|
if [ -e "jobs/common/vars/${CTCTL_ENV}.yml" ]; then
|
|
CONF_FILES="${CONF_FILES} jobs/common/vars/${CTCTL_ENV}.yml"
|
|
fi
|
|
if [ -e "../common/vars/${CTCTL_ENV}.yml" ]; then
|
|
CONF_FILES="${CONF_FILES} ../common/vars/${CTCTL_ENV}.yml"
|
|
fi
|
|
if [ -e "./vars/${CTCTL_ENV}.yml" ]; then
|
|
CONF_FILES="${CONF_FILES} ./vars/${CTCTL_ENV}.yml"
|
|
fi
|
|
if [ "${CONF_FILES}" != "" ]; then
|
|
echo "---"
|
|
yq ea '. as $item ireduce ({}; . * $item | ... comments="")' $CONF_FILES
|
|
else
|
|
echo -n ""
|
|
fi
|
|
}
|
|
|
|
# Replace ${local.conf.foo} or ${foo} with the value of foo from the various merged configuration files
|
|
# This is used to have policies (vault, consul, nomad) and config (consul intentions etc.) with variables
|
|
ctctl_replace_conf_var() {
|
|
MERGED_CONF=$(mktemp)
|
|
ctctl_get_merged_conf > $MERGED_CONF
|
|
RES=$(cat $1 | \
|
|
# Replace ${local.conf.foo} or ${foo} with the value of foo from the various merged configuration files \
|
|
# This is used to have policies (vault, consul, nomad) and config (consul intentions etc.) with variables \
|
|
perl -pe 'sub replace($) { my $val = shift; chomp(my $res = qx(yq .$val '$MERGED_CONF')); return $res; }; s!\$\{(local\.conf\.)?([^\}]+)\}! replace($2) !ge' | \
|
|
# Replace $(foo) with the output of foo command, mainly used to fetch secrets from vault \
|
|
perl -pe 'sub replace($) { my $val = shift; chomp(my $res = qx($val)); return $res; }; s!\$\(([^\)]+)\)! replace($1) !ge'
|
|
)
|
|
rm -f $MERGED_CONF
|
|
echo "${RES}"
|
|
}
|
|
|
|
# Get a value from the conf
|
|
ctctl_get_conf(){
|
|
ctctl_get_merged_conf | yq ".$1"
|
|
}
|
|
|
|
# Return a space separated list of jobs the current dir
|
|
ctctl_ls_jobs(){
|
|
local JOBS=""
|
|
if [ $(find . -maxdepth 1 \( -name \*.nomad -o -name \*.nomad.hcl \) | wc -l) -gt 0 ]; then
|
|
for JOBFILE in $(find . -maxdepth 1 \( -name \*.nomad -o -name \*.nomad.hcl \)); do
|
|
echo $(nomad run -output ${JOBFILE} | jq -r '.Job.Name')
|
|
done
|
|
else
|
|
# If current dir has no job file, return all running jobs
|
|
nomad job status -short | grep -E '\s+running\s+' | cut -d' ' -f1
|
|
fi
|
|
unset JOB JOBFILE
|
|
}
|
|
|
|
# Return a list of allocation for the given job
|
|
ctctl_ls_alloc_of_job(){
|
|
local JOB=$1
|
|
local IFS=$'\n'
|
|
for ALLOC in $(nomad alloc status -json | jq -c ".[] | select(.JobID==\"${JOB}\") | select(.ClientStatus==\"running\")" | sort); do
|
|
local ID="$(echo ${ALLOC} | jq -r .ID)"
|
|
local GROUP="$(echo ${ALLOC} | jq -r .TaskGroup)"
|
|
local ALLOC_INDEX="$(echo ${ALLOC} | jq -r .Name | sed -E "s/.*\[([0-9]+)\].*/\1/")"
|
|
local HOST="$(echo ${ALLOC} | jq -r .NodeName)"
|
|
echo "${ID} (Task group ${GROUP}, allocation index ${ALLOC_INDEX} on host ${HOST}"
|
|
done
|
|
unset JOB ID GROUP ALLOC_INDEX HOST
|
|
}
|
|
|
|
# Return a list of tasks for the given allocation
|
|
ctctl_ls_tasks_of_alloc(){
|
|
local ALLOC=$1
|
|
local IFS=$'\n'
|
|
for TASK in $(nomad alloc status -json "${ALLOC}" | jq -r '.TaskStates | to_entries[] | select(.value.State=="running") | select(.key | startswith("connect-proxy") | not) | .key' | sort); do
|
|
echo "${TASK}"
|
|
done
|
|
unset TASK ALLOC
|
|
}
|
|
|
|
# Exec a command in a container
|
|
ctctl_exec_ct(){
|
|
local IFS=$'\n'
|
|
local CMD=$1
|
|
|
|
ALLOCS=$(for JOB in $(ctctl_ls_jobs); do ctctl_ls_alloc_of_job ${JOB}; done)
|
|
if [ $(echo "${ALLOCS}" | wc -l) -eq 1 ]; then
|
|
ALLOC="${ALLOCS}"
|
|
else
|
|
ALLOC=$(echo "${ALLOCS}" | fzf --header "Select desired allocation")
|
|
fi
|
|
ALLOC=$(echo ${ALLOC} | sed -E 's/^([^ \(]+).*/\1/')
|
|
# Only Keep the UUID of the target alloc
|
|
ALLOC=$(echo ${ALLOC} | sed -E 's/^([^ \(]+).*/\1/')
|
|
TASKS=$(ctctl_ls_tasks_of_alloc "${ALLOC}")
|
|
if [ $(echo "${TASKS}" | wc -l) -eq 1 ]; then
|
|
TASK=${TASKS}
|
|
else
|
|
TASK=$(echo "${TASKS}" | fzf --header "Select desired task")
|
|
fi
|
|
echo "Running nomad alloc exec -task ${TASK} ${ALLOC} ${CMD}"
|
|
nomad alloc exec -task ${TASK} ${ALLOC} ${CMD}
|
|
unset TASKS TASK ALLOCS ALLOC CMD
|
|
}
|
|
|
|
# Enter a container by execing sh
|
|
# This is just a shortcut for exec sh
|
|
ctctl_enter_ct(){
|
|
ctctl_exec_ct sh
|
|
}
|
|
|
|
# Follow logs of a task
|
|
ctctl_alloc_logs(){
|
|
local IFS=$'\n'
|
|
ALLOCS=$(for JOB in $(ctctl_ls_jobs); do ctctl_ls_alloc_of_job ${JOB}; done)
|
|
if [ $(echo "${ALLOCS}" | wc -l) -eq 1 ]; then
|
|
ALLOC="${ALLOCS}"
|
|
else
|
|
ALLOC=$(echo "${ALLOCS}" | fzf --header "Select desired allocation")
|
|
fi
|
|
ALLOC=$(echo ${ALLOC} | sed -E 's/^([^ \(]+).*/\1/')
|
|
TASKS=$(ctctl_ls_tasks_of_alloc ${ALLOC})
|
|
if [ $(echo "${TASKS}" | wc -l) -eq 1 ]; then
|
|
TASK=${TASKS}
|
|
else
|
|
TASK=$(echo "${TASKS}" | fzf --header "Select desired task")
|
|
fi
|
|
echo "Running nomad alloc logs -f ${ALLOC} ${TASK}"
|
|
nomad alloc logs -f ${ALLOC} ${TASK}
|
|
unset ALLOCS ALLOC TASKS TASK
|
|
}
|
|
|
|
ctctl_exit(){
|
|
# Cleanup by unseting all functions
|
|
for FUNC in $(declare -F | grep -E '^declare -f ctctl_' | sed -E 's/^declare -f //'); do
|
|
unset -f ${FUNC}
|
|
done
|
|
# Remove trap on SIGINT
|
|
trap - INT
|
|
kill -INT $$
|
|
}
|
|
|
|
export FZF_DEFAULT_OPTS=${CTCTL_FZF_DEFAULT_OPTS:-"--height=~25% --cycle --bind 'space:toggle' --marker='*'"}
|
|
|
|
case $1 in
|
|
current)
|
|
ctctl_current_env
|
|
ctctl_renew_leases
|
|
;;
|
|
auth)
|
|
ctctl_auth_env
|
|
;;
|
|
disconnect)
|
|
ctctl_logout_env
|
|
;;
|
|
ls|list)
|
|
ctctl_ls_env
|
|
ctctl_renew_leases
|
|
;;
|
|
render)
|
|
ctctl_render_templates
|
|
ctctl_renew_leases
|
|
;;
|
|
fetch)
|
|
ctctl_update_submodules
|
|
ctctl_renew_leases
|
|
;;
|
|
prep|prepare)
|
|
ctctl_update_submodules
|
|
ctctl_render_templates
|
|
ctctl_handle_prep_scripts
|
|
ctctl_load_policies
|
|
ctctl_load_consul_conf
|
|
ctctl_build_required_images
|
|
ctctl_renew_leases
|
|
;;
|
|
load-conf)
|
|
ctctl_load_policies
|
|
ctctl_load_consul_conf
|
|
ctctl_renew_leases
|
|
;;
|
|
build)
|
|
ctctl_build_selected_images
|
|
ctctl_renew_leases
|
|
;;
|
|
build-no-cache)
|
|
ctctl_build_selected_images "no-cache"
|
|
ctctl_renew_leases
|
|
;;
|
|
tokens)
|
|
ctctl_print_tokens
|
|
ctctl_renew_leases
|
|
;;
|
|
logs)
|
|
shift
|
|
ctctl_alloc_logs "$@"
|
|
ctctl_renew_leases
|
|
;;
|
|
loki)
|
|
ctctl_loki_logs "$@"
|
|
ctctl_renew_leases
|
|
;;
|
|
conf)
|
|
ctctl_get_merged_conf
|
|
ctctl_renew_leases
|
|
;;
|
|
exec)
|
|
shift
|
|
ctctl_exec_ct "$@"
|
|
ctctl_renew_leases
|
|
;;
|
|
sh)
|
|
ctctl_enter_ct
|
|
ctctl_renew_leases
|
|
;;
|
|
switch)
|
|
shift
|
|
ctctl_switch_env "$@"
|
|
ctctl_auth_env
|
|
;;
|
|
*)
|
|
ctctl_switch_env "$@"
|
|
ctctl_auth_env
|
|
;;
|
|
esac
|
|
|
|
ctctl_exit
|