From 17b73c955543677c264c0530e16bcafda93b89ff Mon Sep 17 00:00:00 2001 From: Andrew Cutler Date: Thu, 9 Jan 2025 13:29:40 +1100 Subject: [PATCH] Add Image-Triggers support --- Dockerfile | 20 +++++++ ansible-bootstrap/main.yml | 1 + ansible-bootstrap/scripts.yml | 16 ++++++ .../templates/trigger_registry_rules.sh.j2 | 29 ++++++++++ .../templates/trigger_rundeck_job.sh.j2 | 56 +++++++++++++++++++ 5 files changed, 122 insertions(+) create mode 100644 ansible-bootstrap/templates/trigger_registry_rules.sh.j2 create mode 100644 ansible-bootstrap/templates/trigger_rundeck_job.sh.j2 diff --git a/Dockerfile b/Dockerfile index 8e2f587..58484dd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -125,6 +125,26 @@ RUN set -x \ && rm -rf /tmp/k8s-sidecar \ ; +# Install Image Triggers +ENV IMAGE_TRIGGERS_VERSION=0.0.4 \ + IMAGE_TRIGGERS_CHECKSUM_X86_64=d48257a84ca50a9d955a5e41ba954e68724ad0a6baf5ecf4fab8120262925efc \ + IMAGE_TRIGGERS_CHECKSUM_AARCH64=b242e58d4502e11542d64e5d4905c7f480a0444a3081b03ba9f3d6d7256ef298 +RUN set -x \ + && if [ "$(uname -m)" = "x86_64" ] ; then \ + IMAGE_TRIGGERS_CHECKSUM="${IMAGE_TRIGGERS_CHECKSUM_X86_64}"; \ + ARCH="linux_amd64"; \ + elif [ "$(uname -m)" = "aarch64" ]; then \ + IMAGE_TRIGGERS_CHECKSUM="${IMAGE_TRIGGERS_CHECKSUM_AARCH64}"; \ + ARCH="linux_arm64"; \ + fi \ + && wget --no-verbose https://github.com/panubo/image-triggers/releases/download/v${IMAGE_TRIGGERS_VERSION}/image-triggers_${IMAGE_TRIGGERS_VERSION}_${ARCH}.tar.gz -O /tmp/image-triggers.tar.gz \ + && echo "${IMAGE_TRIGGERS_CHECKSUM} image-triggers.tar.gz" > /tmp/SHA256SUM \ + && ( cd /tmp; sha256sum -c SHA256SUM || ( echo "Expected $(sha256sum image-triggers.tar.gz)"; exit 1; )) \ + && tar -C /usr/local/bin -zxf /tmp/image-triggers.tar.gz \ + && chmod +x /usr/local/bin/image-triggers \ + && rm -f /tmp/image-triggers.tar.gz /tmp/SHA256SUM \ + ; + # Download plugins COPY install-plugins.sh / RUN /install-plugins.sh diff --git a/ansible-bootstrap/main.yml b/ansible-bootstrap/main.yml index 0873473..5e22e38 100644 --- a/ansible-bootstrap/main.yml +++ b/ansible-bootstrap/main.yml @@ -5,6 +5,7 @@ vars: - rundeck_tokens: [] + - rundeck_triggers_registry_rules: [] tasks: - include_tasks: scripts.yml diff --git a/ansible-bootstrap/scripts.yml b/ansible-bootstrap/scripts.yml index f160c1d..25fdfea 100644 --- a/ansible-bootstrap/scripts.yml +++ b/ansible-bootstrap/scripts.yml @@ -27,3 +27,19 @@ mode: "0700" owner: root group: root + +- name: Write trigger_rundeck_job.sh + template: + dest: "/scripts/trigger_rundeck_job.sh" + src: "templates/trigger_rundeck_job.sh.j2" + mode: "0700" + owner: root + group: root + +- name: Write trigger_registry_rules.sh + template: + dest: "/scripts/trigger_registry_rules.sh" + src: "templates/trigger_registry_rules.sh.j2" + mode: "0700" + owner: root + group: root diff --git a/ansible-bootstrap/templates/trigger_registry_rules.sh.j2 b/ansible-bootstrap/templates/trigger_registry_rules.sh.j2 new file mode 100644 index 0000000..70c9d3f --- /dev/null +++ b/ansible-bootstrap/templates/trigger_registry_rules.sh.j2 @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# +# LICENSE: MIT License, Copyright (C) 2020-2025 Volt Grid Pty Ltd +# +# This triggers Rundeck jobs in response to registry events. Acts as a +# filter on which images/tags trigger a corresponding action. +# This is used by image-triggers. + +set -euo pipefail +IFS=$'\n\t' + +image_name="${1}" +image_tag="${2}" + +rundeck() { + echo ">> Running: trigger_rundeck_job.sh ${@}" + /scripts/trigger_rundeck_job.sh "${@}" +} + +{% for rule in rundeck_triggers_registry_rules %} +{% if loop.first %}if{% else %}elif{% endif %} [[ "${image_name}" =~ {{ rule.rule.name }} ]] && [[ "${image_tag}" =~ {{ rule.rule.tag }} ]]; then +{% for action in rule.actions %} + echo ">> Matched ${image_name}:${image_tag}" + {{ action }} +{% endfor %} +{% endfor %} +else + echo ">> No matching rules for ${image_name}:${image_tag}" +fi diff --git a/ansible-bootstrap/templates/trigger_rundeck_job.sh.j2 b/ansible-bootstrap/templates/trigger_rundeck_job.sh.j2 new file mode 100644 index 0000000..c03b8ac --- /dev/null +++ b/ansible-bootstrap/templates/trigger_rundeck_job.sh.j2 @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +# +# LICENSE: MIT License, Copyright (C) 2020-2025 Volt Grid Pty Ltd +# +# Triggers a Rundeck Job using the API +# Used by image triggers to trigger a job in response to a registry event + +set -euo pipefail +IFS=$'\n\t' + +echo ">> Running $(basename "$0")" + +RD_TOKEN="{{ rundeck_token_configuresh }}" +CONFIG_DIR="${CONFIG_DIR:-/config}" + +project="${1}" +job="${2}" +shift 2 + +# wait_http URL [TIMEOUT] [HTTP TIMEOUT] +wait_http() { + # Wait for http service to be available + command -v curl >/dev/null 2>&1 || { error "This function requires curl to be installed."; return 1; } + local url="${1:-'http://localhost'}" + local timeout="${2:-30}" + local http_timeout="${3:-2}" + echo -n "Connecting to HTTP at ${url}" + for (( i=0;; i++ )); do + if [[ "${i}" -eq "${timeout}" ]]; then + echo " timeout!" + return 99 + fi + sleep 1 + (curl --max-time "${http_timeout}" "${url}") &>/dev/null && break + echo -n "." + done + echo " connected." + exec 3>&- + exec 3<&- +} + +wait_http "${RD_URL}" 300 + +data=() + +for item in "${@}"; do + data+=("-d" "option.${item}") +done + +get_job_id() { + curl "${RD_URL}/api/14/project/${project}/jobs?jobExactFilter=${job}" -H "Accept: application/json" -H "X-Rundeck-Auth-Token: ${RD_TOKEN}" -sSf | jq -r '.[0].id' +} + +curl -XPOST "${RD_URL}/api/18/job/$(get_job_id)/run" -H "Accept: application/json" -H "X-Rundeck-Auth-Token: ${RD_TOKEN}" -sSf "${data[@]}" | jq . + +echo ">> Finished $(basename "$0")"