build: resolve --remote as SSH config alias when it has no @
scripts/build-and-push.sh now parses ~/.ssh/config (or --ssh-config) when --remote is a bare alias like 'prod'. It extracts HostName, User, Port and IdentityFile from the matching Host block, falls back to the current user / port 22, and uses the config IdentityFile when --ssh-key is not given. --ssh-key always wins. The resolved target is shown in the logs before any docker/pussh call, and is the form passed to docker pussh and the verification ssh. Wildcards, Include and Match directives are intentionally not handled: ssh itself resolves them when the alias is passed through, but the script logs the expanded target first for visibility.
This commit is contained in:
@@ -22,6 +22,29 @@ It can be invoked from any directory: by default it resolves the project root
|
|||||||
from the script's own location. Override with `--project-dir PATH` or the
|
from the script's own location. Override with `--project-dir PATH` or the
|
||||||
`PROJECT_DIR` environment variable when needed.
|
`PROJECT_DIR` environment variable when needed.
|
||||||
|
|
||||||
|
### SSH config aliases
|
||||||
|
|
||||||
|
`--remote` accepts either an explicit `user@host[:port]` or a bare alias that
|
||||||
|
is resolved from `~/.ssh/config`. The matching `Host` block supplies
|
||||||
|
`HostName`, `User`, `Port` and `IdentityFile` automatically:
|
||||||
|
|
||||||
|
```text
|
||||||
|
# ~/.ssh/config
|
||||||
|
Host prod
|
||||||
|
HostName prod.example.com
|
||||||
|
User deploy
|
||||||
|
Port 22
|
||||||
|
IdentityFile ~/.ssh/deploy_ed25519
|
||||||
|
```
|
||||||
|
|
||||||
|
```shell script
|
||||||
|
./scripts/build-and-push.sh --remote prod
|
||||||
|
# Resolves to deploy@prod.example.com:22 using ~/.ssh/deploy_ed25519
|
||||||
|
```
|
||||||
|
|
||||||
|
`--ssh-key` always overrides the config `IdentityFile`. Use `--ssh-config PATH`
|
||||||
|
to point at a non-default config file.
|
||||||
|
|
||||||
## Running the application in dev mode
|
## Running the application in dev mode
|
||||||
|
|
||||||
You can run your application in dev mode that enables live coding using:
|
You can run your application in dev mode that enables live coding using:
|
||||||
|
|||||||
+82
-10
@@ -59,7 +59,9 @@ Build the native Quarkus image and push it to a remote Docker host using
|
|||||||
unregistry (docker-pussh).
|
unregistry (docker-pussh).
|
||||||
|
|
||||||
Required:
|
Required:
|
||||||
--remote USER@HOST[:PORT] SSH destination (e.g. deploy@prod.example.com)
|
--remote TARGET SSH destination. Either 'user@host[:port]'
|
||||||
|
or a bare alias resolved from ~/.ssh/config
|
||||||
|
(e.g. 'prod'). See SSH config aliases below.
|
||||||
|
|
||||||
Image identity (defaults read from pom.xml):
|
Image identity (defaults read from pom.xml):
|
||||||
--name NAME Image repository name
|
--name NAME Image repository name
|
||||||
@@ -74,8 +76,8 @@ Build options:
|
|||||||
(platform is fixed to ${DEFAULT_PLATFORM})
|
(platform is fixed to ${DEFAULT_PLATFORM})
|
||||||
|
|
||||||
SSH options forwarded to docker pussh:
|
SSH options forwarded to docker pussh:
|
||||||
--ssh-key PATH Private key file
|
--ssh-key PATH Private key file (overrides SSH config)
|
||||||
--ssh-config PATH SSH config file
|
--ssh-config PATH SSH config file (default: ~/.ssh/config)
|
||||||
|
|
||||||
Post-push:
|
Post-push:
|
||||||
--no-verify Skip the ssh/docker images verification step
|
--no-verify Skip the ssh/docker images verification step
|
||||||
@@ -83,8 +85,15 @@ Post-push:
|
|||||||
Other:
|
Other:
|
||||||
-h, --help Show this help
|
-h, --help Show this help
|
||||||
|
|
||||||
|
SSH config aliases:
|
||||||
|
When --remote is a bare alias (no '@'), it is resolved from the SSH
|
||||||
|
config: HostName, User, Port and IdentityFile are pulled from the
|
||||||
|
matching Host block, with sensible fallbacks. --ssh-key always wins
|
||||||
|
over the config IdentityFile.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
$(basename "$0") --remote deploy@prod.example.com
|
$(basename "$0") --remote deploy@prod.example.com
|
||||||
|
$(basename "$0") --remote prod # uses 'Host prod' in ~/.ssh/config
|
||||||
$(basename "$0") --remote ubuntu@1.2.3.4 --ssh-key ~/.ssh/deploy_ed25519
|
$(basename "$0") --remote ubuntu@1.2.3.4 --ssh-key ~/.ssh/deploy_ed25519
|
||||||
$(basename "$0") --remote deploy@prod --skip-build --tag 2.0.0
|
$(basename "$0") --remote deploy@prod --skip-build --tag 2.0.0
|
||||||
/absolute/path/to/test-quarkus/scripts/$(basename "$0") --remote deploy@prod
|
/absolute/path/to/test-quarkus/scripts/$(basename "$0") --remote deploy@prod
|
||||||
@@ -109,6 +118,57 @@ require() {
|
|||||||
command -v "$1" >/dev/null 2>&1 || die "Required command '$1' not found in PATH."
|
command -v "$1" >/dev/null 2>&1 || die "Required command '$1' not found in PATH."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolve_ssh_alias() {
|
||||||
|
local alias="$1"
|
||||||
|
local config="${SSH_CONFIG:-$HOME/.ssh/config}"
|
||||||
|
|
||||||
|
if [[ "$alias" == *@* ]]; then
|
||||||
|
printf '%s|%s\n' "$alias" ""
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -f "$config" ]] \
|
||||||
|
|| die "Cannot resolve '$alias': $config not found and value has no '@'."
|
||||||
|
|
||||||
|
local in_block=0 hostname="" user="" port="" identity="" line key value p
|
||||||
|
local -a patterns
|
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||||
|
line="${line#"${line%%[![:space:]]*}"}"
|
||||||
|
[[ -z "$line" || "${line:0:1}" == "#" ]] && continue
|
||||||
|
key="${line%% *}"
|
||||||
|
if [[ "$key" == "Host" ]]; then
|
||||||
|
if (( in_block )); then break; fi
|
||||||
|
read -r -a patterns <<< "${line#Host }"
|
||||||
|
in_block=0
|
||||||
|
for p in "${patterns[@]}"; do
|
||||||
|
if [[ "$p" == "$alias" ]]; then
|
||||||
|
in_block=1
|
||||||
|
hostname=""; user=""; port=""; identity=""
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if (( in_block )); then
|
||||||
|
case "$key" in
|
||||||
|
HostName) hostname="${line#* }" ;;
|
||||||
|
User) user="${line#* }" ;;
|
||||||
|
Port) port="${line#* }" ;;
|
||||||
|
IdentityFile) identity="${line#* }" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
done < "$config"
|
||||||
|
|
||||||
|
(( in_block )) \
|
||||||
|
|| die "No matching Host entry in $config for alias '$alias'. Use user@host[:port] or check ~/.ssh/config."
|
||||||
|
[[ -z "$hostname" ]] && die "Host '$alias' has no HostName in $config."
|
||||||
|
[[ -z "$user" ]] && user="$(whoami)"
|
||||||
|
[[ -z "$port" ]] && port="22"
|
||||||
|
identity="${identity/#\~/$HOME}"
|
||||||
|
|
||||||
|
printf '%s@%s:%s|%s\n' "$user" "$hostname" "$port" "$identity"
|
||||||
|
}
|
||||||
|
|
||||||
# ---------- arg parsing ----------
|
# ---------- arg parsing ----------
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@@ -138,11 +198,23 @@ PROJECT_DIR="$(pwd)"
|
|||||||
|
|
||||||
IMAGE_REF="${IMAGE_NAME}:${IMAGE_TAG}"
|
IMAGE_REF="${IMAGE_NAME}:${IMAGE_TAG}"
|
||||||
|
|
||||||
|
# ---------- resolve SSH target ----------
|
||||||
|
resolved=$(resolve_ssh_alias "$REMOTE")
|
||||||
|
REMOTE_TARGET="${resolved%|*}"
|
||||||
|
REMOTE_IDENTITY="${resolved##*|}"
|
||||||
|
if [[ "$REMOTE" != *@* ]]; then
|
||||||
|
log "Resolved alias '${REMOTE}' → ${REMOTE_TARGET}"
|
||||||
|
fi
|
||||||
|
if [[ -z "$SSH_KEY" && -n "$REMOTE_IDENTITY" ]]; then
|
||||||
|
SSH_KEY="$REMOTE_IDENTITY"
|
||||||
|
log "Using IdentityFile from SSH config: ${SSH_KEY}"
|
||||||
|
fi
|
||||||
|
|
||||||
# ---------- pre-flight ----------
|
# ---------- pre-flight ----------
|
||||||
log "Image: ${IMAGE_REF}"
|
log "Image: ${IMAGE_REF}"
|
||||||
log "Platform: ${DEFAULT_PLATFORM}"
|
log "Platform: ${DEFAULT_PLATFORM}"
|
||||||
log "Dockerfile: ${DOCKERFILE}"
|
log "Dockerfile: ${DOCKERFILE}"
|
||||||
log "Remote: ${REMOTE}"
|
log "Remote: ${REMOTE_TARGET}"
|
||||||
|
|
||||||
require docker
|
require docker
|
||||||
docker info >/dev/null 2>&1 \
|
docker info >/dev/null 2>&1 \
|
||||||
@@ -181,9 +253,9 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# ---------- pussh ----------
|
# ---------- pussh ----------
|
||||||
log "Pusshing ${IMAGE_REF} to ${REMOTE} via unregistry…"
|
log "Pusshing ${IMAGE_REF} to ${REMOTE_TARGET} via unregistry…"
|
||||||
|
|
||||||
pussh_args=( "$REMOTE" )
|
pussh_args=( "$REMOTE_TARGET" )
|
||||||
[[ -n "$SSH_KEY" ]] && pussh_args+=( -i "$SSH_KEY" )
|
[[ -n "$SSH_KEY" ]] && pussh_args+=( -i "$SSH_KEY" )
|
||||||
[[ -n "$SSH_CONFIG" ]] && pussh_args+=( -F "$SSH_CONFIG" )
|
[[ -n "$SSH_CONFIG" ]] && pussh_args+=( -F "$SSH_CONFIG" )
|
||||||
|
|
||||||
@@ -194,13 +266,13 @@ ok "Pussh complete."
|
|||||||
if [[ "$SKIP_VERIFY" -eq 1 ]]; then
|
if [[ "$SKIP_VERIFY" -eq 1 ]]; then
|
||||||
warn "Skipping post-push verification (--no-verify)."
|
warn "Skipping post-push verification (--no-verify)."
|
||||||
else
|
else
|
||||||
log "Verifying ${IMAGE_REF} on ${REMOTE}…"
|
log "Verifying ${IMAGE_REF} on ${REMOTE_TARGET}…"
|
||||||
ssh_args=( "$REMOTE" )
|
ssh_args=( "$REMOTE_TARGET" )
|
||||||
[[ -n "$SSH_KEY" ]] && ssh_args=( -i "$SSH_KEY" "${ssh_args[@]}" )
|
[[ -n "$SSH_KEY" ]] && ssh_args=( -i "$SSH_KEY" "${ssh_args[@]}" )
|
||||||
[[ -n "$SSH_CONFIG" ]] && ssh_args=( -F "$SSH_CONFIG" "${ssh_args[@]}" )
|
[[ -n "$SSH_CONFIG" ]] && ssh_args=( -F "$SSH_CONFIG" "${ssh_args[@]}" )
|
||||||
|
|
||||||
if ! ssh "${ssh_args[@]}" "docker images --format '{{.Repository}}:{{.Tag}} {{.Size}}' | grep -E '^${IMAGE_NAME}:${IMAGE_TAG} '"; then
|
if ! ssh "${ssh_args[@]}" "docker images --format '{{.Repository}}:{{.Tag}} {{.Size}}' | grep -E '^${IMAGE_NAME}:${IMAGE_TAG} '"; then
|
||||||
die "Image ${IMAGE_REF} not found on ${REMOTE} after pussh."
|
die "Image ${IMAGE_REF} not found on ${REMOTE_TARGET} after pussh."
|
||||||
fi
|
fi
|
||||||
ok "Image present on remote."
|
ok "Image present on remote."
|
||||||
fi
|
fi
|
||||||
@@ -208,4 +280,4 @@ fi
|
|||||||
# ---------- next step hint ----------
|
# ---------- next step hint ----------
|
||||||
printf '\n%s→ To run on the remote:%s\n' "$C_OK" "$C_RESET"
|
printf '\n%s→ To run on the remote:%s\n' "$C_OK" "$C_RESET"
|
||||||
printf ' ssh %s "docker run -d --name %s --restart unless-stopped -p 8080:8080 %s"\n\n' \
|
printf ' ssh %s "docker run -d --name %s --restart unless-stopped -p 8080:8080 %s"\n\n' \
|
||||||
"$REMOTE" "$IMAGE_NAME" "$IMAGE_REF"
|
"$REMOTE_TARGET" "$IMAGE_NAME" "$IMAGE_REF"
|
||||||
|
|||||||
Reference in New Issue
Block a user