update
This commit is contained in:
+167
-31
@@ -102,6 +102,24 @@ print(token.lower())
|
||||
' 2>/dev/null
|
||||
}
|
||||
|
||||
TAPM_PULSE_AGENT_REGISTERED_FROM_RESPONSE() {
|
||||
local response="${1:-}"
|
||||
|
||||
AGENT_RESPONSE="$response" python3 -c '
|
||||
import json, os
|
||||
try:
|
||||
agent = json.loads(os.environ["AGENT_RESPONSE"]).get("agent", {})
|
||||
except (AttributeError, TypeError, ValueError):
|
||||
raise SystemExit(1)
|
||||
if not isinstance(agent, dict) or not str(agent.get("id", "")).strip():
|
||||
raise SystemExit(1)
|
||||
' 2>/dev/null
|
||||
}
|
||||
|
||||
TAPM_PULSE_AGENT_TOKEN_REQUEST_JSON() {
|
||||
printf '%s\n' '{"type":"pve","enableCommands":false}'
|
||||
}
|
||||
|
||||
TAPM_PULSE_ONLINE_NODES_FROM_JSON() {
|
||||
local nodes_json="${1:-[]}"
|
||||
|
||||
@@ -146,7 +164,8 @@ except (TypeError, ValueError):
|
||||
for item in resources:
|
||||
tags = str(item.get("tags", "")).split(";")
|
||||
if item.get("type") == "lxc" and (
|
||||
"pulse" in tags or str(item.get("name", "")).lower() == "pulse"
|
||||
"pulse" in tags or
|
||||
str(item.get("name", "")).lower() in {"pulse", "pulse-monitor"}
|
||||
):
|
||||
raise SystemExit(0)
|
||||
raise SystemExit(1)
|
||||
@@ -198,6 +217,7 @@ TAPM_PULSE_CONFIRM_CREDENTIALS_SAVED() {
|
||||
local primary_api_token="$4"
|
||||
local installed="$5"
|
||||
local failed="$6"
|
||||
local cluster_status="$7"
|
||||
local acknowledgement
|
||||
|
||||
while true; do
|
||||
@@ -210,6 +230,7 @@ TAPM_PULSE_CONFIRM_CREDENTIALS_SAVED() {
|
||||
echo -e " Username: ${idsCL[White]}${admin_username}${idsCL[Default]}"
|
||||
echo -e " Password: ${idsCL[LightGreen]}${admin_password}${idsCL[Default]}"
|
||||
echo -e " API token: ${idsCL[LightGreen]}${primary_api_token}${idsCL[Default]}"
|
||||
echo " Cluster: ${cluster_status}"
|
||||
echo " Agents: ${installed} installed, ${failed} failed or offline"
|
||||
echo -e "${idsCL[LightYellow]}============================================================================${idsCL[Default]}"
|
||||
echo
|
||||
@@ -444,6 +465,48 @@ raise SystemExit(0 if success is True else 1)
|
||||
unset generated_password generated_api_token
|
||||
}
|
||||
|
||||
TAPM_PULSE_REGISTER_CLUSTER() {
|
||||
local ctid="$1"
|
||||
local container_ip="$2"
|
||||
local pulse_port="$3"
|
||||
local installer="$4"
|
||||
local primary_token="$5"
|
||||
local temp_dir="$6"
|
||||
local pulse_url="http://${container_ip}:${pulse_port}"
|
||||
local curl_config="${temp_dir}/pulse-cluster-registration.curl"
|
||||
|
||||
printf 'header = "X-API-Token: %s"\n' "$primary_token" >"$curl_config" ||
|
||||
return 1
|
||||
chmod 0600 "$curl_config" || return 1
|
||||
|
||||
(
|
||||
trap 'rm -f /tmp/pulse-auto-register-request.json /tmp/pulse-auto-register-response.json' EXIT
|
||||
# Reuse the verified release's registration implementation so its
|
||||
# Proxmox roles, token contract, and compatibility checks stay in sync.
|
||||
# shellcheck disable=SC1090
|
||||
source "$installer"
|
||||
IN_CONTAINER=false
|
||||
|
||||
# Pulse v6.1.1 requires authentication for setup-token creation. Add
|
||||
# the primary token only to that request; never send it to Proxmox.
|
||||
curl() {
|
||||
local curl_argument
|
||||
|
||||
for curl_argument in "$@"; do
|
||||
if [[ "$curl_argument" == "${pulse_url}/api/setup-script-url" ]]; then
|
||||
command curl --config "$curl_config" "$@"
|
||||
return
|
||||
fi
|
||||
done
|
||||
command curl "$@"
|
||||
}
|
||||
|
||||
wait_for_pulse_ready "$pulse_url" 120 1 || return 1
|
||||
auto_register_pve_node "$ctid" "$container_ip" "$pulse_port"
|
||||
[[ "${AUTO_NODE_REGISTERED:-false}" == true ]]
|
||||
)
|
||||
}
|
||||
|
||||
TAPM_PULSE_ISSUE_AGENT_TOKEN() {
|
||||
local pulse_url="$1"
|
||||
local primary_token="$2"
|
||||
@@ -453,14 +516,7 @@ TAPM_PULSE_ISSUE_AGENT_TOKEN() {
|
||||
local curl_config="${temp_dir}/agent-${node}.curl"
|
||||
local response
|
||||
|
||||
TAPM_PULSE_AGENT_NAME="tapm-pve-${node}" python3 -c '
|
||||
import json, os, sys
|
||||
json.dump({
|
||||
"type": "host",
|
||||
"name": os.environ["TAPM_PULSE_AGENT_NAME"],
|
||||
"enableCommands": False,
|
||||
}, sys.stdout)
|
||||
' >"$request_file" || return 1
|
||||
TAPM_PULSE_AGENT_TOKEN_REQUEST_JSON >"$request_file" || return 1
|
||||
chmod 0600 "$request_file" || return 1
|
||||
{
|
||||
printf 'header = "Content-Type: application/json"\n'
|
||||
@@ -478,10 +534,44 @@ json.dump({
|
||||
TAPM_PULSE_TOKEN_FROM_RESPONSE "$response"
|
||||
}
|
||||
|
||||
TAPM_PULSE_INSTALL_AGENT_LOCAL() {
|
||||
TAPM_PULSE_WAIT_AGENT_REGISTERED() {
|
||||
local pulse_url="$1"
|
||||
local token="$2"
|
||||
local token_file installer_file artifact
|
||||
local node="$3"
|
||||
local temp_dir="$4"
|
||||
local curl_config="${temp_dir}/agent-${node}-verify.curl"
|
||||
local encoded_node response attempt
|
||||
|
||||
printf 'header = "X-API-Token: %s"\n' "$token" >"$curl_config" || return 1
|
||||
chmod 0600 "$curl_config" || return 1
|
||||
encoded_node="$(
|
||||
TAPM_PULSE_NODE_NAME="$node" python3 -c '
|
||||
import os, urllib.parse
|
||||
print(urllib.parse.quote(os.environ["TAPM_PULSE_NODE_NAME"], safe=""))
|
||||
'
|
||||
)" || return 1
|
||||
|
||||
for (( attempt = 1; attempt <= 20; attempt++ )); do
|
||||
response="$(
|
||||
curl --fail --silent --show-error \
|
||||
--connect-timeout 3 --max-time 5 \
|
||||
--config "$curl_config" \
|
||||
"${pulse_url}/api/agents/agent/lookup?hostname=${encoded_node}" \
|
||||
2>/dev/null
|
||||
)" || response=''
|
||||
if TAPM_PULSE_AGENT_REGISTERED_FROM_RESPONSE "$response"; then
|
||||
return 0
|
||||
fi
|
||||
sleep 3
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
TAPM_PULSE_INSTALL_AGENT_LOCAL() {
|
||||
local node="$1"
|
||||
local pulse_url="$2"
|
||||
local token="$3"
|
||||
local token_file installer_file cleanup_state_dir artifact
|
||||
local status=0
|
||||
local -a old_artifacts=(
|
||||
/usr/local/bin/pulse-agent
|
||||
@@ -496,19 +586,39 @@ TAPM_PULSE_INSTALL_AGENT_LOCAL() {
|
||||
rm -f -- "$token_file"
|
||||
return 1
|
||||
}
|
||||
cleanup_state_dir="$(mktemp -d /tmp/tapm-pulse-agent-cleanup.XXXXXX)" || {
|
||||
rm -f -- "$token_file" "$installer_file"
|
||||
return 1
|
||||
}
|
||||
chmod 0600 "$token_file" "$installer_file" || {
|
||||
rm -f -- "$token_file" "$installer_file"
|
||||
rm -rf -- "$cleanup_state_dir"
|
||||
return 1
|
||||
}
|
||||
printf '%s' "$token" >"$token_file" || {
|
||||
rm -f -- "$token_file" "$installer_file"
|
||||
rm -rf -- "$cleanup_state_dir"
|
||||
return 1
|
||||
}
|
||||
curl --fail --silent --show-error --location \
|
||||
--output "$installer_file" "${pulse_url}/install.sh" || status=$?
|
||||
if (( status == 0 )); then
|
||||
echo " Removing any previous Pulse Unified Agent installation..."
|
||||
bash "$installer_file" --uninstall --non-interactive || status=$?
|
||||
# Remove its connection sources before invoking the supported cleanup
|
||||
# routine. This is a replacement install, so contacting the retired
|
||||
# Pulse server to unregister is unnecessary.
|
||||
systemctl stop pulse-agent >/dev/null 2>&1 || true
|
||||
systemctl disable pulse-agent >/dev/null 2>&1 || true
|
||||
pkill -x pulse-agent >/dev/null 2>&1 || true
|
||||
rm -f -- \
|
||||
/etc/systemd/system/pulse-agent.service \
|
||||
/etc/systemd/system/multi-user.target.wants/pulse-agent.service
|
||||
systemctl daemon-reload >/dev/null 2>&1 || true
|
||||
rm -rf -- /var/lib/pulse-agent
|
||||
bash "$installer_file" \
|
||||
--uninstall \
|
||||
--non-interactive \
|
||||
--state-dir "$cleanup_state_dir" || status=$?
|
||||
fi
|
||||
if (( status == 0 )) && systemctl is-active --quiet pulse-agent; then
|
||||
echo " The previous pulse-agent service is still active." >&2
|
||||
@@ -531,12 +641,14 @@ TAPM_PULSE_INSTALL_AGENT_LOCAL() {
|
||||
bash "$installer_file" \
|
||||
--url "$pulse_url" \
|
||||
--token-file "$token_file" \
|
||||
--hostname "$node" \
|
||||
--enable-proxmox \
|
||||
--proxmox-type pve \
|
||||
--non-interactive \
|
||||
--insecure || status=$?
|
||||
fi
|
||||
rm -f -- "$token_file" "$installer_file"
|
||||
rm -rf -- "$cleanup_state_dir"
|
||||
(( status == 0 )) || return "$status"
|
||||
systemctl is-active --quiet pulse-agent
|
||||
}
|
||||
@@ -562,18 +674,34 @@ TAPM_PULSE_INSTALL_AGENT_REMOTE() {
|
||||
[[ "$remote_token_file" =~ ^/tmp/tapm-pulse-agent-token\.[A-Za-z0-9]+$ ]] ||
|
||||
return 1
|
||||
|
||||
"${ssh_args[@]}" bash -s -- "$pulse_url" "$remote_token_file" <<'TAPM_PULSE_REMOTE_AGENT'
|
||||
"${ssh_args[@]}" bash -s -- \
|
||||
"$pulse_url" "$remote_token_file" "$node" <<'TAPM_PULSE_REMOTE_AGENT'
|
||||
set -eu -o pipefail
|
||||
pulse_url="$1"
|
||||
token_file="$2"
|
||||
node="$3"
|
||||
installer_file="$(mktemp /tmp/tapm-pulse-agent-installer.XXXXXX)"
|
||||
trap 'rm -f -- "$token_file" "$installer_file"' EXIT
|
||||
cleanup_state_dir="$(mktemp -d /tmp/tapm-pulse-agent-cleanup.XXXXXX)"
|
||||
trap 'rm -f -- "$token_file" "$installer_file"; rm -rf -- "$cleanup_state_dir"' EXIT
|
||||
chmod 0600 "$token_file" "$installer_file"
|
||||
curl --fail --silent --show-error --location \
|
||||
--output "$installer_file" "${pulse_url}/install.sh"
|
||||
|
||||
echo " Removing any previous Pulse Unified Agent installation..."
|
||||
bash "$installer_file" --uninstall --non-interactive
|
||||
# This is a replacement install. Remove the old connection sources first so
|
||||
# the supported cleanup routine cannot contact the retired Pulse server.
|
||||
systemctl stop pulse-agent >/dev/null 2>&1 || true
|
||||
systemctl disable pulse-agent >/dev/null 2>&1 || true
|
||||
pkill -x pulse-agent >/dev/null 2>&1 || true
|
||||
rm -f -- \
|
||||
/etc/systemd/system/pulse-agent.service \
|
||||
/etc/systemd/system/multi-user.target.wants/pulse-agent.service
|
||||
systemctl daemon-reload >/dev/null 2>&1 || true
|
||||
rm -rf -- /var/lib/pulse-agent
|
||||
bash "$installer_file" \
|
||||
--uninstall \
|
||||
--non-interactive \
|
||||
--state-dir "$cleanup_state_dir"
|
||||
if systemctl is-active --quiet pulse-agent; then
|
||||
echo " The previous pulse-agent service is still active." >&2
|
||||
exit 1
|
||||
@@ -598,6 +726,7 @@ done
|
||||
bash "$installer_file" \
|
||||
--url "$pulse_url" \
|
||||
--token-file "$token_file" \
|
||||
--hostname "$node" \
|
||||
--enable-proxmox \
|
||||
--proxmox-type pve \
|
||||
--non-interactive \
|
||||
@@ -632,13 +761,20 @@ TAPM_PULSE_DEPLOY_CLUSTER_AGENTS() {
|
||||
}
|
||||
|
||||
if [[ "$node" == "$current_node" || "$node" == "$(hostname)" ]]; then
|
||||
TAPM_PULSE_INSTALL_AGENT_LOCAL "$pulse_url" "$agent_token"
|
||||
TAPM_PULSE_INSTALL_AGENT_LOCAL "$node" "$pulse_url" "$agent_token"
|
||||
else
|
||||
TAPM_PULSE_INSTALL_AGENT_REMOTE "$node" "$pulse_url" "$agent_token"
|
||||
fi
|
||||
if (( $? == 0 )); then
|
||||
echo -e "${idsCL[Green]}Pulse Unified Agent is active on ${node}.${idsCL[Default]}"
|
||||
((installed += 1))
|
||||
echo " Waiting for Pulse to confirm registration from ${node}..."
|
||||
if TAPM_PULSE_WAIT_AGENT_REGISTERED \
|
||||
"$pulse_url" "$agent_token" "$node" "$temp_dir"; then
|
||||
echo -e "${idsCL[Green]}Pulse confirmed Unified Agent registration for ${node}.${idsCL[Default]}"
|
||||
((installed += 1))
|
||||
else
|
||||
echo -e "${idsCL[LightRed]}pulse-agent is active on ${node}, but Pulse did not confirm its registration.${idsCL[Default]}"
|
||||
((failed += 1))
|
||||
fi
|
||||
else
|
||||
echo -e "${idsCL[LightRed]}Pulse Unified Agent installation failed on ${node}.${idsCL[Default]}"
|
||||
((failed += 1))
|
||||
@@ -665,6 +801,7 @@ TAPM_DEPLOY_PULSE_LXC() {
|
||||
local memory disk cores cpulimit swap onboot firewall unprivileged nameserver startup
|
||||
local network_config choice add_ha='no' auto_updates='yes' container_ip timezone temp_dir
|
||||
local default_bridge pulse_url admin_username admin_password primary_api_token
|
||||
local cluster_status='Registration failed'
|
||||
local container_created=0
|
||||
local -a create_args=()
|
||||
|
||||
@@ -898,7 +1035,6 @@ TAPM_DEPLOY_PULSE_LXC() {
|
||||
--net0 "$network_config"
|
||||
--onboot "$onboot"
|
||||
--startup "order=${startup}"
|
||||
--tags 'tapm;pulse'
|
||||
)
|
||||
[[ "$cpulimit" != 0 ]] && create_args+=(--cpulimit "$cpulimit")
|
||||
[[ -n "$nameserver" ]] && create_args+=(--nameserver "$nameserver")
|
||||
@@ -945,17 +1081,6 @@ TAPM_DEPLOY_PULSE_LXC() {
|
||||
|
||||
if [[ -n "$container_ip" ]]; then
|
||||
pulse_url="http://${container_ip}:${pulse_port}"
|
||||
echo -e "\n${idsCL[LightCyan]}Registering the Proxmox cluster with Pulse...${idsCL[Default]}"
|
||||
(
|
||||
trap 'rm -f /tmp/pulse-auto-register-request.json /tmp/pulse-auto-register-response.json' EXIT
|
||||
# Reuse the verified release's registration implementation so its
|
||||
# API contract and least-privilege role handling stay in sync.
|
||||
# shellcheck disable=SC1090
|
||||
source "$installer"
|
||||
IN_CONTAINER=false
|
||||
wait_for_pulse_ready "$pulse_url" 120 1 || true
|
||||
auto_register_pve_node "$ctid" "$container_ip" "$pulse_port"
|
||||
) || echo -e "${idsCL[LightYellow]}Pulse is installed, but automatic Proxmox registration did not complete.${idsCL[Default]}"
|
||||
fi
|
||||
|
||||
if [[ "$add_ha" == 'yes' ]] &&
|
||||
@@ -984,6 +1109,16 @@ TAPM_DEPLOY_PULSE_LXC() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e "\n${idsCL[LightCyan]}Registering the Proxmox cluster with authenticated Pulse access...${idsCL[Default]}"
|
||||
if TAPM_PULSE_REGISTER_CLUSTER \
|
||||
"$ctid" "$container_ip" "$pulse_port" "$installer" \
|
||||
"$primary_api_token" "$temp_dir"; then
|
||||
cluster_status='Registered'
|
||||
echo -e "${idsCL[Green]}Pulse confirmed Proxmox cluster registration.${idsCL[Default]}"
|
||||
else
|
||||
echo -e "${idsCL[LightRed]}Pulse is secured, but Proxmox cluster registration did not complete.${idsCL[Default]}"
|
||||
fi
|
||||
|
||||
echo -e "\n${idsCL[LightCyan]}Deploying clean Pulse Unified Agents to cluster nodes...${idsCL[Default]}"
|
||||
TAPM_PULSE_AGENTS_INSTALLED=0
|
||||
TAPM_PULSE_AGENTS_FAILED=0
|
||||
@@ -999,5 +1134,6 @@ TAPM_DEPLOY_PULSE_LXC() {
|
||||
echo -e "${idsCL[Green]}Pulse ${release} was installed and its service is active.${idsCL[Default]}"
|
||||
TAPM_PULSE_CONFIRM_CREDENTIALS_SAVED \
|
||||
"$pulse_url" "$admin_username" "$admin_password" "$primary_api_token" \
|
||||
"$TAPM_PULSE_AGENTS_INSTALLED" "$TAPM_PULSE_AGENTS_FAILED"
|
||||
"$TAPM_PULSE_AGENTS_INSTALLED" "$TAPM_PULSE_AGENTS_FAILED" \
|
||||
"$cluster_status"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user