diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ff10d7c..5d7776c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -256,7 +256,7 @@ jobs: ssh -v -i "${{ env.SSH_KEY_PRIVATE_PATH }}" -o 'UserKnownHostsFile=${{ env.KNOWN_HOST_PATH }}' -o 'StrictHostKeyChecking=yes' \ -p "${{ env.CONTAINER_HOST_PORT }}" "${{ env.SSH_USERNAME }}@${{ env.CONTAINER_HOST_NAME}}" docker info - test1: + test_basic: runs-on: ubuntu-latest name: "Basic" needs: ["utils", "generate_key", "build_run_test_service", "run_test_service"] @@ -280,7 +280,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 1 - - name: Start Deployment 1 - Basic + - name: Deployment uses: ./ with: deployment_mode: docker-swarm @@ -288,13 +288,12 @@ jobs: remote_docker_port: "${{ env.CONTAINER_PORT }}" remote_docker_username: "${{ env.SSH_USERNAME }}" ssh_private_key: "${{ needs.generate_key.outputs.private_key }}" - ssh_public_key: "${{ needs.run_test_service.outputs.ssh_server_public_key }}" stack_file_path: ./tests/docker-compose.yml - stack_name: nginx_1 + stack_name: nginx - test2: + test_public_key: runs-on: ubuntu-latest - name: "No pub key" + name: "Public key" needs: ["utils", "generate_key", "build_run_test_service", "run_test_service"] services: docker-throw-ssh: @@ -316,7 +315,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 1 - - name: Start Deployment 2 - No pub key + - name: Deployment uses: ./ with: deployment_mode: docker-swarm @@ -324,10 +323,11 @@ jobs: remote_docker_port: "${{ env.CONTAINER_PORT }}" remote_docker_username: "${{ env.SSH_USERNAME }}" ssh_private_key: "${{ needs.generate_key.outputs.private_key }}" + ssh_public_key: "${{ needs.run_test_service.outputs.ssh_server_public_key }}" stack_file_path: ./tests/docker-compose.yml - stack_name: nginx_2 + stack_name: nginx - test3: + test_background_deploy: runs-on: ubuntu-latest name: "Background deploy" needs: ["utils", "generate_key", "build_run_test_service", "run_test_service"] @@ -351,7 +351,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 1 - - name: Start Deployment 3 - Background deploy + - name: Deployment uses: ./ with: deployment_mode: docker-swarm @@ -359,12 +359,11 @@ jobs: remote_docker_port: "${{ env.CONTAINER_PORT }}" remote_docker_username: "${{ env.SSH_USERNAME }}" ssh_private_key: "${{ needs.generate_key.outputs.private_key }}" - ssh_public_key: "${{ needs.run_test_service.outputs.ssh_server_public_key }}" stack_file_path: ./tests/docker-compose.yml - stack_name: nginx_3 + stack_name: nginx deploy_foreground: false - test4: + test_debug: runs-on: ubuntu-latest name: "Debug" needs: ["utils", "generate_key", "build_run_test_service", "run_test_service"] @@ -388,7 +387,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 1 - - name: Start Deployment 4 - Debug + - name: Deployment uses: ./ with: deployment_mode: docker-swarm @@ -396,7 +395,93 @@ jobs: remote_docker_port: "${{ env.CONTAINER_PORT }}" remote_docker_username: "${{ env.SSH_USERNAME }}" ssh_private_key: "${{ needs.generate_key.outputs.private_key }}" - ssh_public_key: "${{ needs.run_test_service.outputs.ssh_server_public_key }}" stack_file_path: ./tests/docker-compose.yml - stack_name: nginx_4 + stack_name: nginx debug: true + + test_secrets: + runs-on: ubuntu-latest + name: "Secrets" + needs: ["utils", "generate_key", "build_run_test_service", "run_test_service"] + services: + docker-throw-ssh: + image: "ghcr.io/tristiisch/docker_throw_ssh_with_key:test-${{ needs.utils.outputs.short_sha }}" + ports: + - 2222:22 + options: > + --privileged + --tty + -v /sys/fs/cgroup:/sys/fs/cgroup + --cgroupns=host + --cap-add=NET_ADMIN + --cap-add=NET_RAW + --cap-add=SYS_ADMIN + --tmpfs /run + --tmpfs /run/lock + --tmpfs /tmp + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Deployment - Add secrets + uses: ./ + with: + deployment_mode: docker-swarm + remote_docker_host: "${{ env.CONTAINER_NAME }}" + remote_docker_port: "${{ env.CONTAINER_PORT }}" + remote_docker_username: "${{ env.SSH_USERNAME }}" + ssh_private_key: "${{ needs.generate_key.outputs.private_key }}" + stack_file_path: ./tests/docker-compose.yml + stack_name: nginx + secrets: web secrets_env key1 value1 key2 value2 + + - name: Deployment - Reusing secrets + uses: ./ + with: + deployment_mode: docker-swarm + remote_docker_host: "${{ env.CONTAINER_NAME }}" + remote_docker_port: "${{ env.CONTAINER_PORT }}" + remote_docker_username: "${{ env.SSH_USERNAME }}" + ssh_private_key: "${{ needs.generate_key.outputs.private_key }}" + stack_file_path: ./tests/docker-compose.yml + stack_name: nginx + secrets: web secrets_env key1 value1 key2 value2 + + - name: Deployment - Change secrets + uses: ./ + with: + deployment_mode: docker-swarm + remote_docker_host: "${{ env.CONTAINER_NAME }}" + remote_docker_port: "${{ env.CONTAINER_PORT }}" + remote_docker_username: "${{ env.SSH_USERNAME }}" + ssh_private_key: "${{ needs.generate_key.outputs.private_key }}" + stack_file_path: ./tests/docker-compose.yml + stack_name: nginx + secrets: web secrets_env key1_b value1_b key2_b value2_b + + - name: Deployment - Change secrets without deleting old ones + uses: ./ + with: + deployment_mode: docker-swarm + remote_docker_host: "${{ env.CONTAINER_NAME }}" + remote_docker_port: "${{ env.CONTAINER_PORT }}" + remote_docker_username: "${{ env.SSH_USERNAME }}" + ssh_private_key: "${{ needs.generate_key.outputs.private_key }}" + stack_file_path: ./tests/docker-compose.yml + stack_name: nginx + secrets: web secrets_env key1_c value1_c key2_c value2_c + secrets_delete_old: false + + - name: Deployment - Prune secrets + uses: ./ + with: + deployment_mode: docker-swarm + remote_docker_host: "${{ env.CONTAINER_NAME }}" + remote_docker_port: "${{ env.CONTAINER_PORT }}" + remote_docker_username: "${{ env.SSH_USERNAME }}" + ssh_private_key: "${{ needs.generate_key.outputs.private_key }}" + stack_file_path: ./tests/docker-compose.yml + stack_name: nginx_2 + secrets: web secrets_env_2 key1 value1 key2 value2 + secrets_prune: true diff --git a/Dockerfile b/Dockerfile index 74d49ae..cb0c062 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ LABEL 'com.github.actions.description'='supports docker-compose and Docker Swarm LABEL 'com.github.actions.icon'='send' LABEL 'com.github.actions.color'='green' -RUN apk --no-cache add openssh-client docker-compose yq +RUN apk --no-cache add openssh-client docker-compose jq yq WORKDIR /app diff --git a/action.yml b/action.yml index 3675761..c7ced41 100644 --- a/action.yml +++ b/action.yml @@ -18,7 +18,7 @@ inputs: required: true deployment_mode: description: 'Deployment mode: docker-swarm or docker-compose (default: docker-compose)' - default: './docker-compose' + default: 'docker-compose' copy_stack_file: description: 'Copy stack file to remote server and deploy from the server (default: false)' deploy_path: @@ -44,7 +44,13 @@ inputs: description: '[Docker Swarm] Waiting for the stack to complete the rolling update.' default: true secrets: - description: 'Update Docker Secret using rotation during Stack Update. Format is service_name secret_name key1 value1 key2 value2 ...' + description: 'Update Docker Secret using rotation during stack update. The format is: service_name secret_name key1 value1 key2 value2 ...' + secrets_delete_old: + description: 'Remove any replaced secrets during stack update (default: true).' + default: true + secrets_prune: + description: 'Remove all unused Docker secrets (default: false).' + default: false args: description: 'Command arguments for deployment' debug: diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index a24b4e0..686ac0b 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -84,7 +84,7 @@ case $INPUT_DEPLOYMENT_MODE in if [ -n "${INPUT_SECRETS+set}" ] && [ -n "$INPUT_SECRETS" ]; then POST_SCRIPTS_FOLDER="/opt/scripts/post" export POST_SCRIPTS_FOLDER - "$WORKDIR/scripts/docker_secrets.sh" "$INPUT_STACK_FILE_PATH" "$INPUT_STACK_NAME" $INPUT_SECRETS + "$WORKDIR/scripts/docker_secrets.sh" "$INPUT_STACK_FILE_PATH" "$INPUT_STACK_NAME" "$INPUT_SECRETS_DELETE_OLD" "$INPUT_SECRETS_PRUNE" $INPUT_SECRETS fi "$WORKDIR/scripts/docker_swarm.sh" @@ -98,7 +98,11 @@ esac # Execute post commands if any if [ -n "$POST_SCRIPTS_FOLDER" ] && [ -d "$POST_SCRIPTS_FOLDER" ]; then - find "$POST_SCRIPTS_FOLDER" -type f -executable -exec sh {} \; + debug "Execute post scripts in $POST_SCRIPTS_FOLDER ..." + find "$POST_SCRIPTS_FOLDER" -type f -executable | while read -r script; do + info "Execute post script $script ..." + sh "$script" + done fi # Delete temp file diff --git a/scripts/docker_secrets.sh b/scripts/docker_secrets.sh index 3a84d78..650bf5e 100755 --- a/scripts/docker_secrets.sh +++ b/scripts/docker_secrets.sh @@ -6,7 +6,7 @@ get_service_secrets() { service_name=$1 return_secrets="" - secrets=$(docker service inspect --format '{{ range .Spec.TaskTemplate.ContainerSpec.Secrets }}{{ .SecretName }} {{ end }}' "$service_name") + secrets=$(docker service inspect --format '{{ range .Spec.TaskTemplate.ContainerSpec.Secrets }}{{ .SecretID }} {{ end }}' "$service_name") for secret in $secrets; do return_secrets="$return_secrets$secret " done @@ -31,10 +31,10 @@ format_secret_input() { # Check if the secrets have been configured by this script is_secret_exists() { - old_service_sercrets="$1" + old_service_secrets="$1" secret_label_hash_name="$2" - for secret in $old_service_sercrets; do + for secret in $old_service_secrets; do old_hash=$(docker secret inspect "$secret" --format="{{index .Spec.Labels \"$secret_label_hash_name\"}}") if [ -n "$old_hash" ]; then return 0 @@ -43,14 +43,30 @@ is_secret_exists() { return 1 } +get_secrets_with_name() { + old_service_secrets="$1" + secret_label_name="$2" + name_to_retrieve="$3" + secrets_with_name="" + new_line=$(printf '\n') + + for secret in $old_service_secrets; do + old_hash=$(docker secret inspect "$secret" --format="{{index .Spec.Labels \"$secret_label_name\"}}") + if [ -n "$old_hash" ] && printf "%s" "$old_hash" | grep -q "$new_line" && [ "$old_hash" = "$name_to_retrieve" ]; then + secrets_with_name="$secrets_with_name$secret " + fi + done + echo "$secrets_with_name" +} + get_secrets_obsolete() { - old_service_sercrets="$1" + old_service_secrets="$1" secret_label_hash_name="$2" dotenv_secret_hash="$3" secret_obsolete="" new_line=$(printf '\n') - for secret in $old_service_sercrets; do + for secret in $old_service_secrets; do old_hash=$(docker secret inspect "$secret" --format="{{index .Spec.Labels \"$secret_label_hash_name\"}}") if [ -n "$old_hash" ] && printf "%s" "$old_hash" | grep -q "$new_line" && [ "$old_hash" != "$dotenv_secret_hash" ]; then secret_obsolete="$secret_obsolete$secret " @@ -60,13 +76,13 @@ get_secrets_obsolete() { } get_secrets_to_preserve() { - old_service_sercrets="$1" + old_service_secrets="$1" secret_label_hash_name="$2" dotenv_secret_hash="$3" secret_to_preserve="" new_line=$(printf '\n') - for secret in $old_service_sercrets; do + for secret in $old_service_secrets; do old_hash=$(docker secret inspect "$secret" --format="{{index .Spec.Labels \"$secret_label_hash_name\"}}") if [ -n "$old_hash" ] && printf "%s" "$old_hash" | grep -q "$new_line" && [ "$old_hash" = "$dotenv_secret_hash" ]; then secret_to_preserve="$secret_to_preserve$secret " @@ -75,12 +91,50 @@ get_secrets_to_preserve() { echo "$secret_to_preserve" } +prune_secrets() { + if ! command -v "jq" >/dev/null 2>&1; then + echo "jq is not installed. Please install it to prune secrets." + exit 1 + fi + if is_debug; then + debug "All secrets :" + for all_secret in $(docker secret ls -q); do + all_secret_name=$(get_secret_name "$all_secret") + printf "\"%s\" " "$all_secret_name" + done + printf "\n" + fi + used_secrets=$(docker service ls -q | xargs -I {} docker service inspect {} --format '{{json .Spec.TaskTemplate.ContainerSpec.Secrets}}' | jq -r 'select(. != null) | .[].SecretID' | sort -u) + if is_debug; then + debug "Secrets currently used :" + for used_secret in $used_secrets; do + used_secret_name=$(get_secret_name "$used_secret") + printf "\"%s\" " "$used_secret_name" + done + printf "\n" + fi + + for secret in $(docker secret ls -q); do + if ! echo "$used_secrets" | grep -qw "$secret"; then + secret_name=$(get_secret_name "$secret") + info "Prune unused secret: \"$secret_name\"" + docker secret rm "$secret" + fi + done +} + +get_secret_name() { + secret=$1 + secret_name=$(docker secret inspect "$secret" --format '{{.Spec.Name}}') + echo "$secret_name" +} + if ! command -v yq >/dev/null 2>&1; then echo "yq is needed to use this script." >&2 exit 1 fi -debug "docker_secret.sh $*" +debug "$0 \"$*\"" if [ -z "${1+set}" ] || [ -z "${2+set}" ] || [ -z "${3+set}" ] || [ -z "${4+set}" ]; then echo "Usage: $0 docker-compose.yml stack_name service_name secret_name key1 value1 key2 value2 ..." >&2 @@ -93,15 +147,18 @@ fi docker_compose_file_path=$1 stack_name=$2 -service_name=$3 -secret_name=$4 +secret_delete_old=$3 +secret_prune=$4 +service_name=$5 +secret_name=$6 service_fullname=${stack_name}_${service_name} secret_name_suffix=$(openssl rand -hex 2) secret_name_full="${secret_name}_${secret_name_suffix}" secret_values="" -secret_start_after=4 +secret_start_after=6 secret_label_hash_name="hash" +secret_label_name="name" # Check if there are enough arguments for key-value pairs num_args=$(($# - secret_start_after)) @@ -129,31 +186,66 @@ dotenv_secret=$(format_secret_input "$secret_values") # Hash indicates when to update the secret info "Calculating hash for secrets" dotenv_secret_hash=$(calculate_hash "$dotenv_secret") -debug "Result: $dotenv_secret_hash" +debug "Secret hash: $dotenv_secret_hash" + +if [ "$secret_prune" = "true" ]; then + info "Pruning secrets ..." + prune_secrets +fi -# Check if service exists +# Check if the service exists; if not, there are no old secrets to handle. if docker service inspect "$service_fullname" >/dev/null 2>&1; then - info "Fetching the current secrets for service $service_fullname" - old_service_sercrets=$(get_service_secrets "$service_fullname") - debug "Result: $old_service_sercrets" + info "Fetching all secrets for service \"$service_fullname\"" + old_service_secrets=$(get_service_secrets "$service_fullname") + if is_debug; then + debug "Secrets used by service \"$service_fullname\":" + for used_secret in $old_service_secrets; do + used_secret_name=$(get_secret_name "$used_secret") + printf "\"%s\" " "$used_secret_name" + done + printf "\n" + fi + + # TODO: test more than one secret + info "Fetching the secrets with name \"$secret_name\" for service \"$service_fullname\"" + old_service_secrets=$(get_secrets_with_name "$old_service_secrets" "$secret_label_name" "$secret_name") + if is_debug; then + debug "Secrets with name \"$secret_name\" used by service \"$service_fullname\":" + for used_secret in $old_service_secrets; do + used_secret_name=$(get_secret_name "$used_secret") + printf "\"%s\" " "$used_secret_name" + done + printf "\n" + fi info "Identifying secrets for removal" - secrets_obsolete=$(get_secrets_obsolete "$old_service_sercrets" "$secret_label_hash_name" "$dotenv_secret_hash") - if [ "$secrets_obsolete" != "" ]; then - info "Secrets to remove: $secrets_obsolete" + secrets_obsolete=$(get_secrets_obsolete "$old_service_secrets" "$secret_label_hash_name" "$dotenv_secret_hash") + if [ -n "$secrets_obsolete" ]; then + info "Secrets to remove:" + for secret_obsolete in $secrets_obsolete; do + secret_obsolete_name=$(get_secret_name "$secret_obsolete") + printf "\"%s\" " "$secret_obsolete_name" + done + printf "\n" fi info "Identifying secrets to preserve" - secrets_preserves=$(get_secrets_to_preserve "$old_service_sercrets" "$secret_label_hash_name" "$dotenv_secret_hash") + secrets_preserves=$(get_secrets_to_preserve "$old_service_secrets" "$secret_label_hash_name" "$dotenv_secret_hash") for secret_preserve in $secrets_preserves; do - info "Preserve the old secret \"$secret_preserve\" into the docker-compose file" - yq --inplace ".secrets.$secret_preserve.external = true" "$docker_compose_file_path" + secret_preserve_name=$(get_secret_name "$secret_preserve") + info "Preserve the old secret \"$secret_preserve_name\" into the docker-compose file" + yq --inplace ".secrets.$secret_preserve_name.external = true" "$docker_compose_file_path" - info "Updating the $service_name service within the docker-compose file with the old secret" - yq --inplace ".services.$service_name.secrets += [\"$secret_preserve\"]" "$docker_compose_file_path" + info "Updating the \"$service_name\" service within the docker-compose file with the old secret" + yq --inplace ".services.$service_name.secrets += [\"$secret_preserve_name\"]" "$docker_compose_file_path" done - if is_secret_exists "$old_service_sercrets" "$secret_label_hash_name" && [ "$secrets_obsolete" = "" ]; then + if is_debug; then + debug "Docker compose file $docker_compose_file_path :" + cat "$docker_compose_file_path" + fi + + if is_secret_exists "$old_service_secrets" "$secret_label_hash_name" && [ "$secrets_obsolete" = "" ]; then info "Secret rotation not needed" return fi @@ -161,8 +253,8 @@ else secrets_obsolete="" fi -info "Generate new secret: $secret_name_full" -printf '%b' "$dotenv_secret" | docker secret create "$secret_name_full" -l "$secret_label_hash_name=$dotenv_secret_hash" - +info "Generate new secret: \"$secret_name_full\"" +printf '%b' "$dotenv_secret" | docker secret create "$secret_name_full" -l "$secret_label_name=$secret_name" -l "$secret_label_hash_name=$dotenv_secret_hash" - info "Integrating the new secret \"$secret_name_full\" into the docker-compose file" yq --inplace ".secrets.$secret_name_full.external = true" "$docker_compose_file_path" @@ -170,16 +262,46 @@ yq --inplace ".secrets.$secret_name_full.external = true" "$docker_compose_file_ info "Updating the $service_name service within the docker-compose file with the new secret" yq --inplace ".services.$service_name.secrets += [\"$secret_name_full\"]" "$docker_compose_file_path" -if [ "$secrets_obsolete" != "" ]; then - info "Implementing post-command to remove previous secrets" - mkdir -p "$POST_SCRIPTS_FOLDER" - post_script_path="$POST_SCRIPTS_FOLDER\docker_secret_rm.sh" - touch "$post_script_path" - chmod 700 "$post_script_path" +if is_debug; then + debug "Docker compose file $docker_compose_file_path :" + cat "$docker_compose_file_path" +fi - for obsolete_secret in $secrets_obsolete; do - echo "docker secret remove \"$obsolete_secret\"" >> "$post_script_path" - done +if [ -n "$secrets_obsolete" ]; then + if [ "$secret_delete_old" = "true" ]; then + info "Implementing post-command to delete previous secrets" + debug "Creating post-script folder $POST_SCRIPTS_FOLDER" + mkdir -p "$POST_SCRIPTS_FOLDER" + post_script_path="$POST_SCRIPTS_FOLDER/docker_secret_rm.sh" + debug "Creating post-script file $post_script_path" + touch "$post_script_path" + chmod 700 "$post_script_path" + { + echo "#!/bin/sh" + if ! is_debug; then + echo "set -eu" + else + echo "set -eux" + fi + for obsolete_secret in $secrets_obsolete; do + echo "secret=\"$obsolete_secret\"" + echo "secret_name=\$(docker secret inspect \"\$secret\" --format '{{.Spec.Name}}')" + echo "echo \"Delete unused secret: \$secret_name\"" + echo "docker secret rm \"\$secret\"" + done + } >> "$post_script_path" + if is_debug; then + debug "Post-script file $post_script_path :" + cat "$post_script_path" + fi + else + info "Secrets not deleted because of secret deletion policy :" + for secret_obsolete in $secrets_obsolete; do + secret_obsolete_name=$(get_secret_name "$secret_obsolete") + printf "\"%s\" " "$secret_obsolete_name" + done + printf "\n" + fi fi info "Completion of Docker secret rotation" diff --git a/scripts/docker_swarm.sh b/scripts/docker_swarm.sh index 57408e5..f5b81ea 100755 --- a/scripts/docker_swarm.sh +++ b/scripts/docker_swarm.sh @@ -9,18 +9,28 @@ DEPLOYMENT_COMMAND="docker$DOCKER_OPTIONS stack deploy" if [ -n "$INPUT_DOCKER_REMOVE_ORPHANS" ] && [ "$INPUT_DOCKER_REMOVE_ORPHANS" = "true" ] ; then DEPLOYMENT_COMMAND="$DEPLOYMENT_COMMAND --prune" fi -if [ "$INPUT_DEPLOY_FOREGROUND" = "true" ] ; then - DEPLOYMENT_COMMAND="$DEPLOYMENT_COMMAND --detach=false" -elif [ "$INPUT_DEPLOY_FOREGROUND" = "false" ] ; then - DEPLOYMENT_COMMAND="$DEPLOYMENT_COMMAND --detach=true" -fi if [ -n "$INPUT_DOCKER_PRUNE" ] && [ "$INPUT_DOCKER_PRUNE" = "true" ] ; then info "Cleaning up Docker resources with pruning" yes | docker "$DOCKER_OPTIONS" system prune -a 2>&1 fi +info "Checking remote docker version" +execute_ssh_raw "docker --version" +docker_version=$(echo "$EXECUTE_SSH_RAW_OUTPUT" | cut -d ' ' -f 3 | cut -d '.' -f 1) +info "Remote docker version is $docker_version" + if [ "$INPUT_COPY_STACK_FILE" = "true" ] ; then + if [ "$docker_version" -ge 26 ]; then + if [ "$INPUT_DEPLOY_FOREGROUND" = "true" ] ; then + DEPLOYMENT_COMMAND="$DEPLOYMENT_COMMAND --detach=false" + elif [ "$INPUT_DEPLOY_FOREGROUND" = "false" ] ; then + DEPLOYMENT_COMMAND="$DEPLOYMENT_COMMAND --detach=true" + fi + elif [ "$INPUT_DEPLOY_FOREGROUND" = "true" ]; then + warning "Cannot deploy in foreground, it require Docker version 26, but you use Docker version $docker_version" + fi + STACK_FINAL_PATH="$INPUT_DEPLOY_PATH/$STACK_LOCAL_FILE" DEPLOYMENT_COMMAND="$DEPLOYMENT_COMMAND -c \"$STACK_FINAL_PATH\"" @@ -41,6 +51,11 @@ if [ "$INPUT_COPY_STACK_FILE" = "true" ] ; then execute_ssh "$DEPLOYMENT_COMMAND $INPUT_STACK_NAME $INPUT_ARGS" 2>&1 else + if [ "$INPUT_DEPLOY_FOREGROUND" = "true" ] ; then + DEPLOYMENT_COMMAND="$DEPLOYMENT_COMMAND --detach=false" + elif [ "$INPUT_DEPLOY_FOREGROUND" = "false" ] ; then + DEPLOYMENT_COMMAND="$DEPLOYMENT_COMMAND --detach=true" + fi DEPLOYMENT_COMMAND="$DEPLOYMENT_COMMAND -c \"$INPUT_STACK_FILE_PATH\"" info "Executing command on $DOCKER_USER_HOST" diff --git a/scripts/functions.sh b/scripts/functions.sh index 8d24961..ea136b8 100755 --- a/scripts/functions.sh +++ b/scripts/functions.sh @@ -22,15 +22,15 @@ setup_ssh() { mkdir -p "$SSH_FOLDER" chmod 700 "$SSH_FOLDER" if is_debug; then - debug "Verify permission on ssh folder" - ls -l "$SSH_FOLDER" + debug "Checking permissions on SSH folder at $SSH_FOLDER" + ls -ld "$SSH_FOLDER" fi info "Registering SSH key" printf '%s\n' "$INPUT_SSH_PRIVATE_KEY" > "$KEY_PATH" chmod 600 "$KEY_PATH" if is_debug; then - debug "Verify permission on private key" + debug "Checking permissions on private key at $KEY_PATH" ls -l "$KEY_PATH" fi @@ -63,15 +63,19 @@ EOF ls -l "$KNOWN_HOST_PATH" fi - KNOWN_HOST=$(cat "$KNOWN_HOST_PATH") - debug "$KNOWN_HOST_PATH :" "$KNOWN_HOST" + if is_debug; then + debug "SSH known host $KNOWN_HOST_PATH :" + cat "$KNOWN_HOST_PATH" + fi fi printf ' StrictHostKeyChecking %s\n' $STRICT_HOST >> "$SSH_CONFIG_PATH" - SSH_CONFIG=$(cat "$SSH_CONFIG_PATH") - debug "$SSH_CONFIG_PATH :" "$SSH_CONFIG" + if is_debug; then + debug "SSH config $SSH_CONFIG_PATH :" + cat "$SSH_CONFIG_PATH" + fi info "Testing SSH connection ..." - if is_debug; then + if is_running_debug; then ssh -v -p "$SSH_PORT" "$DOCKER_USER_HOST" exit else ssh -p "$SSH_PORT" "$DOCKER_USER_HOST" exit @@ -98,17 +102,25 @@ setup_remote_docker() { execute_ssh(){ SSH_PORT=$INPUT_REMOTE_DOCKER_PORT verbose_arg="" - if is_debug; then + if is_running_debug; then verbose_arg="-v" fi - debug "Execute Over SSH : $ $*" + debug "Execute over SSH : $ $*" ssh $verbose_arg -p "$SSH_PORT" "$DOCKER_USER_HOST" "$@" 2>&1 } +execute_ssh_raw(){ + SSH_PORT=$INPUT_REMOTE_DOCKER_PORT + debug "Execute over SSH with raw response : $ $*" + output=$(ssh -p "$SSH_PORT" "$DOCKER_USER_HOST" "$@") + debug "Output : $output" + export EXECUTE_SSH_RAW_OUTPUT="$output" +} + copy_ssh(){ SSH_PORT=$INPUT_REMOTE_DOCKER_PORT verbose_arg="" - if is_debug; then + if is_running_debug; then verbose_arg="-v" fi local_file="$1" @@ -124,6 +136,13 @@ is_debug() { return 0 } +is_running_debug() { + if [ -z "${RUNNER_DEBUG+set}" ] || [ "$RUNNER_DEBUG" != "1" ]; then + return 1 + fi + return 0 +} + # Define color variables BLACK='\e[0;30m' RED='\e[0;31m'