diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..a8d8f93 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,199 @@ +name: Test Composite Action + +on: [push, pull_request] + +jobs: + test-action: + runs-on: ubuntu-latest + services: + sshd: + image: rastasheep/ubuntu-sshd:jammy # Updated to jammy for Ubuntu 22.04 + ports: + - 2222:22 + # We will configure the sshd service using a step below + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Generate SSH keys & Configure Service Container + id: ssh_setup # Give an id to this step to reference its outputs + run: | + # Generate SSH keys + ssh-keygen -t rsa -b 2048 -f test_ssh_key -N "" + sudo apt-get update && sudo apt-get install -y sshpass netcat-openbsd + + echo "Waiting for SSH service (localhost:2222) to be ready..." + MAX_WAIT_ATTEMPTS=12 # Wait for up to 60 seconds (12 * 5s) + CURRENT_WAIT_ATTEMPT=0 + until nc -zv localhost 2222; do + CURRENT_WAIT_ATTEMPT=$((CURRENT_WAIT_ATTEMPT+1)) + if [ $CURRENT_WAIT_ATTEMPT -gt $MAX_WAIT_ATTEMPTS ]; then + echo "Service sshd on port 2222 did not become available." + exit 1 + fi + echo "Waiting for port 2222... attempt $CURRENT_WAIT_ATTEMPT" + sleep 5 + done + echo "SSH service port is open." + + echo "Ensuring /root/.ssh directory exists on service container..." + sshpass -p root ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 root@localhost "mkdir -p /root/.ssh && chmod 700 /root/.ssh" || { echo "Failed to create /root/.ssh on service container"; exit 1; } + + echo "Attempting to copy SSH public key to service container..." + MAX_SCP_ATTEMPTS=5 + COUNT=0 + while [ $COUNT -lt $MAX_SCP_ATTEMPTS ]; do + sshpass -p root scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -P 2222 ./test_ssh_key.pub root@localhost:/root/.ssh/authorized_keys && break + COUNT=$((COUNT+1)) + echo "SSH key copy attempt $COUNT failed. Retrying in 5s..." + sleep 5 + done + if [ $COUNT -eq $MAX_SCP_ATTEMPTS ]; then + echo "Failed to copy SSH key to service container after $MAX_SCP_ATTEMPTS attempts." + # For debugging, show if the .ssh directory exists + sshpass -p root ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 root@localhost "ls -la /root/ && ls -la /root/.ssh/" || echo "Failed to list /root/.ssh on service." + exit 1 + fi + echo "Copied generated public key to service container's /root/.ssh/authorized_keys." + + # Output keys for other steps + # Need to escape multi-line private key for ::set-output (deprecated) or GITHUB_OUTPUT + # Using GITHUB_OUTPUT format + echo "private_key<> $GITHUB_OUTPUT + cat test_ssh_key >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + echo "public_key=$(cat test_ssh_key.pub)" >> $GITHUB_OUTPUT + echo "Generated and set SSH key outputs for use in subsequent steps." + + - name: Setup Mock Docker Command + run: | + echo '#!/bin/bash' > ./docker_mock.sh + echo 'echo "DOCKER_MOCK_CALLED_WITH: $@" >> /tmp/docker_calls.log' >> ./docker_mock.sh + echo 'if [[ "$1" == "context" && "$2" == "create" ]]; then echo "Context created"; exit 0; fi' >> ./docker_mock.sh + echo 'if [[ "$1" == "context" && "$2" == "use" ]]; then echo "Context used"; exit 0; fi' >> ./docker_mock.sh + echo 'if [[ "$1" == "ps" ]]; then echo "CONTAINER ID IMAGE COMMAND"; exit 0; fi' >> ./docker_mock.sh + echo 'if [[ "$1" == "login" ]]; then echo "Login Succeeded"; exit 0; fi' >> ./docker_mock.sh + echo 'if [[ "$1" == "compose" && "$3" == "pull" ]]; then echo "Pulling done"; exit 0; fi' >> ./docker_mock.sh + echo 'if [[ "$1" == "compose" ]]; then echo "Compose command executed"; exit 0; fi' >> ./docker_mock.sh + echo 'if [[ "$1" == "stack" && "$2" == "deploy" ]]; then echo "Stack deploy command executed"; exit 0; fi' >> ./docker_mock.sh + echo 'exit 0' >> ./docker_mock.sh + chmod +x ./docker_mock.sh + sudo ln -sf "$PWD/docker_mock.sh" /usr/local/bin/docker + echo "Mock Docker command setup at /usr/local/bin/docker. Calls logged to /tmp/docker_calls.log" + # Ensure log file is clean before first test + rm -f /tmp/docker_calls.log + + # --- Test Case 1: Basic SSH and Docker Context (Compose ps) --- + - name: Test 1 - Basic SSH, Docker Context, Compose + uses: ./ # Uses the composite action in the root of the repository + with: + remote_docker_host: root@localhost + ssh_port: 2222 + ssh_private_key: ${{ steps.ssh_setup.outputs.private_key }} + ssh_public_key: ${{ steps.ssh_setup.outputs.public_key }} + args: "ps" # For docker compose ps + + - name: Verify Test 1 + shell: bash + run: | + echo "Verifying Test 1..." + if [ ! -f /tmp/docker_calls.log ]; then echo "Docker log not found!"; exit 1; fi + cat /tmp/docker_calls.log + grep -q "DOCKER_MOCK_CALLED_WITH: context create remote --docker host=ssh://root@localhost:2222" /tmp/docker_calls.log || exit 1 + grep -q "DOCKER_MOCK_CALLED_WITH: context use remote" /tmp/docker_calls.log || exit 1 + grep -q "DOCKER_MOCK_CALLED_WITH: ps" /tmp/docker_calls.log || exit 1 # From action's context setup test + grep -q "DOCKER_MOCK_CALLED_WITH: compose -f docker-compose.yml pull" /tmp/docker_calls.log || exit 1 + grep -q "DOCKER_MOCK_CALLED_WITH: compose -f docker-compose.yml ps" /tmp/docker_calls.log || exit 1 + echo "Test 1 Verification Successful" + rm -f /tmp/docker_calls.log + + # --- Test Case 2: Upload Directory --- + - name: Test 2 - Upload Directory + uses: ./ + with: + remote_docker_host: root@localhost + ssh_port: 2222 + ssh_private_key: ${{ steps.ssh_setup.outputs.private_key }} + ssh_public_key: ${{ steps.ssh_setup.outputs.public_key }} + upload_directory: 'true' + docker_compose_directory: '.github' # Upload this directory for testing + args: "ps" # Dummy args for compose + post_upload_command: "mkdir -p /tmp && echo 'post_upload_executed' > /tmp/post_upload.txt" + + - name: Verify Test 2 + shell: bash + run: | + echo "Verifying Test 2..." + sshpass -p root ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 root@localhost "ls -d /root/.github/workflows" || (echo "Uploaded directory not found" && exit 1) + sshpass -p root ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 root@localhost "cat /tmp/post_upload.txt | grep 'post_upload_executed'" || (echo "Post upload command verification failed" && exit 1) + echo "Test 2 Verification Successful" + sshpass -p root ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2222 root@localhost "rm -rf /root/.github /tmp/post_upload.txt" + rm -f /tmp/docker_calls.log + + # --- Test Case 3: Docker Swarm Mode --- + - name: Test 3 - Docker Swarm Mode + uses: ./ + with: + remote_docker_host: root@localhost + ssh_port: 2222 + ssh_private_key: ${{ steps.ssh_setup.outputs.private_key }} + ssh_public_key: ${{ steps.ssh_setup.outputs.public_key }} + docker_swarm: 'true' + args: "deploy --prune myapp" # Example swarm args + compose_file_path: "docker-stack.yml" + + - name: Verify Test 3 + shell: bash + run: | + echo "Verifying Test 3..." + if [ ! -f /tmp/docker_calls.log ]; then echo "Docker log not found!"; exit 1; fi + cat /tmp/docker_calls.log + grep -q "DOCKER_MOCK_CALLED_WITH: deploy --prune myapp stack deploy --compose-file docker-stack.yml" /tmp/docker_calls.log || exit 1 + echo "Test 3 Verification Successful" + rm -f /tmp/docker_calls.log + + # --- Test Case 4: Docker Login --- + - name: Test 4 - Docker Login + uses: ./ + with: + remote_docker_host: root@localhost + ssh_port: 2222 + ssh_private_key: ${{ steps.ssh_setup.outputs.private_key }} + ssh_public_key: ${{ steps.ssh_setup.outputs.public_key }} + args: "ps" # Dummy args + docker_login_user: "testuser" + docker_login_password: "testpassword" + docker_login_registry: "fakeregistry.com" + + - name: Verify Test 4 + shell: bash + run: | + echo "Verifying Test 4..." + if [ ! -f /tmp/docker_calls.log ]; then echo "Docker log not found!"; exit 1; fi + cat /tmp/docker_calls.log + grep -q "DOCKER_MOCK_CALLED_WITH: login -u testuser --password-stdin fakeregistry.com" /tmp/docker_calls.log || exit 1 + echo "Test 4 Verification Successful" + rm -f /tmp/docker_calls.log + + # --- Test Case 5: Tailscale SSH (mocked - verifies action proceeds without explicit key inputs) --- + - name: Test 5 - Tailscale SSH + uses: ./ + with: + remote_docker_host: root@localhost # Still need for Docker context setup + ssh_port: 2222 + tailscale_ssh: 'true' + args: "ps" + # ssh_private_key and ssh_public_key are intentionally omitted for this test case + + - name: Verify Test 5 + shell: bash + run: | + echo "Verifying Test 5 (Tailscale SSH mode)..." + if [ ! -f /tmp/docker_calls.log ]; then echo "Docker log not found!"; exit 1; fi + cat /tmp/docker_calls.log + # Essential Docker commands should still be logged by the mock + grep -q "DOCKER_MOCK_CALLED_WITH: context create remote --docker host=ssh://root@localhost:2222" /tmp/docker_calls.log || exit 1 + grep -q "DOCKER_MOCK_CALLED_WITH: compose -f docker-compose.yml ps" /tmp/docker_calls.log || exit 1 + echo "Test 5 Verification Successful" + rm -f /tmp/docker_calls.log diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index bf1561d..0000000 --- a/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM docker:cli - -COPY docker-entrypoint.sh /docker-entrypoint.sh - -ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/README.md b/README.md index d387ac6..75d290e 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,70 @@ -# Docker Compose Gitops +# Docker Compose Gitops Action A [GitHub Action](https://github.com/marketplace/actions/docker-compose-gitops) making GitOps with the simplicity of docker-compose possible, using SSH or optionally Tailscale SSH, with support for docker swarm, uploading directory for bind mounts and other features! -The Action is adapted from work by [TapTap21](https://github.com/TapTap21/docker-remote-deployment-action) and [wshihadeh](https://github.com/marketplace/actions/docker-deployment) +**Note:** This action has been refactored into a [composite action](https://docs.github.com/en/actions/creating-actions/creating-a-composite-action). This change aims to speed up workflow execution by eliminating the need to pull a Docker image for the action itself, running steps directly on the runner. The functionality and inputs remain the same. +The Action is adapted from work by [TapTap21](https://github.com/TapTap21/docker-remote-deployment-action) and [wshihadeh](https://github.com/marketplace/actions/docker-deployment). ## Example -Here is an example of how to use the action +Here is an example of how to use the action. Usage remains the same as before: ```yaml - name: Tailscale - uses: tailscale/github-action@ce41a99162202a647a4b24c30c558a567b926709 + uses: tailscale/github-action@v2 # Consider using a more specific version/commit SHA with: authkey: ${{ secrets.TAILSCALE_AUTHKEY }} - hostname: Github-actions + hostname: Github-actions # Optional: set a hostname for the Tailscale node - name: Start Deployment - uses: FarisZR/docker-compose-gitops-action@v1 + uses: FarisZR/docker-compose-gitops-action@v1 # Or your current version with: - remote_docker_host: root@100.107.201.124 - tailscale_ssh: true # no need for manual private and public keys + remote_docker_host: root@your_tailscale_ip_or_hostname # e.g., root@100.x.x.x or your custom hostname + tailscale_ssh: true # Set to true if using Tailscale for SSH compose_file_path: postgres/docker-compose.yml - upload_directory: true # upload docker directory - docker_compose_directory: postgres # directory to upload - docker_login_password: ${{ secrets.DOCKER_REPO_PASSWORD }} - docker_login_user: ${{ secrets.DOCKER_REPO_USERNAME }} - docker_login_registry : ${{ steps.login-ecr.outputs.registry }} - args: -p postgres up -d + upload_directory: true + docker_compose_directory: postgres + # Example Docker login (optional) + # docker_login_user: ${{ secrets.DOCKER_HUB_USER }} + # docker_login_password: ${{ secrets.DOCKER_HUB_PASSWORD }} + # docker_login_registry: docker.io # Optional, defaults to Docker Hub + args: -p postgres up -d --remove-orphans ``` ## Action Inputs -- `args` - Docker compose/stack command arguments. Example: `-p app_stack_name -d up` required -- `remote_docker_host` Specify Remote Docker host. The input value must be in the following format (user@host) required -- `tailscale_ssh` Enables Tailscale ssh mode, which uses managed ssh keys from Tailscale, and skips the private and public keys. default: false -- `ssh_public_key` Remote Docker SSH public key. Required when Tailscale ssh isn't enabled -- `ssh_private_key` SSH private key used in PEM format to connect to the docker host. Required when Tailscale ssh isn't enabled -- `ssh_port` The SSH port to be used. Default is 22. -- `compose_file_path` Docker compose file path. Default is `docker-compose.yml`(repo root), sub-directory Example: `caddy/docker-compose.yml` -- `upload_directory` Uploads docker compose directory, useful for extra files like Configs. Optional -- `docker_compose_directory` Specifies which directory in the repository to upload, needed for upload_directory -- `post_upload_command` Optional input to execute a command post upload, when `upload_directory` is enabled. Useful for things like changing permissions before starting containers. -- `docker_swarm` Uses docker swarm instead of compose by using the docker stack command, default: false -- `docker_login_user` The username for the container repository user. (DockerHub, ECR, etc.). Optional. -- `docker_login_password` The password for the container repository user. -- `docker_login_registry` The docker container registry to authenticate against Optional +The inputs remain unchanged: + +- `args` - Docker compose/stack command arguments. Example: `-p app_stack_name -d up` (required) +- `remote_docker_host` - Specify Remote Docker host. The input value must be in the following format `user@host` (required) +- `tailscale_ssh` - Enables Tailscale SSH mode, which leverages Tailscale's managed SSH connections. If `true`, the `ssh_public_key` and `ssh_private_key` inputs are not required by this action (though your Tailscale setup handles authentication). Default: `false` +- `ssh_public_key` - Remote Docker SSH public key. Required when `tailscale_ssh` is `false`. +- `ssh_private_key` - SSH private key used in PEM format to connect to the docker host. Required when `tailscale_ssh` is `false`. +- `ssh_port` - The SSH port to be used. Default is `22`. +- `compose_file_path` - Docker compose file path. Default is `docker-compose.yml` (in the repo root). Example for a sub-directory: `caddy/docker-compose.yml` +- `upload_directory` - If `true`, uploads the `docker_compose_directory`. Useful for configuration files needed alongside your containers. Default: `false` (Optional) +- `docker_compose_directory` - Specifies which directory in the repository to upload. Required if `upload_directory` is `true`. +- `post_upload_command` - Optional command to execute on the remote host after a successful upload (if `upload_directory` is `true`). Useful for tasks like setting file permissions. +- `docker_swarm` - If `true`, uses `docker stack deploy` for Docker Swarm mode instead of `docker compose`. Default: `false` +- `docker_login_user` - The username for your container registry (e.g., Docker Hub, GHCR, ECR). (Optional) +- `docker_login_password` - The password or access token for your container registry user. (Optional) +- `docker_login_registry` - The container registry hostname (e.g., `ghcr.io`, `your_aws_account_id.dkr.ecr.your_region.amazonaws.com`). If not specified, defaults to Docker Hub (`docker.io`). (Optional) + +## Development & Testing + +This action includes a testing workflow located at `.github/workflows/test.yml`. This workflow automatically tests various functionalities of the action upon pushes and pull requests. Key features of the testing setup include: + +- **Service Container:** An SSH server (`rastasheep/ubuntu-sshd`) is run as a service container to act as a mock remote host. +- **SSH Key Management:** SSH keys are dynamically generated and configured for communication between the action and the mock SSH server. +- **Docker Command Mocking:** The `docker` command is replaced with a mock script during tests. This script logs the calls made to `docker` (e.g., `context create`, `login`, `compose`, `stack deploy`), allowing verification of the action's command construction logic without requiring a full Docker-in-Docker setup. +- **Test Cases:** The workflow includes tests for: + - Basic SSH connectivity and Docker context setup. + - File uploads using `upload_directory` and `post_upload_command`. + - Docker Swarm mode (`docker_swarm: true`). + - Docker registry login. + - Tailscale SSH mode (verifying that SSH key inputs are not strictly required by the action). + +This testing suite helps ensure the reliability of the action and serves as a reference for future development. ## License diff --git a/action.yml b/action.yml index f9088c2..f274a51 100644 --- a/action.yml +++ b/action.yml @@ -1,29 +1,35 @@ -name: Docker-Compose gitops action -author: FarisZR -description: A GitHub Action making gitops with docker-compose easy. +name: Docker-Compose gitops action (Composite) +author: FarisZR (Composite by AI) +description: A GitHub Action making gitops with docker-compose easy (Composite Version). inputs: remote_docker_host: description: Remote Docker host ie (user@host) required: true ssh_public_key: description: Remote Docker SSH public key + required: false # Not required if tailscale_ssh is true ssh_private_key: description: SSH private key used to connect to the docker host + required: false # Not required if tailscale_ssh is true tailscale_ssh: description: Use Tailscale SSH to conncet to the server with managed SSH keys required: false + default: 'false' args: description: Deployment command args. required: true compose_file_path: description: path for Docker compose file used. Default is is repo root(docker-compose.yml) required: false + default: 'docker-compose.yml' ssh_port: description: The ssh port of the server. Default is 22 required: false + default: '22' upload_directory: description: when enabled, uploads entire docker directory, useful for configuration files needed along the container required: false + default: 'false' post_upload_command: description: sets command to run post upload, useful to fix permission issues in configuration files required: false @@ -36,6 +42,7 @@ inputs: docker_swarm: description: enables docker swarm mode (docker stack deploy), defaults to false required: false + default: 'false' docker_login_user: description: The docker login user required: false @@ -44,11 +51,140 @@ inputs: required: false runs: - using: docker - image: 'Dockerfile' + using: "composite" + steps: + - name: Input Validation and Defaults + shell: bash + run: | + if [[ -z "${{ inputs.remote_docker_host }}" ]]; then + echo "Input remote_docker_host is required!" + exit 1 + fi + if [[ "${{ inputs.tailscale_ssh }}" == "false" ]]; then + if [[ -z "${{ inputs.ssh_public_key }}" ]]; then + echo "Input ssh_public_key is required when not using Tailscale SSH!" + exit 1 + fi + if [[ -z "${{ inputs.ssh_private_key }}" ]]; then + echo "Input ssh_private_key is required when not using Tailscale SSH!" + exit 1 + fi + else + echo "Tailscale SSH mode enabled. Manual SSH keys not required if Tailscale handles SSH agent." + fi + + if [[ -z "${{ inputs.args }}" ]]; then + echo "Input args is required!" + exit 1 + fi + echo "COMPOSE_FILE_PATH=${{ inputs.compose_file_path }}" + echo "SSH_PORT=${{ inputs.ssh_port }}" + + - name: Setup SSH + shell: bash + run: | + set -eu + SSH_USER_HOST="${{ inputs.remote_docker_host }}" + SSH_HOST=$(echo "$SSH_USER_HOST" | sed 's/.*@//') # Extract host part + mkdir -p ~/.ssh + chmod 700 ~/.ssh + + if [[ "${{ inputs.tailscale_ssh }}" == "true" ]]; then + echo "Using Tailscale SSH. Assuming ssh-agent is managed by Tailscale or started if needed." + # Start ssh-agent if not already running (common practice for Tailscale SSH scenarios) + # The original script started ssh-agent even for Tailscale. + # However, Tailscale's own SSH often injects keys directly or expects agent to be running. + # For safety, we can ensure it's running. + if ! ssh-add -l >/dev/null 2>&1; then + echo "Starting ssh-agent for Tailscale SSH..." + eval $(ssh-agent -s) + else + echo "ssh-agent already running or has keys." + fi + else + echo "Registering SSH keys..." + echo "${{ inputs.ssh_private_key }}" > ~/.ssh/id_rsa + echo "${{ inputs.ssh_public_key }}" > ~/.ssh/id_rsa.pub + chmod 600 ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa.pub + eval $(ssh-agent -s) + ssh-add ~/.ssh/id_rsa + fi + + echo "Adding known hosts for $SSH_HOST on port ${{ inputs.ssh_port }}" + ssh-keyscan -p "${{ inputs.ssh_port }}" "$SSH_HOST" >> ~/.ssh/known_hosts + # Also add to system known_hosts for some tools that might look there, though user's known_hosts is primary for ssh client + sudo mkdir -p /etc/ssh + sudo ssh-keyscan -p "${{ inputs.ssh_port }}" "$SSH_HOST" >> /etc/ssh/ssh_known_hosts + + + - name: Setup Docker Context + shell: bash + run: | + set -eu + echo "Creating Docker context 'remote' for host ssh://${{ inputs.remote_docker_host }}:${{ inputs.ssh_port }}" + docker context create remote --docker "host=ssh://${{ inputs.remote_docker_host }}:${{ inputs.ssh_port }}" + docker context use remote + echo "Docker context 'remote' created and selected." + docker ps # Test command to verify context + + - name: Upload Directory + if: inputs.upload_directory == 'true' + shell: bash + run: | + set -eu + if [[ -z "${{ inputs.docker_compose_directory }}" ]]; then + echo "Input docker_compose_directory is required when upload_directory is enabled!" + exit 1 + fi + echo "Uploading directory '${{ inputs.docker_compose_directory }}' from $GITHUB_WORKSPACE to ${{ inputs.remote_docker_host }}..." + # Use ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null if issues with known_hosts persist for this specific command + tar cjvf - -C "$GITHUB_WORKSPACE" "${{ inputs.docker_compose_directory }}" | ssh -p "${{ inputs.ssh_port }}" "${{ inputs.remote_docker_host }}" 'tar -xjvf -' + echo "Upload finished." + + if [[ -n "${{ inputs.post_upload_command }}" ]]; then + echo "Running post-upload command: ${{ inputs.post_upload_command }}" + ssh -p "${{ inputs.ssh_port }}" "${{ inputs.remote_docker_host }}" "eval ${{ inputs.post_upload_command }}" + fi + + - name: Docker Login + if: inputs.docker_login_password != '' || inputs.docker_login_user != '' || inputs.docker_login_registry != '' + shell: bash + run: | + set -eu + if [[ -z "${{ inputs.docker_login_user }}" || -z "${{ inputs.docker_login_password }}" ]]; then + echo "Both docker_login_user and docker_login_password are required if one is provided for Docker login." + # exit 1 # Decide if this should be a fatal error or just a warning + fi + echo "Attempting Docker login to '${{ inputs.docker_login_registry || 'Docker Hub' }}'..." + docker login -u "${{ inputs.docker_login_user }}" --password-stdin <<< "${{ inputs.docker_login_password }}" ${{ inputs.docker_login_registry }} + echo "Docker login successful." + + - name: Execute Docker Command + shell: bash + run: | + set -eu + DOCKER_COMPOSE_COMMAND="docker compose" + if [[ "${{ inputs.docker_swarm }}" == "true" ]]; then + echo "Docker Swarm mode enabled. Using 'docker stack deploy'." + # Note: INPUT_ARGS in the original script was `docker ${INPUT_ARGS} stack deploy ...` + # This implies INPUT_ARGS could contain global docker options like --log-level. + # For simplicity here, assuming args are primarily for the deploy command itself. + # If INPUT_ARGS needs to be split for docker global options vs stack deploy options, this needs refinement. + echo "Command: docker ${{ inputs.args }} stack deploy --compose-file ${{ inputs.compose_file_path }}" + docker ${{ inputs.args }} stack deploy --compose-file "${{ inputs.compose_file_path }}" + else + echo "Using Docker Compose." + COMPOSE_FILE_ARG="-f ${{ inputs.compose_file_path }}" + echo "Pulling images for compose file: ${{ inputs.compose_file_path }}" + $DOCKER_COMPOSE_COMMAND $COMPOSE_FILE_ARG pull + + echo "Executing compose command: $DOCKER_COMPOSE_COMMAND $COMPOSE_FILE_ARG ${{ inputs.args }}" + $DOCKER_COMPOSE_COMMAND $COMPOSE_FILE_ARG ${{ inputs.args }} + fi + echo "Docker command executed." branding: icon: upload-cloud - color: orange - + color: green # Changed color to distinguish from original diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh deleted file mode 100755 index 19e0c03..0000000 --- a/docker-entrypoint.sh +++ /dev/null @@ -1,104 +0,0 @@ -#!/bin/sh -set -eu - -if [ -z "$INPUT_REMOTE_DOCKER_HOST" ]; then - echo "Input remote_docker_host is required!" - exit 1 -fi - -# Ignore SSH keys when using Tailscale SSH -if [ -n "$INPUT_TAILSCALE_SSH" ]; -then - echo "Tailscale SSH mode enabled, Manual SSH keys not required" -else - echo "Normal SSH mode, checking SSH keys" - if [ -z "$INPUT_SSH_PUBLIC_KEY" ]; then - echo "Input ssh_public_key is required!" - exit 1 - fi - - if [ -z "$INPUT_SSH_PRIVATE_KEY" ]; then - echo "Input ssh_private_key is required!" - exit 1 - fi -fi - -if [ -z "$INPUT_ARGS" ]; then - echo "Input input_args is required!" - exit 1 -fi - -if [ -z "$INPUT_COMPOSE_FILE_PATH" ]; then - INPUT_COMPOSE_FILE_PATH=docker-compose.yml -fi - -if [ -z "$INPUT_SSH_PORT" ]; then - INPUT_SSH_PORT=22 -fi - -DOCKER_HOST=ssh://${INPUT_REMOTE_DOCKER_HOST}:${INPUT_SSH_PORT} - -SSH_HOST=${INPUT_REMOTE_DOCKER_HOST#*@} - - -if [ -n "$INPUT_TAILSCALE_SSH" ]; -then - echo "Using Tailscale SSH, Skipping Manual SSH key registeration" - mkdir -p ~/.ssh - eval $(ssh-agent) -else - echo "Registering SSH keys..." - # register the private key with the agent, when not using Tailscale - mkdir -p ~/.ssh - ls ~/.ssh - printf '%s\n' "$INPUT_SSH_PRIVATE_KEY" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - printf '%s\n' "$INPUT_SSH_PUBLIC_KEY" > ~/.ssh/id_rsa.pub - chmod 600 ~/.ssh/id_rsa.pub - #chmod 600 "~/.ssh" - eval $(ssh-agent) - ssh-add ~/.ssh/id_rsa -fi - -echo "Add known hosts" -ssh-keyscan -p $INPUT_SSH_PORT "$SSH_HOST" >> ~/.ssh/known_hosts -ssh-keyscan -p $INPUT_SSH_PORT "$SSH_HOST" >> /etc/ssh/ssh_known_hosts -# set context -echo "Create docker context" -docker context create remote --docker "host=ssh://$INPUT_REMOTE_DOCKER_HOST:$INPUT_SSH_PORT" -docker context use remote - -if [ -n "$INPUT_UPLOAD_DIRECTORY" ]; -then - echo "upload_directory enabled" - if [ -z "$INPUT_DOCKER_COMPOSE_DIRECTORY" ]; - then - echo "Input docker_compose_directory is required when upload_directory is enabled!" - exit 1 - fi - tar cjvf - -C "$GITHUB_WORKSPACE" "$INPUT_DOCKER_COMPOSE_DIRECTORY" | ssh -o StrictHostKeyChecking=no "$INPUT_REMOTE_DOCKER_HOST" -p "$INPUT_SSH_PORT" 'tar -xjvf -' - echo "Upload finished" - if [ -n "$INPUT_POST_UPLOAD_COMMAND" ]; - then - echo "Upload post command specified, runnig. $INPUT_POST_UPLOAD_COMMAND" - ssh -o StrictHostKeyChecking=no "$INPUT_REMOTE_DOCKER_HOST" -p "$INPUT_SSH_PORT" "eval $INPUT_POST_UPLOAD_COMMAND" - fi -fi - -if [ -n "$INPUT_DOCKER_LOGIN_PASSWORD" ] || [ -n "$INPUT_DOCKER_LOGIN_USER" ] || [ -n "$INPUT_DOCKER_LOGIN_REGISTRY" ]; then - echo "Connecting to $INPUT_REMOTE_DOCKER_HOST... Command: docker login" - docker login -u "$INPUT_DOCKER_LOGIN_USER" -p "$INPUT_DOCKER_LOGIN_PASSWORD" "$INPUT_DOCKER_LOGIN_REGISTRY" -fi - -if [ -n "$INPUT_DOCKER_SWARM" ]; -then - echo "docker swarm mode enabled, using docker stack command" - echo "Command: docker ${INPUT_ARGS} stack deploy --compose-file ${INPUT_COMPOSE_FILE_PATH}" - docker ${INPUT_ARGS} stack deploy --compose-file ${INPUT_COMPOSE_FILE_PATH} -else - echo "Command: docker compose -f ${INPUT_COMPOSE_FILE_PATH} pull" - docker compose -f ${INPUT_COMPOSE_FILE_PATH} pull - - echo "Command: docker compose -f ${INPUT_COMPOSE_FILE_PATH} ${INPUT_ARGS}" - docker compose -f ${INPUT_COMPOSE_FILE_PATH} ${INPUT_ARGS} -fi