Add get-env/set-env commands to portainer.sh; fix redeploy env var wipe
- get-env: display env vars for a named stack - set-env: merge KEY=VALUE pairs into a stack's env vars and redeploy (uses git/redeploy endpoint with pullImage:false for git-linked stacks) - redeploy: now preserves existing env vars by including them in the git/redeploy payload (previously wiped them when env was omitted)
This commit is contained in:
+145
-9
@@ -4,6 +4,8 @@
|
|||||||
# ./portainer.sh list
|
# ./portainer.sh list
|
||||||
# ./portainer.sh redeploy <stack-name>
|
# ./portainer.sh redeploy <stack-name>
|
||||||
# ./portainer.sh deploy <stack-name> <compose-path>
|
# ./portainer.sh deploy <stack-name> <compose-path>
|
||||||
|
# ./portainer.sh get-env <stack-name>
|
||||||
|
# ./portainer.sh set-env <stack-name> KEY=VALUE [KEY=VALUE ...]
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -54,6 +56,19 @@ print(s['Id'])
|
|||||||
"
|
"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_stack_json_by_name() {
|
||||||
|
local name="$1"
|
||||||
|
api_get "stacks?filters=%7B%22EndpointID%22%3A${ENDPOINT_ID}%7D" \
|
||||||
|
| python3 -c "
|
||||||
|
import json, sys
|
||||||
|
stacks = json.load(sys.stdin)
|
||||||
|
matches = [s for s in stacks if s['Name'] == '$name']
|
||||||
|
if not matches:
|
||||||
|
sys.exit(1)
|
||||||
|
print(json.dumps(matches[0]))
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
# Commands
|
# Commands
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
@@ -82,27 +97,37 @@ cmd_redeploy() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Looking up stack '$name'..."
|
echo "Looking up stack '$name'..."
|
||||||
local stack_id
|
local stack_json
|
||||||
if ! stack_id=$(get_stack_by_name "$name"); then
|
if ! stack_json=$(get_stack_json_by_name "$name"); then
|
||||||
echo "Error: stack '$name' not found" >&2
|
echo "Error: stack '$name' not found" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
local stack_id
|
||||||
|
stack_id=$(python3 -c "import json,sys; print(json.loads(sys.argv[1])['Id'])" "$stack_json")
|
||||||
echo "Found stack ID: $stack_id"
|
echo "Found stack ID: $stack_id"
|
||||||
|
|
||||||
|
# Preserve existing env vars — git/redeploy clears them if env is omitted
|
||||||
|
local payload
|
||||||
|
payload=$(python3 -c "
|
||||||
|
import json, sys
|
||||||
|
stack = json.loads(sys.argv[1])
|
||||||
|
env = stack.get('Env') or []
|
||||||
|
print(json.dumps({'pullImage': True, 'prune': False, 'env': env}))
|
||||||
|
" "$stack_json")
|
||||||
|
|
||||||
echo "Redeploying..."
|
echo "Redeploying..."
|
||||||
local response
|
local response
|
||||||
response=$(api_put "stacks/${stack_id}/git/redeploy?endpointId=${ENDPOINT_ID}" \
|
response=$(api_put "stacks/${stack_id}/git/redeploy?endpointId=${ENDPOINT_ID}" "$payload")
|
||||||
'{"pullImage": true, "prune": false}')
|
|
||||||
|
|
||||||
python3 -c "
|
python3 -c "
|
||||||
import json, sys
|
import json, sys
|
||||||
d = json.load(sys.stdin)
|
d = json.loads(sys.argv[1])
|
||||||
if 'message' in d and 'Id' not in d:
|
if 'message' in d and 'Id' not in d:
|
||||||
print('Error:', d['message'])
|
print('Error:', d['message'])
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
hash = d.get('GitConfig', {}).get('ConfigHash', 'unknown')[:10]
|
hash = d.get('GitConfig', {}).get('ConfigHash', 'unknown')[:10]
|
||||||
print(f'Done. ConfigHash: {hash}')
|
print(f'Done. ConfigHash: {hash}')
|
||||||
" <<< "$response"
|
" "$response"
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_deploy() {
|
cmd_deploy() {
|
||||||
@@ -142,6 +167,113 @@ print(f\"Done. Stack ID: {d['Id']}, Name: {d['Name']}\")
|
|||||||
" <<< "$response"
|
" <<< "$response"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd_get_env() {
|
||||||
|
local name="${1:-}"
|
||||||
|
if [[ -z "$name" ]]; then
|
||||||
|
echo "Usage: $0 get-env <stack-name>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Looking up stack '$name'..."
|
||||||
|
local stack_json
|
||||||
|
if ! stack_json=$(get_stack_json_by_name "$name"); then
|
||||||
|
echo "Error: stack '$name' not found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
python3 -c "
|
||||||
|
import json, sys
|
||||||
|
s = json.loads(sys.argv[1])
|
||||||
|
env = s.get('Env') or []
|
||||||
|
if not env:
|
||||||
|
print('(no env vars set)')
|
||||||
|
else:
|
||||||
|
for e in sorted(env, key=lambda x: x['name']):
|
||||||
|
print(f\"{e['name']}={e['value']}\")
|
||||||
|
" "$stack_json"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_set_env() {
|
||||||
|
local name="${1:-}"
|
||||||
|
shift || true
|
||||||
|
if [[ -z "$name" || $# -eq 0 ]]; then
|
||||||
|
echo "Usage: $0 set-env <stack-name> KEY=VALUE [KEY=VALUE ...]" >&2
|
||||||
|
echo " Example: $0 set-env authelia SECRET_KEY=abc123 OTHER_KEY=xyz" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Looking up stack '$name'..."
|
||||||
|
local stack_json
|
||||||
|
if ! stack_json=$(get_stack_json_by_name "$name"); then
|
||||||
|
echo "Error: stack '$name' not found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local stack_id
|
||||||
|
stack_id=$(python3 -c "import json,sys; print(json.loads(sys.argv[1])['Id'])" "$stack_json")
|
||||||
|
echo "Found stack ID: $stack_id"
|
||||||
|
|
||||||
|
local kvs=("$@")
|
||||||
|
local payload
|
||||||
|
payload=$(python3 -c "
|
||||||
|
import json, sys
|
||||||
|
|
||||||
|
stack = json.loads(sys.argv[1])
|
||||||
|
new_kvs = sys.argv[2:]
|
||||||
|
|
||||||
|
# Merge env vars: preserve existing, override/add new
|
||||||
|
env_dict = {e['name']: e['value'] for e in (stack.get('Env') or [])}
|
||||||
|
for kv in new_kvs:
|
||||||
|
eq = kv.index('=')
|
||||||
|
env_dict[kv[:eq]] = kv[eq+1:]
|
||||||
|
env_list = [{'name': k, 'value': v} for k, v in env_dict.items()]
|
||||||
|
|
||||||
|
git = stack.get('GitConfig') or {}
|
||||||
|
if git:
|
||||||
|
# Use git/redeploy endpoint (pullImage:false = redeploy with existing images only)
|
||||||
|
p = {'pullImage': False, 'prune': False, 'env': env_list}
|
||||||
|
else:
|
||||||
|
print('Error: string-based stacks are not supported; update env vars via Portainer UI.', file=sys.stderr)
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
print(json.dumps(p))
|
||||||
|
" "$stack_json" "${kvs[@]}")
|
||||||
|
|
||||||
|
echo "Updating env vars (redeploys with existing images)..."
|
||||||
|
local endpoint
|
||||||
|
local stack_json_check
|
||||||
|
stack_json_check=$(python3 -c "
|
||||||
|
import json, sys
|
||||||
|
stack = json.loads(sys.argv[1])
|
||||||
|
git = stack.get('GitConfig') or {}
|
||||||
|
print('git' if git else 'string')
|
||||||
|
" "$stack_json")
|
||||||
|
|
||||||
|
local response
|
||||||
|
if [[ "$stack_json_check" == "git" ]]; then
|
||||||
|
response=$(api_put "stacks/${stack_id}/git/redeploy?endpointId=${ENDPOINT_ID}" "$payload")
|
||||||
|
else
|
||||||
|
echo "Error: string-based stacks are not supported; update env vars via Portainer UI." >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
python3 -c "
|
||||||
|
import json, sys
|
||||||
|
try:
|
||||||
|
d = json.loads(sys.argv[1])
|
||||||
|
except Exception:
|
||||||
|
print('Failed to parse response:', sys.argv[1][:300])
|
||||||
|
sys.exit(1)
|
||||||
|
if 'message' in d and 'Id' not in d:
|
||||||
|
print('Error:', d['message'])
|
||||||
|
if 'details' in d:
|
||||||
|
print('Details:', d['details'])
|
||||||
|
sys.exit(1)
|
||||||
|
updated = len(d.get('Env') or [])
|
||||||
|
print(f'Done. Stack has {updated} env var(s) set.')
|
||||||
|
" "$response"
|
||||||
|
}
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
# Dispatch
|
# Dispatch
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
@@ -151,13 +283,17 @@ case "$command" in
|
|||||||
list) cmd_list ;;
|
list) cmd_list ;;
|
||||||
redeploy) cmd_redeploy "${2:-}" ;;
|
redeploy) cmd_redeploy "${2:-}" ;;
|
||||||
deploy) cmd_deploy "${2:-}" "${3:-}" ;;
|
deploy) cmd_deploy "${2:-}" "${3:-}" ;;
|
||||||
|
get-env) cmd_get_env "${2:-}" ;;
|
||||||
|
set-env) cmd_set_env "${2:-}" "${@:3}" ;;
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 <command> [args]"
|
echo "Usage: $0 <command> [args]"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Commands:"
|
echo "Commands:"
|
||||||
echo " list List all stacks"
|
echo " list List all stacks"
|
||||||
echo " redeploy <stack-name> Pull latest git commit and redeploy"
|
echo " redeploy <stack-name> Pull latest git commit and redeploy"
|
||||||
echo " deploy <stack-name> <path> Create new git-linked stack"
|
echo " deploy <stack-name> <path> Create new git-linked stack"
|
||||||
|
echo " get-env <stack-name> Show env vars for a stack"
|
||||||
|
echo " set-env <stack-name> KEY=VAL [...] Set env vars (redeploys without new image pull)"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
Reference in New Issue
Block a user