diff --git a/defaults.inc b/defaults.inc index 7e679b3..220c5b2 100755 --- a/defaults.inc +++ b/defaults.inc @@ -3,7 +3,7 @@ action="${1:-}" FOLDER='/opt/idssys/ta-proxmenu' -VERS='2026.7.25-58' +VERS='2026.7.25-60' noupdate=' ' diff --git a/inc/deploy-pulse-lxc.sh b/inc/deploy-pulse-lxc.sh index 68906f8..1d6bc3e 100644 --- a/inc/deploy-pulse-lxc.sh +++ b/inc/deploy-pulse-lxc.sh @@ -18,6 +18,36 @@ TAPM_PULSE_VALID_CTID() { [[ "${1:-}" =~ ^[1-9][0-9]{2,8}$ ]] } +TAPM_PULSE_FIRST_AVAILABLE_CTID_FROM_RESOURCES() { + local resources_json="${1:-[]}" + local starting_id="${2:-200}" + + RESOURCES_JSON="$resources_json" STARTING_ID="$starting_id" python3 -c ' +import json, os +try: + resources = json.loads(os.environ["RESOURCES_JSON"]) + candidate = int(os.environ["STARTING_ID"]) +except (TypeError, ValueError): + raise SystemExit(1) +if not isinstance(resources, list) or candidate < 100 or candidate > 999999999: + raise SystemExit(1) +used = set() +for resource in resources: + if not isinstance(resource, dict): + continue + try: + vmid = int(resource.get("vmid")) + except (TypeError, ValueError): + continue + used.add(vmid) +while candidate in used and candidate <= 999999999: + candidate += 1 +if candidate > 999999999: + raise SystemExit(1) +print(candidate) +' 2>/dev/null +} + TAPM_PULSE_VALID_HOSTNAME() { [[ "${1:-}" =~ ^[A-Za-z0-9][A-Za-z0-9.-]{0,62}$ ]] } @@ -267,8 +297,6 @@ TAPM_PULSE_CONFIRM_CREDENTIALS_SAVED() { local admin_username="$2" local admin_password="$3" local primary_api_token="$4" - local cluster_status="$5" - local agent_status="$6" local acknowledgement while true; do @@ -281,8 +309,6 @@ 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: ${agent_status}" echo -e "${idsCL[LightYellow]}============================================================================${idsCL[Default]}" echo read -r -p " Type saved after recording the password and API token: " acknowledgement @@ -1022,15 +1048,13 @@ TAPM_PULSE_DEPLOY_CLUSTER_AGENTS() { TAPM_DEPLOY_PULSE_LXC() { local release="${PULSE_RELEASE:-v6.1.1}" local pulse_port="${PULSE_PORT:-7655}" auto_update_flag='--disable-auto-updates' - local ctid default_ctid hostname bridge address_cidr gateway vlan_id + local ctid default_ctid cluster_resources hostname bridge address_cidr gateway vlan_id local root_storage default_root_storage template_storage template_name template_path local arch archive_name base_url installer archive signature installer_signature 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 admin_password_mode local primary_api_token - local cluster_status='Registration failed' - local agent_status='Skipped because cluster registration failed' local container_created=0 local -a create_args=() @@ -1064,7 +1088,16 @@ TAPM_DEPLOY_PULSE_LXC() { TAPM_PULSE_VALID_PORT "$pulse_port" || { TAPM_PULSE_FAIL "Configured Pulse port '${pulse_port}' is invalid."; return 1; } - default_ctid="$(pvesh get /cluster/nextid 2>/dev/null || true)" + default_ctid="$( + cluster_resources="$( + pvesh get /cluster/resources --type vm --output-format json 2>/dev/null + )" && + TAPM_PULSE_FIRST_AVAILABLE_CTID_FROM_RESOURCES \ + "$cluster_resources" 200 + )" || default_ctid='' + if [[ -z "$default_ctid" ]]; then + default_ctid="$(pvesh get /cluster/nextid 2>/dev/null || true)" + fi while true; do TAPM_PULSE_PROMPT_UNTIL_VALID ctid "Container ID" "$default_ctid" \ TAPM_PULSE_VALID_CTID "The container ID must be a whole number of at least three digits." @@ -1072,7 +1105,7 @@ TAPM_DEPLOY_PULSE_LXC() { break fi TAPM_PULSE_FAIL "Container ${ctid} already exists. Choose another container ID." - default_ctid="$(pvesh get /cluster/nextid 2>/dev/null || true)" + default_ctid="$((ctid + 1))" done TAPM_PULSE_PROMPT_UNTIL_VALID hostname "Container hostname" "Pulse-Monitor" \ @@ -1348,29 +1381,6 @@ 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]}" - - 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 - TAPM_PULSE_DEPLOY_CLUSTER_AGENTS \ - "$pulse_url" "$primary_api_token" "$temp_dir" || true - agent_status="${TAPM_PULSE_AGENTS_INSTALLED} registered, ${TAPM_PULSE_AGENTS_FAILED} failed or offline" - else - echo -e "${idsCL[LightRed]}Pulse is secured, but Proxmox cluster registration did not complete.${idsCL[Default]}" - echo -e "${idsCL[LightYellow]}Skipping Unified Agent deployment until cluster registration succeeds.${idsCL[Default]}" - if TAPM_PULSE_OFFER_FAILED_LXC_REMOVAL "$ctid"; then - TAPM_CLEAN_TEMP_DIR "$temp_dir" - unset admin_password primary_api_token - return 1 - fi - fi - pct exec "$ctid" -- rm -f \ /tmp/install.sh "/tmp/${archive_name}" "/tmp/${archive_name}.sshsig" || true TAPM_CLEAN_TEMP_DIR "$temp_dir" @@ -1378,7 +1388,7 @@ TAPM_DEPLOY_PULSE_LXC() { echo echo -e "${idsCL[Green]}Pulse ${release} was installed and its service is active.${idsCL[Default]}" + echo -e "${idsCL[LightCyan]}Add Proxmox inventory and host telemetry from the Pulse web interface.${idsCL[Default]}" TAPM_PULSE_CONFIRM_CREDENTIALS_SAVED \ - "$pulse_url" "$admin_username" "$admin_password" "$primary_api_token" \ - "$cluster_status" "$agent_status" + "$pulse_url" "$admin_username" "$admin_password" "$primary_api_token" } diff --git a/tests/test-pulse.sh b/tests/test-pulse.sh index f8dbb03..68705d4 100644 --- a/tests/test-pulse.sh +++ b/tests/test-pulse.sh @@ -128,6 +128,19 @@ assert_equal 'pve3' \ assert_success "valid Pulse CTID" TAPM_PULSE_VALID_CTID 210 assert_failure "invalid Pulse CTID" TAPM_PULSE_VALID_CTID 99 +ctid_resources='[ + {"type":"qemu","vmid":200}, + {"type":"lxc","vmid":"201"}, + {"type":"storage","storage":"local"} +]' +assert_equal 202 \ + "$(TAPM_PULSE_FIRST_AVAILABLE_CTID_FROM_RESOURCES "$ctid_resources" 200)" \ + "first available Pulse CTID starts at 200 and skips occupied IDs" +assert_equal 200 \ + "$(TAPM_PULSE_FIRST_AVAILABLE_CTID_FROM_RESOURCES '[]' 200)" \ + "Pulse CTID 200 selected when available" +assert_failure "invalid Pulse CTID resource data rejected" \ + TAPM_PULSE_FIRST_AVAILABLE_CTID_FROM_RESOURCES '{}' 200 assert_success "valid Pulse hostname" TAPM_PULSE_VALID_HOSTNAME pulse-monitor assert_failure "invalid Pulse hostname" TAPM_PULSE_VALID_HOSTNAME 'pulse monitor' assert_success "valid positive integer" TAPM_PULSE_VALID_POSITIVE_INTEGER 1024