diff --git a/entrypoint.sh b/entrypoint.sh index 68cc3d2..8e9d5fe 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -2,7 +2,7 @@ set -e -# Technically not nessecary but it cleans up the logs from having token/secret values +# Technically not necessary, but it cleans up the logs from having token/secret values run_command() { local cmd="$@" # Replace any --token or --secret with [REDACTED] @@ -26,92 +26,73 @@ fi # Handle if `command` is passed, as command appends arguments to the entrypoint if [ "$#" -gt 0 ]; then - run_command $@ - exit + run_command $@ + exit fi -# Handle and alter the config file -if [[ -z "${CONFIG_FILE}" ]]; then - echo "CONFIG_FILE is not set" - CONFIG_FILE="/data/config.yml" -fi -CONFIG_ARG="--config ${CONFIG_FILE}" +# Use environment variables directly, with fallback defaults if not set +RUNNER__CONFIG_FILE="${RUNNER__CONFIG_FILE:-/data/config.yml}" +ENV_FILE="${ENV_FILE:-/data/.env}" +RUNNER__RUNNER__FILE="${RUNNER__RUNNER__FILE:-/data/runner.json}" + +# Set config arguments +CONFIG_ARG="--config ${RUNNER__CONFIG_FILE}" + +# Container-specific environment variables +RUNNER__CONTAINER__NETWORK="${RUNNER__CONTAINER__NETWORK:-host}" +RUNNER__CONTAINER__ENABLE_IPV6="${RUNNER__CONTAINER__ENABLE_IPV6:-false}" +RUNNER__CONTAINER__PRIVILEGED="${RUNNER__CONTAINER__PRIVILEGED:-false}" +RUNNER__CONTAINER__LABELS="${RUNNER__CONTAINER__LABELS:-}" +RUNNER__CONTAINER__VALID_VOLUMES="${RUNNER__CONTAINER__VALID_VOLUMES:-}" + +# Show config variables decho "CONFIG: ${CONFIG_ARG}" -DOCKER_HOST=${DOCKER_HOST:-"tcp://docker:2367"} -DOCKER_CERT_PATH=${DOCKER_CERT_PATH:-"/certs/client"} -DOCKER_TLS_VERIFY=${DOCKER_TLS_VERIFY:-1} -decho "DOCKER_HOST: ${DOCKER_HOST}" -decho "DOCKER_CERT_PATH: ${DOCKER_CERT_PATH}" -decho "DOCKER_TLS_VERIFY: ${DOCKER_TLS_VERIFY}" -if [[ ! -f "${CONFIG_FILE}" ]]; then - echo "Creating ${CONFIG_FILE}" - run_command "forgejo-runner generate-config > ${CONFIG_FILE}" - - # Remove test environment variables if they exist in the config file - sed -i "/^ A_TEST_ENV_NAME_1:/d" ${CONFIG_FILE} - sed -i "/^ A_TEST_ENV_NAME_2:/d" ${CONFIG_FILE} - - # Apply default values for docker - sed -i "/^ labels:/c\ labels: [\"docker:docker://code.forgejo.org/oci/node:20-bookworm\", \"ubuntu-22.04:docker://catthehacker/ubuntu:act-22.04\"]" ${CONFIG_FILE} - sed -i "/^ network:/c\ network: host" ${CONFIG_FILE} - - if [[ "${DOCKER_PRIVILEGED}" == "true" ]]; then - sed -i "/^ privileged:/c\ privileged: true" ${CONFIG_FILE} - sed -i "/^ options:/c\ options: -v /certs/client:/certs/client:ro" ${CONFIG_FILE} - sed -i "/^ valid_volumes:/c\ valid_volumes:\n - /certs/client" ${CONFIG_FILE} - - sed -i "/^ envs:/c\ envs:\n DOCKER_HOST: ${DOCKER_HOST}\n DOCKER_TLS_VERIFY: ${DOCKER_TLS_VERIFY}\n DOCKER_CERT_PATH: ${DOCKER_CERT_PATH}" ${CONFIG_FILE} - fi - +# Generate config if not found +if [[ ! -f "${RUNNER__CONFIG_FILE}" ]]; then + echo "Creating ${RUNNER__CONFIG_FILE}" + run_command "forgejo-runner generate-config > ${RUNNER__CONFIG_FILE}" fi -ENV_FILE=${ENV_FILE:-"/data/.env"} -decho "ENV_FILE: ${ENV_FILE}" -sed -i "/^ env_file:/c\ env_file: ${ENV_FILE}" ${CONFIG_FILE} +# Use environment variables directly in the config, no need for sed edits +decho "Using config from: ${RUNNER__CONFIG_FILE}" +decho "Using environment file: ${ENV_FILE}" +# Set extra arguments from environment variables EXTRA_ARGS="" -if [[ ! -z "${RUNNER_LABELS}" ]]; then - EXTRA_ARGS="${EXTRA_ARGS} --labels ${RUNNER_LABELS}" +if [[ -n "${RUNNER__CONTAINER__LABELS}" ]]; then + EXTRA_ARGS="${EXTRA_ARGS} --labels ${RUNNER__CONTAINER__LABELS}" fi decho "EXTRA_ARGS: ${EXTRA_ARGS}" -# Set the runner file -RUNNER_FILE=${RUNNER_FILE:-"runner.json"} # use json so editors know how to highlight -decho "RUNNER_FILE: ${RUNNER_FILE}" -sed -i "/^ file:/c\ file: ${RUNNER_FILE}" ${CONFIG_FILE} - if [[ "${SKIP_WAIT}" != "true" ]]; then echo "Waiting 10s to allow other services to start up..." sleep 10 fi -if [[ ! -s "${RUNNER_FILE}" ]]; then - touch ${RUNNER_FILE} +# Try to register the runner +if [[ ! -s "${RUNNER__RUNNER__FILE}" ]]; then + touch ${RUNNER__RUNNER__FILE} try=$((try + 1)) success=0 decho "try: ${try}, success: ${success}" - # The point of this loop is to make it simple, when running both forgejo-runner and gitea in docker, - # for the forgejo-runner to wait a moment for gitea to become available before erroring out. Within - # the context of a single docker-compose, something similar could be done via healthchecks, but - # this is more flexible. while [[ $success -eq 0 ]] && [[ $try -lt ${MAX_REG_ATTEMPTS:-10} ]]; do - if [[ ! -z "${FORGEJO_SECRET}" ]]; then + if [[ -n "${FORGEJO_SECRET}" ]]; then run_command forgejo-runner create-runner-file --connect \ - --instance "${FORGEJO_URL:-http://forgejo:3000}" \ - --name "${RUNNER_NAME:-$(hostname)}" \ - --secret "${FORGEJO_SECRET}" \ - ${CONFIG_ARG}\ - ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log + --instance "${FORGEJO_URL:-http://forgejo:3000}" \ + --name "${RUNNER_NAME:-$(hostname)}" \ + --secret "${FORGEJO_SECRET}" \ + ${CONFIG_ARG} \ + ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log else run_command forgejo-runner register \ - --instance "${FORGEJO_URL:-http://forgejo:3000}" \ - --name "${RUNNER_NAME:-$(hostname)}" \ - --token "${RUNNER_TOKEN}" \ - --no-interactive \ - ${CONFIG_ARG}\ - ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log + --instance "${FORGEJO_URL:-http://forgejo:3000}" \ + --name "${RUNNER_NAME:-$(hostname)}" \ + --token "${RUNNER_TOKEN}" \ + --no-interactive \ + ${CONFIG_ARG} \ + ${EXTRA_ARGS} 2>&1 | tee /tmp/reg.log fi cat /tmp/reg.log | grep -E 'connection successful|registered successfully' >/dev/null if [[ $? -eq 0 ]]; then diff --git a/internal/pkg/config/config-env.go b/internal/pkg/config/config-env.go index 063b7c9..0664df2 100644 --- a/internal/pkg/config/config-env.go +++ b/internal/pkg/config/config-env.go @@ -5,12 +5,6 @@ import ( "strconv" "strings" "time" - - log "github.com/sirupsen/logrus" -) - -var ( - envPrefix = "RUNNER__" ) // loadEnvVars loads configuration settings from environment variables @@ -20,42 +14,47 @@ func loadEnvVars(config *Config) { // This implementation causes env-vars to override config file settings, // without writing to the config file. + // SkipEnv if variable is set + if _, ok := os.LookupEnv("RUNNER__SKIP_ENV"); ok { + return + } + // Log - loadEnvStr(config, envPrefix+"LOG__LEVEL", &config.Log.Level) - loadEnvStr(config, envPrefix+"LOG__JOB_LEVEL", &config.Log.JobLevel) + loadEnvStr(config, "RUNNER__LOG__LEVEL", &config.Log.Level) + loadEnvStr(config, "RUNNER__LOG__JOB_LEVEL", &config.Log.JobLevel) // Runner - loadEnvStr(config, envPrefix+"RUNNER__FILE", &config.Runner.File) - loadEnvInt(config, envPrefix+"RUNNER__CAPACITY", &config.Runner.Capacity) - loadEnvTable(config, envPrefix+"RUNNER__ENVS", &config.Runner.Envs) - loadEnvStr(config, envPrefix+"RUNNER__ENV_FILE", &config.Runner.EnvFile) - loadEnvDuration(config, envPrefix+"RUNNER__SHUTDOWN_TIMEOUT", &config.Runner.ShutdownTimeout) - loadEnvBool(config, envPrefix+"RUNNER__INSECURE", &config.Runner.Insecure) - loadEnvDuration(config, envPrefix+"RUNNER__FETCH_TIMEOUT", &config.Runner.FetchTimeout) - loadEnvDuration(config, envPrefix+"RUNNER__FETCH_INTERVAL", &config.Runner.FetchInterval) - loadEnvDuration(config, envPrefix+"RUNNER__REPORT_INTERVAL", &config.Runner.ReportInterval) - loadEnvList(config, envPrefix+"RUNNER__LABELS", &config.Runner.Labels) + loadEnvStr(config, "RUNNER__RUNNER__FILE", &config.Runner.File) + loadEnvInt(config, "RUNNER__RUNNER__CAPACITY", &config.Runner.Capacity) + loadEnvTable(config, "RUNNER__RUNNER__ENVS", &config.Runner.Envs) + loadEnvStr(config, "RUNNER__RUNNER__ENV_FILE", &config.Runner.EnvFile) + loadEnvDuration(config, "RUNNER__RUNNER__SHUTDOWN_TIMEOUT", &config.Runner.ShutdownTimeout) + loadEnvBool(config, "RUNNER__RUNNER__INSECURE", &config.Runner.Insecure) + loadEnvDuration(config, "RUNNER__RUNNER__FETCH_TIMEOUT", &config.Runner.FetchTimeout) + loadEnvDuration(config, "RUNNER__RUNNER__FETCH_INTERVAL", &config.Runner.FetchInterval) + loadEnvDuration(config, "RUNNER__RUNNER__REPORT_INTERVAL", &config.Runner.ReportInterval) + loadEnvList(config, "RUNNER__RUNNER__LABELS", &config.Runner.Labels) // Cache - loadEnvBool(config, envPrefix+"CACHE__ENABLED", config.Cache.Enabled) - loadEnvStr(config, envPrefix+"CACHE__DIR", &config.Cache.Dir) - loadEnvStr(config, envPrefix+"CACHE__HOST", &config.Cache.Host) - loadEnvUInt16(config, envPrefix+"CACHE__PORT", &config.Cache.Port) - loadEnvStr(config, envPrefix+"CACHE__EXTERNAL_SERVER", &config.Cache.ExternalServer) + loadEnvBool(config, "RUNNER__CACHE__ENABLED", config.Cache.Enabled) + loadEnvStr(config, "RUNNER__CACHE__DIR", &config.Cache.Dir) + loadEnvStr(config, "RUNNER__CACHE__HOST", &config.Cache.Host) + loadEnvUInt16(config, "RUNNER__CACHE__PORT", &config.Cache.Port) + loadEnvStr(config, "RUNNER__CACHE__EXTERNAL_SERVER", &config.Cache.ExternalServer) // Container - loadEnvStr(config, envPrefix+"CONTAINER__NETWORK", &config.Container.Network) - loadEnvStr(config, envPrefix+"CONTAINER__NETWORK_MODE", &config.Container.NetworkMode) - loadEnvBool(config, envPrefix+"CONTAINER__ENABLE_IPV6", &config.Container.EnableIPv6) - loadEnvBool(config, envPrefix+"CONTAINER__PRIVILEGED", &config.Container.Privileged) - loadEnvStr(config, envPrefix+"CONTAINER__OPTIONS", &config.Container.Options) - loadEnvStr(config, envPrefix+"CONTAINER__WORKDIR_PARENT", &config.Container.WorkdirParent) - loadEnvList(config, envPrefix+"CONTAINER__VALID_VOLUMES", &config.Container.ValidVolumes) - loadEnvStr(config, envPrefix+"CONTAINER__DOCKER_HOST", &config.Container.DockerHost) - loadEnvBool(config, envPrefix+"CONTAINER__FORCE_PULL", &config.Container.ForcePull) + loadEnvStr(config, "RUNNER__CONTAINER__NETWORK", &config.Container.Network) + loadEnvStr(config, "RUNNER__CONTAINER__NETWORK_MODE", &config.Container.NetworkMode) + loadEnvBool(config, "RUNNER__CONTAINER__ENABLE_IPV6", &config.Container.EnableIPv6) + loadEnvBool(config, "RUNNER__CONTAINER__PRIVILEGED", &config.Container.Privileged) + loadEnvStr(config, "RUNNER__CONTAINER__OPTIONS", &config.Container.Options) + loadEnvStr(config, "RUNNER__CONTAINER__WORKDIR_PARENT", &config.Container.WorkdirParent) + loadEnvList(config, "RUNNER__CONTAINER__VALID_VOLUMES", &config.Container.ValidVolumes) + loadEnvStr(config, "RUNNER__CONTAINER__DOCKER_HOST", &config.Container.DockerHost) + loadEnvBool(config, "RUNNER__CONTAINER__FORCE_PULL", &config.Container.ForcePull) // Host - loadEnvStr(config, envPrefix+"HOST__WORKDIR_PARENT", &config.Host.WorkdirParent) + loadEnvStr(config, "RUNNER__HOST__WORKDIR_PARENT", &config.Host.WorkdirParent) } // loadEnvStr loads an environment variable into the provided string pointer if it exists. @@ -108,10 +107,16 @@ func loadEnvBool(config *Config, key string, dest *bool) { // loadEnvTable loads an environment variable into the provided map[string]string pointer if it exists. func loadEnvTable(config *Config, key string, dest *map[string]string) { - // This is a placeholder function. - // This function is not yet implemented. - // This function is meant to be replaced by those more competent than me. - log.Warn("Loading Tables from env is not yet implemented: ", key) + // Example: RUNNER__RUNNER__ENVS = "key1=value1, key2=value2, key3=value3" + if v := os.Getenv(key); v != "" { + *dest = make(map[string]string) + for _, pair := range splitAndTrim(v) { + kv := strings.SplitN(pair, "=", 2) + if len(kv) == 2 { + (*dest)[kv[0]] = kv[1] + } + } + } } // loadEnvList loads an environment variable into the provided []string pointer if it exists.