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
|
||||
`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
|
||||
|
||||
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).
|
||||
|
||||
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):
|
||||
--name NAME Image repository name
|
||||
@@ -74,8 +76,8 @@ Build options:
|
||||
(platform is fixed to ${DEFAULT_PLATFORM})
|
||||
|
||||
SSH options forwarded to docker pussh:
|
||||
--ssh-key PATH Private key file
|
||||
--ssh-config PATH SSH config file
|
||||
--ssh-key PATH Private key file (overrides SSH config)
|
||||
--ssh-config PATH SSH config file (default: ~/.ssh/config)
|
||||
|
||||
Post-push:
|
||||
--no-verify Skip the ssh/docker images verification step
|
||||
@@ -83,8 +85,15 @@ Post-push:
|
||||
Other:
|
||||
-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:
|
||||
$(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 deploy@prod --skip-build --tag 2.0.0
|
||||
/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."
|
||||
}
|
||||
|
||||
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 ----------
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
@@ -138,11 +198,23 @@ PROJECT_DIR="$(pwd)"
|
||||
|
||||
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 ----------
|
||||
log "Image: ${IMAGE_REF}"
|
||||
log "Platform: ${DEFAULT_PLATFORM}"
|
||||
log "Dockerfile: ${DOCKERFILE}"
|
||||
log "Remote: ${REMOTE}"
|
||||
log "Remote: ${REMOTE_TARGET}"
|
||||
|
||||
require docker
|
||||
docker info >/dev/null 2>&1 \
|
||||
@@ -181,9 +253,9 @@ else
|
||||
fi
|
||||
|
||||
# ---------- 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_CONFIG" ]] && pussh_args+=( -F "$SSH_CONFIG" )
|
||||
|
||||
@@ -194,13 +266,13 @@ ok "Pussh complete."
|
||||
if [[ "$SKIP_VERIFY" -eq 1 ]]; then
|
||||
warn "Skipping post-push verification (--no-verify)."
|
||||
else
|
||||
log "Verifying ${IMAGE_REF} on ${REMOTE}…"
|
||||
ssh_args=( "$REMOTE" )
|
||||
log "Verifying ${IMAGE_REF} on ${REMOTE_TARGET}…"
|
||||
ssh_args=( "$REMOTE_TARGET" )
|
||||
[[ -n "$SSH_KEY" ]] && ssh_args=( -i "$SSH_KEY" "${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
|
||||
die "Image ${IMAGE_REF} not found on ${REMOTE} after pussh."
|
||||
die "Image ${IMAGE_REF} not found on ${REMOTE_TARGET} after pussh."
|
||||
fi
|
||||
ok "Image present on remote."
|
||||
fi
|
||||
@@ -208,4 +280,4 @@ fi
|
||||
# ---------- next step hint ----------
|
||||
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' \
|
||||
"$REMOTE" "$IMAGE_NAME" "$IMAGE_REF"
|
||||
"$REMOTE_TARGET" "$IMAGE_NAME" "$IMAGE_REF"
|
||||
|
||||
Reference in New Issue
Block a user