0.2.73
This commit is contained in:
+25
-121
@@ -26,8 +26,7 @@ SSH performs the password prompt directly. The password is never read or stored
|
||||
by this script.
|
||||
|
||||
This deploys the current local working tree, including uncommitted server changes.
|
||||
Use -SkipAppRelease -SkipBuilder for an admin/server-only deployment: no APK is built or
|
||||
published, and the running Android builder container and image are left untouched.
|
||||
Use -SkipAppRelease for an admin/server-only deployment: no APK is built or published.
|
||||
|
||||
.EXAMPLE
|
||||
.\deploy-server.ps1
|
||||
@@ -48,7 +47,7 @@ published, and the running Android builder container and image are left untouche
|
||||
.\deploy-server.ps1 -EstimateOnly
|
||||
|
||||
.EXAMPLE
|
||||
.\deploy-server.ps1 -SkipAppRelease -SkipBuilder
|
||||
.\deploy-server.ps1 -SkipAppRelease
|
||||
#>
|
||||
|
||||
#Requires -Version 7.2
|
||||
@@ -88,11 +87,6 @@ param(
|
||||
[Parameter()]
|
||||
[switch] $SkipAppRelease,
|
||||
|
||||
# Preserve the Android builder container and reuse its image. This skips the SDK
|
||||
# image build and leaves the release controller untouched during an admin/server deploy.
|
||||
[Parameter()]
|
||||
[switch] $SkipBuilder,
|
||||
|
||||
[Parameter()]
|
||||
[Alias('m')]
|
||||
[switch] $MandatoryUpdate,
|
||||
@@ -427,9 +421,6 @@ function Write-Banner {
|
||||
if ($quietDeployment) {
|
||||
Write-Styled -Message '│ NOTICE quiet (no advance television announcement)' -Colour Gray
|
||||
}
|
||||
if ($SkipBuilder) {
|
||||
Write-Styled -Message '│ BUILDER preserve the running Android builder' -Colour Gray
|
||||
}
|
||||
$initialEstimate = ($script:PhaseOrder | ForEach-Object { (Get-PhaseEstimate -Key $_).Seconds } |
|
||||
Measure-Object -Sum).Sum
|
||||
$sampleCounts = @($script:PhaseOrder | ForEach-Object { (Get-PhaseEstimate -Key $_).Samples })
|
||||
@@ -630,8 +621,7 @@ function New-DeploymentArchive {
|
||||
'--exclude', 'admin-ui/node_modules', '--exclude', 'admin-ui/node_modules/*',
|
||||
'--exclude', 'admin-ui/dist', '--exclude', 'admin-ui/dist/*',
|
||||
'-C', $RepositoryDirectory,
|
||||
'server', 'admin-ui', 'builder', 'docker-compose.yml', '.env.example',
|
||||
'builder.env.example'
|
||||
'server', 'admin-ui', 'docker-compose.yml', '.env.example'
|
||||
)
|
||||
if ($ReleaseDirectory) {
|
||||
$arguments += @(
|
||||
@@ -789,13 +779,8 @@ try {
|
||||
(Join-Path $checkoutDirectory 'admin-ui/Dockerfile'),
|
||||
(Join-Path $checkoutDirectory 'admin-ui/package.json'),
|
||||
(Join-Path $checkoutDirectory 'admin-ui/src'),
|
||||
(Join-Path $checkoutDirectory 'builder'),
|
||||
(Join-Path $checkoutDirectory 'builder/Dockerfile'),
|
||||
(Join-Path $checkoutDirectory 'builder/release.sh'),
|
||||
(Join-Path $checkoutDirectory 'builder/controller.go'),
|
||||
(Join-Path $checkoutDirectory 'docker-compose.yml'),
|
||||
(Join-Path $checkoutDirectory '.env.example'),
|
||||
(Join-Path $checkoutDirectory 'builder.env.example')
|
||||
(Join-Path $checkoutDirectory '.env.example')
|
||||
)
|
||||
foreach ($requiredPath in $requiredPaths) {
|
||||
if (-not (Test-Path -LiteralPath $requiredPath)) {
|
||||
@@ -804,7 +789,6 @@ try {
|
||||
}
|
||||
Write-Detail 'server/ build context'
|
||||
Write-Detail 'admin-ui/ build context'
|
||||
Write-Detail 'builder/ release toolchain'
|
||||
Write-Detail 'docker-compose.yml'
|
||||
Write-Detail '.env.example'
|
||||
$releaseDirectory = ''
|
||||
@@ -914,7 +898,6 @@ set -eu
|
||||
destination='__DESTINATION__'
|
||||
health_timeout=__HEALTH_TIMEOUT__
|
||||
publish_release=__PUBLISH_RELEASE__
|
||||
skip_builder=__SKIP_BUILDER__
|
||||
mandatory_update=__MANDATORY_UPDATE__
|
||||
quiet_deployment=__QUIET_DEPLOYMENT__
|
||||
colour_output=__COLOUR_OUTPUT__
|
||||
@@ -950,14 +933,7 @@ failure() {
|
||||
}
|
||||
|
||||
start_restored_stack() {
|
||||
if [ "$skip_builder" -eq 1 ]; then
|
||||
# Restore the previous gateway/admin sources without rebuilding the large
|
||||
# Android SDK image or touching the still-running builder, database and cache.
|
||||
docker compose build server memby-admin >/dev/null 2>&1 &&
|
||||
docker compose up -d --no-build --no-deps memby-admin server >/dev/null 2>&1
|
||||
else
|
||||
docker compose up -d --build --remove-orphans >/dev/null 2>&1
|
||||
fi
|
||||
docker compose up -d --build --remove-orphans >/dev/null 2>&1
|
||||
}
|
||||
|
||||
rollback() {
|
||||
@@ -976,12 +952,7 @@ rollback() {
|
||||
detail "Stopping the incomplete application release"
|
||||
(
|
||||
cd "$destination"
|
||||
if [ "$skip_builder" -eq 1 ]; then
|
||||
docker compose stop server memby-admin >/dev/null 2>&1
|
||||
docker compose rm -f server memby-admin >/dev/null 2>&1
|
||||
else
|
||||
docker compose down --remove-orphans >/dev/null 2>&1
|
||||
fi
|
||||
docker compose down --remove-orphans >/dev/null 2>&1
|
||||
) || true
|
||||
fi
|
||||
|
||||
@@ -1090,9 +1061,6 @@ test -f "$staging/docker-compose.yml"
|
||||
test -f "$staging/server/Dockerfile"
|
||||
test -f "$staging/admin-ui/Dockerfile"
|
||||
test -f "$staging/admin-ui/package.json"
|
||||
test -f "$staging/builder/Dockerfile"
|
||||
test -f "$staging/builder/release.sh"
|
||||
test -f "$staging/builder/controller.go"
|
||||
if [ "$publish_release" -eq 1 ]; then
|
||||
test -f "$staging/release/version.txt"
|
||||
test -f "$staging/release/sha256.txt"
|
||||
@@ -1112,7 +1080,7 @@ if [ -f "$destination/.env" ]; then
|
||||
# tell the televisions anything. It is usually the same as the incoming one, but
|
||||
# reading it from the release being replaced is what makes that not a requirement.
|
||||
previous_admin_token=$(sed -n 's/^MEMBY_ADMIN_TOKEN=//p' "$destination/.env" | head -n 1 | tr -d '\r')
|
||||
# First Docker-builder deployment only: migrate the established publish token out
|
||||
# First file-backed-secret deployment only: migrate the established publish token out
|
||||
# of the old environment file rather than making the operator rotate it mid-release.
|
||||
previous_release_token=$(sed -n 's/^MEMBY_RELEASE_PUBLISH_TOKEN=//p' "$destination/.env" | head -n 1 | tr -d '\r')
|
||||
# Kept beside the new one purely so a bad edit is recoverable by hand.
|
||||
@@ -1168,44 +1136,18 @@ if [ ! -s "$release_token_file" ]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
missing_builder_secrets=0
|
||||
check_required_secret() {
|
||||
required_secret="$1"
|
||||
if [ ! -s "$required_secret" ]; then
|
||||
failure "Required secret is missing or empty: $required_secret"
|
||||
missing_builder_secrets=1
|
||||
fi
|
||||
}
|
||||
check_required_secret "$release_token_file"
|
||||
if [ "$skip_builder" -ne 1 ]; then
|
||||
check_required_secret "$secrets_dir/memby-release.jks"
|
||||
check_required_secret "$secrets_dir/memby-keystore-password"
|
||||
check_required_secret "$secrets_dir/memby-key-alias"
|
||||
check_required_secret "$secrets_dir/memby-key-password"
|
||||
fi
|
||||
if [ "$missing_builder_secrets" -ne 0 ]; then
|
||||
if [ "$skip_builder" -eq 1 ]; then
|
||||
detail 'Restore the existing gateway release token at the path above, then rerun this deployment'
|
||||
else
|
||||
detail 'Copy the existing signing identity and its three values to the paths above, then rerun this deployment'
|
||||
detail 'Never create a new keystore: installed Memby clients can upgrade only from the existing certificate'
|
||||
fi
|
||||
if [ ! -s "$release_token_file" ]; then
|
||||
failure "Required secret is missing or empty: $release_token_file"
|
||||
detail 'Restore the existing gateway release token at the path above, then rerun this deployment'
|
||||
exit 1
|
||||
fi
|
||||
# Docker Compose file-backed secrets are read-only bind mounts on the NAS. The gateway
|
||||
# and builder deliberately run as uid 65532, so files created as the SSH user with 0600
|
||||
# would be present but unreadable in those containers. The 0700 parent prevents every
|
||||
# other NAS account from traversing to them; 0444 makes only the read-only secret mounts
|
||||
# usable by the non-root container processes and also prevents accidental host writes.
|
||||
# deliberately runs as uid 65532, so a file created as the SSH user with 0600 would be
|
||||
# present but unreadable in that container. The 0700 parent prevents every other NAS
|
||||
# account from traversing to it; 0444 makes only the read-only secret mount usable by the
|
||||
# non-root container process and also prevents accidental host writes.
|
||||
chmod 700 "$secrets_dir"
|
||||
chmod 444 "$release_token_file"
|
||||
if [ "$skip_builder" -ne 1 ]; then
|
||||
chmod 444 \
|
||||
"$secrets_dir/memby-release.jks" \
|
||||
"$secrets_dir/memby-keystore-password" \
|
||||
"$secrets_dir/memby-key-alias" \
|
||||
"$secrets_dir/memby-key-password"
|
||||
fi
|
||||
success 'Required gateway configuration is present'
|
||||
if [ -n "$previous_password" ] && [ "$previous_password" != "$new_password" ]; then
|
||||
failure 'POSTGRES_PASSWORD differs from the deployed value'
|
||||
@@ -1256,34 +1198,15 @@ step 'Pulling PostgreSQL and Redis'
|
||||
)
|
||||
success 'Dependency images are ready'
|
||||
|
||||
if [ "$skip_builder" -eq 1 ]; then
|
||||
step 'Building the gateway and admin console; reusing the Android builder'
|
||||
else
|
||||
step 'Building the gateway, admin console and Android builder'
|
||||
fi
|
||||
step 'Building the gateway and admin console'
|
||||
(
|
||||
cd "$staging"
|
||||
# `up` reuses an existing image when one is present. Build both local contexts here,
|
||||
# otherwise a new React/nginx console can be packaged and activated while the NAS
|
||||
# continues to serve the previous console image (and its old route configuration).
|
||||
if [ "$skip_builder" -eq 1 ]; then
|
||||
existing_builder=$(docker compose ps -q memby-builder 2>/dev/null || true)
|
||||
if [ -z "$existing_builder" ] ||
|
||||
[ "$(docker inspect --format '{{.State.Status}}' "$existing_builder" 2>/dev/null || true)" != 'running' ]; then
|
||||
failure 'No running memby-builder container is available to preserve'
|
||||
detail 'Run once without -SkipBuilder to install and start the Android builder'
|
||||
exit 1
|
||||
fi
|
||||
docker compose build --pull server memby-admin
|
||||
else
|
||||
docker compose build --pull server memby-admin memby-builder
|
||||
fi
|
||||
docker compose build --pull server memby-admin
|
||||
)
|
||||
if [ "$skip_builder" -eq 1 ]; then
|
||||
success 'Gateway and admin console images built; Android builder container retained'
|
||||
else
|
||||
success 'Gateway, admin console and Android builder images built'
|
||||
fi
|
||||
success 'Gateway and admin console images built'
|
||||
|
||||
step 'Activating the release'
|
||||
rm -rf -- "$backup"
|
||||
@@ -1292,20 +1215,11 @@ if [ -e "$destination" ] || [ -L "$destination" ]; then
|
||||
# Compose projects created by older releases may use a different project
|
||||
# name. Stop them from their original directory before moving it so their
|
||||
# published ports (especially 32768) are released for the new stack.
|
||||
if [ "$skip_builder" -eq 1 ]; then
|
||||
detail 'Stopping only the gateway and admin console; preserving builder, database and cache'
|
||||
(
|
||||
cd "$destination"
|
||||
docker compose stop server memby-admin
|
||||
docker compose rm -f server memby-admin
|
||||
)
|
||||
else
|
||||
detail 'Stopping the previous Compose application'
|
||||
(
|
||||
cd "$destination"
|
||||
docker compose down --remove-orphans
|
||||
)
|
||||
fi
|
||||
detail 'Stopping the previous Compose application'
|
||||
(
|
||||
cd "$destination"
|
||||
docker compose down --remove-orphans
|
||||
)
|
||||
previous_stopped=1
|
||||
success 'Previous Compose application stopped'
|
||||
fi
|
||||
@@ -1318,17 +1232,12 @@ success 'Release activated'
|
||||
|
||||
step 'Starting the Compose stack'
|
||||
cd "$destination"
|
||||
if [ "$skip_builder" -eq 1 ]; then
|
||||
compose_start='docker compose up -d --no-build --no-deps memby-admin server'
|
||||
else
|
||||
compose_start='docker compose up -d --no-build --remove-orphans'
|
||||
fi
|
||||
if ! $compose_start; then
|
||||
if ! docker compose up -d --no-build --remove-orphans; then
|
||||
failure 'Compose could not start the complete application'
|
||||
detail 'Container state before rollback:'
|
||||
docker compose ps --all || true
|
||||
detail 'Gateway and builder logs before rollback:'
|
||||
docker compose logs --no-color --tail 100 server memby-builder || true
|
||||
detail 'Gateway logs before rollback:'
|
||||
docker compose logs --no-color --tail 100 server || true
|
||||
exit 1
|
||||
fi
|
||||
success 'Compose start command completed'
|
||||
@@ -1338,7 +1247,6 @@ wait_for_service postgres
|
||||
wait_for_service redis
|
||||
wait_for_service memby-admin
|
||||
wait_for_service server
|
||||
wait_for_service memby-builder
|
||||
|
||||
published_address=$(docker compose port server 32768 | head -n 1)
|
||||
actual_port=${published_address##*:}
|
||||
@@ -1418,10 +1326,6 @@ success 'Memby gateway: https://mserver.sublogue.com'
|
||||
'__PUBLISH_RELEASE__',
|
||||
$(if ($SkipAppRelease) { '0' } else { '1' })
|
||||
)
|
||||
$remoteCommand = $remoteCommand.Replace(
|
||||
'__SKIP_BUILDER__',
|
||||
$(if ($SkipBuilder) { '1' } else { '0' })
|
||||
)
|
||||
$remoteCommand = $remoteCommand.Replace(
|
||||
'__MANDATORY_UPDATE__',
|
||||
$(if ($mandatoryRelease) { '1' } else { '0' })
|
||||
|
||||
Reference in New Issue
Block a user