360 lines
14 KiB
Bash
360 lines
14 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
MODULE_NAME="${MODULE_NAME:-ngx_http_monitoring_module}"
|
|
BUILD_NGINX_VERSIONS="${BUILD_NGINX_VERSIONS:-}"
|
|
NEXT_VERSION="${NEXT_VERSION:-0.0.0}"
|
|
NEXT_TAG="${NEXT_TAG:-v${NEXT_VERSION}}"
|
|
LATEST_TAG="${LATEST_TAG:-none}"
|
|
TARGET_ARCH="${TARGET_ARCH:-$(uname -m)}"
|
|
DOCKER_PLATFORM="${DOCKER_PLATFORM:-unknown}"
|
|
RELEASE_BUILD_IMAGE="${RELEASE_BUILD_IMAGE:-unknown}"
|
|
RELEASE_LIBC_BASELINE="${RELEASE_LIBC_BASELINE:-unknown}"
|
|
NGINX_CONFIGURE_ARGS="${NGINX_CONFIGURE_ARGS:---with-compat --with-http_ssl_module --with-http_stub_status_module}"
|
|
DIST_DIR="${DIST_DIR:-/work/dist}"
|
|
WORK_ROOT="${WORK_ROOT:-/work/.release-work/upstream}"
|
|
VALIDATION_PORT="${VALIDATION_PORT:-18080}"
|
|
GITHUB_REF="${GITHUB_REF:-unknown}"
|
|
GITHUB_SHA="${GITHUB_SHA:-unknown}"
|
|
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
|
|
fail() {
|
|
echo "error: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
slugify() {
|
|
tr '[:upper:]' '[:lower:]' \
|
|
| sed -E 's/[^a-z0-9.+~]+/./g; s/^[.]+//; s/[.]+$//'
|
|
}
|
|
|
|
validate_module() {
|
|
local nginx_bin="$1"
|
|
local module_path="$2"
|
|
local runtime_root="$3"
|
|
local config_path="$runtime_root/nginx.conf"
|
|
local base_url="http://127.0.0.1:${VALIDATION_PORT}"
|
|
local status
|
|
local dashboard
|
|
local sse_output
|
|
|
|
rm -rf "$runtime_root"
|
|
mkdir -p \
|
|
"$runtime_root/logs" \
|
|
"$runtime_root/temp/client_body" \
|
|
"$runtime_root/temp/proxy" \
|
|
"$runtime_root/temp/fastcgi" \
|
|
"$runtime_root/temp/uwsgi" \
|
|
"$runtime_root/temp/scgi"
|
|
|
|
{
|
|
printf 'load_module %s;\n\n' "$module_path"
|
|
printf 'worker_processes 1;\n'
|
|
printf 'error_log %s/logs/error.log info;\n' "$runtime_root"
|
|
printf 'pid %s/logs/nginx.pid;\n\n' "$runtime_root"
|
|
printf 'events {\n'
|
|
printf ' worker_connections 1024;\n'
|
|
printf '}\n\n'
|
|
printf 'http {\n'
|
|
printf ' access_log off;\n'
|
|
printf ' default_type application/octet-stream;\n'
|
|
printf ' client_body_temp_path %s/temp/client_body;\n' "$runtime_root"
|
|
printf ' proxy_temp_path %s/temp/proxy;\n' "$runtime_root"
|
|
printf ' fastcgi_temp_path %s/temp/fastcgi;\n' "$runtime_root"
|
|
printf ' uwsgi_temp_path %s/temp/uwsgi;\n' "$runtime_root"
|
|
printf ' scgi_temp_path %s/temp/scgi;\n\n' "$runtime_root"
|
|
printf ' monitor_refresh_interval 1s;\n'
|
|
printf ' monitor_history 1m;\n'
|
|
printf ' monitor_resolution 1s;\n'
|
|
printf ' monitor_shm_size 8m;\n'
|
|
printf ' monitor_collect_system on;\n'
|
|
printf ' monitor_collect_nginx on;\n'
|
|
printf ' monitor_collect_network on;\n'
|
|
printf ' monitor_access_log on;\n'
|
|
printf ' monitor_max_top_urls 100;\n\n'
|
|
printf ' server {\n'
|
|
printf ' listen 127.0.0.1:%s;\n' "$VALIDATION_PORT"
|
|
printf ' server_name localhost;\n\n'
|
|
printf ' location /monitor {\n'
|
|
printf ' monitor on;\n'
|
|
printf ' monitor_dashboard on;\n'
|
|
printf ' monitor_api on;\n'
|
|
printf ' monitor_sse on;\n'
|
|
printf ' monitor_allow all;\n'
|
|
printf ' monitor_basic_auth off;\n'
|
|
printf ' monitor_cors off;\n'
|
|
printf ' monitor_rate_limit 120;\n'
|
|
printf ' }\n\n'
|
|
printf ' location / {\n'
|
|
printf ' return 200 "ok\\n";\n'
|
|
printf ' }\n'
|
|
printf ' }\n'
|
|
printf '}\n'
|
|
} > "$config_path"
|
|
|
|
"$nginx_bin" -t -p "$runtime_root" -c "$config_path"
|
|
|
|
cleanup() {
|
|
"$nginx_bin" -p "$runtime_root" -c "$config_path" -s quit >/dev/null 2>&1 || true
|
|
}
|
|
trap cleanup RETURN
|
|
|
|
"$nginx_bin" -p "$runtime_root" -c "$config_path"
|
|
|
|
for attempt in $(seq 1 50); do
|
|
if curl -fsS "$base_url/" >/dev/null; then
|
|
break
|
|
fi
|
|
|
|
if [[ "$attempt" -eq 50 ]]; then
|
|
echo "Nginx did not become ready" >&2
|
|
return 1
|
|
fi
|
|
|
|
sleep 0.2
|
|
done
|
|
|
|
curl -fsS "$base_url/" | grep -q '^ok'
|
|
|
|
status="$(curl -fsS -o "$runtime_root/dashboard.html" -w '%{http_code}' "$base_url/monitor")"
|
|
[[ "$status" == "200" ]] || fail "/monitor returned HTTP $status"
|
|
dashboard="$(cat "$runtime_root/dashboard.html")"
|
|
printf '%s' "$dashboard" | grep -q '<title>Nginx Monitor</title>'
|
|
printf '%s' "$dashboard" | grep -q '/monitor/api'
|
|
printf '%s' "$dashboard" | grep -q '/monitor/live'
|
|
|
|
curl -fsS "$base_url/monitor/api" \
|
|
| jq -e '.version == 1 and has("system") and has("nginx") and has("requests") and has("history")' >/dev/null
|
|
curl -fsS "$base_url/monitor/api/system" \
|
|
| jq -e '.version == 1 and .scope == "system" and has("system")' >/dev/null
|
|
curl -fsS "$base_url/monitor/api/nginx" \
|
|
| jq -e '.version == 1 and .scope == "nginx" and has("nginx")' >/dev/null
|
|
curl -fsS "$base_url/monitor/health" \
|
|
| jq -e '.version == 1 and .scope == "health" and .status == "ok"' >/dev/null
|
|
curl -fsS "$base_url/monitor/metrics" \
|
|
| grep -q '^nginx_monitor_requests_total '
|
|
|
|
sse_output="$(timeout 5s curl -fsS -N "$base_url/monitor/live" || true)"
|
|
printf '%s' "$sse_output" | grep -q '^event: metrics'
|
|
printf '%s' "$sse_output" | grep -q '^data: {'
|
|
|
|
cleanup
|
|
trap - RETURN
|
|
}
|
|
|
|
[[ -n "$BUILD_NGINX_VERSIONS" ]] || fail "BUILD_NGINX_VERSIONS is required"
|
|
|
|
apt-get update
|
|
apt-get install -y --no-install-recommends \
|
|
binutils \
|
|
build-essential \
|
|
ca-certificates \
|
|
curl \
|
|
file \
|
|
jq \
|
|
libpcre2-dev \
|
|
libssl-dev \
|
|
zlib1g-dev
|
|
rm -rf /var/lib/apt/lists/*
|
|
|
|
mkdir -p "$DIST_DIR" "$WORK_ROOT"
|
|
|
|
for nginx_version in $BUILD_NGINX_VERSIONS; do
|
|
archive="nginx-${nginx_version}.tar.gz"
|
|
archive_path="${WORK_ROOT}/${archive}"
|
|
workdir="${WORK_ROOT}/nginx-${nginx_version}"
|
|
runtime_root="${WORK_ROOT}/runtime/nginx-${nginx_version}"
|
|
|
|
if [[ ! -f "$archive_path" ]]; then
|
|
curl -fsSLo "$archive_path" "https://nginx.org/download/${archive}"
|
|
fi
|
|
|
|
rm -rf "$workdir"
|
|
tar -xzf "$archive_path" -C "$WORK_ROOT"
|
|
|
|
nginx_version_slug="$(printf '%s' "$nginx_version" | slugify)"
|
|
build_metadata="$(printf 'nginxorg.%s.%s.%s' "$nginx_version_slug" "$TARGET_ARCH" "$RELEASE_LIBC_BASELINE" | slugify)"
|
|
module_cflags="-DNGX_HTTP_MONITORING_MODULE_VERSION=\\\"${NEXT_VERSION}\\\" -DNGX_HTTP_MONITORING_BUILD_METADATA=\\\"${build_metadata}\\\""
|
|
|
|
cd "$workdir"
|
|
./configure \
|
|
--prefix=/usr/local/nginx \
|
|
--sbin-path=/usr/local/sbin/nginx \
|
|
--modules-path=/usr/local/nginx/modules \
|
|
--conf-path=/etc/nginx/nginx.conf \
|
|
--error-log-path=/var/log/nginx/error.log \
|
|
--http-log-path=/var/log/nginx/access.log \
|
|
--pid-path=/var/run/nginx.pid \
|
|
--lock-path=/var/run/nginx.lock \
|
|
--http-client-body-temp-path=/var/cache/nginx/client_temp \
|
|
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
|
|
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
|
|
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
|
|
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
|
|
--with-cc-opt="$module_cflags" \
|
|
$NGINX_CONFIGURE_ARGS \
|
|
--add-dynamic-module=/work
|
|
|
|
build_jobs="$(nproc)"
|
|
if [[ "$TARGET_ARCH" != "linux-x86_64" && "$build_jobs" -gt 2 ]]; then
|
|
build_jobs=2
|
|
fi
|
|
|
|
make -j"$build_jobs"
|
|
make -j"$build_jobs" modules
|
|
|
|
module_path="$workdir/objs/${MODULE_NAME}.so"
|
|
nginx_bin="$workdir/objs/nginx"
|
|
[[ -x "$nginx_bin" ]] || fail "nginx binary was not built at ${nginx_bin}"
|
|
[[ -f "$module_path" ]] || fail "module was not built at ${module_path}"
|
|
|
|
strip --strip-unneeded "$module_path" || true
|
|
validate_module "$nginx_bin" "$module_path" "$runtime_root"
|
|
|
|
module_sha256="$(sha256sum "$module_path" | awk '{ print $1 }')"
|
|
archive_sha256="$(sha256sum "$archive_path" | awk '{ print $1 }')"
|
|
artifact_base="${MODULE_NAME}-${NEXT_TAG}-nginxorg-${nginx_version_slug}-${TARGET_ARCH}"
|
|
package_root="${WORK_ROOT}/packages/${artifact_base}"
|
|
compatibility_json="${package_root}/COMPATIBILITY.json"
|
|
|
|
rm -rf "$package_root"
|
|
mkdir -p "$package_root/modules" "$package_root/docs" "$package_root/examples"
|
|
|
|
cp "$module_path" "$package_root/modules/${MODULE_NAME}.so"
|
|
cp /work/examples/nginx.conf "$package_root/examples/nginx.conf"
|
|
cp /work/examples/monitoring-site.conf "$package_root/examples/monitoring-site.conf"
|
|
cp /work/README.md "$package_root/README.md"
|
|
cp /work/docs/API.md "$package_root/docs/API.md"
|
|
cp /work/docs/CONFIGURATION.md "$package_root/docs/CONFIGURATION.md"
|
|
cp /work/docs/PERFORMANCE.md "$package_root/docs/PERFORMANCE.md"
|
|
"$nginx_bin" -V > "$package_root/NGINX-V.txt" 2>&1
|
|
|
|
tarball_file="${artifact_base}.tar.gz"
|
|
sidecar_file="${artifact_base}.compatibility.json"
|
|
|
|
jq -n \
|
|
--arg schema "1" \
|
|
--arg module "$MODULE_NAME" \
|
|
--arg releaseTag "$NEXT_TAG" \
|
|
--arg releaseVersion "$NEXT_VERSION" \
|
|
--arg previousTag "$LATEST_TAG" \
|
|
--arg gitRef "$GITHUB_REF" \
|
|
--arg gitSha "$GITHUB_SHA" \
|
|
--arg buildImage "$RELEASE_BUILD_IMAGE" \
|
|
--arg libcBaseline "$RELEASE_LIBC_BASELINE" \
|
|
--arg dockerPlatform "$DOCKER_PLATFORM" \
|
|
--arg targetArch "$TARGET_ARCH" \
|
|
--arg nginxVersion "$nginx_version" \
|
|
--arg configureArgs "$NGINX_CONFIGURE_ARGS" \
|
|
--arg archive "$archive" \
|
|
--arg archiveSha256 "$archive_sha256" \
|
|
--arg moduleSha256 "$module_sha256" \
|
|
--arg builtAt "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
--arg artifactBase "$artifact_base" \
|
|
--arg tarballFile "$tarball_file" \
|
|
--arg sidecarFile "$sidecar_file" \
|
|
--arg validationTime "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
'{
|
|
schema: ($schema | tonumber),
|
|
module: $module,
|
|
release: {
|
|
tag: $releaseTag,
|
|
version: $releaseVersion,
|
|
previous_tag: $previousTag,
|
|
git_ref: $gitRef,
|
|
git_sha: $gitSha
|
|
},
|
|
target: {
|
|
os_id: "nginx.org-source",
|
|
os_version: $nginxVersion,
|
|
os_codename: "upstream",
|
|
architecture: $targetArch,
|
|
requested_target: $targetArch,
|
|
docker_image: $buildImage,
|
|
docker_platform: $dockerPlatform,
|
|
libc_baseline: $libcBaseline
|
|
},
|
|
nginx: {
|
|
binary_package: "nginx.org-source-build",
|
|
binary_version: $nginxVersion,
|
|
source_package: "nginx.org",
|
|
source_version: $nginxVersion,
|
|
abi: "",
|
|
modules_path: "/usr/local/nginx/modules",
|
|
build: {
|
|
version: ("nginx/" + $nginxVersion),
|
|
configure_args: ($configureArgs | split(" ")),
|
|
configure_line: $configureArgs
|
|
}
|
|
},
|
|
build: {
|
|
method: "upstream-nginxorg-source",
|
|
source_archive: $archive,
|
|
source_archive_sha256: $archiveSha256,
|
|
module_sha256: $moduleSha256,
|
|
built_at: $builtAt
|
|
},
|
|
artifacts: {
|
|
base_name: $artifactBase,
|
|
deb_package: "",
|
|
deb_version: "",
|
|
deb_file: "",
|
|
tarball_file: $tarballFile,
|
|
compatibility_file: $sidecarFile
|
|
},
|
|
packaging: {
|
|
deb_depends: []
|
|
},
|
|
validation: {
|
|
packaged_nginx_config_test: false,
|
|
packaged_nginx_endpoint_smoke: false,
|
|
built_nginx_config_test: true,
|
|
built_nginx_endpoint_smoke: true,
|
|
validated_at: $validationTime
|
|
}
|
|
}' > "$compatibility_json"
|
|
|
|
{
|
|
printf '# %s for nginx.org %s\n\n' "$MODULE_NAME" "$nginx_version"
|
|
printf 'Release: `%s`\n\n' "$NEXT_TAG"
|
|
printf 'Target: `%s` (`%s`)\n\n' "$TARGET_ARCH" "$DOCKER_PLATFORM"
|
|
printf 'Build baseline: `%s`\n\n' "$RELEASE_LIBC_BASELINE"
|
|
printf 'This tarball is built against upstream nginx.org source, not a Debian or Ubuntu source package.\n\n'
|
|
printf 'Use this artifact for Nginx binaries built from the same upstream source version and compatible configure options. For distribution-packaged Nginx, prefer the distro `.deb` release artifacts.\n\n'
|
|
printf 'Load it near the top of `nginx.conf`:\n\n'
|
|
printf '```nginx\n'
|
|
printf 'load_module modules/%s.so;\n' "$MODULE_NAME"
|
|
printf '```\n'
|
|
} > "$package_root/INSTALL.md"
|
|
|
|
{
|
|
printf 'module=%s\n' "$MODULE_NAME"
|
|
printf 'module_release=%s\n' "$NEXT_TAG"
|
|
printf 'module_version=%s\n' "$NEXT_VERSION"
|
|
printf 'module_build_metadata=%s\n' "$build_metadata"
|
|
printf 'nginx_source=nginx.org\n'
|
|
printf 'nginx_version=%s\n' "$nginx_version"
|
|
printf 'target=%s\n' "$TARGET_ARCH"
|
|
printf 'docker_platform=%s\n' "$DOCKER_PLATFORM"
|
|
printf 'build_image=%s\n' "$RELEASE_BUILD_IMAGE"
|
|
printf 'libc_baseline=%s\n' "$RELEASE_LIBC_BASELINE"
|
|
printf 'configure_args=%s\n' "$NGINX_CONFIGURE_ARGS"
|
|
printf 'git_ref=%s\n' "$GITHUB_REF"
|
|
printf 'git_sha=%s\n' "$GITHUB_SHA"
|
|
printf 'built_at=%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
} > "$package_root/METADATA.txt"
|
|
|
|
(
|
|
cd "$package_root"
|
|
sha256sum "modules/${MODULE_NAME}.so" COMPATIBILITY.json > SHA256SUMS
|
|
file "modules/${MODULE_NAME}.so" > FILE.txt
|
|
)
|
|
|
|
tar -czf "$DIST_DIR/$tarball_file" -C "$(dirname "$package_root")" "$(basename "$package_root")"
|
|
cp "$compatibility_json" "$DIST_DIR/$sidecar_file"
|
|
|
|
echo "Built $DIST_DIR/$tarball_file"
|
|
echo "Built $DIST_DIR/$sidecar_file"
|
|
done
|