Skip to content

Commit

Permalink
Merge pull request #87 from docksal/develop
Browse files Browse the repository at this point in the history
Release 1.8.0
  • Loading branch information
lmakarov authored Mar 12, 2022
2 parents 015c456 + 03b994c commit 321a116
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 50 deletions.
17 changes: 14 additions & 3 deletions .github/scripts/docker-tags.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ join() {
echo "$*"
}

# Outputs the latest stable tag
# For repos that do not set/use VERSION (e.g., system images) => "latest"
# Fore repos that set/use VERSION (e.g., docksal/cli) => <prefix><version>-<suffix> (e.g., php8.1-ide)
get_latest_tag() {
if [[ "${VERSION}" != "" ]]; then
echo "$(join ${VERSION_PREFIX}${VERSION} ${VERSION_SUFFIX})";
else
echo "latest"
fi
}

# Prints resulting image tags and sets output variable
set_output() {
local -n inputArr=${1}
Expand Down Expand Up @@ -52,9 +63,9 @@ if [[ "${GITHUB_REF}" == "refs/heads/develop" ]]; then
imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} edge ${VERSION_SUFFIX})")
fi

# master => version
# master => version | latest
if [[ "${GITHUB_REF}" == "refs/heads/master" ]]; then
imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${VERSION_SUFFIX})")
imageTagArr+=("${IMAGE}:$(get_latest_tag)")
fi

# tags/v1.0.0 => 1.0
Expand All @@ -63,7 +74,7 @@ if [[ "${GITHUB_REF}" =~ "refs/tags/" ]]; then
IFS='.' read -a release_arr <<< "${GITHUB_REF#refs/tags/}"
releaseMajor=${release_arr[0]#v*} # 2.7.0 => "2"
releaseMinor=${release_arr[1]} # "2.7.0" => "7"
imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${VERSION_SUFFIX})")
imageTagArr+=("${IMAGE}:$(get_latest_tag)")
imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${releaseMajor} ${VERSION_SUFFIX})")
imageTagArr+=("${IMAGE}:$(join ${VERSION_PREFIX}${VERSION} ${releaseMajor}.${releaseMinor} ${VERSION_SUFFIX})")
fi
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,9 @@ jobs:
env:
BUILD_IMAGE_TAG: ${{ env.BUILD_IMAGE_TAG }}-${{ env.GIT_SHA7 }}-${{ env.ARCH }}
run: |
# This installs Docksal using the passed DOCKSAL_VERSION value
# Install Docksal using the passed DOCKSAL_VERSION value
curl -sSL http://get.docksal.io | bash
# Reset vhost-proxy using the build image and prepare test project stacks
# Start the service using the build image tag and prepare test project stacks
make start
-
# Run tests
Expand Down
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM openresty/openresty:1.19.3.2-1-alpine
FROM openresty/openresty:1.19.9.1-5-alpine

# amd64 / arm64
ARG TARGETARCH
Expand All @@ -16,9 +16,9 @@ RUN set -xe; \
addgroup -S nginx; \
adduser -D -S -h /var/cache/nginx -s /sbin/nologin -G nginx nginx

ARG DOCKER_VERSION=20.10.7
ARG DOCKER_GEN_VERSION=0.7.6
ARG GOMPLATE_VERSION=3.0.0
ARG DOCKER_VERSION=20.10.12
ARG DOCKER_GEN_VERSION=0.8.2
ARG GOMPLATE_VERSION=3.10.0

# Install docker client binary (if not mounting binary from host)
RUN set -xe; \
Expand Down
10 changes: 6 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ NAME = docksal-vhost-proxy
DOCKSAL_VHOST_PROXY_ACCESS_LOG ?= 1
DOCKSAL_VHOST_PROXY_DEBUG_LOG ?= 1
DOCKSAL_VHOST_PROXY_STATS_LOG ?= 1
PROJECT_AUTOSTART ?= 1
PROJECT_INACTIVITY_TIMEOUT ?= 30s
PROJECT_DANGLING_TIMEOUT ?= 60s

# A delay necessary for container and supervisord inside to initialize all services
INIT_DELAY = 10s
INIT_DELAY = 10
# A delay necessary for docker-gen to reload configuration when containers start/stop
RELOAD_DELAY = 2s
RELOAD_DELAY = 2

# Do not allow to override the value (?=) to prevent possible data loss on the host system
PROJECTS_ROOT = $(PWD)/tests/projects_mount
Expand Down Expand Up @@ -65,10 +66,10 @@ exec:
$(DOCKER) exec $(NAME) bash -lc "$(CMD)"

exec-it:
$(DOCKER) exec -it $(NAME) bash -lic "$(CMD)"
@$(DOCKER) exec -it $(NAME) bash -lic "$(CMD)"

shell:
make exec-it -e CMD="bash"
@make exec-it -e CMD=bash

stop:
$(DOCKER) stop $(NAME)
Expand All @@ -92,6 +93,7 @@ clean:
rm -rf $(PROJECTS_ROOT) &>/dev/null || true
rm -f ~/.docksal/certs/example.com.* &>/dev/null || true

# Make it possible to pass arguments to Makefile from command line
# https://stackoverflow.com/a/6273809/1826109
%:
@:
73 changes: 61 additions & 12 deletions bin/proxyctl
Original file line number Diff line number Diff line change
Expand Up @@ -89,36 +89,60 @@ lookup ()
log "ERROR: No matching projects or containers found for virtual host '${vhost}'."
return 1
else
log "Found a standalone container '$container_id'..."
log "${vhost} belongs to ${container_id} (container)"
# Return value to be passed to start(type, id)
echo "container ${container_id}"
fi
else
log "Found a project stack '$project_name'..."
log "${vhost} belongs to ${project_name} (project)"
# Return value to be passed to start(type, id)
echo "project ${project_name}"
fi
}

# HTTP request handler for nginx
# Looks up a container or project by Host (passed from nginx) and starts it up.
# Skips start if autostart is disabled
# Return codes:
# 0 - nginx will return a "Project loading" screen, but no project will be loaded in this case.
# 1 - nginx will return a "Project not found" screen.
# 2 - nginx will return a "Project autostart disabled" screen.
# See conf/nginx/lua/proxyctl.lua
wakeup ()
{
host=${1}
# Return 1 if lookup failed
id=$(lookup "${host}") || exit 1

log "Matched ${host} to ${id}"

# Skip if autostart is disabled
if [[ "$PROJECT_AUTOSTART" == 0 ]]; then
log "Skipping autostart for: ${id} (autostart is disabled)"
exit 2
fi

start ${id} && exit 0 || exit 1
}

start ()
{
# Set logging prefix for the function and trigger a log entry
export LOG_PREFIX='[start]' && log

# Disable projects autostart in case PROJECT_AUTOSTART set to 0
[[ "$PROJECT_AUTOSTART" == 0 ]] && log "WARNING: Projects autostart is disabled." && return 0

local type=${1}
local id=${2}
local type=${1} # "container" or "project"
local id=${2} # container id or project name

[[ "$type" == "" ]] && log "ERROR: Empty type." && return 1
[[ "$id" == "" ]] && log "ERROR: Empty id." && return 1

if [[ "$type" == "container" ]]; then
local container_id=${id}
log "Starting a standalone container '$container_id'..."
docker start "$container_id"
log "Starting ${container_id} (container)..."
docker start ${container_id}
elif [[ "$type" == "project" ]]; then
local project_name=${id}
log "Starting project stack for '${project_name}'..."
log "Starting ${project_name} (project)..."

# Connecting/re-connecting vhost-proxy to the project network
local network="${project_name}_default"
Expand All @@ -127,7 +151,7 @@ start ()
# Reconnect vhost-proxy to the project network (in case vhost-proxy has been recently reset)
docker network connect "$network" docksal-vhost-proxy >/dev/null 2>&1
if [[ $? == 0 ]]; then
log "Connected proxy to network '${network}'."
log "Connected proxy to ${network} network."
fi

# Reconnect project containers to the re-created network
Expand Down Expand Up @@ -273,6 +297,27 @@ cleanup ()
rm -rf "$mounted_project_root"
done <<< "$projects"

# Cleanup the /projects dir from any orphan folders that have no associated project stack
# Create an array of project names from the list of projects metadata
# Project name is at position 2. ':' is separator.
readarray -t project_names < <(printf '%s\n' ${projects} | awk -F ':' '{print $2}')
# Create an array from the list of folder names in the /projects directory
readarray -t project_folder_names < <(find /projects -type d -mindepth 1 -maxdepth 1 -exec basename {} \;)

# Get the diff between the two arrays
# See: https://stackoverflow.com/questions/2312762/compare-difference-of-two-arrays-in-bash
# This will be an array of orphan folder names
readarray -t orphan_folder_names < <(printf '%s\n' "${project_names[@]}" "${project_folder_names[@]}" | sort | uniq -u)

for f in "${orphan_folder_names[@]}"; do
path="/projects/${f}"
# Ensure we don't delete anything outside the /projects directory (including the dir itself).
if [[ $(readlink -f ${path}) == ${path} ]]; then
log "Removing orphan directory: ${path}..."
rm -rf ${path}
fi
done

log "Removing dangling images..."
docker image prune -f
log "Removing dangling volumes..."
Expand Down Expand Up @@ -378,6 +423,10 @@ case "$1" in
shift
lookup "$@"
;;
wakeup)
shift
wakeup "$@"
;;
start)
shift
start "$@"
Expand All @@ -401,5 +450,5 @@ case "$1" in
stats
;;
*)
echo "Usage: $0 lookup <vhost>|start|stop|cron|notify|networks|cleanup|stats"
echo "Usage: $0 lookup <vhost>|wakeup <vhost>|start|stop|cron|notify|networks|cleanup|stats"
esac
38 changes: 28 additions & 10 deletions conf/nginx/lua/proxyctl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ local function read_file(path)
return content
end

-- Only allow letters, digits, hyphens, and periods in host name
local function safe_host(str)
return string.gsub(str, "[^%a%d%-%.]", "")
end

-- Returns loading.html for HTTP_OK and not-found.html otherwise
local function response(status)
-- Load response body from disk
Expand All @@ -25,6 +30,8 @@ local function response(status)
local response_body
if (status == ngx.HTTP_ACCEPTED) then
response_body = read_file('/var/www/202.html')
elseif (status == ngx.HTTP_NOT_ACCEPTABLE) then
response_body = read_file('/var/www/406.html')
else
response_body = read_file('/var/www/404.html')
end
Expand All @@ -34,46 +41,57 @@ local function response(status)
ngx.print(response_body)

-- Unlock host before exiting
dpr("Unlocking " .. ngx.var.host)
ngx.shared.hosts:delete(ngx.var.host)
local host = safe_host(ngx.var.host)
dpr("Unlocking " .. host)
ngx.shared.hosts:delete(host)

return ngx.exit(status)
end

-- Get the host lock timestamp
local host = safe_host(ngx.var.host)
local timestamp = os.time(os.date("!*t"))
local lock_timestamp = ngx.shared.hosts:get(ngx.var.host)
local lock_timestamp = ngx.shared.hosts:get(host)

if (lock_timestamp == nil) then lock_timestamp = 0 end
local lock_age = timestamp - lock_timestamp

if (lock_age > 30) then
-- Break the lock if it is older than 30s
dpr("Unlocking a stale lock (" .. lock_age .. "s) for " .. ngx.var.host)
ngx.shared.hosts:delete(ngx.var.host)
dpr("Unlocking a stale lock (" .. lock_age .. "s) for " .. host)
ngx.shared.hosts:delete(host)
end

if (lock_timestamp == 0) then
-- No lock timestamp = can proceed with project wake up

dpr("Locking " .. ngx.var.host)
dpr("Locking " .. host)
lock_timestamp = os.time(os.date("!*t"))
ngx.shared.hosts:set(ngx.var.host, lock_timestamp)
ngx.shared.hosts:set(host, lock_timestamp)

-- Lanch project start script
-- os.execute returs multiple values starting with Lua 5.2
local status, exit, exit_code = os.execute("sudo -E /usr/local/bin/proxyctl start $(sudo /usr/local/bin/proxyctl lookup \"" .. ngx.var.host .. "\")")
-- os.execute returns multiple values starting with Lua 5.2
local cmd = "sudo -E /usr/local/bin/proxyctl wakeup " .. host
local status, exit, exit_code = os.execute(cmd)

-- Debug return codes
dpr("cmd: " .. cmd)
dpr("exit_code: " .. exit_code)

if (exit_code == 0) then
-- If all went well, reload the page
dpr("Container start succeeded")
response(ngx.HTTP_ACCEPTED)
elseif (exit_code == 2) then
-- Autostart disabled, return 406
dpr("Container start disabled")
response(ngx.HTTP_NOT_ACCEPTABLE)
else
-- If proxyctl start failed (non-existing environment or something went wrong), return 404
dpr("Container start failed")
response(ngx.HTTP_NOT_FOUND)
end
else
-- There is an active lock, so skip for now
dpr(ngx.var.host .. " is locked. Skipping.")
dpr(host .. " is locked. Skipping.")
end
8 changes: 5 additions & 3 deletions conf/nginx/nginx.conf.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ http {
ssl_certificate_key /etc/certs/server.key;

ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;

# Using recommended settings from https://ssl-config.mozilla.org/#server=nginx&config=intermediate
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;

location / {
# See https://github.com/openresty/lua-nginx-module#ngxeof
Expand Down
Loading

0 comments on commit 321a116

Please sign in to comment.