Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a23126ca5 | ||
|
|
873bb17b62 | ||
|
|
6362844f1a | ||
|
|
f5d7577219 |
@@ -1,3 +1,26 @@
|
|||||||
# TA-Proxmenu - Proxmox Scripts for TA Use
|
# TA-Proxmenu - Proxmox Scripts for TA Use
|
||||||
|
|
||||||
bash <(curl -sL https://go.scity.us/install-tapm)
|
bash <(curl -sL https://go.scity.us/install-tapm)
|
||||||
|
|
||||||
|
To update an installed main-branch copy, switch it to V2, and immediately load
|
||||||
|
the V2 menu:
|
||||||
|
|
||||||
|
tapm V2
|
||||||
|
|
||||||
|
To change the TA-ProxMenu `origin` URL on every installed node in the current
|
||||||
|
Proxmox cluster, either select `G` in the legacy menu or run:
|
||||||
|
|
||||||
|
tapm git-url
|
||||||
|
|
||||||
|
The command prompts for the new repository URL, discovers cluster nodes with
|
||||||
|
`pvecm`, verifies that each node can read the new repository's `main` branch,
|
||||||
|
and only then changes that node's `origin`. A URL can also be supplied:
|
||||||
|
|
||||||
|
tapm git-url https://git.example.com/organization/TA-ProxMenu.git
|
||||||
|
|
||||||
|
Add `--yes` as the third argument for a non-interactive confirmation:
|
||||||
|
|
||||||
|
tapm git-url https://git.example.com/organization/TA-ProxMenu.git --yes
|
||||||
|
|
||||||
|
Private repositories require read credentials to be configured on every node
|
||||||
|
before migration. Repository credentials must not be embedded in the URL.
|
||||||
|
|||||||
+1
-2
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
action="$1"
|
action="$1"
|
||||||
FOLDER='/opt/idssys/ta-proxmenu'
|
FOLDER='/opt/idssys/ta-proxmenu'
|
||||||
VERS='2026.7.25-4'
|
VERS='2026.7.28-1'
|
||||||
|
|
||||||
noupdate=' '
|
noupdate=' '
|
||||||
|
|
||||||
@@ -32,4 +32,3 @@ VIRTIO_FILE=${VIRTIO_DOWNLOAD_URL##*/}
|
|||||||
# apt-get update
|
# apt-get update
|
||||||
# fi
|
# fi
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+9
-2
@@ -6,6 +6,12 @@
|
|||||||
source /opt/idssys/defaults/default.inc
|
source /opt/idssys/defaults/default.inc
|
||||||
source /opt/idssys/ta-proxmenu/defaults.inc
|
source /opt/idssys/ta-proxmenu/defaults.inc
|
||||||
|
|
||||||
|
# An older run.sh may update main on disk while continuing to execute its
|
||||||
|
# already-loaded code. Hand V2 to the new launcher loaded from disk.
|
||||||
|
if [[ "${1:-}" == "V2" ]]; then
|
||||||
|
exec /opt/idssys/ta-proxmenu/run.sh V2
|
||||||
|
fi
|
||||||
|
|
||||||
INSTALL_PULSE() {
|
INSTALL_PULSE() {
|
||||||
echo
|
echo
|
||||||
bash <(curl -fsSL https://github.com/rcourtman/Pulse/releases/latest/download/install.sh)
|
bash <(curl -fsSL https://github.com/rcourtman/Pulse/releases/latest/download/install.sh)
|
||||||
@@ -366,6 +372,7 @@ MAIN_MENU() {
|
|||||||
echo -e "${idsCL[White]} [${idsCL[LightYellow]}R${idsCL[Default]}] ${idsCL[White]}Restart Proxmox Services${idsCL[Default]}"
|
echo -e "${idsCL[White]} [${idsCL[LightYellow]}R${idsCL[Default]}] ${idsCL[White]}Restart Proxmox Services${idsCL[Default]}"
|
||||||
echo
|
echo
|
||||||
echo -e "${idsCL[White]} [${idsCL[LightYellow]}K${idsCL[Default]}] ${idsCL[White]}Install Keepalive on all Hosts${idsCL[Default]}"
|
echo -e "${idsCL[White]} [${idsCL[LightYellow]}K${idsCL[Default]}] ${idsCL[White]}Install Keepalive on all Hosts${idsCL[Default]}"
|
||||||
|
echo -e "${idsCL[White]} [${idsCL[LightYellow]}G${idsCL[Default]}] ${idsCL[White]}Change TA-ProxMenu Git URL on all Hosts${idsCL[Default]}"
|
||||||
echo
|
echo
|
||||||
echo -e "${idsCL[White]} [${idsCL[LightYellow]}Q${idsCL[Default]}] ${idsCL[White]}Quit${idsCL[Default]}"
|
echo -e "${idsCL[White]} [${idsCL[LightYellow]}Q${idsCL[Default]}] ${idsCL[White]}Quit${idsCL[Default]}"
|
||||||
echo
|
echo
|
||||||
@@ -388,6 +395,7 @@ MAIN_MENU() {
|
|||||||
[Mm]) MAINTENANCE_MODE;;
|
[Mm]) MAINTENANCE_MODE;;
|
||||||
[Rr]) RESTART_PVE_SERVICES;;
|
[Rr]) RESTART_PVE_SERVICES;;
|
||||||
[Kk]) INSTALL_KEEPALIVE;;
|
[Kk]) INSTALL_KEEPALIVE;;
|
||||||
|
[Gg]) exec /opt/idssys/ta-proxmenu/run.sh git-url;;
|
||||||
[Qq]) EXIT1; exit 0;;
|
[Qq]) EXIT1; exit 0;;
|
||||||
*) echo -e "Thats an invaild option,\nplease select a valid option only."; sleep 1;;
|
*) echo -e "Thats an invaild option,\nplease select a valid option only."; sleep 1;;
|
||||||
esac
|
esac
|
||||||
@@ -408,6 +416,7 @@ if [ ${action-x} ]; then
|
|||||||
cpu) DETECT_CPU;;
|
cpu) DETECT_CPU;;
|
||||||
mm) MAINTENANCE_MODE;;
|
mm) MAINTENANCE_MODE;;
|
||||||
timeout) SET_VM_SHUTDOWNTIMEOUT ${2};;
|
timeout) SET_VM_SHUTDOWNTIMEOUT ${2};;
|
||||||
|
git-url) exec /opt/idssys/ta-proxmenu/run.sh git-url "${2:-}";;
|
||||||
*) MAIN_MENU;;
|
*) MAIN_MENU;;
|
||||||
esac
|
esac
|
||||||
else
|
else
|
||||||
@@ -418,5 +427,3 @@ exit 0
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,205 @@
|
|||||||
source /opt/idssys/defaults/default.inc
|
source /opt/idssys/defaults/default.inc
|
||||||
source /opt/idssys/ta-proxmenu/defaults.inc
|
source /opt/idssys/ta-proxmenu/defaults.inc
|
||||||
|
|
||||||
|
VALID_GIT_URL() {
|
||||||
|
[[ "$1" =~ ^https?://[A-Za-z0-9._-]+(:[0-9]+)?/[A-Za-z0-9._/-]+$ ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
SWITCH_GIT_URL() {
|
||||||
|
local repository='/opt/idssys/ta-proxmenu'
|
||||||
|
local new_url="${1:-}"
|
||||||
|
local assume_yes="${2:-}"
|
||||||
|
local local_hostname
|
||||||
|
local local_short_hostname
|
||||||
|
local node
|
||||||
|
local node_output
|
||||||
|
local successful=0
|
||||||
|
local failed=0
|
||||||
|
local -a cluster_nodes=()
|
||||||
|
|
||||||
|
if [[ ! -d "${repository}/.git" ]]; then
|
||||||
|
echo -e "${idsCL[Red]}TA-ProxMenu is not a Git repository.${idsCL[Default]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$new_url" ]]; then
|
||||||
|
echo -en "${idsCL[LightCyan]}New TA-ProxMenu Git URL: ${idsCL[Default]}"
|
||||||
|
read -r -e new_url
|
||||||
|
fi
|
||||||
|
if ! VALID_GIT_URL "$new_url"; then
|
||||||
|
echo -e "${idsCL[Red]}Enter a complete HTTP or HTTPS repository URL without embedded credentials.${idsCL[Default]}"
|
||||||
|
echo -e "${idsCL[LightYellow]}Example: https://git.example.com/organization/TA-ProxMenu.git${idsCL[Default]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v pvecm >/dev/null 2>&1; then
|
||||||
|
mapfile -t cluster_nodes < <(
|
||||||
|
pvecm nodes 2>/dev/null |
|
||||||
|
awk '
|
||||||
|
$1 ~ /^(0x)?[[:xdigit:]]+$/ &&
|
||||||
|
$2 ~ /^[0-9]+$/ &&
|
||||||
|
$3 != "" { print $3 }
|
||||||
|
'
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
if (( ${#cluster_nodes[@]} == 0 )); then
|
||||||
|
cluster_nodes=("$(hostname -s)")
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo -e "${idsCL[LightCyan]}Repository URL:${idsCL[Default]} $new_url"
|
||||||
|
echo -e "${idsCL[LightCyan]}Target nodes:${idsCL[Default]} ${cluster_nodes[*]}"
|
||||||
|
if [[ "$assume_yes" != "--yes" ]]; then
|
||||||
|
echo -en "${idsCL[LightYellow]}Change origin on every listed node (y/N)? ${idsCL[Default]}"
|
||||||
|
read -r -n 1 choice
|
||||||
|
echo
|
||||||
|
[[ "$choice" == [Yy] ]] || {
|
||||||
|
echo -e "${idsCL[LightYellow]}Git URL migration cancelled.${idsCL[Default]}"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
local_hostname="$(hostname)"
|
||||||
|
local_short_hostname="$(hostname -s)"
|
||||||
|
for node in "${cluster_nodes[@]}"; do
|
||||||
|
echo -en "${idsCL[LightCyan]}${node}:${idsCL[Default]} "
|
||||||
|
if [[ "$node" == "$local_hostname" || "$node" == "$local_short_hostname" ]]; then
|
||||||
|
if ! GIT_TERMINAL_PROMPT=0 timeout 20 \
|
||||||
|
git -C "$repository" ls-remote --exit-code \
|
||||||
|
"$new_url" refs/heads/main >/dev/null 2>&1; then
|
||||||
|
echo -e "${idsCL[Red]}new repository is unavailable or requires credentials${idsCL[Default]}"
|
||||||
|
((failed += 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if git -C "$repository" remote set-url origin "$new_url"; then
|
||||||
|
echo -e "${idsCL[Green]}origin updated${idsCL[Default]}"
|
||||||
|
((successful += 1))
|
||||||
|
else
|
||||||
|
echo -e "${idsCL[Red]}could not update origin${idsCL[Default]}"
|
||||||
|
((failed += 1))
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
node_output="$(
|
||||||
|
ssh \
|
||||||
|
-o BatchMode=yes \
|
||||||
|
-o ConnectTimeout=10 \
|
||||||
|
"root@${node}" \
|
||||||
|
"test -d '${repository}/.git' &&
|
||||||
|
GIT_TERMINAL_PROMPT=0 timeout 20 git -C '${repository}' ls-remote --exit-code '${new_url}' refs/heads/main >/dev/null 2>&1 &&
|
||||||
|
git -C '${repository}' remote set-url origin '${new_url}'" \
|
||||||
|
2>&1
|
||||||
|
)"
|
||||||
|
if [[ $? -eq 0 ]]; then
|
||||||
|
echo -e "${idsCL[Green]}origin updated${idsCL[Default]}"
|
||||||
|
((successful += 1))
|
||||||
|
else
|
||||||
|
echo -e "${idsCL[Red]}failed${idsCL[Default]}"
|
||||||
|
[[ -n "$node_output" ]] && echo " $node_output"
|
||||||
|
((failed += 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo -e "${idsCL[Green]}Updated nodes: ${successful}${idsCL[Default]}"
|
||||||
|
if ((failed > 0)); then
|
||||||
|
echo -e "${idsCL[Red]}Failed nodes: ${failed}${idsCL[Default]}"
|
||||||
|
echo -e "${idsCL[LightYellow]}A failed node was left on its existing origin URL.${idsCL[Default]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo -e "${idsCL[Green]}Every installed cluster node now uses the new Git URL.${idsCL[Default]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
SWITCH_TO_V2() {
|
||||||
|
local repository='/opt/idssys/ta-proxmenu'
|
||||||
|
local current_branch
|
||||||
|
local head_commit
|
||||||
|
local local_commit
|
||||||
|
local main_commit
|
||||||
|
local remote_commit
|
||||||
|
|
||||||
|
if [[ ! -d "${repository}/.git" ]]; then
|
||||||
|
echo -e "${idsCL[Red]}TA-ProxMenu is not a Git repository.${idsCL[Default]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
current_branch="$(git -C "$repository" branch --show-current 2>/dev/null)"
|
||||||
|
if [[ "$current_branch" == "V2" ]]; then
|
||||||
|
exec /opt/idssys/ta-proxmenu/run.sh
|
||||||
|
fi
|
||||||
|
if [[ -n "$(git -C "$repository" status --porcelain --untracked-files=normal)" ]]; then
|
||||||
|
echo -e "${idsCL[LightYellow]}TA-ProxMenu has local changes; branch switching was refused to preserve them.${idsCL[Default]}"
|
||||||
|
git -C "$repository" status --short
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${idsCL[LightCyan]}Fetching TA-ProxMenu branch 'V2'...${idsCL[Default]}"
|
||||||
|
if ! timeout 30 git -C "$repository" fetch --prune origin \
|
||||||
|
'+refs/heads/main:refs/remotes/origin/main' \
|
||||||
|
'+refs/heads/V2:refs/remotes/origin/V2' >/dev/null 2>&1; then
|
||||||
|
echo -e "${idsCL[Red]}Could not fetch branch 'V2' from origin.${idsCL[Default]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$current_branch" ]]; then
|
||||||
|
head_commit="$(git -C "$repository" rev-parse --verify 'HEAD^{commit}' 2>/dev/null)"
|
||||||
|
main_commit="$(git -C "$repository" rev-parse --verify \
|
||||||
|
'refs/remotes/origin/main^{commit}' 2>/dev/null)"
|
||||||
|
if [[ -z "$head_commit" || "$head_commit" != "$main_commit" ]]; then
|
||||||
|
echo -e "${idsCL[Red]}TA-ProxMenu has an unrecognized detached HEAD; branch switching was refused.${idsCL[Default]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo -e "${idsCL[LightCyan]}Recovered the legacy updater's detached main checkout.${idsCL[Default]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
remote_commit="$(git -C "$repository" rev-parse --verify \
|
||||||
|
'refs/remotes/origin/V2^{commit}' 2>/dev/null)" || {
|
||||||
|
echo -e "${idsCL[Red]}Origin does not provide a usable V2 branch.${idsCL[Default]}"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if git -C "$repository" show-ref --verify --quiet refs/heads/V2; then
|
||||||
|
local_commit="$(git -C "$repository" rev-parse --verify \
|
||||||
|
'refs/heads/V2^{commit}' 2>/dev/null)" || return 1
|
||||||
|
|
||||||
|
if [[ "$local_commit" != "$remote_commit" ]] &&
|
||||||
|
! git -C "$repository" merge-base --is-ancestor \
|
||||||
|
"$local_commit" "$remote_commit"; then
|
||||||
|
echo -e "${idsCL[LightYellow]}Local branch 'V2' has local-only or diverged commits; switching was refused.${idsCL[Default]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
git -C "$repository" switch V2 >/dev/null || return 1
|
||||||
|
if [[ "$local_commit" != "$remote_commit" ]] &&
|
||||||
|
! git -C "$repository" merge --ff-only \
|
||||||
|
refs/remotes/origin/V2 >/dev/null; then
|
||||||
|
echo -e "${idsCL[Red]}Could not fast-forward V2; no commits were discarded.${idsCL[Default]}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
git -C "$repository" switch --create V2 \
|
||||||
|
--track origin/V2 >/dev/null || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f /var/cache/ta-proxmenu/update-status 2>/dev/null || true
|
||||||
|
echo -e "${idsCL[Green]}TA-ProxMenu is now using branch 'V2'. Loading the V2 menu...${idsCL[Default]}"
|
||||||
|
exec /opt/idssys/ta-proxmenu/run.sh
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "${1:-}" == "V2" ]]; then
|
||||||
|
SWITCH_TO_V2
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${1:-}" == "git-url" ]]; then
|
||||||
|
SWITCH_GIT_URL "${2:-}" "${3:-}"
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "${noupdate}" != *" ${1} "* ]] && [[ "${noupdate}" != *" ${2} "* ]]; then
|
if [[ "${noupdate}" != *" ${1} "* ]] && [[ "${noupdate}" != *" ${2} "* ]]; then
|
||||||
if curl -m 3 -s --head --request GET https://git.scity.us | grep "HTTP/2 200" > /dev/null; then
|
if GIT_TERMINAL_PROMPT=0 timeout 15 git -C /opt/idssys/ta-proxmenu \
|
||||||
|
ls-remote --exit-code origin refs/heads/main >/dev/null 2>&1; then
|
||||||
if [ "${1}" != "tapm" ]; then
|
if [ "${1}" != "tapm" ]; then
|
||||||
echo -en "${idsCL[LightCyan]}Checking for updates...${idsCL[Default]}"
|
echo -en "${idsCL[LightCyan]}Checking for updates...${idsCL[Default]}"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -59,7 +256,7 @@ if [[ "${noupdate}" != *" ${1} "* ]] && [[ "${noupdate}" != *" ${2} "* ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
else
|
else
|
||||||
echo -e "${idsCL[Red]}Could not connect to 'git.scity.us' for updates${idsCL[Default]}"
|
echo -e "${idsCL[Red]}Could not connect to the configured TA-ProxMenu Git origin for updates${idsCL[Default]}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -68,4 +265,3 @@ if [ "${1}" != "tapm" ] && [ "${1}" != "update" ] && [ "${1}" != "u" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user