Refactor Dockerfiles to streamline PHP extension checks and remove unnecessary installations
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1730,6 +1730,7 @@ CONFIG_PATH="$INSTALL_DIR/config.json"
|
||||
CONFIG_TEMPLATE_PATH="$INSTALL_DIR/config.template.json"
|
||||
HEARTBEAT_MARKER_PATH="$RUNTIME_DIR/last-heartbeat-ok.txt"
|
||||
STACK_SERVICE_PATH="/etc/systemd/system/truckwash-edge-gateway-stack.service"
|
||||
LEGACY_SERVICE_PATH="/etc/systemd/system/truckwash-edge-agent.service"
|
||||
INSTALL_TOKEN="__INSTALL_TOKEN__"
|
||||
INSTALL_STATUS_URL="__STATUS_URL__"
|
||||
CURRENT_STEP="Preparing installer"
|
||||
@@ -1737,7 +1738,6 @@ CURRENT_STEP_CODE="PENDING"
|
||||
CURRENT_METHOD=""
|
||||
CURRENT_URL=""
|
||||
INSTALL_STARTED_AT="$(date +%s)"
|
||||
REUSE_EXISTING_CREDENTIALS=0
|
||||
DIAGNOSTIC_NAMES=()
|
||||
DIAGNOSTIC_OUTPUTS=()
|
||||
json_escape() {
|
||||
@@ -1777,6 +1777,16 @@ emit_diagnostic_json() {
|
||||
json="${json}]"
|
||||
printf '%s' "$json"
|
||||
}
|
||||
print_collected_diagnostics() {
|
||||
local index
|
||||
for index in "${!DIAGNOSTIC_NAMES[@]}"; do
|
||||
if [ -z "${DIAGNOSTIC_OUTPUTS[$index]:-}" ]; then
|
||||
continue
|
||||
fi
|
||||
log_error "Diagnostic: ${DIAGNOSTIC_NAMES[$index]}"
|
||||
printf '%s\n' "${DIAGNOSTIC_OUTPUTS[$index]}" | sed 's/^/[truckwash-edge-agent] /' >&2
|
||||
done
|
||||
}
|
||||
capture_command_diagnostic() {
|
||||
local name="$1"
|
||||
shift
|
||||
@@ -1859,6 +1869,7 @@ on_error() {
|
||||
log_error "Last request: ${CURRENT_METHOD} ${CURRENT_URL}"
|
||||
fi
|
||||
diagnostics_json="$(collect_install_diagnostics)"
|
||||
print_collected_diagnostics
|
||||
gateway_id="$(read_config_value "$CONFIG_PATH" gatewayId 2>/dev/null || true)"
|
||||
report_install_status "FAILED" "FAILED" "$failure_message" "$diagnostics_json" "$gateway_id"
|
||||
exit "$exit_code"
|
||||
@@ -1942,6 +1953,45 @@ fetch_http() {
|
||||
[ "$cleanup_body" -eq 1 ] && rm -f "$body_path"
|
||||
rm -f "$headers_path"
|
||||
}
|
||||
cleanup_existing_installation() {
|
||||
if [ "$INSTALL_DIR" != "/opt/truckwash-edge-agent" ]; then
|
||||
echo "Refusing to remove unexpected install directory: $INSTALL_DIR" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
set +e
|
||||
systemctl stop truckwash-edge-gateway-stack.service >/dev/null 2>&1
|
||||
systemctl stop truckwash-edge-agent.service >/dev/null 2>&1
|
||||
|
||||
if [ -x "$INSTALL_DIR/gateway-launcher.sh" ]; then
|
||||
TRUCKWASH_INSTALL_DIR="$INSTALL_DIR" "$INSTALL_DIR/gateway-launcher.sh" down >/dev/null 2>&1
|
||||
elif [ -f "$INSTALL_DIR/docker-compose.gateway.yml" ]; then
|
||||
if docker compose version >/dev/null 2>&1; then
|
||||
docker compose -f "$INSTALL_DIR/docker-compose.gateway.yml" down >/dev/null 2>&1
|
||||
elif command -v docker-compose >/dev/null 2>&1; then
|
||||
docker-compose -f "$INSTALL_DIR/docker-compose.gateway.yml" down >/dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
docker rm -f \
|
||||
truckwash-edge-agent \
|
||||
truckwash-lan-worker \
|
||||
truckwash-auto-updater \
|
||||
truckwash-redis \
|
||||
truckwash-mariadb \
|
||||
truckwash-minio >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
systemctl disable truckwash-edge-gateway-stack.service >/dev/null 2>&1
|
||||
systemctl disable truckwash-edge-agent.service >/dev/null 2>&1
|
||||
rm -f "$STACK_SERVICE_PATH" "$LEGACY_SERVICE_PATH"
|
||||
rm -rf "$INSTALL_DIR"
|
||||
systemctl daemon-reload >/dev/null 2>&1
|
||||
systemctl reset-failed truckwash-edge-gateway-stack.service >/dev/null 2>&1
|
||||
systemctl reset-failed truckwash-edge-agent.service >/dev/null 2>&1
|
||||
set -e
|
||||
}
|
||||
config_has_claimed_gateway() {
|
||||
local config_path="$1"
|
||||
php -r '
|
||||
@@ -1979,32 +2029,6 @@ read_config_value() {
|
||||
echo (string)$value;
|
||||
' "$config_path" "$key"
|
||||
}
|
||||
merge_agent_config() {
|
||||
local template_path="$1"
|
||||
local config_path="$2"
|
||||
php -r '
|
||||
$templatePath = $argv[1];
|
||||
$configPath = $argv[2];
|
||||
$template = json_decode((string)file_get_contents($templatePath), true);
|
||||
if (!is_array($template)) {
|
||||
fwrite(STDERR, "Invalid edge agent config template.\n");
|
||||
exit(1);
|
||||
}
|
||||
$existing = [];
|
||||
if (is_file($configPath)) {
|
||||
$decoded = json_decode((string)file_get_contents($configPath), true);
|
||||
if (is_array($decoded)) {
|
||||
$existing = $decoded;
|
||||
}
|
||||
}
|
||||
foreach (["gatewayId", "agentToken", "agentInstanceId", "installedVersion", "targetVersion", "lastStagedUpdate"] as $key) {
|
||||
if (array_key_exists($key, $existing) && $existing[$key] !== null && $existing[$key] !== "") {
|
||||
$template[$key] = $existing[$key];
|
||||
}
|
||||
}
|
||||
file_put_contents($configPath, json_encode($template, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL);
|
||||
' "$template_path" "$config_path"
|
||||
}
|
||||
heartbeat_marker_is_fresh() {
|
||||
local heartbeat_path="$1"
|
||||
local minimum_epoch="$2"
|
||||
@@ -2083,25 +2107,10 @@ wait_for_gateway_claim() {
|
||||
print_service_diagnostics
|
||||
return 1
|
||||
}
|
||||
wait_for_post_restart_heartbeat() {
|
||||
local heartbeat_path="$1"
|
||||
local minimum_epoch="$2"
|
||||
local timeout_seconds="${3:-30}"
|
||||
local elapsed=0
|
||||
while [ "$elapsed" -lt "$timeout_seconds" ]; do
|
||||
if heartbeat_marker_is_fresh "$heartbeat_path" "$minimum_epoch"; then
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
elapsed=$((elapsed + 1))
|
||||
done
|
||||
log_error "Gateway heartbeat was not observed within ${timeout_seconds}s after reinstall."
|
||||
print_service_diagnostics
|
||||
return 1
|
||||
}
|
||||
|
||||
begin_install_phase "VERIFY_TOKEN" "Verifying install token"
|
||||
fetch_http "Verify install token" "__VERIFY_URL__"
|
||||
begin_install_phase "REMOVE_EXISTING_INSTALL" "Removing existing edge gateway installation"
|
||||
run_step "Removing existing edge gateway installation" cleanup_existing_installation
|
||||
begin_install_phase "INSTALL_PACKAGES" "Installing runtime dependencies"
|
||||
run_step "Creating install directory" mkdir -p "$INSTALL_DIR" "$RUNTIME_DIR" "$RUNTIME_DIR/backups"
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
@@ -2119,15 +2128,11 @@ fetch_http "Download auto-updater Dockerfile" "__AUTO_UPDATER_DOCKERFILE_URL__"
|
||||
fetch_http "Download gateway launcher" "__LAUNCHER_URL__" "$INSTALL_DIR/gateway-launcher.sh"
|
||||
fetch_http "Download compose stack service unit" "__STACK_SERVICE_URL__" "$INSTALL_DIR/truckwash-edge-gateway-stack.service"
|
||||
fetch_http "Download compatibility service unit" "__LEGACY_SERVICE_URL__" "$INSTALL_DIR/truckwash-edge-agent.service"
|
||||
if config_has_claimed_gateway "$CONFIG_PATH"; then
|
||||
REUSE_EXISTING_CREDENTIALS=1
|
||||
log_info "Existing claimed gateway detected; reinstall will reuse saved gateway credentials."
|
||||
fi
|
||||
begin_install_phase "WRITE_CONFIG" "Writing gateway configuration"
|
||||
cat > "$CONFIG_TEMPLATE_PATH" <<'EOF_JSON'
|
||||
__CONFIG_JSON__
|
||||
EOF_JSON
|
||||
run_step "Writing agent config" merge_agent_config "$CONFIG_TEMPLATE_PATH" "$CONFIG_PATH"
|
||||
run_step "Writing fresh agent config" cp "$CONFIG_TEMPLATE_PATH" "$CONFIG_PATH"
|
||||
rm -f "$CONFIG_TEMPLATE_PATH"
|
||||
begin_install_phase "START_STACK" "Starting edge gateway stack"
|
||||
run_step "Installing systemd stack definition" install -m 0644 "$INSTALL_DIR/truckwash-edge-gateway-stack.service" "$STACK_SERVICE_PATH"
|
||||
@@ -2140,17 +2145,10 @@ run_step "Enabling truckwash-edge-gateway-stack.service" systemctl enable truckw
|
||||
run_step "Restarting truckwash-edge-gateway-stack.service" systemctl restart truckwash-edge-gateway-stack.service
|
||||
run_step "Verifying truckwash-edge-gateway-stack.service is active" systemctl is-active --quiet truckwash-edge-gateway-stack.service
|
||||
begin_install_phase "WAIT_FOR_CLAIM" "Waiting for gateway heartbeat and claim"
|
||||
if [ "$REUSE_EXISTING_CREDENTIALS" -eq 1 ]; then
|
||||
run_step "Waiting for post-reinstall heartbeat" wait_for_post_restart_heartbeat "$HEARTBEAT_MARKER_PATH" "$INSTALL_STARTED_AT" 180
|
||||
claimed_gateway_id="$(read_config_value "$CONFIG_PATH" gatewayId)"
|
||||
report_install_status "CLAIMED" "CLAIMED" "Gateway reconnected using preserved credentials." "[]" "$claimed_gateway_id"
|
||||
log_info "Reinstall reused gateway ${claimed_gateway_id}."
|
||||
else
|
||||
run_step "Waiting for gateway claim" wait_for_gateway_claim "$CONFIG_PATH" "$HEARTBEAT_MARKER_PATH" "$INSTALL_STARTED_AT" 180
|
||||
claimed_gateway_id="$(read_config_value "$CONFIG_PATH" gatewayId)"
|
||||
report_install_status "CLAIMED" "CLAIMED" "Gateway claim completed successfully." "[]" "$claimed_gateway_id"
|
||||
log_info "Gateway claim completed for gateway ${claimed_gateway_id}."
|
||||
fi
|
||||
run_step "Waiting for gateway claim" wait_for_gateway_claim "$CONFIG_PATH" "$HEARTBEAT_MARKER_PATH" "$INSTALL_STARTED_AT" 180
|
||||
claimed_gateway_id="$(read_config_value "$CONFIG_PATH" gatewayId)"
|
||||
report_install_status "CLAIMED" "CLAIMED" "Gateway claim completed successfully." "[]" "$claimed_gateway_id"
|
||||
log_info "Gateway claim completed for gateway ${claimed_gateway_id}."
|
||||
echo 'TruckWash edge gateway stack installed.'
|
||||
BASH;
|
||||
|
||||
|
||||
@@ -3,10 +3,8 @@ FROM ${BASE_IMAGE}
|
||||
|
||||
RUN set -eux; \
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends bash ca-certificates curl docker.io docker-compose libcurl4-openssl-dev libsqlite3-dev pkg-config; \
|
||||
docker-php-ext-install sqlite3 pdo_sqlite; \
|
||||
if ! php -m | grep -qi '^curl$'; then docker-php-ext-install curl; fi; \
|
||||
php -r 'foreach (["curl", "sqlite3"] as $extension) { if (!extension_loaded($extension)) { fwrite(STDERR, "Missing PHP extension: {$extension}\n"); exit(1); } }'; \
|
||||
apt-get install -y --no-install-recommends bash ca-certificates curl docker.io docker-compose; \
|
||||
php -r 'foreach (["curl", "sqlite3", "pdo_sqlite"] as $extension) { if (!extension_loaded($extension)) { fwrite(STDERR, "Missing PHP extension: {$extension}\n"); exit(1); } }'; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY auto-updater.php /usr/local/bin/auto-updater.php
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
ARG BASE_IMAGE=php:8.2-cli-bookworm
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
RUN set -eux; \
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends libcurl4-openssl-dev libsqlite3-dev pkg-config; \
|
||||
docker-php-ext-install sqlite3 pdo_sqlite; \
|
||||
if ! php -m | grep -qi '^curl$'; then docker-php-ext-install curl; fi; \
|
||||
php -r 'foreach (["curl", "sqlite3"] as $extension) { if (!extension_loaded($extension)) { fwrite(STDERR, "Missing PHP extension: {$extension}\n"); exit(1); } }'; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
RUN php -r 'foreach (["curl", "sqlite3", "pdo_sqlite"] as $extension) { if (!extension_loaded($extension)) { fwrite(STDERR, "Missing PHP extension: {$extension}\n"); exit(1); } }'
|
||||
|
||||
WORKDIR /opt/truckwash-edge-agent
|
||||
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
ARG BASE_IMAGE=php:8.2-cli-bookworm
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
RUN set -eux; \
|
||||
apt-get update; \
|
||||
apt-get install -y --no-install-recommends libcurl4-openssl-dev libsqlite3-dev pkg-config; \
|
||||
docker-php-ext-install sqlite3 pdo_sqlite; \
|
||||
if ! php -m | grep -qi '^curl$'; then docker-php-ext-install curl; fi; \
|
||||
php -r 'foreach (["curl", "sqlite3"] as $extension) { if (!extension_loaded($extension)) { fwrite(STDERR, "Missing PHP extension: {$extension}\n"); exit(1); } }'; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
RUN php -r 'foreach (["curl", "sqlite3", "pdo_sqlite"] as $extension) { if (!extension_loaded($extension)) { fwrite(STDERR, "Missing PHP extension: {$extension}\n"); exit(1); } }'
|
||||
|
||||
WORKDIR /opt/truckwash-edge-agent
|
||||
|
||||
|
||||
@@ -37,18 +37,33 @@ it('builds the installer around the compose stack artifacts and management polli
|
||||
expect($managerSource)->toContain('apt-get install -y docker-compose-plugin');
|
||||
expect($managerSource)->toContain('apt-get install -y docker-compose');
|
||||
expect($managerSource)->toContain('Unable to install Docker Compose using docker-compose-plugin or docker-compose.');
|
||||
expect($managerSource)->toContain('Existing claimed gateway detected; reinstall will reuse saved gateway credentials.');
|
||||
expect($managerSource)->toContain('begin_install_phase "REMOVE_EXISTING_INSTALL" "Removing existing edge gateway installation"');
|
||||
expect($managerSource)->toContain('run_step "Removing existing edge gateway installation" cleanup_existing_installation');
|
||||
expect($managerSource)->toContain('cleanup_existing_installation()');
|
||||
expect($managerSource)->toContain('systemctl stop truckwash-edge-gateway-stack.service');
|
||||
expect($managerSource)->toContain('systemctl stop truckwash-edge-agent.service');
|
||||
expect($managerSource)->toContain('TRUCKWASH_INSTALL_DIR="$INSTALL_DIR" "$INSTALL_DIR/gateway-launcher.sh" down');
|
||||
expect($managerSource)->toContain('docker rm -f');
|
||||
expect($managerSource)->toContain('truckwash-minio');
|
||||
expect($managerSource)->toContain('rm -f "$STACK_SERVICE_PATH" "$LEGACY_SERVICE_PATH"');
|
||||
expect($managerSource)->toContain('rm -rf "$INSTALL_DIR"');
|
||||
expect($managerSource)->toContain('report_install_status() {');
|
||||
expect($managerSource)->toContain('begin_install_phase "START_STACK" "Starting edge gateway stack"');
|
||||
expect($managerSource)->toContain('report_install_status "RUNNING" "$CURRENT_STEP_CODE" "$CURRENT_STEP"');
|
||||
expect($managerSource)->toContain('report_install_status "FAILED" "FAILED" "$failure_message" "$diagnostics_json" "$gateway_id"');
|
||||
expect($managerSource)->toContain('run_step "Writing agent config" merge_agent_config "$CONFIG_TEMPLATE_PATH" "$CONFIG_PATH"');
|
||||
expect($managerSource)->toContain('print_collected_diagnostics()');
|
||||
expect($managerSource)->toContain('log_error "Diagnostic: ${DIAGNOSTIC_NAMES[$index]}"');
|
||||
expect($managerSource)->toContain('print_collected_diagnostics');
|
||||
expect($managerSource)->toContain('run_step "Writing fresh agent config" cp "$CONFIG_TEMPLATE_PATH" "$CONFIG_PATH"');
|
||||
expect($managerSource)->not->toContain('REUSE_EXISTING_CREDENTIALS');
|
||||
expect($managerSource)->not->toContain('merge_agent_config()');
|
||||
expect($managerSource)->toContain('chmod 0755 "$INSTALL_DIR/agent.php" "$INSTALL_DIR/lan-worker.php" "$INSTALL_DIR/auto-updater.php" "$INSTALL_DIR/gateway-launcher.sh"');
|
||||
expect($managerSource)->toContain('systemctl enable truckwash-edge-gateway-stack.service');
|
||||
expect($managerSource)->toContain('systemctl restart truckwash-edge-gateway-stack.service');
|
||||
expect($managerSource)->toContain('systemctl is-active --quiet truckwash-edge-gateway-stack.service');
|
||||
expect($managerSource)->toContain('run_step "Waiting for gateway claim" wait_for_gateway_claim "$CONFIG_PATH" "$HEARTBEAT_MARKER_PATH" "$INSTALL_STARTED_AT" 180');
|
||||
expect($managerSource)->toContain('run_step "Waiting for post-reinstall heartbeat" wait_for_post_restart_heartbeat "$HEARTBEAT_MARKER_PATH" "$INSTALL_STARTED_AT" 180');
|
||||
expect($managerSource)->not->toContain('run_step "Waiting for post-reinstall heartbeat"');
|
||||
expect($managerSource)->not->toContain('Gateway reconnected using preserved credentials.');
|
||||
expect($managerSource)->toContain('journalctl -u truckwash-edge-gateway-stack.service -n 60 --no-pager || true');
|
||||
expect($managerSource)->not->toContain('agent.mjs');
|
||||
expect($managerSource)->toContain("'brokerUrl' => \$this->buildBrokerPublicUrl()");
|
||||
@@ -114,27 +129,25 @@ it('builds the installer around the compose stack artifacts and management polli
|
||||
expect($agentSource)->toContain("'last_transport_error'");
|
||||
expect($agentSource)->toContain('private function recordTransportFailure(string $context, Throwable $throwable): void');
|
||||
expect($edgeDockerfileSource)->toContain('FROM ${BASE_IMAGE}');
|
||||
expect($edgeDockerfileSource)->toContain('apt-get install -y --no-install-recommends libcurl4-openssl-dev libsqlite3-dev pkg-config;');
|
||||
expect($edgeDockerfileSource)->toContain('docker-php-ext-install sqlite3 pdo_sqlite;');
|
||||
expect($edgeDockerfileSource)->toContain("if ! php -m | grep -qi '^curl$'; then docker-php-ext-install curl; fi;");
|
||||
expect($edgeDockerfileSource)->not->toContain('docker-php-ext-install');
|
||||
expect($edgeDockerfileSource)->toContain('extension_loaded($extension)');
|
||||
expect($edgeDockerfileSource)->toContain('"pdo_sqlite"');
|
||||
expect($edgeDockerfileSource)->toContain('Missing PHP extension: {$extension}');
|
||||
expect($edgeDockerfileSource)->toContain('COPY agent.php /opt/truckwash-edge-agent/agent.php');
|
||||
expect($workerDockerfileSource)->toContain('FROM ${BASE_IMAGE}');
|
||||
expect($workerDockerfileSource)->toContain('apt-get install -y --no-install-recommends libcurl4-openssl-dev libsqlite3-dev pkg-config;');
|
||||
expect($workerDockerfileSource)->toContain('docker-php-ext-install sqlite3 pdo_sqlite;');
|
||||
expect($workerDockerfileSource)->toContain("if ! php -m | grep -qi '^curl$'; then docker-php-ext-install curl; fi;");
|
||||
expect($workerDockerfileSource)->not->toContain('docker-php-ext-install');
|
||||
expect($workerDockerfileSource)->toContain('extension_loaded($extension)');
|
||||
expect($workerDockerfileSource)->toContain('"pdo_sqlite"');
|
||||
expect($workerDockerfileSource)->toContain('Missing PHP extension: {$extension}');
|
||||
expect($workerDockerfileSource)->toContain('COPY lan-worker.php /opt/truckwash-edge-agent/lan-worker.php');
|
||||
expect($workerSource)->toContain('worker_require_authorization');
|
||||
expect($agentSource)->toContain('X-Truckwash-Worker-Token: ');
|
||||
expect($autoUpdaterSource)->toContain("'/bin/bash ' . escapeshellarg(\$launcherPath) . ' reconcile 2>&1'");
|
||||
expect($autoUpdaterDockerfileSource)->toContain('COPY auto-updater.php /usr/local/bin/auto-updater.php');
|
||||
expect($autoUpdaterDockerfileSource)->toContain('apt-get install -y --no-install-recommends bash ca-certificates curl docker.io docker-compose libcurl4-openssl-dev libsqlite3-dev pkg-config;');
|
||||
expect($autoUpdaterDockerfileSource)->toContain('docker-php-ext-install sqlite3 pdo_sqlite;');
|
||||
expect($autoUpdaterDockerfileSource)->toContain("if ! php -m | grep -qi '^curl$'; then docker-php-ext-install curl; fi;");
|
||||
expect($autoUpdaterDockerfileSource)->toContain('apt-get install -y --no-install-recommends bash ca-certificates curl docker.io docker-compose;');
|
||||
expect($autoUpdaterDockerfileSource)->not->toContain('docker-php-ext-install');
|
||||
expect($autoUpdaterDockerfileSource)->toContain('extension_loaded($extension)');
|
||||
expect($autoUpdaterDockerfileSource)->toContain('"pdo_sqlite"');
|
||||
expect($serviceSource)->not->toContain('node /opt/truckwash-edge-agent/agent.mjs');
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user