mirror of
https://github.com/Melorise/nPanel.git
synced 2026-11-07 14:49:35 +00:00
chore: establish nPanel fork baseline
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# OpenResty Dynamic Module Diagnostics
|
||||
|
||||
This script collects diagnostics from an installed 1Panel OpenResty instance.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Bash 4.3 or newer
|
||||
- Docker Engine with the Compose v2 plugin
|
||||
- `jq`, `python3`, `file`, `binutils`, `tar`, and GNU coreutils
|
||||
|
||||
On Debian or Ubuntu:
|
||||
|
||||
```bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y jq python3 file binutils tar
|
||||
```
|
||||
|
||||
Make the scripts executable:
|
||||
|
||||
```bash
|
||||
chmod +x scripts/openresty-modules/*.sh
|
||||
```
|
||||
|
||||
## Installed Instance Diagnostics
|
||||
|
||||
Find the OpenResty installation directory first. A common path is similar to:
|
||||
|
||||
```text
|
||||
/opt/1panel/apps/openresty/openresty
|
||||
```
|
||||
|
||||
Run the diagnostic collector:
|
||||
|
||||
```bash
|
||||
./scripts/openresty-modules/diagnose-install.sh \
|
||||
/opt/1panel/apps/openresty/openresty
|
||||
```
|
||||
|
||||
Override container discovery when needed:
|
||||
|
||||
```bash
|
||||
./scripts/openresty-modules/diagnose-install.sh \
|
||||
/opt/1panel/apps/openresty/openresty \
|
||||
--container 1Panel-openresty
|
||||
```
|
||||
|
||||
The collector checks:
|
||||
|
||||
- `module.json` artifact paths and SHA-256 checksums
|
||||
- managed `load_module` files and host/container path mapping
|
||||
- read-only Compose mounts
|
||||
- current container image ID versus enabled module target image IDs
|
||||
- container state, Nginx build options, `nginx -t`, loaded module directives,
|
||||
module checksums inside the container, `ldd`, and recent logs
|
||||
|
||||
The default report does not retain full `nginx -T` output. Use
|
||||
`--full-config` only on a test host because the resulting archive may contain
|
||||
credentials or private site configuration.
|
||||
|
||||
Module scripts are redacted from the copied state files by default. Container
|
||||
logs and error strings can still contain site names, URLs, or command output;
|
||||
review an archive before sharing it outside your team.
|
||||
|
||||
Do not edit generated module state or managed config files while a 1Panel app
|
||||
task is running. Review the diagnostic archive before sharing it.
|
||||
@@ -0,0 +1,475 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
RUN_ID="$(date -u +%Y%m%dT%H%M%SZ)-$$"
|
||||
INSTALL_DIR=""
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-${PWD}/openresty-module-diagnostics/${RUN_ID}}"
|
||||
CONTAINER=""
|
||||
FULL_CONFIG=0
|
||||
CREATE_ARCHIVE=1
|
||||
NGINX_TEST=1
|
||||
UNEXPECTED_FAILURE=""
|
||||
declare -a FAILED_CHECKS=()
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: diagnose-install.sh INSTALL_DIR [options]
|
||||
|
||||
Collect a mostly read-only diagnostic report for an installed 1Panel OpenResty.
|
||||
The only container command with behavior is `nginx -t`; no reload is performed.
|
||||
|
||||
Options:
|
||||
--output PATH Result directory
|
||||
--container NAME Override the container discovered from Docker Compose
|
||||
--full-config Retain full `nginx -T` output (may contain sensitive data)
|
||||
--no-nginx-test Do not execute nginx -t/-T in the running container
|
||||
--no-archive Do not create a .tar.gz report
|
||||
-h, --help Show this help
|
||||
EOF
|
||||
}
|
||||
|
||||
log() {
|
||||
printf '[%s] %s\n' "$(date -u +%H:%M:%S)" "$*" | tee -a "${OUTPUT_DIR}/run.log"
|
||||
}
|
||||
|
||||
mark_failed() {
|
||||
FAILED_CHECKS+=("$1")
|
||||
log "CHECK FAILED: $1"
|
||||
}
|
||||
|
||||
mark_passed() {
|
||||
log "CHECK PASSED: $1"
|
||||
}
|
||||
|
||||
require_command() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
printf 'Required command not found: %s\n' "$1" >&2
|
||||
exit 2
|
||||
fi
|
||||
}
|
||||
|
||||
on_error() {
|
||||
local status="$1" line="$2" command="$3"
|
||||
UNEXPECTED_FAILURE="line ${line}: ${command} (exit ${status})"
|
||||
return "${status}"
|
||||
}
|
||||
|
||||
finalize() {
|
||||
local status=$?
|
||||
set +e
|
||||
if [[ -n "${UNEXPECTED_FAILURE}" ]]; then
|
||||
printf '%s\n' "${UNEXPECTED_FAILURE}" >"${OUTPUT_DIR}/unexpected-failure.txt"
|
||||
fi
|
||||
{
|
||||
printf 'install_dir=%s\n' "${INSTALL_DIR}"
|
||||
printf 'container=%s\n' "${CONTAINER}"
|
||||
printf 'failed_checks=%s\n' "${#FAILED_CHECKS[@]}"
|
||||
local check
|
||||
for check in "${FAILED_CHECKS[@]:-}"; do
|
||||
[[ -n "${check}" ]] && printf 'failure=%s\n' "${check}"
|
||||
done
|
||||
} >"${OUTPUT_DIR}/summary.txt"
|
||||
|
||||
if [[ "${CREATE_ARCHIVE}" -eq 1 ]]; then
|
||||
local archive="${OUTPUT_DIR%/}.tar.gz"
|
||||
tar -czf "${archive}" -C "$(dirname -- "${OUTPUT_DIR}")" "$(basename -- "${OUTPUT_DIR}")" 2>/dev/null || true
|
||||
printf 'Diagnostic archive: %s\n' "${archive}"
|
||||
fi
|
||||
printf 'Diagnostic directory: %s\n' "${OUTPUT_DIR}"
|
||||
|
||||
if [[ "${status}" -eq 0 && "${#FAILED_CHECKS[@]}" -gt 0 ]]; then
|
||||
status=1
|
||||
fi
|
||||
exit "${status}"
|
||||
}
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
usage >&2
|
||||
exit 2
|
||||
fi
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
INSTALL_DIR="$1"
|
||||
shift
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--output)
|
||||
OUTPUT_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
--container)
|
||||
CONTAINER="$2"
|
||||
shift 2
|
||||
;;
|
||||
--full-config)
|
||||
FULL_CONFIG=1
|
||||
shift
|
||||
;;
|
||||
--no-nginx-test)
|
||||
NGINX_TEST=0
|
||||
shift
|
||||
;;
|
||||
--no-archive)
|
||||
CREATE_ARCHIVE=0
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
printf 'Unknown option: %s\n' "$1" >&2
|
||||
usage >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -d "${INSTALL_DIR}" ]] || {
|
||||
printf 'Install directory not found: %s\n' "${INSTALL_DIR}" >&2
|
||||
exit 2
|
||||
}
|
||||
INSTALL_DIR="$(cd -- "${INSTALL_DIR}" && pwd -P)"
|
||||
if [[ -d "${OUTPUT_DIR}" ]] && find "${OUTPUT_DIR}" -mindepth 1 -print -quit | grep -q .; then
|
||||
printf 'Output directory must be empty: %s\n' "${OUTPUT_DIR}" >&2
|
||||
exit 2
|
||||
fi
|
||||
mkdir -p "${OUTPUT_DIR}"
|
||||
OUTPUT_DIR="$(cd -- "${OUTPUT_DIR}" && pwd -P)"
|
||||
|
||||
trap 'on_error "$?" "$LINENO" "$BASH_COMMAND"' ERR
|
||||
trap finalize EXIT
|
||||
|
||||
preflight() {
|
||||
[[ "$(uname -s)" == "Linux" ]] || {
|
||||
printf 'This diagnostic script must run on Linux.\n' >&2
|
||||
exit 2
|
||||
}
|
||||
require_command docker
|
||||
require_command jq
|
||||
require_command python3
|
||||
require_command sha256sum
|
||||
require_command tar
|
||||
|
||||
docker version >"${OUTPUT_DIR}/docker-version.txt" 2>&1
|
||||
docker info >"${OUTPUT_DIR}/docker-info.txt" 2>&1
|
||||
uname -a >"${OUTPUT_DIR}/uname.txt"
|
||||
cp /etc/os-release "${OUTPUT_DIR}/os-release.txt" 2>/dev/null || true
|
||||
df -h >"${OUTPUT_DIR}/disk-free.txt"
|
||||
free -h >"${OUTPUT_DIR}/memory.txt" 2>&1 || true
|
||||
log "Inspecting ${INSTALL_DIR}"
|
||||
}
|
||||
|
||||
collect_filesystem_state() {
|
||||
[[ -d "${INSTALL_DIR}/modules" ]] || mark_failed "module artifact directory is missing"
|
||||
[[ -d "${INSTALL_DIR}/conf/modules-enabled" ]] || mark_failed "managed module config directory is missing"
|
||||
find "${INSTALL_DIR}/modules" -maxdepth 5 -printf '%M\t%u:%g\t%s\t%TY-%Tm-%TdT%TH:%TM:%TS\t%p\n' \
|
||||
>"${OUTPUT_DIR}/module-files.txt" 2>&1 || true
|
||||
find "${INSTALL_DIR}/conf/modules-enabled" -maxdepth 1 -type f -printf '%f\n' \
|
||||
>"${OUTPUT_DIR}/managed-config-files.txt" 2>&1 || true
|
||||
grep -RnsE '^[[:space:]]*load_module[[:space:]]+' "${INSTALL_DIR}/conf/modules-enabled" \
|
||||
>"${OUTPUT_DIR}/load-module-directives.txt" 2>&1 || true
|
||||
grep -E '^(RESTY_|CONTAINER_NAME=|PANEL_APP_PORT_HTTP=)' "${INSTALL_DIR}/.env" \
|
||||
>"${OUTPUT_DIR}/relevant-env.txt" 2>/dev/null || true
|
||||
|
||||
if [[ -f "${INSTALL_DIR}/build/module.json" ]]; then
|
||||
jq 'map(if has("script") then .script = "<redacted>" else . end)' \
|
||||
"${INSTALL_DIR}/build/module.json" >"${OUTPUT_DIR}/module-state.json"
|
||||
else
|
||||
mark_failed "module state file is missing"
|
||||
fi
|
||||
if [[ -f "${INSTALL_DIR}/build/module.catalog.json" ]]; then
|
||||
jq 'map(if has("script") then .script = "<redacted>" else . end)' \
|
||||
"${INSTALL_DIR}/build/module.catalog.json" >"${OUTPUT_DIR}/module-catalog.json"
|
||||
fi
|
||||
}
|
||||
|
||||
validate_artifacts() {
|
||||
local state="${INSTALL_DIR}/build/module.json"
|
||||
[[ -f "${state}" ]] || return 0
|
||||
if python3 - "${state}" "${INSTALL_DIR}/modules" >"${OUTPUT_DIR}/artifact-validation.tsv" <<'PY'
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
state_path = pathlib.Path(sys.argv[1])
|
||||
modules_root = pathlib.Path(sys.argv[2]).resolve()
|
||||
modules = json.loads(state_path.read_text(encoding="utf-8"))
|
||||
failed = False
|
||||
print("module\tbuild_status\ttarget_key\tartifact\texpected\tactual\tresult")
|
||||
for module in modules:
|
||||
for build in module.get("builds") or []:
|
||||
target_key = (build.get("target") or {}).get("key", "")
|
||||
for artifact in build.get("artifacts") or []:
|
||||
relative = artifact.get("path", "")
|
||||
expected = artifact.get("checksum", "")
|
||||
result = "OK"
|
||||
actual = ""
|
||||
try:
|
||||
pure = pathlib.PurePosixPath(relative)
|
||||
if not relative or pure.is_absolute() or ".." in pure.parts or "\\" in relative:
|
||||
raise ValueError("unsafe-path")
|
||||
candidate = modules_root / pathlib.Path(*pure.parts)
|
||||
if candidate.is_symlink():
|
||||
raise ValueError("symlink-not-allowed")
|
||||
full_path = candidate.resolve(strict=True)
|
||||
if modules_root not in full_path.parents:
|
||||
raise ValueError("outside-module-root")
|
||||
if not full_path.is_file():
|
||||
raise ValueError("not-regular-file")
|
||||
digest = hashlib.sha256()
|
||||
with full_path.open("rb") as handle:
|
||||
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
|
||||
digest.update(chunk)
|
||||
actual = digest.hexdigest()
|
||||
if actual.lower() != expected.lower():
|
||||
raise ValueError("checksum-mismatch")
|
||||
except Exception as error:
|
||||
result = str(error)
|
||||
failed = True
|
||||
print("\t".join([
|
||||
module.get("name", ""), build.get("status", ""), target_key,
|
||||
relative, expected, actual, result,
|
||||
]))
|
||||
sys.exit(1 if failed else 0)
|
||||
PY
|
||||
then
|
||||
mark_passed "artifact paths and checksums"
|
||||
else
|
||||
mark_failed "artifact paths or checksums"
|
||||
fi
|
||||
}
|
||||
|
||||
validate_managed_configs() {
|
||||
if python3 - "${INSTALL_DIR}/conf/modules-enabled" "${INSTALL_DIR}/modules" \
|
||||
>"${OUTPUT_DIR}/managed-config-validation.tsv" <<'PY'
|
||||
import pathlib
|
||||
import re
|
||||
import sys
|
||||
|
||||
config_root = pathlib.Path(sys.argv[1])
|
||||
modules_root = pathlib.Path(sys.argv[2]).resolve()
|
||||
container_prefix = "/usr/local/openresty/nginx/modules/1panel/"
|
||||
pattern = re.compile(r"^\s*load_module\s+([^;]+);", re.MULTILINE)
|
||||
failed = False
|
||||
print("config\tcontainer_path\thost_path\tresult")
|
||||
if config_root.exists():
|
||||
for config in sorted(config_root.glob("1panel-module-*.conf")):
|
||||
content = config.read_text(encoding="utf-8")
|
||||
for value in pattern.findall(content):
|
||||
container_path = value.strip().strip('"\'')
|
||||
result = "OK"
|
||||
host_path = ""
|
||||
try:
|
||||
if not container_path.startswith(container_prefix):
|
||||
raise ValueError("unexpected-container-path")
|
||||
relative = pathlib.PurePosixPath(container_path[len(container_prefix):])
|
||||
if ".." in relative.parts:
|
||||
raise ValueError("unsafe-path")
|
||||
resolved = (modules_root / pathlib.Path(*relative.parts)).resolve(strict=True)
|
||||
if modules_root not in resolved.parents or not resolved.is_file():
|
||||
raise ValueError("missing-artifact")
|
||||
host_path = str(resolved)
|
||||
except Exception as error:
|
||||
result = str(error)
|
||||
failed = True
|
||||
print("\t".join([config.name, container_path, host_path, result]))
|
||||
sys.exit(1 if failed else 0)
|
||||
PY
|
||||
then
|
||||
mark_passed "managed load_module configs"
|
||||
else
|
||||
mark_failed "managed load_module configs"
|
||||
fi
|
||||
}
|
||||
|
||||
collect_compose_state() {
|
||||
local compose_file="${INSTALL_DIR}/docker-compose.yml"
|
||||
if [[ ! -f "${compose_file}" ]]; then
|
||||
mark_failed "docker-compose.yml is missing"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if (cd "${INSTALL_DIR}" && docker compose config --format json) >"${OUTPUT_DIR}/compose.json" 2>"${OUTPUT_DIR}/compose-config.log"; then
|
||||
mark_passed "docker compose config"
|
||||
else
|
||||
mark_failed "docker compose config"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if jq -e '
|
||||
[.services[].volumes[]?]
|
||||
| (any(.[]; (.target | rtrimstr("/")) == "/usr/local/openresty/nginx/modules/1panel" and .read_only == true))
|
||||
and (any(.[]; (.target | rtrimstr("/")) == "/usr/local/openresty/nginx/conf/modules-enabled" and .read_only == true))
|
||||
' "${OUTPUT_DIR}/compose.json" >/dev/null; then
|
||||
mark_passed "read-only module mounts"
|
||||
else
|
||||
mark_failed "read-only module mounts"
|
||||
fi
|
||||
|
||||
(cd "${INSTALL_DIR}" && docker compose ps -a --format json) >"${OUTPUT_DIR}/compose-ps.json" 2>&1 || true
|
||||
if [[ -z "${CONTAINER}" ]]; then
|
||||
local cid
|
||||
cid="$(cd "${INSTALL_DIR}" && docker compose ps -q 2>/dev/null | head -n 1)"
|
||||
if [[ -n "${cid}" ]]; then
|
||||
CONTAINER="$(docker inspect --format '{{.Name}}' "${cid}" | sed 's#^/##')"
|
||||
else
|
||||
CONTAINER="$(jq -r '[.services[] | select((.image // "") | test("openresty"; "i")) | .container_name][0] // empty' \
|
||||
"${OUTPUT_DIR}/compose.json")"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
compare_target_identity() {
|
||||
local state="${INSTALL_DIR}/build/module.json"
|
||||
local current_image_id="$1"
|
||||
[[ -f "${state}" ]] || return 0
|
||||
if python3 - "${state}" "${current_image_id}" "${INSTALL_DIR}/conf/modules-enabled" \
|
||||
>"${OUTPUT_DIR}/target-identity.tsv" <<'PY'
|
||||
import json
|
||||
import pathlib
|
||||
import re
|
||||
import sys
|
||||
|
||||
modules = json.load(open(sys.argv[1], encoding="utf-8"))
|
||||
current = sys.argv[2]
|
||||
config_root = pathlib.Path(sys.argv[3])
|
||||
pattern = re.compile(r"^\s*load_module\s+([^;]+);", re.MULTILINE)
|
||||
prefix = "/usr/local/openresty/nginx/modules/1panel/"
|
||||
loaded = set()
|
||||
if config_root.exists():
|
||||
for config in config_root.glob("1panel-module-*.conf"):
|
||||
for value in pattern.findall(config.read_text(encoding="utf-8")):
|
||||
container_path = value.strip().strip('"\'')
|
||||
if container_path.startswith(prefix):
|
||||
loaded.add(container_path[len(prefix):])
|
||||
failed = False
|
||||
print("module\tenabled\tmode\tready_image_ids\tmanaged_artifacts\tresult")
|
||||
for module in modules:
|
||||
mode = module.get("buildMode") or "static"
|
||||
if module.get("deleted") or not module.get("enable") or mode == "static":
|
||||
continue
|
||||
ready = [build for build in module.get("builds") or [] if build.get("status") == "ready"]
|
||||
digests = sorted({(build.get("target") or {}).get("imageDigest", "") for build in ready})
|
||||
candidates = []
|
||||
if not ready:
|
||||
result = "NO-READY-BUILD"
|
||||
failed = True
|
||||
elif current in digests:
|
||||
result = "MATCH"
|
||||
candidates = [build for build in ready if (build.get("target") or {}).get("imageDigest") == current]
|
||||
elif not any(digests):
|
||||
result = "UNKNOWN-NO-IMAGE-DIGEST"
|
||||
candidates = ready
|
||||
else:
|
||||
result = "MISMATCH"
|
||||
failed = True
|
||||
|
||||
managed = []
|
||||
if candidates:
|
||||
for build in candidates:
|
||||
paths = [artifact.get("path", "") for artifact in build.get("artifacts") or []]
|
||||
if paths and all(path in loaded for path in paths):
|
||||
managed = paths
|
||||
break
|
||||
if not managed:
|
||||
result += "+NOT-IN-MANAGED-CONFIG"
|
||||
failed = True
|
||||
print("\t".join([
|
||||
module.get("name", ""), str(module.get("enable", False)),
|
||||
mode, ",".join(digests), ",".join(managed), result,
|
||||
]))
|
||||
sys.exit(1 if failed else 0)
|
||||
PY
|
||||
then
|
||||
mark_passed "enabled module target image identity"
|
||||
else
|
||||
mark_failed "enabled module target image identity"
|
||||
fi
|
||||
}
|
||||
|
||||
collect_container_state() {
|
||||
if [[ -z "${CONTAINER}" ]]; then
|
||||
mark_failed "OpenResty container could not be discovered"
|
||||
return 0
|
||||
fi
|
||||
if ! docker inspect "${CONTAINER}" >/dev/null 2>&1; then
|
||||
mark_failed "container ${CONTAINER} does not exist"
|
||||
return 0
|
||||
fi
|
||||
|
||||
docker inspect "${CONTAINER}" | jq '.[0] | {
|
||||
Id, Name, Image, State,
|
||||
Config: {Image: .Config.Image},
|
||||
Mounts: [.Mounts[] | {Type, Source, Destination, RW}]
|
||||
}' >"${OUTPUT_DIR}/container.json"
|
||||
docker logs --tail 1000 --timestamps "${CONTAINER}" >"${OUTPUT_DIR}/container.log" 2>&1 || true
|
||||
|
||||
local running image_id image_name
|
||||
running="$(docker inspect --format '{{.State.Running}}' "${CONTAINER}")"
|
||||
image_id="$(docker inspect --format '{{.Image}}' "${CONTAINER}")"
|
||||
image_name="$(docker inspect --format '{{.Config.Image}}' "${CONTAINER}")"
|
||||
docker image inspect "${image_id}" | jq '.[0] | {Id, RepoTags, RepoDigests, Architecture, Os, Created}' \
|
||||
>"${OUTPUT_DIR}/runtime-image.json" 2>&1 || true
|
||||
printf 'container=%s\nrunning=%s\nimage_name=%s\nimage_id=%s\n' \
|
||||
"${CONTAINER}" "${running}" "${image_name}" "${image_id}" >"${OUTPUT_DIR}/runtime.txt"
|
||||
compare_target_identity "${image_id}"
|
||||
|
||||
if [[ "${running}" != "true" ]]; then
|
||||
mark_failed "container ${CONTAINER} is not running"
|
||||
return 0
|
||||
fi
|
||||
mark_passed "container is running"
|
||||
|
||||
docker exec "${CONTAINER}" /usr/local/openresty/nginx/sbin/nginx -V \
|
||||
>"${OUTPUT_DIR}/nginx-version.txt" 2>&1 || mark_failed "nginx -V"
|
||||
docker exec "${CONTAINER}" /bin/sh -c \
|
||||
'find /usr/local/openresty/nginx/modules/1panel -type f -name "*.so" -exec sha256sum {} \; | sort' \
|
||||
>"${OUTPUT_DIR}/container-artifact-checksums.txt" 2>&1 || true
|
||||
docker exec "${CONTAINER}" /bin/sh -c \
|
||||
'for f in $(find /usr/local/openresty/nginx/modules/1panel -type f -name "*.so" | sort); do echo "### $f"; ldd "$f" || true; done' \
|
||||
>"${OUTPUT_DIR}/container-artifact-ldd.txt" 2>&1 || true
|
||||
|
||||
if [[ "${NGINX_TEST}" -eq 1 ]]; then
|
||||
if docker exec "${CONTAINER}" /usr/local/openresty/nginx/sbin/nginx -t \
|
||||
>"${OUTPUT_DIR}/nginx-test.txt" 2>&1; then
|
||||
mark_passed "running container nginx -t"
|
||||
else
|
||||
mark_failed "running container nginx -t"
|
||||
fi
|
||||
|
||||
local full_output="${OUTPUT_DIR}/nginx-T.full.tmp"
|
||||
docker exec "${CONTAINER}" /usr/local/openresty/nginx/sbin/nginx -T >"${full_output}" 2>&1 || true
|
||||
if [[ "${FULL_CONFIG}" -eq 1 ]]; then
|
||||
mv "${full_output}" "${OUTPUT_DIR}/nginx-T.full.txt"
|
||||
log "WARNING: nginx-T.full.txt may contain credentials or private configuration"
|
||||
else
|
||||
grep -nE 'load_module|modules-enabled|nginx version:|configure arguments:' "${full_output}" \
|
||||
>"${OUTPUT_DIR}/nginx-T-modules.txt" 2>/dev/null || true
|
||||
rm -f "${full_output}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
preflight
|
||||
collect_filesystem_state
|
||||
validate_artifacts
|
||||
validate_managed_configs
|
||||
collect_compose_state
|
||||
collect_container_state
|
||||
|
||||
if [[ "${#FAILED_CHECKS[@]}" -gt 0 ]]; then
|
||||
log "Diagnostics completed with ${#FAILED_CHECKS[@]} failed checks"
|
||||
return 0
|
||||
fi
|
||||
log "Diagnostics completed without failed checks"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user