83 lines
4.6 KiB
Bash
Executable file
83 lines
4.6 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
manifest=${1:?usage: deploy-release-candidate.sh MANIFEST}
|
|
: "${CLUSTERFLUX_DEPLOY_COMMAND:?set the documented exact-candidate deployment command}"
|
|
: "${CLUSTERFLUX_STRICT_SSH_TARGET:?set the production SSH target}"
|
|
|
|
service_unit=${CLUSTERFLUX_STRICT_SERVICE_UNIT:-clusterflux-hosted.service}
|
|
proxy_unit=${CLUSTERFLUX_STRICT_PROXY_UNIT:-nginx.service}
|
|
evidence_path=${CLUSTERFLUX_DEPLOYMENT_EVIDENCE_PATH:-target/acceptance/deployment.json}
|
|
staging=$(mktemp -d)
|
|
trap 'rm -rf "$staging"' EXIT
|
|
|
|
IFS=$'\t' read -r archive expected_archive_sha < <(
|
|
node - "$manifest" <<'NODE'
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const manifestPath = path.resolve(process.argv[2]);
|
|
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
const asset = (manifest.assets || []).find((entry) => entry.name.startsWith("clusterflux-hosted-"));
|
|
if (!asset) throw new Error("candidate manifest has no hosted archive");
|
|
const file = path.isAbsolute(asset.file)
|
|
? asset.file
|
|
: path.resolve(path.dirname(manifestPath), asset.file);
|
|
process.stdout.write(`${file}\t${asset.sha256}\n`);
|
|
NODE
|
|
)
|
|
|
|
actual_archive_sha=$(sha256sum "$archive" | awk '{print $1}')
|
|
test "$actual_archive_sha" = "${expected_archive_sha#sha256:}"
|
|
tar -xzf "$archive" -C "$staging"
|
|
candidate_coordinator=$(find "$staging" -type f -name clusterflux-hosted-service -perm -u+x -print -quit)
|
|
test -n "$candidate_coordinator"
|
|
candidate_sha=$(sha256sum "$candidate_coordinator" | awk '{print $1}')
|
|
|
|
export CLUSTERFLUX_CANDIDATE_ARCHIVE="$archive"
|
|
export CLUSTERFLUX_CANDIDATE_ARCHIVE_SHA256="sha256:$actual_archive_sha"
|
|
export CLUSTERFLUX_CANDIDATE_COORDINATOR="$candidate_coordinator"
|
|
export CLUSTERFLUX_CANDIDATE_COORDINATOR_SHA256="sha256:$candidate_sha"
|
|
bash -euo pipefail -c "$CLUSTERFLUX_DEPLOY_COMMAND"
|
|
|
|
main_pid=$(ssh "$CLUSTERFLUX_STRICT_SSH_TARGET" systemctl show --property=MainPID --value "$service_unit")
|
|
test "$main_pid" != 0
|
|
remote_executable=$(ssh "$CLUSTERFLUX_STRICT_SSH_TARGET" readlink -f "/proc/$main_pid/exe")
|
|
remote_sha=$(ssh "$CLUSTERFLUX_STRICT_SSH_TARGET" sha256sum "$remote_executable" | awk '{print $1}')
|
|
test "$remote_sha" = "$candidate_sha"
|
|
service_fragment=$(ssh "$CLUSTERFLUX_STRICT_SSH_TARGET" systemctl show --property=FragmentPath --value "$service_unit")
|
|
service_fragment_sha=$(ssh "$CLUSTERFLUX_STRICT_SSH_TARGET" sha256sum "$service_fragment" | awk '{print $1}')
|
|
service_configuration_sha=$(ssh "$CLUSTERFLUX_STRICT_SSH_TARGET" systemctl cat "$service_unit" | sha256sum | awk '{print $1}')
|
|
proxy_fragment=$(ssh "$CLUSTERFLUX_STRICT_SSH_TARGET" systemctl show --property=FragmentPath --value "$proxy_unit")
|
|
proxy_fragment_sha=$(ssh "$CLUSTERFLUX_STRICT_SSH_TARGET" sha256sum "$proxy_fragment" | awk '{print $1}')
|
|
proxy_exec_start=$(ssh "$CLUSTERFLUX_STRICT_SSH_TARGET" systemctl show --property=ExecStart --value "$proxy_unit")
|
|
proxy_executable=$(sed -n 's/.*path=\([^ ;]*\).*/\1/p' <<<"$proxy_exec_start")
|
|
proxy_configuration=$(sed -n 's/.* argv\[\]=.* -c \([^ ;]*\).*/\1/p' <<<"$proxy_exec_start")
|
|
test -n "$proxy_executable"
|
|
test -n "$proxy_configuration"
|
|
proxy_configuration_sha=$(ssh "$CLUSTERFLUX_STRICT_SSH_TARGET" "$proxy_executable" -T -c "$proxy_configuration" 2>/dev/null | sha256sum | awk '{print $1}')
|
|
mkdir -p "$(dirname "$evidence_path")"
|
|
|
|
EVIDENCE_PATH="$evidence_path" SERVICE_UNIT="$service_unit" \
|
|
SERVICE_FRAGMENT="$service_fragment" SERVICE_FRAGMENT_SHA="$service_fragment_sha" \
|
|
SERVICE_CONFIGURATION_SHA="$service_configuration_sha" \
|
|
REMOTE_EXECUTABLE="$remote_executable" REMOTE_SHA="$remote_sha" \
|
|
PROXY_UNIT="$proxy_unit" PROXY_FRAGMENT="$proxy_fragment" \
|
|
PROXY_FRAGMENT_SHA="$proxy_fragment_sha" PROXY_EXECUTABLE="$proxy_executable" \
|
|
PROXY_CONFIGURATION="$proxy_configuration" PROXY_CONFIGURATION_SHA="$proxy_configuration_sha" node <<'NODE'
|
|
const fs = require("fs");
|
|
fs.writeFileSync(process.env.EVIDENCE_PATH, JSON.stringify({
|
|
kind: "clusterflux-exact-candidate-deployment",
|
|
service_unit: process.env.SERVICE_UNIT,
|
|
service_unit_fragment: process.env.SERVICE_FRAGMENT,
|
|
service_unit_sha256: `sha256:${process.env.SERVICE_FRAGMENT_SHA}`,
|
|
service_configuration_sha256: `sha256:${process.env.SERVICE_CONFIGURATION_SHA}`,
|
|
hosted_service_executable: process.env.REMOTE_EXECUTABLE,
|
|
hosted_service_sha256: `sha256:${process.env.REMOTE_SHA}`,
|
|
proxy_unit: process.env.PROXY_UNIT,
|
|
proxy_unit_fragment: process.env.PROXY_FRAGMENT,
|
|
proxy_unit_sha256: `sha256:${process.env.PROXY_FRAGMENT_SHA}`,
|
|
proxy_executable: process.env.PROXY_EXECUTABLE,
|
|
proxy_configuration: process.env.PROXY_CONFIGURATION,
|
|
proxy_configuration_sha256: `sha256:${process.env.PROXY_CONFIGURATION_SHA}`,
|
|
}, null, 2) + "\n");
|
|
NODE
|