mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-04-25 08:56:21 +00:00
Update repository and clean up
This commit is contained in:
@@ -1,720 +0,0 @@
|
|||||||
# base-packages.txt - Generated on 2025-05-15 21:15:29
|
|
||||||
# Proxmox Version: pve-manager/8.4.1/ (running kernel: 6.8.12-9-pve)
|
|
||||||
|
|
||||||
adduser
|
|
||||||
apparmor
|
|
||||||
apt
|
|
||||||
apt-listchanges
|
|
||||||
apt-utils
|
|
||||||
attr
|
|
||||||
base-files
|
|
||||||
base-passwd
|
|
||||||
bash
|
|
||||||
bash-completion
|
|
||||||
bc
|
|
||||||
bind9-dnsutils
|
|
||||||
bind9-host
|
|
||||||
bind9-libs
|
|
||||||
binutils
|
|
||||||
binutils-common
|
|
||||||
binutils-x86-64-linux-gnu
|
|
||||||
bridge-utils
|
|
||||||
bsdextrautils
|
|
||||||
bsd-mailx
|
|
||||||
bsdutils
|
|
||||||
btrfs-progs
|
|
||||||
busybox
|
|
||||||
bzip2
|
|
||||||
ca-certificates
|
|
||||||
ceph-common
|
|
||||||
ceph-fuse
|
|
||||||
chrony
|
|
||||||
cifs-utils
|
|
||||||
console-setup
|
|
||||||
console-setup-linux
|
|
||||||
coreutils
|
|
||||||
corosync
|
|
||||||
cpio
|
|
||||||
criu
|
|
||||||
cron
|
|
||||||
cron-daemon-common
|
|
||||||
cstream
|
|
||||||
curl
|
|
||||||
dash
|
|
||||||
dbus
|
|
||||||
dbus-bin
|
|
||||||
dbus-daemon
|
|
||||||
dbus-session-bus-common
|
|
||||||
dbus-system-bus-common
|
|
||||||
debconf
|
|
||||||
debconf-i18n
|
|
||||||
debian-archive-keyring
|
|
||||||
debian-faq
|
|
||||||
debianutils
|
|
||||||
dialog
|
|
||||||
diffutils
|
|
||||||
dirmngr
|
|
||||||
distro-info-data
|
|
||||||
dmeventd
|
|
||||||
dmidecode
|
|
||||||
dmsetup
|
|
||||||
doc-debian
|
|
||||||
dosfstools
|
|
||||||
dpkg
|
|
||||||
dtach
|
|
||||||
e2fsprogs
|
|
||||||
ebtables
|
|
||||||
efibootmgr
|
|
||||||
eject
|
|
||||||
ethtool
|
|
||||||
faketime
|
|
||||||
fdisk
|
|
||||||
fdutils
|
|
||||||
file
|
|
||||||
findutils
|
|
||||||
fontconfig
|
|
||||||
fontconfig-config
|
|
||||||
fonts-dejavu-core
|
|
||||||
fonts-font-awesome
|
|
||||||
fonts-font-logos
|
|
||||||
fonts-glyphicons-halflings
|
|
||||||
frr
|
|
||||||
frr-pythontools
|
|
||||||
fuse
|
|
||||||
gcc-12-base
|
|
||||||
gdisk
|
|
||||||
genisoimage
|
|
||||||
gettext-base
|
|
||||||
glusterfs-client
|
|
||||||
glusterfs-common
|
|
||||||
gnupg
|
|
||||||
gnupg-l10n
|
|
||||||
gnupg-utils
|
|
||||||
gnutls-bin
|
|
||||||
gpg
|
|
||||||
gpg-agent
|
|
||||||
gpgconf
|
|
||||||
gpgsm
|
|
||||||
gpgv
|
|
||||||
gpg-wks-client
|
|
||||||
gpg-wks-server
|
|
||||||
grep
|
|
||||||
groff-base
|
|
||||||
grub2-common
|
|
||||||
grub-common
|
|
||||||
grub-efi-amd64
|
|
||||||
grub-efi-amd64-bin
|
|
||||||
grub-efi-amd64-signed
|
|
||||||
grub-pc-bin
|
|
||||||
gzip
|
|
||||||
hdparm
|
|
||||||
hostname
|
|
||||||
ifupdown2
|
|
||||||
inetutils-telnet
|
|
||||||
init
|
|
||||||
initramfs-tools
|
|
||||||
initramfs-tools-core
|
|
||||||
init-system-helpers
|
|
||||||
iproute2
|
|
||||||
ipset
|
|
||||||
iptables
|
|
||||||
iputils-ping
|
|
||||||
isc-dhcp-client
|
|
||||||
isc-dhcp-common
|
|
||||||
iso-codes
|
|
||||||
jq
|
|
||||||
kbd
|
|
||||||
keyboard-configuration
|
|
||||||
keyutils
|
|
||||||
klibc-utils
|
|
||||||
kmod
|
|
||||||
krb5-locales
|
|
||||||
ksm-control-daemon
|
|
||||||
less
|
|
||||||
libacl1
|
|
||||||
libaio1
|
|
||||||
libanyevent-http-perl
|
|
||||||
libanyevent-perl
|
|
||||||
libapparmor1
|
|
||||||
libappconfig-perl
|
|
||||||
libapt-pkg6.0
|
|
||||||
libapt-pkg-perl
|
|
||||||
libarchive13
|
|
||||||
libargon2-1
|
|
||||||
libasound2
|
|
||||||
libasound2-data
|
|
||||||
libassuan0
|
|
||||||
libasyncns0
|
|
||||||
libattr1
|
|
||||||
libaudit1
|
|
||||||
libaudit-common
|
|
||||||
libauthen-pam-perl
|
|
||||||
libavahi-client3
|
|
||||||
libavahi-common3
|
|
||||||
libavahi-common-data
|
|
||||||
libbabeltrace1
|
|
||||||
libbinutils
|
|
||||||
libblas3
|
|
||||||
libblkid1
|
|
||||||
libbpf1
|
|
||||||
libbrotli1
|
|
||||||
libbsd0
|
|
||||||
libbytes-random-secure-perl
|
|
||||||
libbz2-1.0
|
|
||||||
libc6
|
|
||||||
libcairo2
|
|
||||||
libcap2
|
|
||||||
libcap2-bin
|
|
||||||
libcap-ng0
|
|
||||||
libc-ares2
|
|
||||||
libc-bin
|
|
||||||
libcbor0.8
|
|
||||||
libcephfs2
|
|
||||||
libcfg7
|
|
||||||
libc-l10n
|
|
||||||
libclone-perl
|
|
||||||
libcmap4
|
|
||||||
libcom-err2
|
|
||||||
libcommon-sense-perl
|
|
||||||
libconvert-asn1-perl
|
|
||||||
libcorosync-common4
|
|
||||||
libcpg4
|
|
||||||
libcrypt1
|
|
||||||
libcrypt-openssl-bignum-perl
|
|
||||||
libcrypt-openssl-random-perl
|
|
||||||
libcrypt-openssl-rsa-perl
|
|
||||||
libcrypt-random-seed-perl
|
|
||||||
libcryptsetup12
|
|
||||||
libcrypt-ssleay-perl
|
|
||||||
libctf0
|
|
||||||
libctf-nobfd0
|
|
||||||
libcurl3-gnutls
|
|
||||||
libcurl4
|
|
||||||
libdatrie1
|
|
||||||
libdb5.3
|
|
||||||
libdbi1
|
|
||||||
libdbus-1-3
|
|
||||||
libdebconfclient0
|
|
||||||
libdevel-cycle-perl
|
|
||||||
libdevmapper1.02.1
|
|
||||||
libdevmapper-event1.02.1
|
|
||||||
libdigest-hmac-perl
|
|
||||||
libdouble-conversion3
|
|
||||||
libdrm2
|
|
||||||
libdrm-common
|
|
||||||
libdw1
|
|
||||||
libedit2
|
|
||||||
libefiboot1
|
|
||||||
libefivar1
|
|
||||||
libelf1
|
|
||||||
libencode-locale-perl
|
|
||||||
libepoxy0
|
|
||||||
libevent-2.1-7
|
|
||||||
libevent-core-2.1-7
|
|
||||||
libexpat1
|
|
||||||
libext2fs2
|
|
||||||
libfaketime
|
|
||||||
libfdisk1
|
|
||||||
libfdt1
|
|
||||||
libffi8
|
|
||||||
libfido2-1
|
|
||||||
libfile-chdir-perl
|
|
||||||
libfile-find-rule-perl
|
|
||||||
libfile-listing-perl
|
|
||||||
libfile-readbackwards-perl
|
|
||||||
libfilesys-df-perl
|
|
||||||
libflac12
|
|
||||||
libfmt9
|
|
||||||
libfontconfig1
|
|
||||||
libfreetype6
|
|
||||||
libfribidi0
|
|
||||||
libfstrm0
|
|
||||||
libfuse2
|
|
||||||
libfuse3-3
|
|
||||||
libgbm1
|
|
||||||
libgcc-s1
|
|
||||||
libgcrypt20
|
|
||||||
libgdbm6
|
|
||||||
libgdbm-compat4
|
|
||||||
libgfapi0
|
|
||||||
libgfchangelog0
|
|
||||||
libgfrpc0
|
|
||||||
libgfxdr0
|
|
||||||
libglib2.0-0
|
|
||||||
libglusterd0
|
|
||||||
libglusterfs0
|
|
||||||
libgmp10
|
|
||||||
libgnutls30
|
|
||||||
libgnutls-dane0
|
|
||||||
libgnutlsxx30
|
|
||||||
libgoogle-perftools4
|
|
||||||
libgpg-error0
|
|
||||||
libgprofng0
|
|
||||||
libgraphite2-3
|
|
||||||
libgssapi-krb5-2
|
|
||||||
libgstreamer1.0-0
|
|
||||||
libgstreamer-plugins-base1.0-0
|
|
||||||
libharfbuzz0b
|
|
||||||
libhogweed6
|
|
||||||
libhtml-parser-perl
|
|
||||||
libhtml-tagset-perl
|
|
||||||
libhtml-tree-perl
|
|
||||||
libhttp-cookies-perl
|
|
||||||
libhttp-daemon-perl
|
|
||||||
libhttp-date-perl
|
|
||||||
libhttp-message-perl
|
|
||||||
libhttp-negotiate-perl
|
|
||||||
libibverbs1
|
|
||||||
libicu72
|
|
||||||
libidn2-0
|
|
||||||
libinih1
|
|
||||||
libio-html-perl
|
|
||||||
libio-multiplex-perl
|
|
||||||
libio-socket-ssl-perl
|
|
||||||
libio-stringy-perl
|
|
||||||
libip4tc2
|
|
||||||
libip6tc2
|
|
||||||
libipset13
|
|
||||||
libiscsi7
|
|
||||||
libisns0
|
|
||||||
libjansson4
|
|
||||||
libjemalloc2
|
|
||||||
libjpeg62-turbo
|
|
||||||
libjq1
|
|
||||||
libjs-bootstrap
|
|
||||||
libjs-extjs
|
|
||||||
libjs-jquery
|
|
||||||
libjson-c5
|
|
||||||
libjson-glib-1.0-0
|
|
||||||
libjson-glib-1.0-common
|
|
||||||
libjson-perl
|
|
||||||
libjson-xs-perl
|
|
||||||
libjs-qrcodejs
|
|
||||||
libjs-sencha-touch
|
|
||||||
libk5crypto3
|
|
||||||
libkeyutils1
|
|
||||||
libklibc
|
|
||||||
libkmod2
|
|
||||||
libknet1
|
|
||||||
libkrb5-3
|
|
||||||
libkrb5support0
|
|
||||||
libksba8
|
|
||||||
libldap-2.5-0
|
|
||||||
libldb2
|
|
||||||
liblinear4
|
|
||||||
liblinux-inotify2-perl
|
|
||||||
liblmdb0
|
|
||||||
liblocale-gettext-perl
|
|
||||||
liblockfile1
|
|
||||||
liblockfile-bin
|
|
||||||
liblttng-ust1
|
|
||||||
liblttng-ust-common1
|
|
||||||
liblttng-ust-ctl5
|
|
||||||
liblua5.3-0
|
|
||||||
liblvm2cmd2.03
|
|
||||||
liblwp-mediatypes-perl
|
|
||||||
liblwp-protocol-https-perl
|
|
||||||
liblz4-1
|
|
||||||
liblzma5
|
|
||||||
liblzo2-2
|
|
||||||
libmagic1
|
|
||||||
libmagic-mgc
|
|
||||||
libmath-random-isaac-perl
|
|
||||||
libmaxminddb0
|
|
||||||
libmd0
|
|
||||||
libmime-base32-perl
|
|
||||||
libmnl0
|
|
||||||
libmount1
|
|
||||||
libmp3lame0
|
|
||||||
libmpg123-0
|
|
||||||
libncurses6
|
|
||||||
libncursesw6
|
|
||||||
libnet1
|
|
||||||
libnetaddr-ip-perl
|
|
||||||
libnet-dbus-perl
|
|
||||||
libnet-dns-perl
|
|
||||||
libnetfilter-conntrack3
|
|
||||||
libnetfilter-log1
|
|
||||||
libnet-http-perl
|
|
||||||
libnet-ip-perl
|
|
||||||
libnet-ldap-perl
|
|
||||||
libnet-ssleay-perl
|
|
||||||
libnet-subnet-perl
|
|
||||||
libnettle8
|
|
||||||
libnewt0.52
|
|
||||||
libnfnetlink0
|
|
||||||
libnfsidmap1
|
|
||||||
libnftables1
|
|
||||||
libnftnl11
|
|
||||||
libnghttp2-14
|
|
||||||
libnl-3-200
|
|
||||||
libnl-route-3-200
|
|
||||||
libnozzle1
|
|
||||||
libnpth0
|
|
||||||
libnsl2
|
|
||||||
libnspr4
|
|
||||||
libnss3
|
|
||||||
libnss-systemd
|
|
||||||
libnuma1
|
|
||||||
libnumber-compare-perl
|
|
||||||
libnvpair3linux
|
|
||||||
liboath0
|
|
||||||
libogg0
|
|
||||||
libonig5
|
|
||||||
libopeniscsiusr
|
|
||||||
libopus0
|
|
||||||
liborc-0.4-0
|
|
||||||
libp11-kit0
|
|
||||||
libpam0g
|
|
||||||
libpam-modules
|
|
||||||
libpam-modules-bin
|
|
||||||
libpam-runtime
|
|
||||||
libpam-systemd
|
|
||||||
libpango-1.0-0
|
|
||||||
libpangocairo-1.0-0
|
|
||||||
libpangoft2-1.0-0
|
|
||||||
libpcap0.8
|
|
||||||
libpci3
|
|
||||||
libpcre2-16-0
|
|
||||||
libpcre2-8-0
|
|
||||||
libpcre3
|
|
||||||
libperl5.36
|
|
||||||
libpipeline1
|
|
||||||
libpixman-1-0
|
|
||||||
libpng16-16
|
|
||||||
libpopt0
|
|
||||||
libposix-strptime-perl
|
|
||||||
libproc2-0
|
|
||||||
libprotobuf32
|
|
||||||
libprotobuf-c1
|
|
||||||
libproxmox-acme-perl
|
|
||||||
libproxmox-acme-plugins
|
|
||||||
libproxmox-backup-qemu0
|
|
||||||
libproxmox-rs-perl
|
|
||||||
libpsl5
|
|
||||||
libpulse0
|
|
||||||
libpve-access-control
|
|
||||||
libpve-apiclient-perl
|
|
||||||
libpve-cluster-api-perl
|
|
||||||
libpve-cluster-perl
|
|
||||||
libpve-common-perl
|
|
||||||
libpve-guest-common-perl
|
|
||||||
libpve-http-server-perl
|
|
||||||
libpve-network-api-perl
|
|
||||||
libpve-network-perl
|
|
||||||
libpve-notify-perl
|
|
||||||
libpve-rs-perl
|
|
||||||
libpve-storage-perl
|
|
||||||
libpve-u2f-server-perl
|
|
||||||
libpython3.11-minimal
|
|
||||||
libpython3.11-stdlib
|
|
||||||
libpython3-stdlib
|
|
||||||
libqb100
|
|
||||||
libqrencode4
|
|
||||||
libqt5core5a
|
|
||||||
libqt5dbus5
|
|
||||||
libqt5network5
|
|
||||||
libquorum5
|
|
||||||
librabbitmq4
|
|
||||||
librados2
|
|
||||||
librados2-perl
|
|
||||||
libradosstriper1
|
|
||||||
librbd1
|
|
||||||
librdkafka1
|
|
||||||
librdmacm1
|
|
||||||
libreadline8
|
|
||||||
libregexp-ipv6-perl
|
|
||||||
librgw2
|
|
||||||
librrd8
|
|
||||||
librrds-perl
|
|
||||||
librtmp1
|
|
||||||
libsasl2-2
|
|
||||||
libsasl2-modules-db
|
|
||||||
libseccomp2
|
|
||||||
libselinux1
|
|
||||||
libsemanage2
|
|
||||||
libsemanage-common
|
|
||||||
libsepol2
|
|
||||||
libslang2
|
|
||||||
libslirp0
|
|
||||||
libsmartcols1
|
|
||||||
libsmbclient
|
|
||||||
libsnappy1v5
|
|
||||||
libsndfile1
|
|
||||||
libsocket6-perl
|
|
||||||
libspice-server1
|
|
||||||
libsqlite3-0
|
|
||||||
libss2
|
|
||||||
libssh2-1
|
|
||||||
libssl3
|
|
||||||
libstatgrab10
|
|
||||||
libstdc++6
|
|
||||||
libstring-shellquote-perl
|
|
||||||
libsubid4
|
|
||||||
libsystemd0
|
|
||||||
libsystemd-shared
|
|
||||||
libtalloc2
|
|
||||||
libtasn1-6
|
|
||||||
libtcmalloc-minimal4
|
|
||||||
libtdb1
|
|
||||||
libtemplate-perl
|
|
||||||
libterm-readline-gnu-perl
|
|
||||||
libtevent0
|
|
||||||
libtext-charwidth-perl
|
|
||||||
libtext-glob-perl
|
|
||||||
libtext-iconv-perl
|
|
||||||
libtext-wrapi18n-perl
|
|
||||||
libthai0
|
|
||||||
libthai-data
|
|
||||||
libthrift-0.17.0
|
|
||||||
libtimedate-perl
|
|
||||||
libtinfo6
|
|
||||||
libtirpc3
|
|
||||||
libtirpc-common
|
|
||||||
libtpms0
|
|
||||||
libtry-tiny-perl
|
|
||||||
libtypes-serialiser-perl
|
|
||||||
libu2f-server0
|
|
||||||
libuchardet0
|
|
||||||
libudev1
|
|
||||||
libunbound8
|
|
||||||
libunistring2
|
|
||||||
libunwind8
|
|
||||||
liburcu8
|
|
||||||
liburing2
|
|
||||||
liburi-perl
|
|
||||||
libusb-1.0-0
|
|
||||||
libusbredirparser1
|
|
||||||
libuuid1
|
|
||||||
libuuid-perl
|
|
||||||
libuutil3linux
|
|
||||||
libuv1
|
|
||||||
libva2
|
|
||||||
libva-drm2
|
|
||||||
libvirglrenderer1
|
|
||||||
libvorbis0a
|
|
||||||
libvorbisenc2
|
|
||||||
libvotequorum8
|
|
||||||
libvulkan1
|
|
||||||
libwayland-server0
|
|
||||||
libwbclient0
|
|
||||||
libwrap0
|
|
||||||
libwww-perl
|
|
||||||
libwww-robotrules-perl
|
|
||||||
libx11-6
|
|
||||||
libx11-data
|
|
||||||
libx11-xcb1
|
|
||||||
libxau6
|
|
||||||
libxcb1
|
|
||||||
libxcb-render0
|
|
||||||
libxcb-shm0
|
|
||||||
libxdmcp6
|
|
||||||
libxext6
|
|
||||||
libxml2
|
|
||||||
libxml-libxml-perl
|
|
||||||
libxml-namespacesupport-perl
|
|
||||||
libxml-parser-perl
|
|
||||||
libxml-sax-base-perl
|
|
||||||
libxml-sax-perl
|
|
||||||
libxml-twig-perl
|
|
||||||
libxrender1
|
|
||||||
libxslt1.1
|
|
||||||
libxtables12
|
|
||||||
libxxhash0
|
|
||||||
libyaml-0-2
|
|
||||||
libyaml-libyaml-perl
|
|
||||||
libyang3
|
|
||||||
libzfs4linux
|
|
||||||
libzpool5linux
|
|
||||||
libzstd1
|
|
||||||
linux-base
|
|
||||||
locales
|
|
||||||
login
|
|
||||||
logrotate
|
|
||||||
logsave
|
|
||||||
lsof
|
|
||||||
lua-lpeg
|
|
||||||
lvm2
|
|
||||||
lxcfs
|
|
||||||
lxc-pve
|
|
||||||
lzop
|
|
||||||
mailcap
|
|
||||||
man-db
|
|
||||||
manpages
|
|
||||||
mawk
|
|
||||||
media-types
|
|
||||||
memtest86+
|
|
||||||
mime-support
|
|
||||||
mokutil
|
|
||||||
mount
|
|
||||||
nano
|
|
||||||
ncurses-base
|
|
||||||
ncurses-bin
|
|
||||||
ncurses-term
|
|
||||||
netbase
|
|
||||||
netcat-traditional
|
|
||||||
nfs-common
|
|
||||||
nftables
|
|
||||||
nmap
|
|
||||||
nmap-common
|
|
||||||
novnc-pve
|
|
||||||
open-iscsi
|
|
||||||
openssh-client
|
|
||||||
openssh-server
|
|
||||||
openssh-sftp-server
|
|
||||||
openssl
|
|
||||||
passwd
|
|
||||||
pci.ids
|
|
||||||
pciutils
|
|
||||||
perl
|
|
||||||
perl-base
|
|
||||||
perl-modules-5.36
|
|
||||||
perl-openssl-defaults
|
|
||||||
pinentry-curses
|
|
||||||
postfix
|
|
||||||
procmail
|
|
||||||
procps
|
|
||||||
proxmox-archive-keyring
|
|
||||||
proxmox-backup-client
|
|
||||||
proxmox-backup-file-restore
|
|
||||||
proxmox-backup-restore-image
|
|
||||||
proxmox-default-kernel
|
|
||||||
proxmox-firewall
|
|
||||||
proxmox-grub
|
|
||||||
proxmox-kernel-6.8
|
|
||||||
proxmox-kernel-6.8.12-10-pve-signed
|
|
||||||
proxmox-kernel-6.8.12-9-pve-signed
|
|
||||||
proxmox-kernel-helper
|
|
||||||
proxmox-mail-forward
|
|
||||||
proxmox-mini-journalreader
|
|
||||||
proxmox-offline-mirror-docs
|
|
||||||
proxmox-offline-mirror-helper
|
|
||||||
proxmox-termproxy
|
|
||||||
proxmox-ve
|
|
||||||
proxmox-websocket-tunnel
|
|
||||||
proxmox-widget-toolkit
|
|
||||||
psmisc
|
|
||||||
pv
|
|
||||||
pve-cluster
|
|
||||||
pve-container
|
|
||||||
pve-docs
|
|
||||||
pve-edk2-firmware
|
|
||||||
pve-edk2-firmware-legacy
|
|
||||||
pve-edk2-firmware-ovmf
|
|
||||||
pve-esxi-import-tools
|
|
||||||
pve-firewall
|
|
||||||
pve-firmware
|
|
||||||
pve-ha-manager
|
|
||||||
pve-i18n
|
|
||||||
pve-lxc-syscalld
|
|
||||||
pve-manager
|
|
||||||
pve-qemu-kvm
|
|
||||||
pve-xtermjs
|
|
||||||
python3
|
|
||||||
python3.11
|
|
||||||
python3.11-minimal
|
|
||||||
python3.11-venv
|
|
||||||
python3-apt
|
|
||||||
python3-ceph-argparse
|
|
||||||
python3-ceph-common
|
|
||||||
python3-cephfs
|
|
||||||
python3-certifi
|
|
||||||
python3-chardet
|
|
||||||
python3-charset-normalizer
|
|
||||||
python3-debconf
|
|
||||||
python3-debian
|
|
||||||
python3-debianbts
|
|
||||||
python3-distutils
|
|
||||||
python3-httplib2
|
|
||||||
python3-idna
|
|
||||||
python3-jwt
|
|
||||||
python3-lib2to3
|
|
||||||
python3-minimal
|
|
||||||
python3-pip-whl
|
|
||||||
python3-pkg-resources
|
|
||||||
python3-prettytable
|
|
||||||
python3-protobuf
|
|
||||||
python3-pycurl
|
|
||||||
python3-pyparsing
|
|
||||||
python3-pysimplesoap
|
|
||||||
python3-pyvmomi
|
|
||||||
python3-rados
|
|
||||||
python3-rbd
|
|
||||||
python3-reportbug
|
|
||||||
python3-requests
|
|
||||||
python3-rgw
|
|
||||||
python3-setuptools
|
|
||||||
python3-setuptools-whl
|
|
||||||
python3-six
|
|
||||||
python3-systemd
|
|
||||||
python3-urllib3
|
|
||||||
python3-venv
|
|
||||||
python3-wcwidth
|
|
||||||
python3-yaml
|
|
||||||
python-apt-common
|
|
||||||
qemu-server
|
|
||||||
qrencode
|
|
||||||
readline-common
|
|
||||||
reportbug
|
|
||||||
rpcbind
|
|
||||||
rrdcached
|
|
||||||
rsync
|
|
||||||
runit-helper
|
|
||||||
samba-common
|
|
||||||
samba-libs
|
|
||||||
sed
|
|
||||||
sensible-utils
|
|
||||||
sgml-base
|
|
||||||
shared-mime-info
|
|
||||||
shim-helpers-amd64-signed
|
|
||||||
shim-signed
|
|
||||||
shim-signed-common
|
|
||||||
shim-unsigned
|
|
||||||
smartmontools
|
|
||||||
smbclient
|
|
||||||
socat
|
|
||||||
spiceterm
|
|
||||||
spl
|
|
||||||
sqlite3
|
|
||||||
ssh
|
|
||||||
ssl-cert
|
|
||||||
strace
|
|
||||||
swtpm
|
|
||||||
swtpm-libs
|
|
||||||
swtpm-tools
|
|
||||||
systemd
|
|
||||||
systemd-boot
|
|
||||||
systemd-boot-efi
|
|
||||||
systemd-sysv
|
|
||||||
sysvinit-utils
|
|
||||||
tar
|
|
||||||
tasksel
|
|
||||||
tasksel-data
|
|
||||||
tcpdump
|
|
||||||
thin-provisioning-tools
|
|
||||||
time
|
|
||||||
traceroute
|
|
||||||
tzdata
|
|
||||||
ucf
|
|
||||||
udev
|
|
||||||
uidmap
|
|
||||||
usbutils
|
|
||||||
usrmerge
|
|
||||||
util-linux
|
|
||||||
util-linux-extra
|
|
||||||
vim-common
|
|
||||||
vim-tiny
|
|
||||||
virtiofsd
|
|
||||||
vncterm
|
|
||||||
wamerican
|
|
||||||
wget
|
|
||||||
whiptail
|
|
||||||
xfsprogs
|
|
||||||
xkb-data
|
|
||||||
xsltproc
|
|
||||||
xz-utils
|
|
||||||
zfs-initramfs
|
|
||||||
zfsutils-linux
|
|
||||||
zfs-zed
|
|
||||||
zlib1g
|
|
||||||
zstd
|
|
||||||
@@ -1,368 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
|
||||||
# ==========================================================
|
|
||||||
# Author : MacRimi
|
|
||||||
# Copyright : (c) 2024 MacRimi
|
|
||||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
|
||||||
# Version : 1.0
|
|
||||||
# Last Updated: 28/01/2025
|
|
||||||
# ==========================================================
|
|
||||||
# Description:
|
|
||||||
# This script allows users to assign physical disks to existing
|
|
||||||
# Proxmox virtual machines (VMs) through an interactive menu.
|
|
||||||
# - Detects the system disk and excludes it from selection.
|
|
||||||
# - Lists all available VMs for the user to choose from.
|
|
||||||
# - Identifies and displays unassigned physical disks.
|
|
||||||
# - Allows the user to select multiple disks and attach them to a VM.
|
|
||||||
# - Supports interface types: SATA, SCSI, VirtIO, and IDE.
|
|
||||||
# - Ensures that disks are not already assigned to active VMs.
|
|
||||||
# - Warns about disk sharing between multiple VMs to avoid data corruption.
|
|
||||||
# - Configures the selected disks for the VM and verifies the assignment.
|
|
||||||
#
|
|
||||||
# The goal of this script is to simplify the process of assigning
|
|
||||||
# physical disks to Proxmox VMs, reducing manual configurations
|
|
||||||
# and preventing potential errors.
|
|
||||||
# ==========================================================
|
|
||||||
|
|
||||||
|
|
||||||
# Configuration ============================================
|
|
||||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
|
||||||
BASE_DIR="/usr/local/share/proxmenux"
|
|
||||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
||||||
VENV_PATH="/opt/googletrans-env"
|
|
||||||
|
|
||||||
if [[ -f "$UTILS_FILE" ]]; then
|
|
||||||
source "$UTILS_FILE"
|
|
||||||
fi
|
|
||||||
load_language
|
|
||||||
initialize_cache
|
|
||||||
show_proxmenux_logo
|
|
||||||
# ==========================================================
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
get_disk_info() {
|
|
||||||
local disk=$1
|
|
||||||
MODEL=$(lsblk -dn -o MODEL "$disk" | xargs)
|
|
||||||
SIZE=$(lsblk -dn -o SIZE "$disk" | xargs)
|
|
||||||
echo "$MODEL" "$SIZE"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
VM_LIST=$(qm list | awk 'NR>1 {print $1, $2}')
|
|
||||||
if [ -z "$VM_LIST" ]; then
|
|
||||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No VMs available in the system.")" 8 40
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
VMID=$(whiptail --title "$(translate "Select VM")" --menu "$(translate "Select the VM to which you want to add disks:")" 15 60 8 $VM_LIST 3>&1 1>&2 2>&3)
|
|
||||||
|
|
||||||
if [ -z "$VMID" ]; then
|
|
||||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No VM was selected.")" 8 40
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
VMID=$(echo "$VMID" | tr -d '"')
|
|
||||||
|
|
||||||
|
|
||||||
msg_ok "$(translate "VM selected successfully.")"
|
|
||||||
|
|
||||||
|
|
||||||
VM_STATUS=$(qm status "$VMID" | awk '{print $2}')
|
|
||||||
if [ "$VM_STATUS" == "running" ]; then
|
|
||||||
whiptail --title "$(translate "Warning")" --msgbox "$(translate "The VM is powered on. Turn it off before adding disks.")" 12 60
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
##########################################
|
|
||||||
|
|
||||||
msg_info "$(translate "Detecting available disks...")"
|
|
||||||
|
|
||||||
USED_DISKS=$(lsblk -n -o PKNAME,TYPE | grep 'lvm' | awk '{print "/dev/" $1}')
|
|
||||||
MOUNTED_DISKS=$(lsblk -ln -o NAME,MOUNTPOINT | awk '$2!="" {print "/dev/" $1}')
|
|
||||||
|
|
||||||
ZFS_DISKS=""
|
|
||||||
ZFS_RAW=$(zpool list -v -H 2>/dev/null | awk '{print $1}' | grep -v '^NAME$' | grep -v '^-' | grep -v '^mirror')
|
|
||||||
|
|
||||||
for entry in $ZFS_RAW; do
|
|
||||||
|
|
||||||
path=""
|
|
||||||
if [[ "$entry" == wwn-* || "$entry" == ata-* ]]; then
|
|
||||||
if [ -e "/dev/disk/by-id/$entry" ]; then
|
|
||||||
path=$(readlink -f "/dev/disk/by-id/$entry")
|
|
||||||
fi
|
|
||||||
elif [[ "$entry" == /dev/* ]]; then
|
|
||||||
path="$entry"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if [ -n "$path" ]; then
|
|
||||||
base_disk=$(lsblk -no PKNAME "$path" 2>/dev/null)
|
|
||||||
if [ -n "$base_disk" ]; then
|
|
||||||
ZFS_DISKS+="/dev/$base_disk"$'\n'
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
ZFS_DISKS=$(echo "$ZFS_DISKS" | sort -u)
|
|
||||||
|
|
||||||
|
|
||||||
is_disk_in_use() {
|
|
||||||
local disk="$1"
|
|
||||||
|
|
||||||
|
|
||||||
while read -r part fstype; do
|
|
||||||
case "$fstype" in
|
|
||||||
zfs_member|linux_raid_member)
|
|
||||||
return 0 ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if echo "$MOUNTED_DISKS" | grep -q "/dev/$part"; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done < <(lsblk -ln -o NAME,FSTYPE "$disk" | tail -n +2)
|
|
||||||
|
|
||||||
|
|
||||||
if echo "$USED_DISKS" | grep -q "$disk" || echo "$ZFS_DISKS" | grep -q "$disk"; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FREE_DISKS=()
|
|
||||||
|
|
||||||
LVM_DEVICES=$(pvs --noheadings -o pv_name 2> >(grep -v 'File descriptor .* leaked') | xargs -n1 readlink -f | sort -u)
|
|
||||||
RAID_ACTIVE=$(grep -Po 'md\d+\s*:\s*active\s+raid[0-9]+' /proc/mdstat | awk '{print $1}' | sort -u)
|
|
||||||
|
|
||||||
while read -r DISK; do
|
|
||||||
|
|
||||||
[[ "$DISK" =~ /dev/zd ]] && continue
|
|
||||||
|
|
||||||
INFO=($(get_disk_info "$DISK"))
|
|
||||||
MODEL="${INFO[@]::${#INFO[@]}-1}"
|
|
||||||
SIZE="${INFO[-1]}"
|
|
||||||
LABEL=""
|
|
||||||
SHOW_DISK=true
|
|
||||||
|
|
||||||
IS_MOUNTED=false
|
|
||||||
IS_RAID=false
|
|
||||||
IS_ZFS=false
|
|
||||||
IS_LVM=false
|
|
||||||
|
|
||||||
while read -r part fstype; do
|
|
||||||
[[ "$fstype" == "zfs_member" ]] && IS_ZFS=true
|
|
||||||
[[ "$fstype" == "linux_raid_member" ]] && IS_RAID=true
|
|
||||||
[[ "$fstype" == "LVM2_member" ]] && IS_LVM=true
|
|
||||||
if grep -q "/dev/$part" <<< "$MOUNTED_DISKS"; then
|
|
||||||
IS_MOUNTED=true
|
|
||||||
fi
|
|
||||||
done < <(lsblk -ln -o NAME,FSTYPE "$DISK" | tail -n +2)
|
|
||||||
|
|
||||||
REAL_PATH=$(readlink -f "$DISK")
|
|
||||||
if echo "$LVM_DEVICES" | grep -qFx "$REAL_PATH"; then
|
|
||||||
IS_MOUNTED=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
USED_BY=""
|
|
||||||
REAL_PATH=$(readlink -f "$DISK")
|
|
||||||
CONFIG_DATA=$(grep -vE '^\s*#' /etc/pve/qemu-server/*.conf /etc/pve/lxc/*.conf 2>/dev/null)
|
|
||||||
|
|
||||||
if grep -Fq "$REAL_PATH" <<< "$CONFIG_DATA"; then
|
|
||||||
USED_BY="⚠ $(translate "In use")"
|
|
||||||
else
|
|
||||||
for SYMLINK in /dev/disk/by-id/*; do
|
|
||||||
if [[ "$(readlink -f "$SYMLINK")" == "$REAL_PATH" ]]; then
|
|
||||||
if grep -Fq "$SYMLINK" <<< "$CONFIG_DATA"; then
|
|
||||||
USED_BY="⚠ $(translate "In use")"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if $IS_RAID && grep -q "$DISK" <<< "$(cat /proc/mdstat)"; then
|
|
||||||
if grep -q "active raid" /proc/mdstat; then
|
|
||||||
SHOW_DISK=false
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if $IS_ZFS; then
|
|
||||||
SHOW_DISK=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if $IS_MOUNTED; then
|
|
||||||
SHOW_DISK=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if qm config "$VMID" | grep -vE '^\s*#|^description:' | grep -q "$DISK"; then
|
|
||||||
SHOW_DISK=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $SHOW_DISK; then
|
|
||||||
[[ -n "$USED_BY" ]] && LABEL+=" [$USED_BY]"
|
|
||||||
[[ "$IS_RAID" == true ]] && LABEL+=" ⚠ RAID"
|
|
||||||
[[ "$IS_LVM" == true ]] && LABEL+=" ⚠ LVM"
|
|
||||||
[[ "$IS_ZFS" == true ]] && LABEL+=" ⚠ ZFS"
|
|
||||||
|
|
||||||
DESCRIPTION=$(printf "%-30s %10s%s" "$MODEL" "$SIZE" "$LABEL")
|
|
||||||
FREE_DISKS+=("$DISK" "$DESCRIPTION" "OFF")
|
|
||||||
fi
|
|
||||||
done < <(lsblk -dn -e 7,11 -o PATH)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if [ "${#FREE_DISKS[@]}" -eq 0 ]; then
|
|
||||||
cleanup
|
|
||||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No disks available for this VM.")" 8 40
|
|
||||||
clear
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_ok "$(translate "Available disks detected.")"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
######################################################
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MAX_WIDTH=$(printf "%s\n" "${FREE_DISKS[@]}" | awk '{print length}' | sort -nr | head -n1)
|
|
||||||
TOTAL_WIDTH=$((MAX_WIDTH + 20))
|
|
||||||
|
|
||||||
if [ $TOTAL_WIDTH -lt 50 ]; then
|
|
||||||
TOTAL_WIDTH=50
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
SELECTED=$(whiptail --title "$(translate "Select Disks")" --checklist \
|
|
||||||
"$(translate "Select the disks you want to add:")" 20 $TOTAL_WIDTH 10 "${FREE_DISKS[@]}" 3>&1 1>&2 2>&3)
|
|
||||||
|
|
||||||
if [ -z "$SELECTED" ]; then
|
|
||||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No disks were selected.")" 10 64
|
|
||||||
clear
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_ok "$(translate "Disks selected successfully.")"
|
|
||||||
|
|
||||||
|
|
||||||
INTERFACE=$(whiptail --title "$(translate "Interface Type")" --menu "$(translate "Select the interface type for all disks:")" 15 40 4 \
|
|
||||||
"sata" "$(translate "Add as SATA")" \
|
|
||||||
"scsi" "$(translate "Add as SCSI")" \
|
|
||||||
"virtio" "$(translate "Add as VirtIO")" \
|
|
||||||
"ide" "$(translate "Add as IDE")" 3>&1 1>&2 2>&3)
|
|
||||||
|
|
||||||
if [ -z "$INTERFACE" ]; then
|
|
||||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No interface type was selected for the disks.")" 8 40
|
|
||||||
clear
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_ok "$(translate "Interface type selected: $INTERFACE")"
|
|
||||||
|
|
||||||
DISKS_ADDED=0
|
|
||||||
ERROR_MESSAGES=""
|
|
||||||
SUCCESS_MESSAGES=""
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
msg_info "$(translate "Processing selected disks...")"
|
|
||||||
|
|
||||||
for DISK in $SELECTED; do
|
|
||||||
DISK=$(echo "$DISK" | tr -d '"')
|
|
||||||
DISK_INFO=$(get_disk_info "$DISK")
|
|
||||||
|
|
||||||
ASSIGNED_TO=""
|
|
||||||
RUNNING_VMS=""
|
|
||||||
RUNNING_CTS=""
|
|
||||||
|
|
||||||
|
|
||||||
while read -r VM_ID VM_NAME; do
|
|
||||||
if [[ "$VM_ID" =~ ^[0-9]+$ ]] && qm config "$VM_ID" | grep -q "$DISK"; then
|
|
||||||
ASSIGNED_TO+="VM $VM_ID $VM_NAME\n"
|
|
||||||
VM_STATUS=$(qm status "$VM_ID" | awk '{print $2}')
|
|
||||||
if [ "$VM_STATUS" == "running" ]; then
|
|
||||||
RUNNING_VMS+="VM $VM_ID $VM_NAME\n"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done < <(qm list | awk 'NR>1 {print $1, $2}')
|
|
||||||
|
|
||||||
|
|
||||||
while read -r CT_ID CT_NAME; do
|
|
||||||
if [[ "$CT_ID" =~ ^[0-9]+$ ]] && pct config "$CT_ID" | grep -q "$DISK"; then
|
|
||||||
ASSIGNED_TO+="CT $CT_ID $CT_NAME\n"
|
|
||||||
CT_STATUS=$(pct status "$CT_ID" | awk '{print $2}')
|
|
||||||
if [ "$CT_STATUS" == "running" ]; then
|
|
||||||
RUNNING_CTS+="CT $CT_ID $CT_NAME\n"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done < <(pct list | awk 'NR>1 {print $1, $2}')
|
|
||||||
|
|
||||||
if [ -n "$RUNNING_VMS" ] || [ -n "$RUNNING_CTS" ]; then
|
|
||||||
ERROR_MESSAGES+="$(translate "The disk") $DISK_INFO $(translate "is currently in use by the following running VM(s) or CT(s):")\\n$RUNNING_VMS$RUNNING_CTS\\n\\n$(translate "You cannot add this disk while the VM or CT is running.")\\n$(translate "Please shut it down first and run this script again to add the disk.")\\n\\n"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$ASSIGNED_TO" ]; then
|
|
||||||
cleanup
|
|
||||||
whiptail --title "$(translate "Disk Already Assigned")" --yesno "$(translate "The disk") $DISK_INFO $(translate "is already assigned to the following VM(s) or CT(s):")\\n$ASSIGNED_TO\\n\\n$(translate "Do you want to continue anyway?")" 15 70
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
sleep 1
|
|
||||||
exec "$0"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
INDEX=0
|
|
||||||
while qm config "$VMID" | grep -q "${INTERFACE}${INDEX}"; do
|
|
||||||
((INDEX++))
|
|
||||||
done
|
|
||||||
|
|
||||||
RESULT=$(qm set "$VMID" -${INTERFACE}${INDEX} "$DISK" 2>&1)
|
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
MESSAGE="$(translate "The disk") $DISK_INFO $(translate "has been successfully added to VM") $VMID."
|
|
||||||
if [ -n "$ASSIGNED_TO" ]; then
|
|
||||||
MESSAGE+="\\n\\n$(translate "WARNING: This disk is also assigned to the following VM(s):")\\n$ASSIGNED_TO"
|
|
||||||
MESSAGE+="\\n$(translate "Make sure not to start VMs that share this disk at the same time to avoid data corruption.")"
|
|
||||||
fi
|
|
||||||
SUCCESS_MESSAGES+="$MESSAGE\\n\\n"
|
|
||||||
((DISKS_ADDED++))
|
|
||||||
else
|
|
||||||
ERROR_MESSAGES+="$(translate "Could not add disk") $DISK_INFO $(translate "to VM") $VMID.\\n$(translate "Error:") $RESULT\\n\\n"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
msg_ok "$(translate "Disk processing completed.")"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if [ -n "$SUCCESS_MESSAGES" ]; then
|
|
||||||
MSG_LINES=$(echo "$SUCCESS_MESSAGES" | wc -l)
|
|
||||||
whiptail --title "$(translate "Successful Operations")" --msgbox "$SUCCESS_MESSAGES" 16 70
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$ERROR_MESSAGES" ]; then
|
|
||||||
whiptail --title "$(translate "Warnings and Errors")" --msgbox "$ERROR_MESSAGES" 16 70
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
@@ -1,537 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
|
||||||
# ==========================================================
|
|
||||||
# Author : MacRimi
|
|
||||||
# Copyright : (c) 2024 MacRimi
|
|
||||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
|
||||||
# Version : 1.0
|
|
||||||
# Last Updated: 28/01/2025
|
|
||||||
# ==========================================================
|
|
||||||
# Description:
|
|
||||||
# This script allows users to assign physical disks to existing
|
|
||||||
# Proxmox containers (CTs) through an interactive menu.
|
|
||||||
# - Detects the system disk and excludes it from selection.
|
|
||||||
# - Lists all available CTs for the user to choose from.
|
|
||||||
# - Identifies and displays unassigned physical disks.
|
|
||||||
# - Allows the user to select multiple disks and attach them to a CT.
|
|
||||||
# - Configures the selected disks for the CT and verifies the assignment.
|
|
||||||
# ==========================================================
|
|
||||||
|
|
||||||
|
|
||||||
# Configuration ============================================
|
|
||||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
|
||||||
BASE_DIR="/usr/local/share/proxmenux"
|
|
||||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
||||||
VENV_PATH="/opt/googletrans-env"
|
|
||||||
|
|
||||||
if [[ -f "$UTILS_FILE" ]]; then
|
|
||||||
source "$UTILS_FILE"
|
|
||||||
fi
|
|
||||||
load_language
|
|
||||||
initialize_cache
|
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
get_disk_info() {
|
|
||||||
local disk=$1
|
|
||||||
MODEL=$(lsblk -dn -o MODEL "$disk" | xargs)
|
|
||||||
SIZE=$(lsblk -dn -o SIZE "$disk" | xargs)
|
|
||||||
echo "$MODEL" "$SIZE"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CT_LIST=$(pct list | awk 'NR>1 {print $1, $3}')
|
|
||||||
if [ -z "$CT_LIST" ]; then
|
|
||||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No CTs available in the system.")" 8 40
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
CTID=$(whiptail --title "$(translate "Select CT")" --menu "$(translate "Select the CT to which you want to add disks:")" 15 60 8 $CT_LIST 3>&1 1>&2 2>&3)
|
|
||||||
|
|
||||||
if [ -z "$CTID" ]; then
|
|
||||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No CT was selected.")" 8 40
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
CTID=$(echo "$CTID" | tr -d '"')
|
|
||||||
|
|
||||||
msg_ok "$(translate "CT selected successfully.")"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CT_STATUS=$(pct status "$CTID" | awk '{print $2}')
|
|
||||||
if [ "$CT_STATUS" != "running" ]; then
|
|
||||||
msg_info "$(translate "Starting CT") $CTID..."
|
|
||||||
pct start "$CTID"
|
|
||||||
sleep 2
|
|
||||||
if [ "$(pct status "$CTID" | awk '{print $2}')" != "running" ]; then
|
|
||||||
msg_error "$(translate "Failed to start the CT.")"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
msg_ok "$(translate "CT started successfully.")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CONF_FILE="/etc/pve/lxc/$CTID.conf"
|
|
||||||
|
|
||||||
if grep -q '^unprivileged: 1' "$CONF_FILE"; then
|
|
||||||
if whiptail --title "$(translate "Privileged Container")" \
|
|
||||||
--yesno "$(translate "The selected container is unprivileged. A privileged container is required for direct device passthrough.")\\n\\n$(translate "Do you want to convert it to a privileged container now?")" 12 70; then
|
|
||||||
|
|
||||||
msg_info "$(translate "Stopping container") $CTID..."
|
|
||||||
pct shutdown "$CTID" &
|
|
||||||
for i in {1..10}; do
|
|
||||||
sleep 1
|
|
||||||
if [ "$(pct status "$CTID" | awk '{print $2}')" != "running" ]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$(pct status "$CTID" | awk '{print $2}')" == "running" ]; then
|
|
||||||
msg_error "$(translate "Failed to stop the container.")"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_ok "$(translate "Container stopped.")"
|
|
||||||
|
|
||||||
cp "$CONF_FILE" "$CONF_FILE.bak"
|
|
||||||
sed -i '/^unprivileged: 1/d' "$CONF_FILE"
|
|
||||||
echo "unprivileged: 0" >> "$CONF_FILE"
|
|
||||||
|
|
||||||
msg_ok "$(translate "Container successfully converted to privileged.")"
|
|
||||||
|
|
||||||
msg_info "$(translate "Starting container") $CTID..."
|
|
||||||
pct start "$CTID"
|
|
||||||
sleep 2
|
|
||||||
if [ "$(pct status "$CTID" | awk '{print $2}')" != "running" ]; then
|
|
||||||
msg_error "$(translate "Failed to start the container.")"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
msg_ok "$(translate "Container started successfully.")"
|
|
||||||
|
|
||||||
else
|
|
||||||
whiptail --title "$(translate "Aborted")" \
|
|
||||||
--msgbox "$(translate "Operation cancelled. Cannot continue with an unprivileged container.")" 10 60
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##########################################
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
msg_info "$(translate "Detecting available disks...")"
|
|
||||||
|
|
||||||
USED_DISKS=$(lsblk -n -o PKNAME,TYPE | grep 'lvm' | awk '{print "/dev/" $1}')
|
|
||||||
MOUNTED_DISKS=$(lsblk -ln -o NAME,MOUNTPOINT | awk '$2!="" {print "/dev/" $1}')
|
|
||||||
|
|
||||||
ZFS_DISKS=""
|
|
||||||
ZFS_RAW=$(zpool list -v -H 2>/dev/null | awk '{print $1}' | grep -v '^NAME$' | grep -v '^-' | grep -v '^mirror')
|
|
||||||
|
|
||||||
for entry in $ZFS_RAW; do
|
|
||||||
path=""
|
|
||||||
if [[ "$entry" == wwn-* || "$entry" == ata-* ]]; then
|
|
||||||
if [ -e "/dev/disk/by-id/$entry" ]; then
|
|
||||||
path=$(readlink -f "/dev/disk/by-id/$entry")
|
|
||||||
fi
|
|
||||||
elif [[ "$entry" == /dev/* ]]; then
|
|
||||||
path="$entry"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$path" ]; then
|
|
||||||
base_disk=$(lsblk -no PKNAME "$path" 2>/dev/null)
|
|
||||||
if [ -n "$base_disk" ]; then
|
|
||||||
ZFS_DISKS+="/dev/$base_disk"$'\n'
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
ZFS_DISKS=$(echo "$ZFS_DISKS" | sort -u)
|
|
||||||
|
|
||||||
is_disk_in_use() {
|
|
||||||
local disk="$1"
|
|
||||||
|
|
||||||
while read -r part fstype; do
|
|
||||||
case "$fstype" in
|
|
||||||
zfs_member|linux_raid_member)
|
|
||||||
return 0 ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if echo "$MOUNTED_DISKS" | grep -q "/dev/$part"; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done < <(lsblk -ln -o NAME,FSTYPE "$disk" | tail -n +2)
|
|
||||||
|
|
||||||
if echo "$USED_DISKS" | grep -q "$disk" || echo "$ZFS_DISKS" | grep -q "$disk"; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
FREE_DISKS=()
|
|
||||||
|
|
||||||
LVM_DEVICES=$(pvs --noheadings -o pv_name 2> >(grep -v 'File descriptor .* leaked') | xargs -r -n1 readlink -f | sort -u)
|
|
||||||
|
|
||||||
if [[ -n "$LVM_DEVICES" ]] && echo "$LVM_DEVICES" | grep -qFx "$REAL_PATH"; then
|
|
||||||
IS_MOUNTED=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
RAID_ACTIVE=$(grep -Po 'md\d+\s*:\s*active\s+raid[0-9]+' /proc/mdstat | awk '{print $1}' | sort -u)
|
|
||||||
|
|
||||||
while read -r DISK; do
|
|
||||||
[[ "$DISK" =~ /dev/zd ]] && continue
|
|
||||||
|
|
||||||
INFO=($(get_disk_info "$DISK"))
|
|
||||||
MODEL="${INFO[@]::${#INFO[@]}-1}"
|
|
||||||
SIZE="${INFO[-1]}"
|
|
||||||
LABEL=""
|
|
||||||
SHOW_DISK=true
|
|
||||||
|
|
||||||
IS_MOUNTED=false
|
|
||||||
IS_RAID=false
|
|
||||||
IS_ZFS=false
|
|
||||||
IS_LVM=false
|
|
||||||
|
|
||||||
while read -r part fstype; do
|
|
||||||
[[ "$fstype" == "zfs_member" ]] && IS_ZFS=true
|
|
||||||
[[ "$fstype" == "linux_raid_member" ]] && IS_RAID=true
|
|
||||||
[[ "$fstype" == "LVM2_member" ]] && IS_LVM=true
|
|
||||||
if grep -q "/dev/$part" <<< "$MOUNTED_DISKS"; then
|
|
||||||
IS_MOUNTED=true
|
|
||||||
fi
|
|
||||||
done < <(lsblk -ln -o NAME,FSTYPE "$DISK" | tail -n +2)
|
|
||||||
|
|
||||||
REAL_PATH=$(readlink -f "$DISK")
|
|
||||||
if echo "$LVM_DEVICES" | grep -qFx "$REAL_PATH"; then
|
|
||||||
IS_MOUNTED=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
USED_BY=""
|
|
||||||
REAL_PATH=$(readlink -f "$DISK")
|
|
||||||
CONFIG_DATA=$(grep -vE '^\s*#' /etc/pve/qemu-server/*.conf /etc/pve/lxc/*.conf 2>/dev/null)
|
|
||||||
|
|
||||||
if grep -Fq "$REAL_PATH" <<< "$CONFIG_DATA"; then
|
|
||||||
USED_BY="⚠ $(translate "In use")"
|
|
||||||
else
|
|
||||||
for SYMLINK in /dev/disk/by-id/*; do
|
|
||||||
if [[ "$(readlink -f "$SYMLINK")" == "$REAL_PATH" ]]; then
|
|
||||||
if grep -Fq "$SYMLINK" <<< "$CONFIG_DATA"; then
|
|
||||||
USED_BY="⚠ $(translate "In use")"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if $IS_RAID && grep -q "$DISK" <<< "$(cat /proc/mdstat)"; then
|
|
||||||
if grep -q "active raid" /proc/mdstat; then
|
|
||||||
SHOW_DISK=false
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $IS_ZFS; then
|
|
||||||
SHOW_DISK=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $IS_MOUNTED; then
|
|
||||||
SHOW_DISK=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
if pct config "$CTID" | grep -vE '^\s*#|^description:' | grep -q "$DISK"; then
|
|
||||||
SHOW_DISK=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $SHOW_DISK; then
|
|
||||||
[[ -n "$USED_BY" ]] && LABEL+=" [$USED_BY]"
|
|
||||||
[[ "$IS_RAID" == true ]] && LABEL+=" ⚠ RAID"
|
|
||||||
[[ "$IS_LVM" == true ]] && LABEL+=" ⚠ LVM"
|
|
||||||
[[ "$IS_ZFS" == true ]] && LABEL+=" ⚠ ZFS"
|
|
||||||
|
|
||||||
DESCRIPTION=$(printf "%-30s %10s%s" "$MODEL" "$SIZE" "$LABEL")
|
|
||||||
FREE_DISKS+=("$DISK" "$DESCRIPTION" "OFF")
|
|
||||||
fi
|
|
||||||
done < <(lsblk -dn -e 7,11 -o PATH)
|
|
||||||
|
|
||||||
if [ "${#FREE_DISKS[@]}" -eq 0 ]; then
|
|
||||||
cleanup
|
|
||||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No disks available for this CT.")" 8 40
|
|
||||||
clear
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_ok "$(translate "Available disks detected.")"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
######################################################
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MAX_WIDTH=$(printf "%s\n" "${FREE_DISKS[@]}" | awk '{print length}' | sort -nr | head -n1)
|
|
||||||
TOTAL_WIDTH=$((MAX_WIDTH + 20))
|
|
||||||
|
|
||||||
if [ $TOTAL_WIDTH -lt 50 ]; then
|
|
||||||
TOTAL_WIDTH=50
|
|
||||||
fi
|
|
||||||
|
|
||||||
SELECTED=$(whiptail --title "$(translate "Select Disks")" --radiolist \
|
|
||||||
"$(translate "Select the disks you want to add:")" 20 $TOTAL_WIDTH 10 "${FREE_DISKS[@]}" 3>&1 1>&2 2>&3)
|
|
||||||
|
|
||||||
if [ -z "$SELECTED" ]; then
|
|
||||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No disks were selected.")" 10 64
|
|
||||||
clear
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_ok "$(translate "Disks selected successfully.")"
|
|
||||||
|
|
||||||
DISKS_ADDED=0
|
|
||||||
ERROR_MESSAGES=""
|
|
||||||
SUCCESS_MESSAGES=""
|
|
||||||
|
|
||||||
msg_info "$(translate "Processing selected disks...")"
|
|
||||||
|
|
||||||
for DISK in $SELECTED; do
|
|
||||||
DISK=$(echo "$DISK" | tr -d '"')
|
|
||||||
DISK_INFO=$(get_disk_info "$DISK")
|
|
||||||
|
|
||||||
ASSIGNED_TO=""
|
|
||||||
RUNNING_CTS=""
|
|
||||||
RUNNING_VMS=""
|
|
||||||
|
|
||||||
# Comprobar CTs
|
|
||||||
while read -r CT_ID CT_NAME; do
|
|
||||||
if [[ "$CT_ID" =~ ^[0-9]+$ ]] && pct config "$CT_ID" | grep -q "$DISK"; then
|
|
||||||
ASSIGNED_TO+="CT $CT_ID $CT_NAME\n"
|
|
||||||
CT_STATUS=$(pct status "$CT_ID" | awk '{print $2}')
|
|
||||||
if [ "$CT_STATUS" == "running" ]; then
|
|
||||||
RUNNING_CTS+="CT $CT_ID $CT_NAME\n"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done < <(pct list | awk 'NR>1 {print $1, $3}')
|
|
||||||
|
|
||||||
# Comprobar VMs
|
|
||||||
while read -r VM_ID VM_NAME; do
|
|
||||||
if [[ "$VM_ID" =~ ^[0-9]+$ ]] && qm config "$VM_ID" | grep -q "$DISK"; then
|
|
||||||
ASSIGNED_TO+="VM $VM_ID $VM_NAME\n"
|
|
||||||
VM_STATUS=$(qm status "$VM_ID" | awk '{print $2}')
|
|
||||||
if [ "$VM_STATUS" == "running" ]; then
|
|
||||||
RUNNING_VMS+="VM $VM_ID $VM_NAME\n"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done < <(qm list | awk 'NR>1 {print $1, $2}')
|
|
||||||
|
|
||||||
if [ -n "$RUNNING_CTS" ] || [ -n "$RUNNING_VMS" ]; then
|
|
||||||
ERROR_MESSAGES+="$(translate "The disk") $DISK_INFO $(translate "is in use by the following running VM(s) or CT(s):")\\n$RUNNING_CTS$RUNNING_VMS\\n\\n"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$ASSIGNED_TO" ]; then
|
|
||||||
cleanup
|
|
||||||
whiptail --title "$(translate "Disk Already Assigned")" --yesno "$(translate "The disk") $DISK_INFO $(translate "is already assigned to the following VM(s) or CT(s):")\\n$ASSIGNED_TO\\n\\n$(translate "Do you want to continue anyway?")" 15 70
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
sleep 1
|
|
||||||
exec "$0"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
cleanup
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if lsblk "$DISK" | grep -q "raid" || grep -q "${DISK##*/}" /proc/mdstat; then
|
|
||||||
whiptail --title "$(translate "RAID Detected")" --msgbox "$(translate "The disk") $DISK_INFO $(translate "appears to be part of a") RAID. $(translate "For security reasons, the system cannot format it.")\\n\\n$(translate "If you are sure you want to use it, please remove the") RAID metadata $(translate "or format it manually using external tools.")\\n\\n$(translate "After that, run this script again to add it.")" 18 70
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MOUNT_POINT=$(whiptail --title "$(translate "Mount Point")" --inputbox "$(translate "Enter the mount point for the disk (e.g., /mnt/disk_passthrough):")" 10 60 "/mnt/disk_passthrough" 3>&1 1>&2 2>&3)
|
|
||||||
|
|
||||||
if [ -z "$MOUNT_POINT" ]; then
|
|
||||||
whiptail --title "$(translate "Error")" --msgbox "$(translate "No mount point was specified.")" 8 40
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_ok "$(translate "Mount point specified: $MOUNT_POINT")"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
PARTITION=$(lsblk -rno NAME "$DISK" | awk -v disk="$(basename "$DISK")" '$1 != disk {print $1; exit}')
|
|
||||||
SKIP_FORMAT=false
|
|
||||||
|
|
||||||
if [ -n "$PARTITION" ]; then
|
|
||||||
PARTITION="/dev/$PARTITION"
|
|
||||||
CURRENT_FS=$(lsblk -no FSTYPE "$PARTITION" | xargs)
|
|
||||||
|
|
||||||
if [[ "$CURRENT_FS" == "ext4" || "$CURRENT_FS" == "xfs" || "$CURRENT_FS" == "btrfs" ]]; then
|
|
||||||
SKIP_FORMAT=true
|
|
||||||
msg_ok "$(translate "Detected existing filesystem") $CURRENT_FS $(translate "on") $PARTITION."
|
|
||||||
else
|
|
||||||
whiptail --title "$(translate "Unsupported Filesystem")" --yesno "$(translate "The partition") $PARTITION $(translate "has an unsupported filesystem ($CURRENT_FS).\\nDo you want to format it?")" 10 70
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
|
|
||||||
CURRENT_FS=$(lsblk -no FSTYPE "$DISK" | xargs)
|
|
||||||
|
|
||||||
if [[ "$CURRENT_FS" == "ext4" || "$CURRENT_FS" == "xfs" || "$CURRENT_FS" == "btrfs" ]]; then
|
|
||||||
SKIP_FORMAT=true
|
|
||||||
PARTITION="$DISK"
|
|
||||||
msg_ok "$(translate "Detected filesystem") $CURRENT_FS $(translate "directly on disk") $DISK.)"
|
|
||||||
else
|
|
||||||
|
|
||||||
whiptail --title "$(translate "No Valid Partitions")" --yesno "$(translate "The disk has no partitions and no valid filesystem. Do you want to create a new partition and format it?")" 10 70
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "$(translate "Creating partition table and partition...")"
|
|
||||||
parted -s "$DISK" mklabel gpt
|
|
||||||
parted -s "$DISK" mkpart primary 0% 100%
|
|
||||||
sleep 2
|
|
||||||
partprobe "$DISK"
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
PARTITION=$(lsblk -rno NAME "$DISK" | awk -v disk="$(basename "$DISK")" '$1 != disk {print $1; exit}')
|
|
||||||
if [ -n "$PARTITION" ]; then
|
|
||||||
PARTITION="/dev/$PARTITION"
|
|
||||||
else
|
|
||||||
whiptail --title "$(translate "Partition Error")" --msgbox "$(translate "Failed to create partition on disk") $DISK_INFO." 8 70
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if [ "$SKIP_FORMAT" != true ]; then
|
|
||||||
CURRENT_FS=$(lsblk -no FSTYPE "$PARTITION" | xargs)
|
|
||||||
if [[ "$CURRENT_FS" == "ext4" || "$CURRENT_FS" == "xfs" || "$CURRENT_FS" == "btrfs" ]]; then
|
|
||||||
SKIP_FORMAT=true
|
|
||||||
msg_ok "$(translate "Detected existing filesystem") $CURRENT_FS $(translate "on") $PARTITION. $(translate "Skipping format.")"
|
|
||||||
else
|
|
||||||
|
|
||||||
FORMAT_TYPE=$(whiptail --title "$(translate "Select Format Type")" --menu "$(translate "Select the filesystem type for") $DISK_INFO:" 15 60 6 \
|
|
||||||
"ext4" "$(translate "Extended Filesystem 4 (recommended)")" \
|
|
||||||
"xfs" "$(translate "XFS Filesystem")" \
|
|
||||||
"btrfs" "$(translate "Btrfs Filesystem")" 3>&1 1>&2 2>&3)
|
|
||||||
|
|
||||||
if [ -z "$FORMAT_TYPE" ]; then
|
|
||||||
whiptail --title "$(translate "Format Cancelled")" --msgbox "$(translate "Format operation cancelled. The disk will not be added.")" 8 60
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
whiptail --title "$(translate "WARNING")" --yesno "$(translate "WARNING: This operation will FORMAT the disk") $DISK_INFO $(translate "with") $FORMAT_TYPE.\\n\\n$(translate "ALL DATA ON THIS DISK WILL BE PERMANENTLY LOST!")\\n\\n$(translate "Are you sure you want to continue")" 15 70
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
whiptail --title "$(translate "Format Cancelled")" --msgbox "$(translate "Format operation cancelled. The disk will not be added.")" 8 60
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if [ "$SKIP_FORMAT" != true ]; then
|
|
||||||
echo -e "$(translate "Formatting partition") $PARTITION $(translate "with") $FORMAT_TYPE..."
|
|
||||||
|
|
||||||
case "$FORMAT_TYPE" in
|
|
||||||
"ext4") mkfs.ext4 -F "$PARTITION" ;;
|
|
||||||
"xfs") mkfs.xfs -f "$PARTITION" ;;
|
|
||||||
"btrfs") mkfs.btrfs -f "$PARTITION" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
whiptail --title "$(translate "Format Failed")" --msgbox "$(translate "Failed to format partition") $PARTITION $(translate "with") $FORMAT_TYPE.\\n\\n$(translate "The disk may be in use by the system or have hardware issues.")" 12 70
|
|
||||||
continue
|
|
||||||
else
|
|
||||||
msg_ok "$(translate "Partition") $PARTITION $(translate "successfully formatted with") $FORMAT_TYPE."
|
|
||||||
partprobe "$DISK"
|
|
||||||
sleep 2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
INDEX=0
|
|
||||||
while pct config "$CTID" | grep -q "mp${INDEX}:"; do
|
|
||||||
((INDEX++))
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
RESULT=$(pct set "$CTID" -mp${INDEX} "$PARTITION,mp=$MOUNT_POINT,backup=0,ro=0,acl=1" 2>&1)
|
|
||||||
|
|
||||||
pct exec "$CTID" -- chmod -R 775 "$MOUNT_POINT"
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
MESSAGE="$(translate "The disk") $DISK_INFO $(translate "has been successfully added to CT") $CTID $(translate "as a mount point at") $MOUNT_POINT."
|
|
||||||
if [ -n "$ASSIGNED_TO" ]; then
|
|
||||||
MESSAGE+="\\n\\n$(translate "WARNING: This disk is also assigned to the following CT(s):")\\n$ASSIGNED_TO"
|
|
||||||
MESSAGE+="\\n$(translate "Make sure not to start CTs that share this disk at the same time to avoid data corruption.")"
|
|
||||||
fi
|
|
||||||
SUCCESS_MESSAGES+="$MESSAGE\\n\\n"
|
|
||||||
((DISKS_ADDED++))
|
|
||||||
else
|
|
||||||
ERROR_MESSAGES+="$(translate "Could not add disk") $DISK_INFO $(translate "to CT") $CTID.\\n$(translate "Error:") $RESULT\\n\\n"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
msg_ok "$(translate "Disk processing completed.")"
|
|
||||||
|
|
||||||
if [ -n "$SUCCESS_MESSAGES" ]; then
|
|
||||||
MSG_LINES=$(echo "$SUCCESS_MESSAGES" | wc -l)
|
|
||||||
whiptail --title "$(translate "Successful Operations")" --msgbox "$SUCCESS_MESSAGES" 16 70
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$ERROR_MESSAGES" ]; then
|
|
||||||
whiptail --title "$(translate "Warnings and Errors")" --msgbox "$ERROR_MESSAGES" 16 70
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
@@ -1,277 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# ==========================================================
|
|
||||||
# Remove Subscription Banner - Proxmox VE (v3 - Minimal Intrusive)
|
|
||||||
# ==========================================================
|
|
||||||
# This version makes a surgical change to the checked_command function
|
|
||||||
# by changing the condition to 'if (false)' and commenting out the banner logic.
|
|
||||||
# Also patches the mobile UI to remove the subscription dialog.
|
|
||||||
# ==========================================================
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Source utilities if available
|
|
||||||
BASE_DIR="/usr/local/share/proxmenux"
|
|
||||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
||||||
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
|
|
||||||
|
|
||||||
if [[ -f "$UTILS_FILE" ]]; then
|
|
||||||
source "$UTILS_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
load_language
|
|
||||||
initialize_cache
|
|
||||||
|
|
||||||
# File paths
|
|
||||||
JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
|
|
||||||
GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz"
|
|
||||||
MIN_JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.min.js"
|
|
||||||
MOBILE_UI_FILE="/usr/share/pve-yew-mobile-gui/index.html.tpl"
|
|
||||||
BACKUP_DIR="$BASE_DIR/backups"
|
|
||||||
APT_HOOK="/etc/apt/apt.conf.d/no-nag-script"
|
|
||||||
PATCH_BIN="/usr/local/bin/pve-remove-nag-v3.sh"
|
|
||||||
MARK="/* PROXMENUX_NAG_PATCH_V3 */"
|
|
||||||
MOBILE_MARK="<!-- PROXMENUX_MOBILE_NAG_PATCH -->"
|
|
||||||
|
|
||||||
# Ensure tools JSON exists
|
|
||||||
ensure_tools_json() {
|
|
||||||
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Register tool in JSON
|
|
||||||
register_tool() {
|
|
||||||
command -v jq >/dev/null 2>&1 || return 0
|
|
||||||
local tool="$1" state="$2"
|
|
||||||
ensure_tools_json
|
|
||||||
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" \
|
|
||||||
> "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Verify JS file integrity
|
|
||||||
verify_js_integrity() {
|
|
||||||
local file="$1"
|
|
||||||
[ -f "$file" ] || return 1
|
|
||||||
[ -s "$file" ] || return 1
|
|
||||||
grep -Eq 'Ext|function|var|const|let' "$file" || return 1
|
|
||||||
if LC_ALL=C grep -qP '\x00' "$file" 2>/dev/null; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# Create timestamped backup
|
|
||||||
create_backup() {
|
|
||||||
local file="$1"
|
|
||||||
local timestamp
|
|
||||||
timestamp=$(date +%Y%m%d_%H%M%S)
|
|
||||||
local backup_file="$BACKUP_DIR/$(basename "$file").backup.$timestamp"
|
|
||||||
|
|
||||||
mkdir -p "$BACKUP_DIR"
|
|
||||||
|
|
||||||
if [ -f "$file" ]; then
|
|
||||||
rm -f "$BACKUP_DIR"/"$(basename "$file")".backup.* 2>/dev/null || true
|
|
||||||
|
|
||||||
cp -a "$file" "$backup_file"
|
|
||||||
echo "$backup_file"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Create the patch script that will be called by APT hook
|
|
||||||
create_patch_script() {
|
|
||||||
cat > "$PATCH_BIN" <<'EOFPATCH'
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
# ==========================================================
|
|
||||||
# Proxmox Subscription Banner Patch (v3 - Minimal)
|
|
||||||
# ==========================================================
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
|
|
||||||
GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz"
|
|
||||||
MIN_JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.min.js"
|
|
||||||
MOBILE_UI_FILE="/usr/share/pve-yew-mobile-gui/index.html.tpl"
|
|
||||||
BACKUP_DIR="/usr/local/share/proxmenux/backups"
|
|
||||||
MARK="/* PROXMENUX_NAG_PATCH_V3 */"
|
|
||||||
MOBILE_MARK="<!-- PROXMENUX_MOBILE_NAG_PATCH -->"
|
|
||||||
|
|
||||||
verify_js_integrity() {
|
|
||||||
local file="$1"
|
|
||||||
[ -f "$file" ] && [ -s "$file" ] && grep -Eq 'Ext|function' "$file" && ! LC_ALL=C grep -qP '\x00' "$file" 2>/dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
patch_checked_command() {
|
|
||||||
[ -f "$JS_FILE" ] || return 0
|
|
||||||
|
|
||||||
# Check if already patched
|
|
||||||
grep -q "$MARK" "$JS_FILE" && return 0
|
|
||||||
|
|
||||||
# Create backup
|
|
||||||
mkdir -p "$BACKUP_DIR"
|
|
||||||
local backup="$BACKUP_DIR/$(basename "$JS_FILE").backup.$(date +%Y%m%d_%H%M%S)"
|
|
||||||
cp -a "$JS_FILE" "$backup"
|
|
||||||
|
|
||||||
# Set trap to restore on error
|
|
||||||
trap "cp -a '$backup' '$JS_FILE' 2>/dev/null || true" ERR
|
|
||||||
|
|
||||||
# Add patch marker at the beginning
|
|
||||||
sed -i "1s|^|$MARK\n|" "$JS_FILE"
|
|
||||||
|
|
||||||
# Surgical patch: Change the condition in checked_command function
|
|
||||||
# This changes the if condition to 'if (false)' making the banner never show
|
|
||||||
if grep -q "res\.data\.status\.toLowerCase() !== 'active'" "$JS_FILE"; then
|
|
||||||
# Pattern for newer versions (8.4.5+)
|
|
||||||
sed -i "/checked_command: function/,/},$/s/res === null || res === undefined || !res || res\.data\.status\.toLowerCase() !== 'active'/false/g" "$JS_FILE"
|
|
||||||
elif grep -q "res\.data\.status !== 'Active'" "$JS_FILE"; then
|
|
||||||
# Pattern for older versions
|
|
||||||
sed -i "/checked_command: function/,/},$/s/res === null || res === undefined || !res || res\.data\.status !== 'Active'/false/g" "$JS_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Also handle the NoMoreNagging pattern if present
|
|
||||||
if grep -q "res\.data\.status\.toLowerCase() !== 'NoMoreNagging'" "$JS_FILE"; then
|
|
||||||
sed -i "/checked_command: function/,/},$/s/res === null || res === undefined || !res || res\.data\.status\.toLowerCase() !== 'NoMoreNagging'/false/g" "$JS_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Verify integrity after patch
|
|
||||||
if ! verify_js_integrity "$JS_FILE"; then
|
|
||||||
cp -a "$backup" "$JS_FILE"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Clean up generated files
|
|
||||||
rm -f "$MIN_JS_FILE" "$GZ_FILE" 2>/dev/null || true
|
|
||||||
find /var/cache/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
|
|
||||||
find /var/lib/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
|
|
||||||
find /var/cache/nginx/ -type f -delete 2>/dev/null || true
|
|
||||||
|
|
||||||
trap - ERR
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
patch_mobile_ui() {
|
|
||||||
[ -f "$MOBILE_UI_FILE" ] || return 0
|
|
||||||
|
|
||||||
# Check if already patched
|
|
||||||
grep -q "$MOBILE_MARK" "$MOBILE_UI_FILE" && return 0
|
|
||||||
|
|
||||||
# Create backup
|
|
||||||
mkdir -p "$BACKUP_DIR"
|
|
||||||
local backup="$BACKUP_DIR/$(basename "$MOBILE_UI_FILE").backup.$(date +%Y%m%d_%H%M%S)"
|
|
||||||
cp -a "$MOBILE_UI_FILE" "$backup"
|
|
||||||
|
|
||||||
# Set trap to restore on error
|
|
||||||
trap "cp -a '$backup' '$MOBILE_UI_FILE' 2>/dev/null || true" ERR
|
|
||||||
|
|
||||||
# Insert the script before </head> tag
|
|
||||||
sed -i "/<\/head>/i\\
|
|
||||||
$MOBILE_MARK\\
|
|
||||||
<!-- Script to remove subscription banner from mobile UI -->\\
|
|
||||||
<script>\\
|
|
||||||
function removeNoSubDialog() {\\
|
|
||||||
const observer = new MutationObserver(() => {\\
|
|
||||||
const diag = document.querySelector('dialog[aria-label=\"No valid subscription\"]');\\
|
|
||||||
if (diag) {\\
|
|
||||||
diag.remove();\\
|
|
||||||
}\\
|
|
||||||
});\\
|
|
||||||
observer.observe(document.body, { childList: true, subtree: true });\\
|
|
||||||
}\\
|
|
||||||
window.addEventListener('load', () => {\\
|
|
||||||
setTimeout(removeNoSubDialog, 200);\\
|
|
||||||
});\\
|
|
||||||
</script>" "$MOBILE_UI_FILE"
|
|
||||||
|
|
||||||
trap - ERR
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
reload_services() {
|
|
||||||
systemctl is-active --quiet pveproxy 2>/dev/null && {
|
|
||||||
systemctl reload pveproxy 2>/dev/null || systemctl restart pveproxy 2>/dev/null || true
|
|
||||||
}
|
|
||||||
systemctl is-active --quiet nginx 2>/dev/null && {
|
|
||||||
systemctl reload nginx 2>/dev/null || true
|
|
||||||
}
|
|
||||||
systemctl is-active --quiet pvedaemon 2>/dev/null && {
|
|
||||||
systemctl reload pvedaemon 2>/dev/null || true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
patch_checked_command || return 1
|
|
||||||
patch_mobile_ui || true
|
|
||||||
reload_services
|
|
||||||
}
|
|
||||||
|
|
||||||
main
|
|
||||||
EOFPATCH
|
|
||||||
|
|
||||||
chmod 755 "$PATCH_BIN"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Create APT hook to reapply patch after updates
|
|
||||||
create_apt_hook() {
|
|
||||||
cat > "$APT_HOOK" <<'EOFAPT'
|
|
||||||
/* ProxMenux: reapply minimal nag patch after upgrades */
|
|
||||||
DPkg::Post-Invoke { "/usr/local/bin/pve-remove-nag-v3.sh || true"; };
|
|
||||||
EOFAPT
|
|
||||||
|
|
||||||
chmod 644 "$APT_HOOK"
|
|
||||||
|
|
||||||
# Verify APT hook syntax
|
|
||||||
apt-config dump >/dev/null 2>&1 || {
|
|
||||||
rm -f "$APT_HOOK"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Main function to remove subscription banner
|
|
||||||
remove_subscription_banner_v3() {
|
|
||||||
local pve_version
|
|
||||||
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+' | head -1 || echo "unknown")
|
|
||||||
|
|
||||||
msg_info "$(translate "Detected Proxmox VE") ${pve_version} - $(translate "applying banner patch")"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Remove old APT hooks
|
|
||||||
for f in /etc/apt/apt.conf.d/*nag*; do
|
|
||||||
[[ -e "$f" ]] && rm -f "$f"
|
|
||||||
done
|
|
||||||
|
|
||||||
# Create backup for desktop UI
|
|
||||||
local backup_file
|
|
||||||
backup_file=$(create_backup "$JS_FILE")
|
|
||||||
if [ -n "$backup_file" ]; then
|
|
||||||
# msg_ok "$(translate "Desktop UI backup created"): $backup_file"
|
|
||||||
:
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f "$MOBILE_UI_FILE" ]; then
|
|
||||||
local mobile_backup
|
|
||||||
mobile_backup=$(create_backup "$MOBILE_UI_FILE")
|
|
||||||
if [ -n "$mobile_backup" ]; then
|
|
||||||
# msg_ok "$(translate "Mobile UI backup created"): $mobile_backup"
|
|
||||||
:
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create patch script and APT hook
|
|
||||||
create_patch_script
|
|
||||||
create_apt_hook
|
|
||||||
|
|
||||||
# Apply the patch
|
|
||||||
if ! "$PATCH_BIN"; then
|
|
||||||
msg_error "$(translate "Error applying patch. Backups preserved at"): $BACKUP_DIR"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Register tool as applied
|
|
||||||
register_tool "subscription_banner" true
|
|
||||||
|
|
||||||
msg_ok "$(translate "Subscription banner removed successfully")"
|
|
||||||
msg_ok "$(translate "Desktop and Mobile UI patched")"
|
|
||||||
msg_ok "$(translate "Refresh your browser (Ctrl+Shift+R) to see changes")"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
# Run if executed directly
|
|
||||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
||||||
remove_subscription_banner_v3
|
|
||||||
fi
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# ==========================================================
|
|
||||||
# Remove Subscription Banner - Proxmox VE 9.x
|
|
||||||
# ==========================================================
|
|
||||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
|
||||||
BASE_DIR="/usr/local/share/proxmenux"
|
|
||||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
||||||
VENV_PATH="/opt/googletrans-env"
|
|
||||||
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
|
|
||||||
|
|
||||||
if [[ -f "$UTILS_FILE" ]]; then
|
|
||||||
source "$UTILS_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
load_language
|
|
||||||
initialize_cache
|
|
||||||
|
|
||||||
|
|
||||||
ensure_tools_json() {
|
|
||||||
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
|
|
||||||
}
|
|
||||||
|
|
||||||
register_tool() {
|
|
||||||
local tool="$1"
|
|
||||||
local state="$2"
|
|
||||||
ensure_tools_json
|
|
||||||
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
|
||||||
}
|
|
||||||
|
|
||||||
remove_subscription_banner_pve9() {
|
|
||||||
local JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
|
|
||||||
local MIN_JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.min.js"
|
|
||||||
local GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz"
|
|
||||||
local APT_HOOK="/etc/apt/apt.conf.d/no-nag-script"
|
|
||||||
|
|
||||||
|
|
||||||
local pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+' | head -1)
|
|
||||||
local pve_major=$(echo "$pve_version" | cut -d. -f1)
|
|
||||||
|
|
||||||
if [ "$pve_major" -lt 9 ] 2>/dev/null; then
|
|
||||||
msg_error "This script is for PVE 9.x only. Detected PVE $pve_version"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_info "Detected Proxmox VE $pve_version - Applying PVE 9.x patches"
|
|
||||||
|
|
||||||
|
|
||||||
if [ ! -f "$JS_FILE" ]; then
|
|
||||||
msg_error "JavaScript file not found: $JS_FILE"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local backup_file="${JS_FILE}.backup.pve9.$(date +%Y%m%d_%H%M%S)"
|
|
||||||
cp "$JS_FILE" "$backup_file"
|
|
||||||
|
|
||||||
|
|
||||||
for f in /etc/apt/apt.conf.d/*nag*; do
|
|
||||||
[[ -e "$f" ]] && rm -f "$f"
|
|
||||||
done
|
|
||||||
|
|
||||||
[[ -f "$GZ_FILE" ]] && rm -f "$GZ_FILE"
|
|
||||||
[[ -f "$MIN_JS_FILE" ]] && rm -f "$MIN_JS_FILE"
|
|
||||||
|
|
||||||
find /var/cache/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
|
|
||||||
find /var/lib/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
|
|
||||||
find /var/cache/nginx/ -type f -delete 2>/dev/null || true
|
|
||||||
|
|
||||||
|
|
||||||
sed -i "s/res\.data\.status\.toLowerCase() !== 'active'/false/g" "$JS_FILE"
|
|
||||||
sed -i "s/subscriptionActive: ''/subscriptionActive: true/g" "$JS_FILE"
|
|
||||||
sed -i "s/title: gettext('No valid subscription')/title: gettext('Community Edition')/g" "$JS_FILE"
|
|
||||||
|
|
||||||
|
|
||||||
sed -i "s/You do not have a valid subscription for this server/Community Edition - No subscription required/g" "$JS_FILE"
|
|
||||||
sed -i "s/Enterprise repository needs valid subscription/Enterprise repository configured/g" "$JS_FILE"
|
|
||||||
sed -i "s/icon: Ext\.Msg\.WARNING/icon: Ext.Msg.INFO/g" "$JS_FILE"
|
|
||||||
|
|
||||||
|
|
||||||
sed -i "s/subscription = !(/subscription = false \&\& (/g" "$JS_FILE"
|
|
||||||
|
|
||||||
if grep -q "res\.data\.status\.toLowerCase() !== 'active'" "$JS_FILE"; then
|
|
||||||
msg_warn "Some patches may not have applied correctly, retrying..."
|
|
||||||
sed -i "s/res\.data\.status\.toLowerCase() !== 'active'/false/g" "$JS_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
[[ -f "$APT_HOOK" ]] && rm -f "$APT_HOOK"
|
|
||||||
cat > "$APT_HOOK" << 'EOF'
|
|
||||||
DPkg::Post-Invoke {
|
|
||||||
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/res\\.data\\.status\\.toLowerCase() !== '\''active'\''/false/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
|
|
||||||
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/subscriptionActive: '\'\'\''/subscriptionActive: true/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
|
|
||||||
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/title: gettext('\''No valid subscription'\'')/title: gettext('\''Community Edition'\'')/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
|
|
||||||
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/subscription = !(/subscription = false \\&\\& (/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
|
|
||||||
"rm -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.min.js /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz || true";
|
|
||||||
};
|
|
||||||
EOF
|
|
||||||
|
|
||||||
chmod 644 "$APT_HOOK"
|
|
||||||
|
|
||||||
|
|
||||||
if ! apt-config dump >/dev/null 2>&1; then
|
|
||||||
msg_warn "APT hook has syntax issues, removing..."
|
|
||||||
rm -f "$APT_HOOK"
|
|
||||||
else
|
|
||||||
msg_ok "APT hook created successfully"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
systemctl reload nginx 2>/dev/null || true
|
|
||||||
|
|
||||||
msg_ok "Subscription banner removed successfully for Proxmox VE $pve_version"
|
|
||||||
msg_ok "Banner removal process completed - refresh your browser to see changes"
|
|
||||||
|
|
||||||
register_tool "subscription_banner" true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
||||||
remove_subscription_banner_pve9
|
|
||||||
fi
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# ==========================================================
|
|
||||||
# Remove Subscription Banner - Proxmox VE 9.x ONLY
|
|
||||||
# ==========================================================
|
|
||||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
|
||||||
BASE_DIR="/usr/local/share/proxmenux"
|
|
||||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
||||||
VENV_PATH="/opt/googletrans-env"
|
|
||||||
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
|
|
||||||
|
|
||||||
if [[ -f "$UTILS_FILE" ]]; then
|
|
||||||
source "$UTILS_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
load_language
|
|
||||||
initialize_cache
|
|
||||||
|
|
||||||
# Tool registration system
|
|
||||||
ensure_tools_json() {
|
|
||||||
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
|
|
||||||
}
|
|
||||||
|
|
||||||
register_tool() {
|
|
||||||
local tool="$1"
|
|
||||||
local state="$2"
|
|
||||||
ensure_tools_json
|
|
||||||
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
|
||||||
}
|
|
||||||
|
|
||||||
remove_subscription_banner_pve9() {
|
|
||||||
local JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
|
|
||||||
local MIN_JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.min.js"
|
|
||||||
local GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz"
|
|
||||||
local APT_HOOK="/etc/apt/apt.conf.d/no-nag-script"
|
|
||||||
|
|
||||||
# Verify PVE 9.x
|
|
||||||
local pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+' | head -1)
|
|
||||||
local pve_major=$(echo "$pve_version" | cut -d. -f1)
|
|
||||||
|
|
||||||
if [ "$pve_major" -lt 9 ] 2>/dev/null; then
|
|
||||||
msg_error "This script is for PVE 9.x only. Detected PVE $pve_version"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_info "Detected Proxmox VE $pve_version - Applying PVE 9.x patches"
|
|
||||||
|
|
||||||
# Verify that the file exists
|
|
||||||
if [ ! -f "$JS_FILE" ]; then
|
|
||||||
msg_error "JavaScript file not found: $JS_FILE"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# Create backup of original file
|
|
||||||
local backup_file="${JS_FILE}.backup.pve9.$(date +%Y%m%d_%H%M%S)"
|
|
||||||
cp "$JS_FILE" "$backup_file"
|
|
||||||
|
|
||||||
# Clean any existing problematic APT hooks
|
|
||||||
for f in /etc/apt/apt.conf.d/*nag*; do
|
|
||||||
[[ -e "$f" ]] && rm -f "$f"
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
# Main subscription check patches for PVE 9
|
|
||||||
sed -i "s/res\.data\.status\.toLowerCase() !== 'active'/false/g" "$JS_FILE"
|
|
||||||
sed -i "s/subscriptionActive: ''/subscriptionActive: true/g" "$JS_FILE"
|
|
||||||
sed -i "s/title: gettext('No valid subscription')/title: gettext('Community Edition')/g" "$JS_FILE"
|
|
||||||
|
|
||||||
# Additional UX improvements for PVE 9
|
|
||||||
sed -i "s/You do not have a valid subscription for this server/Community Edition - No subscription required/g" "$JS_FILE"
|
|
||||||
sed -i "s/Enterprise repository needs valid subscription/Enterprise repository configured/g" "$JS_FILE"
|
|
||||||
sed -i "s/icon: Ext\.Msg\.WARNING/icon: Ext.Msg.INFO/g" "$JS_FILE"
|
|
||||||
|
|
||||||
# Additional subscription patterns that may exist in PVE 9
|
|
||||||
sed -i "s/subscription = !(/subscription = false \&\& (/g" "$JS_FILE"
|
|
||||||
|
|
||||||
# Remove compressed/minified files to force regeneration
|
|
||||||
[[ -f "$GZ_FILE" ]] && rm -f "$GZ_FILE"
|
|
||||||
[[ -f "$MIN_JS_FILE" ]] && rm -f "$MIN_JS_FILE"
|
|
||||||
|
|
||||||
# Clear various caches
|
|
||||||
find /var/cache/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
|
|
||||||
find /var/lib/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
|
|
||||||
|
|
||||||
# Create PVE 9.x specific APT hook
|
|
||||||
[[ -f "$APT_HOOK" ]] && rm -f "$APT_HOOK"
|
|
||||||
cat > "$APT_HOOK" << 'EOF'
|
|
||||||
DPkg::Post-Invoke {
|
|
||||||
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/res\\.data\\.status\\.toLowerCase() !== '\''active'\''/false/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
|
|
||||||
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/subscriptionActive: '\'\'\''/subscriptionActive: true/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
|
|
||||||
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/title: gettext('\''No valid subscription'\'')/title: gettext('\''Community Edition'\'')/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
|
|
||||||
"test -e /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js && sed -i 's/subscription = !(/subscription = false \\&\\& (/g' /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js || true";
|
|
||||||
"rm -f /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.min.js /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz || true";
|
|
||||||
};
|
|
||||||
EOF
|
|
||||||
|
|
||||||
chmod 644 "$APT_HOOK"
|
|
||||||
|
|
||||||
# Verify APT hook syntax
|
|
||||||
if ! apt-config dump >/dev/null 2>&1; then
|
|
||||||
msg_warn "APT hook has syntax issues, removing..."
|
|
||||||
rm -f "$APT_HOOK"
|
|
||||||
else
|
|
||||||
msg_ok "APT hook created successfully"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
msg_ok "Subscription banner removed successfully for Proxmox VE $pve_version"
|
|
||||||
msg_ok "Banner removal process completed"
|
|
||||||
|
|
||||||
|
|
||||||
register_tool "subscription_banner" true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Execute function if called directly
|
|
||||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
||||||
remove_subscription_banner_pve9
|
|
||||||
fi
|
|
||||||
@@ -1,257 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# ==========================================================
|
|
||||||
# Remove Subscription Banner - Proxmox VE 9.x (Clean Version)
|
|
||||||
# ==========================================================
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
|
|
||||||
BASE_DIR="/usr/local/share/proxmenux"
|
|
||||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
||||||
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
|
|
||||||
|
|
||||||
if [[ -f "$UTILS_FILE" ]]; then
|
|
||||||
source "$UTILS_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
load_language
|
|
||||||
initialize_cache
|
|
||||||
|
|
||||||
ensure_tools_json() {
|
|
||||||
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
|
|
||||||
}
|
|
||||||
|
|
||||||
register_tool() {
|
|
||||||
command -v jq >/dev/null 2>&1 || return 0
|
|
||||||
local tool="$1" state="$2"
|
|
||||||
ensure_tools_json
|
|
||||||
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" \
|
|
||||||
> "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
|
|
||||||
MIN_JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.min.js"
|
|
||||||
GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz"
|
|
||||||
MOBILE_TPL="/usr/share/pve-yew-mobile-gui/index.html.tpl"
|
|
||||||
APT_HOOK="/etc/apt/apt.conf.d/no-nag-script"
|
|
||||||
PATCH_BIN="/usr/local/bin/pve-remove-nag.sh"
|
|
||||||
|
|
||||||
MARK_JS="PROXMENUX_NAG_REMOVED_v2"
|
|
||||||
MARK_MOBILE="<!-- PROXMENUX: MOBILE NAG PATCH v2 -->"
|
|
||||||
|
|
||||||
|
|
||||||
verify_js_integrity() {
|
|
||||||
local file="$1"
|
|
||||||
[ -f "$file" ] || return 1
|
|
||||||
[ -s "$file" ] || return 1
|
|
||||||
grep -Eq 'Ext|function|var|const|let' "$file" || return 1
|
|
||||||
if LC_ALL=C grep -qP '\x00' "$file" 2>/dev/null; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
create_backup() {
|
|
||||||
local file="$1"
|
|
||||||
local backup_dir="$BASE_DIR/backups"
|
|
||||||
local timestamp
|
|
||||||
timestamp=$(date +%Y%m%d_%H%M%S)
|
|
||||||
local backup_file="$backup_dir/$(basename "$file").backup.$timestamp"
|
|
||||||
mkdir -p "$backup_dir"
|
|
||||||
if [ -f "$file" ]; then
|
|
||||||
cp -a "$file" "$backup_file"
|
|
||||||
ls -t "$backup_dir"/"$(basename "$file")".backup.* 2>/dev/null | tail -n +6 | xargs -r rm -f 2>/dev/null || true
|
|
||||||
echo "$backup_file"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# ----------------------------------------------------
|
|
||||||
|
|
||||||
create_patch_script() {
|
|
||||||
cat > "$PATCH_BIN" <<'EOF'
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js"
|
|
||||||
MIN_JS_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.min.js"
|
|
||||||
GZ_FILE="/usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js.gz"
|
|
||||||
MOBILE_TPL="/usr/share/pve-yew-mobile-gui/index.html.tpl"
|
|
||||||
MARK_JS="PROXMENUX_NAG_REMOVED_v2"
|
|
||||||
MARK_MOBILE="<!-- PROXMENUX: MOBILE NAG PATCH v2 -->"
|
|
||||||
BASE_DIR="/usr/local/share/proxmenux"
|
|
||||||
|
|
||||||
verify_js_integrity() {
|
|
||||||
local file="$1"
|
|
||||||
[ -f "$file" ] && [ -s "$file" ] && grep -Eq 'Ext|function' "$file" && ! LC_ALL=C grep -qP '\x00' "$file" 2>/dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
patch_web() {
|
|
||||||
[ -f "$JS_FILE" ] || return 0
|
|
||||||
grep -q "$MARK_JS" "$JS_FILE" && return 0
|
|
||||||
|
|
||||||
local backup_dir="$BASE_DIR/backups"
|
|
||||||
mkdir -p "$backup_dir"
|
|
||||||
local backup="$backup_dir/$(basename "$JS_FILE").backup.$(date +%Y%m%d_%H%M%S)"
|
|
||||||
cp -a "$JS_FILE" "$backup"
|
|
||||||
trap "cp -a '$backup' '$JS_FILE' 2>/dev/null || true" ERR
|
|
||||||
|
|
||||||
sed -i '1s|^|/* '"$MARK_JS"' */\n|' "$JS_FILE"
|
|
||||||
|
|
||||||
local patterns_found=0
|
|
||||||
|
|
||||||
if grep -q "res\.data\.status\.toLowerCase() !== 'active'" "$JS_FILE"; then
|
|
||||||
sed -i "s/res\.data\.status\.toLowerCase() !== 'active'/false/g" "$JS_FILE"
|
|
||||||
patterns_found=$((patterns_found + 1))
|
|
||||||
fi
|
|
||||||
|
|
||||||
if grep -q "subscriptionActive: ''" "$JS_FILE"; then
|
|
||||||
sed -i "s/subscriptionActive: ''/subscriptionActive: true/g" "$JS_FILE"
|
|
||||||
patterns_found=$((patterns_found + 1))
|
|
||||||
fi
|
|
||||||
|
|
||||||
if grep -q "title: gettext('No valid subscription')" "$JS_FILE"; then
|
|
||||||
sed -i "s/title: gettext('No valid subscription')/title: gettext('Community Edition')/g" "$JS_FILE"
|
|
||||||
patterns_found=$((patterns_found + 1))
|
|
||||||
fi
|
|
||||||
|
|
||||||
if grep -q "icon: Ext\.Msg\.WARNING" "$JS_FILE"; then
|
|
||||||
sed -i "s/icon: Ext\.Msg\.WARNING/icon: Ext.Msg.INFO/g" "$JS_FILE"
|
|
||||||
patterns_found=$((patterns_found + 1))
|
|
||||||
fi
|
|
||||||
|
|
||||||
if grep -q "subscription = !(" "$JS_FILE"; then
|
|
||||||
sed -i "s/subscription = !(/subscription = false \&\& (/g" "$JS_FILE"
|
|
||||||
patterns_found=$((patterns_found + 1))
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Si nada coincidió (cambio upstream), restaura y sal limpio
|
|
||||||
if [ "${patterns_found:-0}" -eq 0 ]; then
|
|
||||||
cp -a "$backup" "$JS_FILE"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Verificación final
|
|
||||||
if ! verify_js_integrity "$JS_FILE"; then
|
|
||||||
cp -a "$backup" "$JS_FILE"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Limpiar artefactos/cachés
|
|
||||||
rm -f "$MIN_JS_FILE" "$GZ_FILE" 2>/dev/null || true
|
|
||||||
find /var/cache/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
|
|
||||||
find /var/lib/pve-manager/ -name "*.js*" -delete 2>/dev/null || true
|
|
||||||
find /var/cache/nginx/ -type f -delete 2>/dev/null || true
|
|
||||||
|
|
||||||
trap - ERR
|
|
||||||
}
|
|
||||||
|
|
||||||
patch_mobile() {
|
|
||||||
[ -f "$MOBILE_TPL" ] || return 0
|
|
||||||
grep -q "$MARK_MOBILE" "$MOBILE_TPL" && return 0
|
|
||||||
|
|
||||||
local backup_dir="$BASE_DIR/backups"
|
|
||||||
mkdir -p "$backup_dir"
|
|
||||||
cp -a "$MOBILE_TPL" "$backup_dir/$(basename "$MOBILE_TPL").backup.$(date +%Y%m%d_%H%M%S)"
|
|
||||||
|
|
||||||
cat >> "$MOBILE_TPL" <<EOM
|
|
||||||
$MARK_MOBILE
|
|
||||||
<script>
|
|
||||||
(function() {
|
|
||||||
'use strict';
|
|
||||||
function removeSubscriptionElements() {
|
|
||||||
try {
|
|
||||||
const dialogs = document.querySelectorAll('dialog.pwt-outer-dialog');
|
|
||||||
dialogs.forEach(d => {
|
|
||||||
const text = (d.textContent || '').toLowerCase();
|
|
||||||
if (text.includes('subscription') || text.includes('no valid')) { d.remove(); }
|
|
||||||
});
|
|
||||||
const cards = document.querySelectorAll('.pwt-card.pwt-p-2.pwt-d-flex.pwt-interactive.pwt-justify-content-center');
|
|
||||||
cards.forEach(c => {
|
|
||||||
const text = (c.textContent || '').toLowerCase();
|
|
||||||
const hasButton = c.querySelector('button');
|
|
||||||
if (!hasButton && (text.includes('subscription') || text.includes('no valid'))) { c.remove(); }
|
|
||||||
});
|
|
||||||
const alerts = document.querySelectorAll('[class*="alert"], [class*="warning"], [class*="notice"]');
|
|
||||||
alerts.forEach(a => {
|
|
||||||
const text = (a.textContent || '').toLowerCase();
|
|
||||||
if (text.includes('subscription') || text.includes('no valid')) { a.remove(); }
|
|
||||||
});
|
|
||||||
} catch (e) { console.warn('Error removing subscription elements:', e); }
|
|
||||||
}
|
|
||||||
if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', removeSubscriptionElements); }
|
|
||||||
else { removeSubscriptionElements(); }
|
|
||||||
const observer = new MutationObserver(removeSubscriptionElements);
|
|
||||||
if (document.body) {
|
|
||||||
observer.observe(document.body, { childList: true, subtree: true });
|
|
||||||
const interval = setInterval(removeSubscriptionElements, 500);
|
|
||||||
setTimeout(() => { try { observer.disconnect(); clearInterval(interval); } catch(e){} }, 30000);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
EOM
|
|
||||||
}
|
|
||||||
|
|
||||||
reload_services() {
|
|
||||||
systemctl is-active --quiet pveproxy 2>/dev/null && {
|
|
||||||
systemctl reload pveproxy 2>/dev/null || systemctl restart pveproxy 2>/dev/null || true
|
|
||||||
}
|
|
||||||
systemctl is-active --quiet nginx 2>/dev/null && {
|
|
||||||
systemctl reload nginx 2>/dev/null || true
|
|
||||||
}
|
|
||||||
systemctl is-active --quiet pvedaemon 2>/dev/null && {
|
|
||||||
systemctl reload pvedaemon 2>/dev/null || true
|
|
||||||
}
|
|
||||||
find /var/cache/pve-manager/ -type f -delete 2>/dev/null || true
|
|
||||||
find /var/lib/pve-manager/ -type f -delete 2>/dev/null || true
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
patch_web || return 1
|
|
||||||
patch_mobile
|
|
||||||
reload_services
|
|
||||||
}
|
|
||||||
|
|
||||||
main
|
|
||||||
EOF
|
|
||||||
chmod 755 "$PATCH_BIN"
|
|
||||||
}
|
|
||||||
# ----------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
create_apt_hook() {
|
|
||||||
cat > "$APT_HOOK" <<'EOF'
|
|
||||||
/* ProxMenux: reapply nag patch after upgrades */
|
|
||||||
DPkg::Post-Invoke { "/usr/local/bin/pve-remove-nag.sh || true"; };
|
|
||||||
EOF
|
|
||||||
chmod 644 "$APT_HOOK"
|
|
||||||
apt-config dump >/dev/null 2>&1 || { msg_warn "APT hook syntax issue"; rm -f "$APT_HOOK"; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
remove_subscription_banner_pve9() {
|
|
||||||
local pve_version
|
|
||||||
pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+' | head -1 || true)
|
|
||||||
local pve_major="${pve_version%%.*}"
|
|
||||||
|
|
||||||
msg_info "$(translate "Detected Proxmox VE ${pve_version:-9.x} – removing subscription banner")"
|
|
||||||
|
|
||||||
create_patch_script
|
|
||||||
create_apt_hook
|
|
||||||
|
|
||||||
if ! "$PATCH_BIN"; then
|
|
||||||
msg_error "$(translate "Error applying patches")"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
register_tool "subscription_banner" true
|
|
||||||
msg_ok "$(translate "Subscription banner removed successfully.")"
|
|
||||||
msg_ok "$(translate "Refresh your browser to see changes.")"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
||||||
remove_subscription_banner_pve9
|
|
||||||
fi
|
|
||||||
@@ -1,339 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# ==========================================================
|
|
||||||
# Proxmox VE Update Script
|
|
||||||
# ==========================================================
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
|
||||||
BASE_DIR="/usr/local/share/proxmenux"
|
|
||||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
||||||
VENV_PATH="/opt/googletrans-env"
|
|
||||||
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
|
|
||||||
|
|
||||||
if [[ -f "$UTILS_FILE" ]]; then
|
|
||||||
source "$UTILS_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
load_language
|
|
||||||
initialize_cache
|
|
||||||
|
|
||||||
ensure_tools_json() {
|
|
||||||
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
|
|
||||||
}
|
|
||||||
|
|
||||||
register_tool() {
|
|
||||||
local tool="$1"
|
|
||||||
local state="$2"
|
|
||||||
ensure_tools_json
|
|
||||||
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
|
||||||
}
|
|
||||||
|
|
||||||
download_common_functions() {
|
|
||||||
if ! source "$LOCAL_SCRIPTS/global/common-functions.sh"; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
update_pve9() {
|
|
||||||
local pve_version=$(pveversion | awk -F'/' '{print $2}' | cut -d'-' -f1)
|
|
||||||
local start_time=$(date +%s)
|
|
||||||
local log_file="/var/log/proxmox-update-$(date +%Y%m%d-%H%M%S).log"
|
|
||||||
local changes_made=false
|
|
||||||
local OS_CODENAME="$(grep "VERSION_CODENAME=" /etc/os-release | cut -d"=" -f 2 | xargs)"
|
|
||||||
local TARGET_CODENAME="trixie"
|
|
||||||
|
|
||||||
if [ -z "$OS_CODENAME" ]; then
|
|
||||||
OS_CODENAME=$(lsb_release -cs 2>/dev/null || echo "trixie")
|
|
||||||
fi
|
|
||||||
|
|
||||||
download_common_functions
|
|
||||||
|
|
||||||
|
|
||||||
msg_info2 "$(translate "Detected: Proxmox VE $pve_version (Current: $OS_CODENAME, Target: $TARGET_CODENAME)")"
|
|
||||||
echo -e
|
|
||||||
|
|
||||||
local available_space=$(df /var/cache/apt/archives | awk 'NR==2 {print int($4/1024)}')
|
|
||||||
if [ "$available_space" -lt 1024 ]; then
|
|
||||||
msg_error "$(translate "Insufficient disk space. Available: ${available_space}MB")"
|
|
||||||
echo -e
|
|
||||||
msg_success "$(translate "Press Enter to return to menu...")"
|
|
||||||
read -r
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! ping -c 1 download.proxmox.com >/dev/null 2>&1; then
|
|
||||||
msg_error "$(translate "Cannot reach Proxmox repositories")"
|
|
||||||
echo -e
|
|
||||||
msg_success "$(translate "Press Enter to return to menu...")"
|
|
||||||
read -r
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
disable_sources_repo() {
|
|
||||||
local file="$1"
|
|
||||||
if [[ -f "$file" ]]; then
|
|
||||||
sed -i ':a;/^\n*$/{$d;N;ba}' "$file"
|
|
||||||
|
|
||||||
if grep -q "^Enabled:" "$file"; then
|
|
||||||
sed -i 's/^Enabled:.*$/Enabled: false/' "$file"
|
|
||||||
else
|
|
||||||
echo "Enabled: false" >> "$file"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! grep -q "^Types: " "$file"; then
|
|
||||||
msg_warn "$(translate "Malformed .sources file detected, removing: $(basename "$file")")"
|
|
||||||
rm -f "$file"
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if disable_sources_repo "/etc/apt/sources.list.d/pve-enterprise.sources"; then
|
|
||||||
msg_ok "$(translate "Enterprise Proxmox repository disabled")"
|
|
||||||
changes_made=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
if disable_sources_repo "/etc/apt/sources.list.d/ceph.sources"; then
|
|
||||||
msg_ok "$(translate "Enterprise Proxmox Ceph repository disabled")"
|
|
||||||
changes_made=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
for legacy_file in /etc/apt/sources.list.d/pve-public-repo.list \
|
|
||||||
/etc/apt/sources.list.d/pve-install-repo.list \
|
|
||||||
/etc/apt/sources.list.d/debian.list; do
|
|
||||||
if [[ -f "$legacy_file" ]]; then
|
|
||||||
rm -f "$legacy_file"
|
|
||||||
msg_ok "$(translate "Removed legacy repository: $(basename "$legacy_file")")"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
if [[ -f /etc/apt/sources.list.d/debian.sources ]]; then
|
|
||||||
rm -f /etc/apt/sources.list.d/debian.sources
|
|
||||||
msg_ok "$(translate "Old debian.sources file removed to prevent duplication")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
msg_info "$(translate "Creating Proxmox VE 9.x no-subscription repository...")"
|
|
||||||
cat > /etc/apt/sources.list.d/proxmox.sources << EOF
|
|
||||||
Enabled: true
|
|
||||||
Types: deb
|
|
||||||
URIs: http://download.proxmox.com/debian/pve
|
|
||||||
Suites: ${TARGET_CODENAME}
|
|
||||||
Components: pve-no-subscription
|
|
||||||
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
|
|
||||||
EOF
|
|
||||||
msg_ok "$(translate "Proxmox VE 9.x no-subscription repository created")"
|
|
||||||
changes_made=true
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
msg_info "$(translate "Creating Debian ${TARGET_CODENAME} sources file...")"
|
|
||||||
cat > /etc/apt/sources.list.d/debian.sources << EOF
|
|
||||||
Types: deb
|
|
||||||
URIs: http://deb.debian.org/debian/
|
|
||||||
Suites: ${TARGET_CODENAME} ${TARGET_CODENAME}-updates
|
|
||||||
Components: main contrib non-free non-free-firmware
|
|
||||||
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
|
||||||
|
|
||||||
Types: deb
|
|
||||||
URIs: http://security.debian.org/debian-security/
|
|
||||||
Suites: ${TARGET_CODENAME}-security
|
|
||||||
Components: main contrib non-free non-free-firmware
|
|
||||||
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
|
||||||
EOF
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
msg_ok "$(translate "Debian repositories configured for $TARGET_CODENAME")"
|
|
||||||
|
|
||||||
local firmware_conf="/etc/apt/apt.conf.d/no-firmware-warnings.conf"
|
|
||||||
if [ ! -f "$firmware_conf" ]; then
|
|
||||||
msg_info "$(translate "Disabling non-free firmware warnings...")"
|
|
||||||
echo 'APT::Get::Update::SourceListWarnings::NonFreeFirmware "false";' > "$firmware_conf"
|
|
||||||
msg_ok "$(translate "Non-free firmware warnings disabled")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
update_output=$(apt-get update 2>&1)
|
|
||||||
update_exit_code=$?
|
|
||||||
|
|
||||||
if [ $update_exit_code -eq 0 ]; then
|
|
||||||
msg_ok "$(translate "Package lists updated successfully")"
|
|
||||||
else
|
|
||||||
if echo "$update_output" | grep -q "NO_PUBKEY\|GPG error"; then
|
|
||||||
msg_info "$(translate "Fixing GPG key issues...")"
|
|
||||||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys $(echo "$update_output" | grep "NO_PUBKEY" | sed 's/.*NO_PUBKEY //' | head -1) 2>/dev/null
|
|
||||||
if apt-get update > "$log_file" 2>&1; then
|
|
||||||
msg_ok "$(translate "Package lists updated after GPG fix")"
|
|
||||||
else
|
|
||||||
msg_error "$(translate "Failed to update package lists. Check log: $log_file")"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
elif echo "$update_output" | grep -q "404\|Failed to fetch"; then
|
|
||||||
msg_warn "$(translate "Some repositories are not available, continuing with available ones...")"
|
|
||||||
else
|
|
||||||
msg_error "$(translate "Failed to update package lists. Check log: $log_file")"
|
|
||||||
echo "Error details: $update_output"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if apt policy 2>/dev/null | grep -q "${TARGET_CODENAME}.*pve-no-subscription"; then
|
|
||||||
msg_ok "$(translate "Proxmox VE 9.x repositories verified")"
|
|
||||||
else
|
|
||||||
msg_warn "$(translate "Proxmox VE 9.x repositories verification inconclusive, continuing...")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
local current_pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
|
||||||
local available_pve_version=$(apt-cache policy pve-manager 2>/dev/null | grep -oP 'Candidate: \K[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
|
||||||
local upgradable=$(apt list --upgradable 2>/dev/null | grep -c "upgradable")
|
|
||||||
local security_updates=$(apt list --upgradable 2>/dev/null | grep -c "security")
|
|
||||||
|
|
||||||
show_update_menu() {
|
|
||||||
local current_version="$1"
|
|
||||||
local target_version="$2"
|
|
||||||
local upgradable_count="$3"
|
|
||||||
local security_count="$4"
|
|
||||||
|
|
||||||
local menu_text="$(translate "System Update Information")\n\n"
|
|
||||||
menu_text+="$(translate "Current PVE Version"): $current_version\n"
|
|
||||||
if [ -n "$target_version" ] && [ "$target_version" != "$current_version" ]; then
|
|
||||||
menu_text+="$(translate "Available PVE Version"): $target_version\n"
|
|
||||||
fi
|
|
||||||
menu_text+="\n$(translate "Package Updates Available"): $upgradable_count\n"
|
|
||||||
menu_text+="$(translate "Security Updates"): $security_count\n\n"
|
|
||||||
|
|
||||||
if [ "$upgradable_count" -eq 0 ]; then
|
|
||||||
menu_text+="$(translate "System is already up to date")"
|
|
||||||
whiptail --title "$(translate "Update Status")" --msgbox "$menu_text" 15 70
|
|
||||||
return 2
|
|
||||||
else
|
|
||||||
menu_text+="$(translate "Do you want to proceed with the system update?")"
|
|
||||||
if whiptail --title "$(translate "Proxmox Update")" --yesno "$menu_text" 18 70; then
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
show_update_menu "$current_pve_version" "$available_pve_version" "$upgradable" "$security_updates"
|
|
||||||
MENU_RESULT=$?
|
|
||||||
|
|
||||||
if [[ $MENU_RESULT -eq 1 ]]; then
|
|
||||||
msg_info2 "$(translate "Update cancelled by user")"
|
|
||||||
apt-get -y autoremove > /dev/null 2>&1 || true
|
|
||||||
apt-get -y autoclean > /dev/null 2>&1 || true
|
|
||||||
return 0
|
|
||||||
elif [[ $MENU_RESULT -eq 2 ]]; then
|
|
||||||
msg_ok "$(translate "System is already up to date. No update needed.")"
|
|
||||||
apt-get -y autoremove > /dev/null 2>&1 || true
|
|
||||||
apt-get -y autoclean > /dev/null 2>&1 || true
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_info "$(translate "Cleaning up unused time synchronization services...")"
|
|
||||||
|
|
||||||
if /usr/bin/env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confdef' purge ntp openntpd systemd-timesyncd > /dev/null 2>&1; then
|
|
||||||
msg_ok "$(translate "Old time services removed successfully")"
|
|
||||||
else
|
|
||||||
msg_warn "$(translate "Some old time services could not be removed (not installed)")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
msg_info "$(translate "Updating packages...")"
|
|
||||||
apt-get install pv -y > /dev/null 2>&1
|
|
||||||
msg_ok "$(translate "Packages updated successfully")"
|
|
||||||
|
|
||||||
tput sc
|
|
||||||
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get -y \
|
|
||||||
-o Dpkg::Options::='--force-confdef' \
|
|
||||||
-o Dpkg::Options::='--force-confold' \
|
|
||||||
dist-upgrade 2>&1 | while IFS= read -r line; do
|
|
||||||
|
|
||||||
echo "$line" >> "$log_file"
|
|
||||||
|
|
||||||
if [[ "$line" =~ \[[#=\-]+\]\ *[0-9]{1,3}% ]]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$line" =~ ^(Setting\ up|Unpacking|Preparing\ to\ unpack|Processing\ triggers\ for) ]]; then
|
|
||||||
package_name=$(echo "$line" | sed -E 's/.*(Setting up|Unpacking|Preparing to unpack|Processing triggers for) ([^ :]+).*/\2/')
|
|
||||||
[ -z "$package_name" ] && package_name="$(translate "Unknown")"
|
|
||||||
|
|
||||||
row=$(( $(tput lines) - 6 ))
|
|
||||||
tput cup $row 0; printf "%s\n" "$(translate "Installing packages...")"
|
|
||||||
tput cup $((row + 1)) 0; printf "%s\n" "──────────────────────────────────────────────"
|
|
||||||
tput cup $((row + 2)) 0; printf "%s %s\n" "$(translate "Package:")" "$package_name"
|
|
||||||
tput cup $((row + 3)) 0; printf "%s\n" "Progress: [ ] 0%"
|
|
||||||
tput cup $((row + 4)) 0; printf "%s\n" "──────────────────────────────────────────────"
|
|
||||||
|
|
||||||
for i in $(seq 1 10); do
|
|
||||||
sleep 0.1
|
|
||||||
progress=$((i * 10))
|
|
||||||
tput cup $((row + 3)) 9
|
|
||||||
printf "[%-50s] %3d%%" "$(printf "#%.0s" $(seq 1 $((progress/2))))" "$progress"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
tput rc
|
|
||||||
tput ed
|
|
||||||
|
|
||||||
upgrade_exit_code=${PIPESTATUS[0]}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if [ $upgrade_exit_code -eq 0 ]; then
|
|
||||||
msg_ok "$(translate "System upgrade completed successfully")"
|
|
||||||
else
|
|
||||||
msg_error "$(translate "System upgrade failed. Check log: $log_file")"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
msg_info "$(translate "Installing essential Proxmox packages...")"
|
|
||||||
local additional_packages="zfsutils-linux proxmox-backup-restore-image chrony"
|
|
||||||
|
|
||||||
if /usr/bin/env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confdef' install $additional_packages >> "$log_file" 2>&1; then
|
|
||||||
msg_ok "$(translate "Essential Proxmox packages installed")"
|
|
||||||
else
|
|
||||||
msg_warn "$(translate "Some essential Proxmox packages may not have been installed")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
lvm_repair_check
|
|
||||||
cleanup_duplicate_repos
|
|
||||||
|
|
||||||
#msg_info "$(translate "Performing system cleanup...")"
|
|
||||||
apt-get -y autoremove > /dev/null 2>&1 || true
|
|
||||||
apt-get -y autoclean > /dev/null 2>&1 || true
|
|
||||||
msg_ok "$(translate "Cleanup finished")"
|
|
||||||
|
|
||||||
local end_time=$(date +%s)
|
|
||||||
local duration=$((end_time - start_time))
|
|
||||||
local minutes=$((duration / 60))
|
|
||||||
local seconds=$((duration % 60))
|
|
||||||
|
|
||||||
echo -e "${TAB}${BGN}$(translate "====== PVE UPDATE COMPLETED ======")${CL}"
|
|
||||||
echo -e "${TAB}${GN}⏱️ $(translate "Duration")${CL}: ${BL}${minutes}m ${seconds}s${CL}"
|
|
||||||
echo -e "${TAB}${GN}📄 $(translate "Log file")${CL}: ${BL}$log_file${CL}"
|
|
||||||
echo -e "${TAB}${GN}📦 $(translate "Packages upgraded")${CL}: ${BL}$upgradable${CL}"
|
|
||||||
echo -e "${TAB}${GN}🖥️ $(translate "Proxmox VE")${CL}: ${BL}$target_version (Debian $OS_CODENAME)${CL}"
|
|
||||||
|
|
||||||
msg_ok "$(translate "Proxmox VE 9.x configuration completed.")"
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
||||||
update_pve9
|
|
||||||
fi
|
|
||||||
@@ -1,304 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# ==========================================================
|
|
||||||
# Proxmox VE Update Script - Improved Version
|
|
||||||
# ==========================================================
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
|
|
||||||
BASE_DIR="/usr/local/share/proxmenux"
|
|
||||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
||||||
VENV_PATH="/opt/googletrans-env"
|
|
||||||
TOOLS_JSON="/usr/local/share/proxmenux/installed_tools.json"
|
|
||||||
|
|
||||||
if [[ -f "$UTILS_FILE" ]]; then
|
|
||||||
source "$UTILS_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
load_language
|
|
||||||
initialize_cache
|
|
||||||
|
|
||||||
ensure_tools_json() {
|
|
||||||
[ -f "$TOOLS_JSON" ] || echo "{}" > "$TOOLS_JSON"
|
|
||||||
}
|
|
||||||
|
|
||||||
register_tool() {
|
|
||||||
local tool="$1"
|
|
||||||
local state="$2"
|
|
||||||
ensure_tools_json
|
|
||||||
jq --arg t "$tool" --argjson v "$state" '.[$t]=$v' "$TOOLS_JSON" > "$TOOLS_JSON.tmp" && mv "$TOOLS_JSON.tmp" "$TOOLS_JSON"
|
|
||||||
}
|
|
||||||
|
|
||||||
download_common_functions() {
|
|
||||||
if ! source <(curl -s "$REPO_URL/scripts/global/common-functions.sh"); then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
update_pve9() {
|
|
||||||
local pve_version=$(pveversion | awk -F'/' '{print $2}' | cut -d'-' -f1)
|
|
||||||
local start_time=$(date +%s)
|
|
||||||
local log_file="/var/log/proxmox-update-$(date +%Y%m%d-%H%M%S).log"
|
|
||||||
local changes_made=false
|
|
||||||
local OS_CODENAME="$(grep "VERSION_CODENAME=" /etc/os-release | cut -d"=" -f 2 | xargs)"
|
|
||||||
local TARGET_CODENAME="trixie"
|
|
||||||
|
|
||||||
local screen_capture="/tmp/proxmenux_screen_capture_$$.txt"
|
|
||||||
|
|
||||||
if [ -z "$OS_CODENAME" ]; then
|
|
||||||
OS_CODENAME=$(lsb_release -cs 2>/dev/null || echo "trixie")
|
|
||||||
fi
|
|
||||||
|
|
||||||
download_common_functions
|
|
||||||
|
|
||||||
{
|
|
||||||
msg_info2 "$(translate "Detected: Proxmox VE $pve_version (Current: $OS_CODENAME, Target: $TARGET_CODENAME)")"
|
|
||||||
} | tee -a "$screen_capture"
|
|
||||||
|
|
||||||
|
|
||||||
local available_space=$(df /var/cache/apt/archives | awk 'NR==2 {print int($4/1024)}')
|
|
||||||
if [ "$available_space" -lt 1024 ]; then
|
|
||||||
msg_error "$(translate "Insufficient disk space. Available: ${available_space}MB")"
|
|
||||||
echo -e
|
|
||||||
msg_success "$(translate "Press Enter to return to menu...")"
|
|
||||||
read -r
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! ping -c 1 download.proxmox.com >/dev/null 2>&1; then
|
|
||||||
msg_error "$(translate "Cannot reach Proxmox repositories")"
|
|
||||||
echo -e
|
|
||||||
msg_success "$(translate "Press Enter to return to menu...")"
|
|
||||||
read -r
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
disable_sources_repo() {
|
|
||||||
local file="$1"
|
|
||||||
if [[ -f "$file" ]]; then
|
|
||||||
sed -i ':a;/^\n*$/{$d;N;ba}' "$file"
|
|
||||||
|
|
||||||
if grep -q "^Enabled:" "$file"; then
|
|
||||||
sed -i 's/^Enabled:.*$/Enabled: false/' "$file"
|
|
||||||
else
|
|
||||||
echo "Enabled: false" >> "$file"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! grep -q "^Types: " "$file"; then
|
|
||||||
msg_warn "$(translate "Malformed .sources file detected, removing: $(basename "$file")")"
|
|
||||||
rm -f "$file"
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if disable_sources_repo "/etc/apt/sources.list.d/pve-enterprise.sources"; then
|
|
||||||
msg_ok "$(translate "Enterprise Proxmox repository disabled")" | tee -a "$screen_capture"
|
|
||||||
changes_made=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
if disable_sources_repo "/etc/apt/sources.list.d/ceph.sources"; then
|
|
||||||
msg_ok "$(translate "Enterprise Proxmox Ceph repository disabled")" | tee -a "$screen_capture"
|
|
||||||
changes_made=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
for legacy_file in /etc/apt/sources.list.d/pve-public-repo.list \
|
|
||||||
/etc/apt/sources.list.d/pve-install-repo.list \
|
|
||||||
/etc/apt/sources.list.d/debian.list; do
|
|
||||||
if [[ -f "$legacy_file" ]]; then
|
|
||||||
rm -f "$legacy_file"
|
|
||||||
msg_ok "$(translate "Removed legacy repository: $(basename "$legacy_file")")" | tee -a "$screen_capture"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ -f /etc/apt/sources.list.d/debian.sources ]]; then
|
|
||||||
rm -f /etc/apt/sources.list.d/debian.sources
|
|
||||||
msg_ok "$(translate "Old debian.sources file removed to prevent duplication")" | tee -a "$screen_capture"
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_info "$(translate "Creating Proxmox VE 9.x no-subscription repository...")"
|
|
||||||
cat > /etc/apt/sources.list.d/proxmox.sources << EOF
|
|
||||||
Enabled: true
|
|
||||||
Types: deb
|
|
||||||
URIs: http://download.proxmox.com/debian/pve
|
|
||||||
Suites: ${TARGET_CODENAME}
|
|
||||||
Components: pve-no-subscription
|
|
||||||
Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg
|
|
||||||
EOF
|
|
||||||
msg_ok "$(translate "Proxmox VE 9.x no-subscription repository created")" | tee -a "$screen_capture"
|
|
||||||
changes_made=true
|
|
||||||
|
|
||||||
msg_info "$(translate "Creating Debian ${TARGET_CODENAME} sources file...")"
|
|
||||||
cat > /etc/apt/sources.list.d/debian.sources << EOF
|
|
||||||
Types: deb
|
|
||||||
URIs: http://deb.debian.org/debian/
|
|
||||||
Suites: ${TARGET_CODENAME} ${TARGET_CODENAME}-updates
|
|
||||||
Components: main contrib non-free non-free-firmware
|
|
||||||
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
|
||||||
|
|
||||||
Types: deb
|
|
||||||
URIs: http://security.debian.org/debian-security/
|
|
||||||
Suites: ${TARGET_CODENAME}-security
|
|
||||||
Components: main contrib non-free non-free-firmware
|
|
||||||
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
|
|
||||||
EOF
|
|
||||||
|
|
||||||
msg_ok "$(translate "Debian repositories configured for $TARGET_CODENAME")"
|
|
||||||
|
|
||||||
local firmware_conf="/etc/apt/apt.conf.d/no-firmware-warnings.conf"
|
|
||||||
if [ ! -f "$firmware_conf" ]; then
|
|
||||||
msg_info "$(translate "Disabling non-free firmware warnings...")"
|
|
||||||
echo 'APT::Get::Update::SourceListWarnings::NonFreeFirmware "false";' > "$firmware_conf"
|
|
||||||
msg_ok "$(translate "Non-free firmware warnings disabled")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
#update_output=$(apt-get update 2>&1)
|
|
||||||
update_output=$(apt-get -o Dpkg::Progress-Fancy=1 update 2>&1)
|
|
||||||
update_exit_code=$?
|
|
||||||
|
|
||||||
if [ $update_exit_code -eq 0 ]; then
|
|
||||||
msg_ok "$(translate "Package lists updated successfully")" | tee -a "$screen_capture"
|
|
||||||
else
|
|
||||||
if echo "$update_output" | grep -q "NO_PUBKEY\|GPG error"; then
|
|
||||||
msg_info "$(translate "Fixing GPG key issues...")"
|
|
||||||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys $(echo "$update_output" | grep "NO_PUBKEY" | sed 's/.*NO_PUBKEY //' | head -1) 2>/dev/null
|
|
||||||
if apt-get update > "$log_file" 2>&1; then
|
|
||||||
msg_ok "$(translate "Package lists updated after GPG fix")" | tee -a "$screen_capture"
|
|
||||||
else
|
|
||||||
msg_error "$(translate "Failed to update package lists. Check log: $log_file")"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
elif echo "$update_output" | grep -q "404\|Failed to fetch"; then
|
|
||||||
msg_warn "$(translate "Some repositories are not available, continuing with available ones...")"
|
|
||||||
else
|
|
||||||
msg_error "$(translate "Failed to update package lists. Check log: $log_file")"
|
|
||||||
echo "Error details: $update_output"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if apt policy 2>/dev/null | grep -q "${TARGET_CODENAME}.*pve-no-subscription"; then
|
|
||||||
msg_ok "$(translate "Proxmox VE 9.x repositories verified")" | tee -a "$screen_capture"
|
|
||||||
else
|
|
||||||
msg_warn "$(translate "Proxmox VE 9.x repositories verification inconclusive, continuing...")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
local current_pve_version=$(pveversion 2>/dev/null | grep -oP 'pve-manager/\K[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
|
||||||
local available_pve_version=$(apt-cache policy pve-manager 2>/dev/null | grep -oP 'Candidate: \K[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
|
||||||
local upgradable=$(apt list --upgradable 2>/dev/null | grep -c "upgradable")
|
|
||||||
local security_updates=$(apt list --upgradable 2>/dev/null | grep -c "security")
|
|
||||||
|
|
||||||
show_update_menu() {
|
|
||||||
local current_version="$1"
|
|
||||||
local target_version="$2"
|
|
||||||
local upgradable_count="$3"
|
|
||||||
local security_count="$4"
|
|
||||||
|
|
||||||
local menu_text="$(translate "System Update Information")\n\n"
|
|
||||||
menu_text+="$(translate "Current PVE Version"): $current_version\n"
|
|
||||||
if [ -n "$target_version" ] && [ "$target_version" != "$current_version" ]; then
|
|
||||||
menu_text+="$(translate "Available PVE Version"): $target_version\n"
|
|
||||||
fi
|
|
||||||
menu_text+="\n$(translate "Package Updates Available"): $upgradable_count\n"
|
|
||||||
menu_text+="$(translate "Security Updates"): $security_count\n\n"
|
|
||||||
|
|
||||||
if [ "$upgradable_count" -eq 0 ]; then
|
|
||||||
menu_text+="$(translate "System is already up to date")"
|
|
||||||
whiptail --title "$(translate "Update Status")" --msgbox "$menu_text" 15 70
|
|
||||||
return 2
|
|
||||||
else
|
|
||||||
menu_text+="$(translate "Do you want to proceed with the system update?")"
|
|
||||||
if whiptail --title "$(translate "Proxmox Update")" --yesno "$menu_text" 18 70; then
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
show_update_menu "$current_pve_version" "$available_pve_version" "$upgradable" "$security_updates"
|
|
||||||
MENU_RESULT=$?
|
|
||||||
|
|
||||||
clear
|
|
||||||
show_proxmenux_logo
|
|
||||||
msg_title "$(translate "$SCRIPT_TITLE")"
|
|
||||||
cat "$screen_capture"
|
|
||||||
|
|
||||||
|
|
||||||
if [[ $MENU_RESULT -eq 1 ]]; then
|
|
||||||
msg_info2 "$(translate "Update cancelled by user")"
|
|
||||||
apt-get -y autoremove > /dev/null 2>&1 || true
|
|
||||||
apt-get -y autoclean > /dev/null 2>&1 || true
|
|
||||||
rm -f "$screen_capture"
|
|
||||||
return 0
|
|
||||||
elif [[ $MENU_RESULT -eq 2 ]]; then
|
|
||||||
msg_ok "$(translate "System is already up to date. No update needed.")"
|
|
||||||
apt-get -y autoremove > /dev/null 2>&1 || true
|
|
||||||
apt-get -y autoclean > /dev/null 2>&1 || true
|
|
||||||
rm -f "$screen_capture"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_info "$(translate "Cleaning up unused time synchronization services...")"
|
|
||||||
if /usr/bin/env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confdef' purge ntp openntpd systemd-timesyncd > /dev/null 2>&1; then
|
|
||||||
msg_ok "$(translate "Old time services removed successfully")"
|
|
||||||
else
|
|
||||||
msg_warn "$(translate "Some old time services could not be removed (not installed)")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e
|
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get -y \
|
|
||||||
-o Dpkg::Options::='--force-confdef' \
|
|
||||||
-o Dpkg::Options::='--force-confold' \
|
|
||||||
dist-upgrade 2>&1 | tee -a "$log_file"
|
|
||||||
|
|
||||||
upgrade_exit_code=${PIPESTATUS[0]}
|
|
||||||
echo -e
|
|
||||||
|
|
||||||
clear
|
|
||||||
show_proxmenux_logo
|
|
||||||
msg_title "$(translate "$SCRIPT_TITLE")"
|
|
||||||
cat "$screen_capture"
|
|
||||||
|
|
||||||
|
|
||||||
if [ $upgrade_exit_code -ne 0 ]; then
|
|
||||||
msg_error "$(translate "System upgrade failed. Check log: $log_file")"
|
|
||||||
rm -f "$screen_capture"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_info "$(translate "Installing essential Proxmox packages...")"
|
|
||||||
local additional_packages="zfsutils-linux proxmox-backup-restore-image chrony"
|
|
||||||
|
|
||||||
if /usr/bin/env DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::='--force-confdef' install $additional_packages >> "$log_file" 2>&1; then
|
|
||||||
msg_ok "$(translate "Essential Proxmox packages installed")"
|
|
||||||
else
|
|
||||||
msg_warn "$(translate "Some essential Proxmox packages may not have been installed")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
lvm_repair_check
|
|
||||||
cleanup_duplicate_repos
|
|
||||||
|
|
||||||
apt-get -y autoremove > /dev/null 2>&1 || true
|
|
||||||
apt-get -y autoclean > /dev/null 2>&1 || true
|
|
||||||
msg_ok "$(translate "Cleanup finished")"
|
|
||||||
|
|
||||||
local end_time=$(date +%s)
|
|
||||||
local duration=$((end_time - start_time))
|
|
||||||
local minutes=$((duration / 60))
|
|
||||||
local seconds=$((duration % 60))
|
|
||||||
|
|
||||||
echo -e "${TAB}${BGN}$(translate "====== PVE UPDATE COMPLETED ======")${CL}"
|
|
||||||
echo -e "${TAB}${GN}⏱️ $(translate "Duration")${CL}: ${BL}${minutes}m ${seconds}s${CL}"
|
|
||||||
echo -e "${TAB}${GN}📄 $(translate "Log file")${CL}: ${BL}$log_file${CL}"
|
|
||||||
echo -e "${TAB}${GN}📦 $(translate "Packages upgraded")${CL}: ${BL}$upgradable${CL}"
|
|
||||||
echo -e "${TAB}${GN}🖥️ $(translate "Proxmox VE")${CL}: ${BL}$available_pve_version (Debian $OS_CODENAME)${CL}"
|
|
||||||
|
|
||||||
msg_ok "$(translate "Proxmox VE 9.x configuration completed.")"
|
|
||||||
|
|
||||||
rm -f "$screen_capture"
|
|
||||||
}
|
|
||||||
|
|
||||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
||||||
update_pve9
|
|
||||||
fi
|
|
||||||
@@ -1,916 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# ProxMenux - NVIDIA Driver Installer (PVE 9.x)
|
|
||||||
# ============================================
|
|
||||||
# Author : MacRimi
|
|
||||||
# License : MIT
|
|
||||||
# Version : 0.9 (PVE9, fixed download issues)
|
|
||||||
# Last Updated: 29/11/2025
|
|
||||||
# ============================================
|
|
||||||
|
|
||||||
SCRIPT_TITLE="NVIDIA GPU Driver Installer for Proxmox VE"
|
|
||||||
|
|
||||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
|
||||||
BASE_DIR="/usr/local/share/proxmenux"
|
|
||||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
||||||
COMPONENTS_STATUS_FILE="$BASE_DIR/components_status.json"
|
|
||||||
LOG_FILE="/tmp/nvidia_install.log"
|
|
||||||
screen_capture="/tmp/proxmenux_nvidia_screen_capture_$$.txt"
|
|
||||||
|
|
||||||
NVIDIA_BASE_URL="https://download.nvidia.com/XFree86/Linux-x86_64"
|
|
||||||
NVIDIA_WORKDIR="/opt/nvidia"
|
|
||||||
|
|
||||||
export BASE_DIR
|
|
||||||
export COMPONENTS_STATUS_FILE
|
|
||||||
|
|
||||||
if [[ -f "$UTILS_FILE" ]]; then
|
|
||||||
source "$UTILS_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -f "$COMPONENTS_STATUS_FILE" ]]; then
|
|
||||||
echo "{}" > "$COMPONENTS_STATUS_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
load_language
|
|
||||||
initialize_cache
|
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
# GPU detection and current status
|
|
||||||
# ==========================================================
|
|
||||||
detect_nvidia_gpus() {
|
|
||||||
# Only video controllers (not audio)
|
|
||||||
local lspci_output
|
|
||||||
lspci_output=$(lspci | grep -i "NVIDIA" \
|
|
||||||
| grep -Ei "VGA compatible controller|3D controller|Display controller" || true)
|
|
||||||
|
|
||||||
if [[ -z "$lspci_output" ]]; then
|
|
||||||
NVIDIA_GPU_PRESENT=false
|
|
||||||
DETECTED_GPUS_TEXT="$(translate 'No NVIDIA GPU detected on this system.')"
|
|
||||||
else
|
|
||||||
NVIDIA_GPU_PRESENT=true
|
|
||||||
DETECTED_GPUS_TEXT=""
|
|
||||||
local i=1
|
|
||||||
while IFS= read -r line; do
|
|
||||||
DETECTED_GPUS_TEXT+=" ${i}. ${line}\n"
|
|
||||||
((i++))
|
|
||||||
done <<< "$lspci_output"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
detect_driver_status() {
|
|
||||||
CURRENT_DRIVER_INSTALLED=false
|
|
||||||
CURRENT_DRIVER_VERSION=""
|
|
||||||
|
|
||||||
# First check if nvidia kernel module is actually loaded
|
|
||||||
if lsmod | grep -q "^nvidia "; then
|
|
||||||
|
|
||||||
modprobe nvidia-uvm 2>/dev/null || true
|
|
||||||
sleep 1
|
|
||||||
|
|
||||||
|
|
||||||
if command -v nvidia-smi >/dev/null 2>&1; then
|
|
||||||
CURRENT_DRIVER_VERSION=$(nvidia-smi --query-gpu=driver_version --format=csv,noheader 2>/dev/null | head -n1)
|
|
||||||
|
|
||||||
if [[ -n "$CURRENT_DRIVER_VERSION" ]]; then
|
|
||||||
CURRENT_DRIVER_INSTALLED=true
|
|
||||||
# Register the installed driver version in components_status.json
|
|
||||||
update_component_status "nvidia_driver" "installed" "$CURRENT_DRIVER_VERSION" "gpu" '{"patched":false}'
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $CURRENT_DRIVER_INSTALLED; then
|
|
||||||
CURRENT_STATUS_TEXT="$(printf '%s %s' "$(translate 'NVIDIA driver installed:')" "$CURRENT_DRIVER_VERSION")"
|
|
||||||
else
|
|
||||||
CURRENT_STATUS_TEXT="$(translate 'No NVIDIA driver installed.')"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $CURRENT_DRIVER_INSTALLED; then
|
|
||||||
CURRENT_STATUS_COLORED="\Z2${CURRENT_STATUS_TEXT}\Zn"
|
|
||||||
else
|
|
||||||
CURRENT_STATUS_COLORED="\Z3${CURRENT_STATUS_TEXT}\Zn"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
# System preparation (repos, headers, etc.)
|
|
||||||
# ==========================================================
|
|
||||||
ensure_repos_and_headers() {
|
|
||||||
msg_info "$(translate 'Checking kernel headers and build tools...')"
|
|
||||||
|
|
||||||
local kver
|
|
||||||
kver=$(uname -r)
|
|
||||||
|
|
||||||
apt-get update -qq >>"$LOG_FILE" 2>&1
|
|
||||||
|
|
||||||
if ! dpkg -s "pve-headers-$kver" >/dev/null 2>&1 && \
|
|
||||||
! dpkg -s "proxmox-headers-$kver" >/dev/null 2>&1; then
|
|
||||||
apt-get install -y "pve-headers-$kver" "proxmox-headers-$kver" build-essential dkms >>"$LOG_FILE" 2>&1 || true
|
|
||||||
else
|
|
||||||
apt-get install -y build-essential dkms >>"$LOG_FILE" 2>&1 || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_ok "$(translate 'Kernel headers and build tools verified.')" | tee -a "$screen_capture"
|
|
||||||
}
|
|
||||||
|
|
||||||
blacklist_nouveau() {
|
|
||||||
msg_info "$(translate 'Blacklisting nouveau driver...')"
|
|
||||||
if ! grep -q '^blacklist nouveau' /etc/modprobe.d/blacklist.conf 2>/dev/null; then
|
|
||||||
echo "blacklist nouveau" >> /etc/modprobe.d/blacklist.conf
|
|
||||||
fi
|
|
||||||
msg_ok "$(translate 'nouveau driver has been blacklisted.')" | tee -a "$screen_capture"
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_modules_config() {
|
|
||||||
msg_info "$(translate 'Configuring NVIDIA and VFIO modules...')"
|
|
||||||
cat > /etc/modules-load.d/nvidia-vfio.conf <<'EOF'
|
|
||||||
vfio
|
|
||||||
vfio_iommu_type1
|
|
||||||
vfio_pci
|
|
||||||
vfio_virqfd
|
|
||||||
nvidia
|
|
||||||
nvidia_uvm
|
|
||||||
EOF
|
|
||||||
msg_ok "$(translate 'Modules configuration updated.')" | tee -a "$screen_capture"
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_and_disable_nvidia_services() {
|
|
||||||
local services=(
|
|
||||||
"nvidia-persistenced.service"
|
|
||||||
"nvidia-persistenced"
|
|
||||||
"nvidia-powerd.service"
|
|
||||||
)
|
|
||||||
|
|
||||||
local services_detected=0
|
|
||||||
|
|
||||||
for service in "${services[@]}"; do
|
|
||||||
if systemctl is-active --quiet "$service" 2>/dev/null || \
|
|
||||||
systemctl is-enabled --quiet "$service" 2>/dev/null; then
|
|
||||||
services_detected=1
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$services_detected" -eq 1 ]; then
|
|
||||||
msg_info "$(translate 'Stopping and disabling NVIDIA services...')"
|
|
||||||
|
|
||||||
for service in "${services[@]}"; do
|
|
||||||
if systemctl is-active --quiet "$service" 2>/dev/null; then
|
|
||||||
systemctl stop "$service" >/dev/null 2>&1 || true
|
|
||||||
fi
|
|
||||||
if systemctl is-enabled --quiet "$service" 2>/dev/null; then
|
|
||||||
systemctl disable "$service" >/dev/null 2>&1 || true
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
msg_ok "$(translate 'NVIDIA services stopped and disabled.')" | tee -a "$screen_capture"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
unload_nvidia_modules() {
|
|
||||||
msg_info "$(translate 'Unloading NVIDIA kernel modules...')"
|
|
||||||
|
|
||||||
for mod in nvidia_uvm nvidia_drm nvidia_modeset nvidia; do
|
|
||||||
modprobe -r "$mod" >/dev/null 2>&1 || true
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
if lsmod | grep -qi '\bnvidia'; then
|
|
||||||
for mod in nvidia_uvm nvidia_drm nvidia_modeset nvidia; do
|
|
||||||
modprobe -r --force "$mod" >/dev/null 2>&1 || true
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
if lsmod | grep -qi '\bnvidia'; then
|
|
||||||
msg_warn "$(translate 'Some NVIDIA modules could not be unloaded. Installation may fail. Ensure no processes are using the GPU.')"
|
|
||||||
if command -v lsof >/dev/null 2>&1; then
|
|
||||||
echo "$(translate 'Processes using NVIDIA:'):" >> "$LOG_FILE"
|
|
||||||
lsof /dev/nvidia* 2>/dev/null >> "$LOG_FILE" || true
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
msg_ok "$(translate 'NVIDIA kernel modules unloaded successfully.')" | tee -a "$screen_capture"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
complete_nvidia_uninstall() {
|
|
||||||
stop_and_disable_nvidia_services
|
|
||||||
unload_nvidia_modules
|
|
||||||
|
|
||||||
if command -v nvidia-uninstall >/dev/null 2>&1; then
|
|
||||||
msg_info "$(translate 'Running NVIDIA uninstaller...')"
|
|
||||||
nvidia-uninstall --silent >>"$LOG_FILE" 2>&1 || true
|
|
||||||
msg_ok "$(translate 'NVIDIA uninstaller completed.')"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cleanup_nvidia_dkms
|
|
||||||
|
|
||||||
msg_info "$(translate 'Removing NVIDIA packages...')"
|
|
||||||
apt-get -y purge 'nvidia-*' 'libnvidia-*' 'cuda-*' 'libcudnn*' >>"$LOG_FILE" 2>&1 || true
|
|
||||||
apt-get -y autoremove --purge >>"$LOG_FILE" 2>&1 || true
|
|
||||||
apt-get -y autoclean >>"$LOG_FILE" 2>&1 || true
|
|
||||||
|
|
||||||
rm -f /etc/modules-load.d/nvidia-vfio.conf
|
|
||||||
rm -f /etc/udev/rules.d/70-nvidia.rules
|
|
||||||
rm -rf /usr/lib/modprobe.d/nvidia*.conf
|
|
||||||
rm -rf /etc/modprobe.d/nvidia*.conf
|
|
||||||
|
|
||||||
if [[ -d "$NVIDIA_WORKDIR" ]]; then
|
|
||||||
find "$NVIDIA_WORKDIR" -type d -name "nvidia-persistenced" -exec rm -rf {} + 2>/dev/null || true
|
|
||||||
find "$NVIDIA_WORKDIR" -type d -name "nvidia-patch" -exec rm -rf {} + 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
update_component_status "nvidia_driver" "removed" "" "gpu" '{}'
|
|
||||||
|
|
||||||
msg_ok "$(translate 'Complete NVIDIA uninstallation finished.')" | tee -a "$screen_capture"
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup_nvidia_dkms() {
|
|
||||||
local versions
|
|
||||||
versions=$(dkms status 2>/dev/null | awk -F, '/nvidia/ {gsub(/ /,"",$2); print $2}' || true)
|
|
||||||
|
|
||||||
[[ -z "$versions" ]] && return 0
|
|
||||||
|
|
||||||
msg_info "$(translate 'Removing NVIDIA DKMS entries...')"
|
|
||||||
while IFS= read -r ver; do
|
|
||||||
[[ -z "$ver" ]] && continue
|
|
||||||
dkms remove -m nvidia -v "$ver" --all >/dev/null 2>&1 || true
|
|
||||||
done <<< "$versions"
|
|
||||||
msg_ok "$(translate 'NVIDIA DKMS entries removed.')"
|
|
||||||
}
|
|
||||||
|
|
||||||
ensure_workdir() {
|
|
||||||
mkdir -p "$NVIDIA_WORKDIR"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
# Kernel compatibility detection
|
|
||||||
# ==========================================================
|
|
||||||
get_kernel_compatibility_info() {
|
|
||||||
local kernel_version
|
|
||||||
kernel_version=$(uname -r)
|
|
||||||
|
|
||||||
# Determine Proxmox and kernel version
|
|
||||||
if [[ -f /etc/pve/.version ]]; then
|
|
||||||
PVE_VERSION=$(cat /etc/pve/.version)
|
|
||||||
else
|
|
||||||
PVE_VERSION="unknown"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Extract kernel major version (6.x, 5.x, etc)
|
|
||||||
KERNEL_MAJOR=$(echo "$kernel_version" | cut -d. -f1)
|
|
||||||
KERNEL_MINOR=$(echo "$kernel_version" | cut -d. -f2)
|
|
||||||
|
|
||||||
# Define minimum compatible versions based on kernel
|
|
||||||
# Based on https://docs.nvidia.com/datacenter/tesla/drivers/index.html
|
|
||||||
if [[ "$KERNEL_MAJOR" -ge 6 ]] && [[ "$KERNEL_MINOR" -ge 17 ]]; then
|
|
||||||
# Kernel 6.17+ (Proxmox 9.x) - Requires 580.82.07 or higher
|
|
||||||
MIN_DRIVER_VERSION="580.82.07"
|
|
||||||
RECOMMENDED_BRANCH="580"
|
|
||||||
COMPATIBILITY_NOTE="Kernel $kernel_version requires NVIDIA driver 580.82.07 or newer"
|
|
||||||
elif [[ "$KERNEL_MAJOR" -ge 6 ]] && [[ "$KERNEL_MINOR" -ge 8 ]]; then
|
|
||||||
# Kernel 6.8-6.16 (Proxmox 8.2+) - Works with 550.x or higher
|
|
||||||
MIN_DRIVER_VERSION="550"
|
|
||||||
RECOMMENDED_BRANCH="580"
|
|
||||||
COMPATIBILITY_NOTE="Kernel $kernel_version works best with NVIDIA driver 550.x or newer"
|
|
||||||
elif [[ "$KERNEL_MAJOR" -ge 6 ]]; then
|
|
||||||
# Kernel 6.2-6.7 (Proxmox 8.x initial) - Works with 535.x or higher
|
|
||||||
MIN_DRIVER_VERSION="535"
|
|
||||||
RECOMMENDED_BRANCH="550"
|
|
||||||
COMPATIBILITY_NOTE="Kernel $kernel_version works with NVIDIA driver 535.x or newer"
|
|
||||||
elif [[ "$KERNEL_MAJOR" -eq 5 ]] && [[ "$KERNEL_MINOR" -ge 15 ]]; then
|
|
||||||
# Kernel 5.15+ (Proxmox 7.x, 8.x legacy) - Works with 470.x or higher
|
|
||||||
MIN_DRIVER_VERSION="470"
|
|
||||||
RECOMMENDED_BRANCH="535"
|
|
||||||
COMPATIBILITY_NOTE="Kernel $kernel_version works with NVIDIA driver 470.x or newer"
|
|
||||||
else
|
|
||||||
# Old kernels
|
|
||||||
MIN_DRIVER_VERSION="450"
|
|
||||||
RECOMMENDED_BRANCH="470"
|
|
||||||
COMPATIBILITY_NOTE="For older kernels, compatibility may vary"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
is_version_compatible() {
|
|
||||||
local version="$1"
|
|
||||||
local ver_major ver_minor ver_patch
|
|
||||||
|
|
||||||
# Extract version components (major.minor.patch)
|
|
||||||
ver_major=$(echo "$version" | cut -d. -f1)
|
|
||||||
ver_minor=$(echo "$version" | cut -d. -f2)
|
|
||||||
ver_patch=$(echo "$version" | cut -d. -f3)
|
|
||||||
|
|
||||||
if [[ "$MIN_DRIVER_VERSION" == "580.82.07" ]]; then
|
|
||||||
# Compare full version: must be >= 580.82.07
|
|
||||||
if [[ ${ver_major} -gt 580 ]]; then
|
|
||||||
return 0
|
|
||||||
elif [[ ${ver_major} -eq 580 ]]; then
|
|
||||||
if [[ $((10#${ver_minor})) -gt 82 ]]; then
|
|
||||||
return 0
|
|
||||||
elif [[ $((10#${ver_minor})) -eq 82 ]]; then
|
|
||||||
if [[ $((10#${ver_patch:-0})) -ge 7 ]]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if [[ ${ver_major} -ge ${MIN_DRIVER_VERSION} ]]; then
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
# NVIDIA version management - FIXED VERSION
|
|
||||||
# ==========================================================
|
|
||||||
download_latest_version() {
|
|
||||||
local latest_line version
|
|
||||||
|
|
||||||
latest_line=$(curl -fsSL "${NVIDIA_BASE_URL}/latest.txt" 2>&1)
|
|
||||||
if [[ -z "$latest_line" ]]; then
|
|
||||||
echo "" >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
version=$(echo "$latest_line" | awk '{print $1}' | tr -d '[:space:]')
|
|
||||||
|
|
||||||
if [[ -z "$version" ]]; then
|
|
||||||
echo "" >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]; then
|
|
||||||
echo "" >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$version"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
list_available_versions() {
|
|
||||||
local html_content versions
|
|
||||||
|
|
||||||
html_content=$(curl -s "$NVIDIA_BASE_URL/" 2>&1)
|
|
||||||
|
|
||||||
if [[ -z "$html_content" ]]; then
|
|
||||||
echo "" >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
versions=$(echo "$html_content" \
|
|
||||||
| grep -o 'href=[^ >]*' \
|
|
||||||
| awk -F"'" '{print $2}' \
|
|
||||||
| grep -E '^[0-9]' \
|
|
||||||
| sed 's/\/$//' \
|
|
||||||
| sed 's/^[[:space:]]*//;s/[[:space:]]*$//' \
|
|
||||||
| sort -Vr \
|
|
||||||
| uniq)
|
|
||||||
|
|
||||||
if [[ -z "$versions" ]]; then
|
|
||||||
echo "" >&2
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$versions"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
verify_version_exists() {
|
|
||||||
local version="$1"
|
|
||||||
local url="${NVIDIA_BASE_URL}/${version}/"
|
|
||||||
|
|
||||||
if curl -fsSL --head "$url" >/dev/null 2>&1; then
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
download_nvidia_installer() {
|
|
||||||
ensure_workdir
|
|
||||||
local version="$1"
|
|
||||||
|
|
||||||
version=$(echo "$version" | tr -d '[:space:]' | tr -d '\n' | tr -d '\r')
|
|
||||||
|
|
||||||
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]; then
|
|
||||||
msg_error "Invalid version format: $version" >&2
|
|
||||||
echo "ERROR: Invalid version format: '$version'" >> "$LOG_FILE"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
local run_file="$NVIDIA_WORKDIR/NVIDIA-Linux-x86_64-${version}.run"
|
|
||||||
|
|
||||||
if [[ -f "$run_file" ]]; then
|
|
||||||
echo "Found existing file: $run_file" >> "$LOG_FILE"
|
|
||||||
local existing_size file_type
|
|
||||||
existing_size=$(stat -c%s "$run_file" 2>/dev/null || stat -f%z "$run_file" 2>/dev/null || echo "0")
|
|
||||||
file_type=$(file "$run_file" 2>/dev/null || echo "unknown")
|
|
||||||
|
|
||||||
echo "Existing file size: $existing_size bytes" >> "$LOG_FILE"
|
|
||||||
echo "Existing file type: $file_type" >> "$LOG_FILE"
|
|
||||||
|
|
||||||
|
|
||||||
if [[ $existing_size -gt 40000000 ]] && echo "$file_type" | grep -q "executable"; then
|
|
||||||
|
|
||||||
if sh "$run_file" --check 2>&1 | tee -a "$LOG_FILE" | grep -q "OK"; then
|
|
||||||
echo "Existing file passed integrity check" >> "$LOG_FILE"
|
|
||||||
msg_ok "$(translate 'Installer already downloaded and verified.')" >&2
|
|
||||||
printf '%s\n' "$run_file"
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
echo "Existing file FAILED integrity check, removing..." >> "$LOG_FILE"
|
|
||||||
msg_warn "$(translate 'Existing file failed verification, re-downloading...')" >&2
|
|
||||||
rm -f "$run_file"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "Existing file invalid (size or type), removing..." >> "$LOG_FILE"
|
|
||||||
msg_warn "$(translate 'Removing invalid existing file...')" >&2
|
|
||||||
rm -f "$run_file"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! verify_version_exists "$version"; then
|
|
||||||
msg_error "Version $version does not exist on NVIDIA servers" >&2
|
|
||||||
echo "ERROR: Version $version not found on server" >> "$LOG_FILE"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
local urls=(
|
|
||||||
"${NVIDIA_BASE_URL}/${version}/NVIDIA-Linux-x86_64-${version}.run"
|
|
||||||
"${NVIDIA_BASE_URL}/${version}/NVIDIA-Linux-x86_64-${version}-no-compat32.run"
|
|
||||||
)
|
|
||||||
|
|
||||||
local success=false
|
|
||||||
local url_index=0
|
|
||||||
|
|
||||||
for url in "${urls[@]}"; do
|
|
||||||
((url_index++))
|
|
||||||
echo "Attempting download from: $url" >> "$LOG_FILE"
|
|
||||||
|
|
||||||
|
|
||||||
rm -f "$run_file"
|
|
||||||
|
|
||||||
|
|
||||||
if curl -fL --connect-timeout 30 --max-time 600 "$url" -o "$run_file" >> "$LOG_FILE" 2>&1; then
|
|
||||||
echo "Download completed, verifying file..." >> "$LOG_FILE"
|
|
||||||
|
|
||||||
|
|
||||||
if [[ ! -f "$run_file" ]]; then
|
|
||||||
echo "ERROR: File not created after download" >> "$LOG_FILE"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
local file_size
|
|
||||||
file_size=$(stat -c%s "$run_file" 2>/dev/null || stat -f%z "$run_file" 2>/dev/null || echo "0")
|
|
||||||
echo "Downloaded file size: $file_size bytes" >> "$LOG_FILE"
|
|
||||||
|
|
||||||
if [[ $file_size -lt 40000000 ]]; then
|
|
||||||
echo "ERROR: File too small ($file_size bytes, expected >40MB)" >> "$LOG_FILE"
|
|
||||||
head -c 200 "$run_file" >> "$LOG_FILE" 2>&1
|
|
||||||
rm -f "$run_file"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
local file_type
|
|
||||||
file_type=$(file "$run_file" 2>/dev/null)
|
|
||||||
echo "File type: $file_type" >> "$LOG_FILE"
|
|
||||||
|
|
||||||
if echo "$file_type" | grep -q "executable"; then
|
|
||||||
echo "SUCCESS: Valid executable downloaded" >> "$LOG_FILE"
|
|
||||||
success=true
|
|
||||||
break
|
|
||||||
else
|
|
||||||
echo "ERROR: Not a valid executable" >> "$LOG_FILE"
|
|
||||||
head -c 200 "$run_file" | od -c >> "$LOG_FILE" 2>&1
|
|
||||||
rm -f "$run_file"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "ERROR: curl failed for $url (exit code: $?)" >> "$LOG_FILE"
|
|
||||||
rm -f "$run_file"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if ! $success; then
|
|
||||||
msg_error "$(translate 'Download failed for all attempted URLs')" >&2
|
|
||||||
msg_error "Version $version may not be available for your architecture" >&2
|
|
||||||
echo "ERROR: All download attempts failed" >> "$LOG_FILE"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
chmod +x "$run_file"
|
|
||||||
echo "Installation file ready: $run_file" >> "$LOG_FILE"
|
|
||||||
printf '%s\n' "$run_file"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
# Installation / uninstallation
|
|
||||||
# ==========================================================
|
|
||||||
run_nvidia_installer() {
|
|
||||||
local installer="$1"
|
|
||||||
|
|
||||||
msg_info2 "$(translate 'Starting NVIDIA installer. This may take several minutes...')"
|
|
||||||
echo "" >>"$LOG_FILE"
|
|
||||||
echo "=== Running NVIDIA installer: $installer ===" >>"$LOG_FILE"
|
|
||||||
|
|
||||||
local tmp_extract_dir="$NVIDIA_WORKDIR/tmp_extract"
|
|
||||||
mkdir -p "$tmp_extract_dir"
|
|
||||||
|
|
||||||
sh "$installer" --tmpdir="$tmp_extract_dir" --no-questions --ui=none --disable-nouveau --dkms 2>&1 | tee -a "$LOG_FILE"
|
|
||||||
local rc=${PIPESTATUS[0]}
|
|
||||||
echo "" >>"$LOG_FILE"
|
|
||||||
|
|
||||||
rm -rf "$tmp_extract_dir"
|
|
||||||
|
|
||||||
if [[ $rc -ne 0 ]]; then
|
|
||||||
msg_error "$(translate 'NVIDIA installer reported an error. Check /tmp/nvidia_install.log')"
|
|
||||||
update_component_status "nvidia_driver" "failed" "" "gpu" '{"patched":false}'
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_ok "$(translate 'NVIDIA driver installed successfully.')" | tee -a "$screen_capture"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
remove_nvidia_driver() {
|
|
||||||
complete_nvidia_uninstall
|
|
||||||
}
|
|
||||||
|
|
||||||
install_udev_rules_and_persistenced() {
|
|
||||||
msg_info "$(translate 'Installing NVIDIA udev rules and persistence service...')"
|
|
||||||
|
|
||||||
cat >/etc/udev/rules.d/70-nvidia.rules <<'EOF'
|
|
||||||
# /etc/udev/rules.d/70-nvidia.rules
|
|
||||||
KERNEL=="nvidia", RUN+="/bin/bash -c '/usr/bin/nvidia-smi -L'"
|
|
||||||
KERNEL=="nvidia_uvm", RUN+="/bin/bash -c '/usr/bin/nvidia-modprobe -c0 -u'"
|
|
||||||
EOF
|
|
||||||
|
|
||||||
udevadm control --reload-rules
|
|
||||||
udevadm trigger --subsystem-match=drm --subsystem-match=pci || true
|
|
||||||
|
|
||||||
ensure_workdir
|
|
||||||
cd "$NVIDIA_WORKDIR" || return 1
|
|
||||||
if [[ ! -d nvidia-persistenced ]]; then
|
|
||||||
git clone https://github.com/NVIDIA/nvidia-persistenced.git >>"$LOG_FILE" 2>&1 || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -d nvidia-persistenced/init ]]; then
|
|
||||||
cd nvidia-persistenced/init || return 1
|
|
||||||
./install.sh >>"$LOG_FILE" 2>&1 || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_ok "$(translate 'NVIDIA udev rules and persistence service installed.')" | tee -a "$screen_capture"
|
|
||||||
}
|
|
||||||
|
|
||||||
apply_nvidia_patch_if_needed() {
|
|
||||||
if ! whiptail --title "$(translate 'NVIDIA Patch')" --yesno \
|
|
||||||
"\n$(translate 'Do you want to apply the optional NVIDIA patch to remove some GPU limitations?')" 10 70; then
|
|
||||||
msg_info2 "$(translate 'NVIDIA patch not applied.')"
|
|
||||||
update_component_status "nvidia_driver" "installed" "$CURRENT_DRIVER_VERSION" "gpu" '{"patched":false}'
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_info "$(translate 'Cloning and applying NVIDIA patch (keylase/nvidia-patch)...')"
|
|
||||||
ensure_workdir
|
|
||||||
cd "$NVIDIA_WORKDIR" || return 1
|
|
||||||
if [[ ! -d nvidia-patch ]]; then
|
|
||||||
git clone https://github.com/keylase/nvidia-patch.git >>"$LOG_FILE" 2>&1 || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -x nvidia-patch/patch.sh ]]; then
|
|
||||||
cd nvidia-patch || return 1
|
|
||||||
./patch.sh >>"$LOG_FILE" 2>&1 || true
|
|
||||||
msg_ok "$(translate 'NVIDIA patch applied - check README for supported versions.')"
|
|
||||||
update_component_status "nvidia_driver" "installed" "$CURRENT_DRIVER_VERSION" "gpu" '{"patched":true}'
|
|
||||||
else
|
|
||||||
msg_warn "$(translate 'Could not run NVIDIA patch script. Please verify repository and driver version.')"
|
|
||||||
update_component_status "nvidia_driver" "installed" "$CURRENT_DRIVER_VERSION" "gpu" '{"patched":false}'
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
restart_prompt() {
|
|
||||||
if whiptail --title "$(translate 'NVIDIA Drivers')" --yesno \
|
|
||||||
"\n$(translate 'The installation/changes require a server restart to apply correctly. Do you want to reboot now?')" 10 70; then
|
|
||||||
msg_success "$(translate 'Installation completed. Press Enter to continue...')"
|
|
||||||
read -r
|
|
||||||
msg_warn "$(translate 'Restarting the server...')"
|
|
||||||
rm -f "$screen_capture"
|
|
||||||
reboot
|
|
||||||
else
|
|
||||||
msg_success "$(translate 'Installation completed. Please reboot the server manually as soon as possible.')"
|
|
||||||
msg_success "$(translate 'Completed. Press Enter to return to menu...')"
|
|
||||||
read -r
|
|
||||||
rm -f "$screen_capture"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
# Dialog menus
|
|
||||||
# ==========================================================
|
|
||||||
show_action_menu_if_installed() {
|
|
||||||
if ! $CURRENT_DRIVER_INSTALLED; then
|
|
||||||
ACTION="install"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
local menu_choices=(
|
|
||||||
"install" "$(translate 'Reinstall/Update NVIDIA drivers')"
|
|
||||||
"remove" "$(translate 'Uninstall NVIDIA drivers and configuration')"
|
|
||||||
)
|
|
||||||
|
|
||||||
ACTION=$(dialog --clear --stdout \
|
|
||||||
--backtitle "ProxMenux" \
|
|
||||||
--title "$(translate 'NVIDIA GPU Driver Management')" \
|
|
||||||
--menu "$(translate 'Choose an action:')" 14 80 8 \
|
|
||||||
"${menu_choices[@]}") || ACTION="cancel"
|
|
||||||
}
|
|
||||||
|
|
||||||
show_install_overview() {
|
|
||||||
local overview
|
|
||||||
overview="\n$(translate 'This installation will:')\n\n"
|
|
||||||
overview+=" • $(translate 'Install NVIDIA proprietary drivers')\n"
|
|
||||||
overview+=" • $(translate 'Configure GPU passthrough with VFIO')\n"
|
|
||||||
overview+=" • $(translate 'Blacklist nouveau driver')\n"
|
|
||||||
overview+=" • $(translate 'Enable IOMMU support if not enabled')\n\n"
|
|
||||||
|
|
||||||
overview+="$(translate 'Detected GPU(s):')\n"
|
|
||||||
overview+="\Zb\Z4$DETECTED_GPUS_TEXT\Zn\n"
|
|
||||||
|
|
||||||
overview+="\n\Zn$(translate 'Current status: ') "
|
|
||||||
overview+="\Zb${CURRENT_STATUS_TEXT}\Zn\n\n"
|
|
||||||
|
|
||||||
overview+="$(translate 'After confirming, you will be asked to choose the NVIDIA driver version to install.')\n\n"
|
|
||||||
overview+="$(translate 'Do you want to continue?')"
|
|
||||||
|
|
||||||
dialog --colors --backtitle "ProxMenux" \
|
|
||||||
--title "$(translate 'NVIDIA GPU Driver Installation')" \
|
|
||||||
--yesno "$overview" 22 90
|
|
||||||
}
|
|
||||||
|
|
||||||
show_version_menu() {
|
|
||||||
local latest versions_list
|
|
||||||
local kernel_version
|
|
||||||
kernel_version=$(uname -r)
|
|
||||||
|
|
||||||
|
|
||||||
latest=$(download_latest_version 2>/dev/null)
|
|
||||||
|
|
||||||
|
|
||||||
versions_list=$(list_available_versions 2>/dev/null)
|
|
||||||
|
|
||||||
|
|
||||||
if [[ -z "$latest" ]] && [[ -z "$versions_list" ]]; then
|
|
||||||
dialog --backtitle "ProxMenux" --title "$(translate 'Error')" --msgbox \
|
|
||||||
"$(translate 'Could not retrieve versions list from NVIDIA. Please check your internet connection.')\n\nURL: ${NVIDIA_BASE_URL}" 10 80
|
|
||||||
DRIVER_VERSION="cancel"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if [[ -z "$latest" ]] && [[ -n "$versions_list" ]]; then
|
|
||||||
latest=$(echo "$versions_list" | head -n1)
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if [[ -n "$latest" ]] && [[ -z "$versions_list" ]]; then
|
|
||||||
versions_list="$latest"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Clean latest version
|
|
||||||
latest=$(echo "$latest" | tr -d '[:space:]')
|
|
||||||
|
|
||||||
local filter=""
|
|
||||||
local selection
|
|
||||||
local choices
|
|
||||||
local current_list
|
|
||||||
local menu_text
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
current_list="$versions_list"
|
|
||||||
|
|
||||||
if [[ -n "$MIN_DRIVER_VERSION" ]]; then
|
|
||||||
local filtered_list=""
|
|
||||||
while IFS= read -r ver; do
|
|
||||||
[[ -z "$ver" ]] && continue
|
|
||||||
if is_version_compatible "$ver"; then
|
|
||||||
filtered_list+="$ver"$'\n'
|
|
||||||
fi
|
|
||||||
done <<< "$current_list"
|
|
||||||
current_list="$filtered_list"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if [[ -n "$filter" ]]; then
|
|
||||||
current_list=$(echo "$current_list" | grep "$filter" || true)
|
|
||||||
fi
|
|
||||||
|
|
||||||
menu_text="$(translate 'Select the NVIDIA driver version to install:')\n\n"
|
|
||||||
menu_text+="$(translate 'Use the filter entry to narrow the list. Latest available (recommended in most cases), or choose a specific version from the list.')"
|
|
||||||
|
|
||||||
choices=()
|
|
||||||
choices+=("latest" "$(translate 'Latest available') (${latest:-unknown})")
|
|
||||||
choices+=("" "")
|
|
||||||
choices+=("filter" "$(translate 'Filter versions')${filter:+: $filter}")
|
|
||||||
|
|
||||||
|
|
||||||
if [[ -n "$current_list" ]]; then
|
|
||||||
while IFS= read -r ver; do
|
|
||||||
[[ -z "$ver" ]] && continue
|
|
||||||
ver=$(echo "$ver" | tr -d '[:space:]')
|
|
||||||
[[ -z "$ver" ]] && continue
|
|
||||||
|
|
||||||
choices+=("$ver" "$ver")
|
|
||||||
done <<< "$current_list"
|
|
||||||
else
|
|
||||||
choices+=("" "$(translate 'No versions match the current filter')")
|
|
||||||
fi
|
|
||||||
|
|
||||||
selection=$(dialog --clear --stdout \
|
|
||||||
--backtitle "ProxMenux" \
|
|
||||||
--title "$(translate 'NVIDIA Driver Version')" \
|
|
||||||
--menu "$menu_text" 26 90 16 \
|
|
||||||
"${choices[@]}") || { DRIVER_VERSION="cancel"; return 1; }
|
|
||||||
|
|
||||||
case "$selection" in
|
|
||||||
"")
|
|
||||||
continue
|
|
||||||
;;
|
|
||||||
filter)
|
|
||||||
filter=$(dialog --clear --stdout \
|
|
||||||
--backtitle "ProxMenux" \
|
|
||||||
--title "$(translate 'Filter NVIDIA versions')" \
|
|
||||||
--inputbox "$(translate 'Enter a filter (e.g., 560, 570, 580). Leave empty to show all.')" 10 80 "$filter") || true
|
|
||||||
;;
|
|
||||||
latest)
|
|
||||||
DRIVER_VERSION="$latest"
|
|
||||||
DRIVER_VERSION=$(echo "$DRIVER_VERSION" | tr -d '[:space:]')
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
DRIVER_VERSION="$selection"
|
|
||||||
DRIVER_VERSION=$(echo "$DRIVER_VERSION" | tr -d '[:space:]')
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
# Main flow
|
|
||||||
# ==========================================================
|
|
||||||
main() {
|
|
||||||
: >"$LOG_FILE"
|
|
||||||
: >"$screen_capture"
|
|
||||||
|
|
||||||
detect_nvidia_gpus
|
|
||||||
detect_driver_status
|
|
||||||
|
|
||||||
if ! $NVIDIA_GPU_PRESENT; then
|
|
||||||
dialog --backtitle "ProxMenux" --title "$(translate 'NVIDIA GPU Driver Installation')" --msgbox \
|
|
||||||
"\n$(translate 'No NVIDIA GPU has been detected on this system. The installer will now exit.')" 20 70
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
show_action_menu_if_installed
|
|
||||||
|
|
||||||
case "$ACTION" in
|
|
||||||
install)
|
|
||||||
if ! show_install_overview; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
get_kernel_compatibility_info
|
|
||||||
|
|
||||||
show_version_menu
|
|
||||||
if [[ "$DRIVER_VERSION" == "cancel" || -z "$DRIVER_VERSION" ]]; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $CURRENT_DRIVER_INSTALLED; then
|
|
||||||
if [[ "$CURRENT_DRIVER_VERSION" == "$DRIVER_VERSION" ]]; then
|
|
||||||
if ! dialog --colors --backtitle "ProxMenux" --title "$(translate 'Same Version Detected')" --yesno \
|
|
||||||
"$(printf '\n\n\n%s \Zb%s\Zn\n\n%s' \
|
|
||||||
"$(translate 'Version')" "$DRIVER_VERSION" \
|
|
||||||
"$(translate 'is already installed. Do you want to reinstall it? This will perform a clean uninstall first.')")" 14 70; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if ! dialog --colors --backtitle "ProxMenux" --title "$(translate 'Version Change Detected')" --yesno \
|
|
||||||
"$(printf '\n\n%s \Zb%s\Zn\n%s \Zb\Z4%s\Zn\n\n%s' \
|
|
||||||
"$(translate 'Current version:')" "$CURRENT_DRIVER_VERSION" \
|
|
||||||
"$(translate 'New version:')" "$DRIVER_VERSION" \
|
|
||||||
"$(translate 'The current driver will be completely uninstalled before installing the new version. Continue?')")" 20 70; then
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
show_proxmenux_logo
|
|
||||||
msg_title "$(translate "$SCRIPT_TITLE")"
|
|
||||||
msg_info2 "$(translate 'Uninstalling current NVIDIA driver before installing new version...')"
|
|
||||||
complete_nvidia_uninstall
|
|
||||||
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
CURRENT_DRIVER_INSTALLED=false
|
|
||||||
CURRENT_DRIVER_VERSION=""
|
|
||||||
fi
|
|
||||||
|
|
||||||
show_proxmenux_logo
|
|
||||||
msg_title "$(translate "$SCRIPT_TITLE")"
|
|
||||||
|
|
||||||
ensure_repos_and_headers
|
|
||||||
blacklist_nouveau
|
|
||||||
ensure_modules_config
|
|
||||||
|
|
||||||
stop_and_disable_nvidia_services
|
|
||||||
unload_nvidia_modules
|
|
||||||
|
|
||||||
msg_info "$(translate 'Downloading NVIDIA driver version:') $DRIVER_VERSION"
|
|
||||||
|
|
||||||
local installer
|
|
||||||
installer=$(download_nvidia_installer "$DRIVER_VERSION" 2>>"$LOG_FILE")
|
|
||||||
local download_result=$?
|
|
||||||
|
|
||||||
if [[ $download_result -ne 0 ]]; then
|
|
||||||
msg_error "$(translate 'Failed to download NVIDIA installer')"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_ok "$(translate 'NVIDIA installer downloaded successfully')"
|
|
||||||
|
|
||||||
if [[ -z "$installer" || ! -f "$installer" ]]; then
|
|
||||||
msg_error "$(translate 'Internal error: NVIDIA installer path is empty or file not found.')"
|
|
||||||
rm -f "$screen_capture"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! run_nvidia_installer "$installer"; then
|
|
||||||
rm -f "$screen_capture"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
sleep 2
|
|
||||||
show_proxmenux_logo
|
|
||||||
msg_title "$(translate "$SCRIPT_TITLE")"
|
|
||||||
cat "$screen_capture"
|
|
||||||
echo -e "${TAB}${GN}📄 $(translate "Log file")${CL}: ${BL}$LOG_FILE${CL}"
|
|
||||||
|
|
||||||
install_udev_rules_and_persistenced
|
|
||||||
|
|
||||||
msg_info "$(translate 'Updating initramfs for all kernels...')"
|
|
||||||
update-initramfs -u -k all >>"$LOG_FILE" 2>&1 || true
|
|
||||||
msg_ok "$(translate 'initramfs updated.')"
|
|
||||||
|
|
||||||
msg_info2 "$(translate 'Checking NVIDIA driver status with nvidia-smi')"
|
|
||||||
if command -v nvidia-smi >/dev/null 2>&1; then
|
|
||||||
nvidia-smi || true
|
|
||||||
CURRENT_DRIVER_VERSION=$(nvidia-smi --query-gpu=driver_version --format=csv,noheader 2>/dev/null | head -n1)
|
|
||||||
CURRENT_DRIVER_INSTALLED=true
|
|
||||||
else
|
|
||||||
msg_warn "$(translate 'nvidia-smi not found in PATH. Please verify the driver installation.')"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -n "$CURRENT_DRIVER_VERSION" ]]; then
|
|
||||||
msg_ok "$(translate 'NVIDIA driver') $CURRENT_DRIVER_VERSION $(translate 'installed successfully.')"
|
|
||||||
update_component_status "nvidia_driver" "installed" "$CURRENT_DRIVER_VERSION" "gpu" '{"patched":false}'
|
|
||||||
msg_success "$(translate 'Driver installed successfully. Press Enter to continue...')"
|
|
||||||
read -r
|
|
||||||
else
|
|
||||||
msg_error "$(translate 'Failed to detect installed NVIDIA driver version.')"
|
|
||||||
update_component_status "nvidia_driver" "failed" "" "gpu" '{"patched":false}'
|
|
||||||
fi
|
|
||||||
|
|
||||||
apply_nvidia_patch_if_needed
|
|
||||||
restart_prompt
|
|
||||||
;;
|
|
||||||
remove)
|
|
||||||
if dialog --backtitle "ProxMenux" --title "$(translate 'NVIDIA Driver Uninstall')" --yesno \
|
|
||||||
"\n\n\n$(translate 'This will remove NVIDIA drivers and related configuration. Do you want to continue?')" 14 70; then
|
|
||||||
|
|
||||||
show_proxmenux_logo
|
|
||||||
msg_title "$(translate "$SCRIPT_TITLE")"
|
|
||||||
|
|
||||||
remove_nvidia_driver
|
|
||||||
|
|
||||||
msg_info "$(translate 'Updating initramfs for all kernels...')"
|
|
||||||
update-initramfs -u -k all >>"$LOG_FILE" 2>&1 || true
|
|
||||||
msg_ok "$(translate 'initramfs updated.')"
|
|
||||||
|
|
||||||
restart_prompt
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
cancel|*)
|
|
||||||
exit 0
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
|
||||||
main
|
|
||||||
fi
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
|
||||||
# ==========================================================
|
|
||||||
# Author : MacRimi
|
|
||||||
# Copyright : (c) 2024 MacRimi
|
|
||||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
|
||||||
# Version : 1.1
|
|
||||||
# Last Updated: 29/05/2025
|
|
||||||
# ==========================================================
|
|
||||||
# Description:
|
|
||||||
# This script automates the process of importing disk images into Proxmox VE virtual machines (VMs),
|
|
||||||
# making it easy to attach pre-existing disk files without manual configuration.
|
|
||||||
#
|
|
||||||
# Before running the script, ensure that disk images are available in /var/lib/vz/template/images/.
|
|
||||||
# The script scans this directory for compatible formats (.img, .qcow2, .vmdk, .raw) and lists the available files.
|
|
||||||
#
|
|
||||||
# Using an interactive menu, you can:
|
|
||||||
# - Select a VM to attach the imported disk.
|
|
||||||
# - Choose one or multiple disk images for import.
|
|
||||||
# - Pick a storage volume in Proxmox for disk placement.
|
|
||||||
# - Assign a suitable interface (SATA, SCSI, VirtIO, or IDE).
|
|
||||||
# - Enable optional settings like SSD emulation or bootable disk configuration.
|
|
||||||
#
|
|
||||||
# Once completed, the script ensures the selected images are correctly attached and ready to use.
|
|
||||||
# ==========================================================
|
|
||||||
|
|
||||||
# Configuration ============================================
|
|
||||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
|
||||||
BASE_DIR="/usr/local/share/proxmenux"
|
|
||||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
||||||
VENV_PATH="/opt/googletrans-env"
|
|
||||||
|
|
||||||
[[ -f "$UTILS_FILE" ]] && source "$UTILS_FILE"
|
|
||||||
load_language
|
|
||||||
initialize_cache
|
|
||||||
# Configuration ============================================
|
|
||||||
|
|
||||||
|
|
||||||
detect_image_dir() {
|
|
||||||
for store in $(pvesm status -content images | awk 'NR>1 {print $1}'); do
|
|
||||||
path=$(pvesm path "${store}:template" 2>/dev/null)
|
|
||||||
if [[ -d "$path" ]]; then
|
|
||||||
for ext in raw img qcow2 vmdk; do
|
|
||||||
if compgen -G "$path/*.$ext" > /dev/null; then
|
|
||||||
echo "$path"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
for sub in images iso; do
|
|
||||||
dir="$path/$sub"
|
|
||||||
if [[ -d "$dir" ]]; then
|
|
||||||
for ext in raw img qcow2 vmdk; do
|
|
||||||
if compgen -G "$dir/*.$ext" > /dev/null; then
|
|
||||||
echo "$dir"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
for fallback in /var/lib/vz/template/images /var/lib/vz/template/iso; do
|
|
||||||
if [[ -d "$fallback" ]]; then
|
|
||||||
for ext in raw img qcow2 vmdk; do
|
|
||||||
if compgen -G "$fallback/*.$ext" > /dev/null; then
|
|
||||||
echo "$fallback"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
IMAGES_DIR=$(detect_image_dir)
|
|
||||||
if [[ -z "$IMAGES_DIR" ]]; then
|
|
||||||
dialog --title "$(translate 'No Images Found')" \
|
|
||||||
--msgbox "$(translate 'Could not find any directory containing disk images')\n\n$(translate 'Make sure there is at least one file with extension .img, .qcow2, .vmdk or .raw')" 15 60
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
IMAGES=$(ls -A "$IMAGES_DIR" | grep -E "\.(img|qcow2|vmdk|raw)$")
|
|
||||||
if [ -z "$IMAGES" ]; then
|
|
||||||
dialog --title "$(translate 'No Disk Images Found')" \
|
|
||||||
--msgbox "$(translate 'No compatible disk images found in:')\n\n$IMAGES_DIR\n\n$(translate 'Supported formats: .img, .qcow2, .vmdk, .raw')" 15 60
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# === Select VM
|
|
||||||
msg_info "$(translate 'Getting VM list')"
|
|
||||||
VM_LIST=$(qm list | awk 'NR>1 {print $1" "$2}')
|
|
||||||
[[ -z "$VM_LIST" ]] && { msg_error "$(translate 'No VMs available in the system')"; exit 1; }
|
|
||||||
msg_ok "$(translate 'VM list obtained')"
|
|
||||||
|
|
||||||
VMID=$(whiptail --title "$(translate 'Select VM')" \
|
|
||||||
--menu "$(translate 'Select the VM where you want to import the disk image:')" 20 70 10 $VM_LIST 3>&1 1>&2 2>&3)
|
|
||||||
[[ -z "$VMID" ]] && exit 1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# === Select storage
|
|
||||||
msg_info "$(translate 'Getting storage volumes')"
|
|
||||||
STORAGE_LIST=$(pvesm status -content images | awk 'NR>1 {print $1}')
|
|
||||||
[[ -z "$STORAGE_LIST" ]] && { msg_error "$(translate 'No storage volumes available')"; exit 1; }
|
|
||||||
msg_ok "$(translate 'Storage volumes obtained')"
|
|
||||||
|
|
||||||
STORAGE_OPTIONS=()
|
|
||||||
while read -r storage; do STORAGE_OPTIONS+=("$storage" ""); done <<< "$STORAGE_LIST"
|
|
||||||
STORAGE=$(whiptail --title "$(translate 'Select Storage')" \
|
|
||||||
--menu "$(translate 'Select the storage volume for disk import:')" 20 70 10 "${STORAGE_OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
|
||||||
[[ -z "$STORAGE" ]] && exit 1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# === Select images
|
|
||||||
IMAGE_OPTIONS=()
|
|
||||||
while read -r img; do IMAGE_OPTIONS+=("$img" "" "OFF"); done <<< "$IMAGES"
|
|
||||||
SELECTED_IMAGES=$(whiptail --title "$(translate 'Select Disk Images')" \
|
|
||||||
--checklist "$(translate 'Select the disk images to import:')" 20 70 12 "${IMAGE_OPTIONS[@]}" 3>&1 1>&2 2>&3)
|
|
||||||
[[ -z "$SELECTED_IMAGES" ]] && exit 1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# === Import each selected image
|
|
||||||
for IMAGE in $SELECTED_IMAGES; do
|
|
||||||
IMAGE=$(echo "$IMAGE" | tr -d '"')
|
|
||||||
INTERFACE=$(whiptail --title "$(translate 'Interface Type')" --menu "$(translate 'Select the interface type for the image:') $IMAGE" 15 40 4 \
|
|
||||||
"sata" "SATA" "scsi" "SCSI" "virtio" "VirtIO" "ide" "IDE" 3>&1 1>&2 2>&3)
|
|
||||||
[[ -z "$INTERFACE" ]] && { msg_error "$(translate 'No interface type selected for') $IMAGE"; continue; }
|
|
||||||
|
|
||||||
FULL_PATH="$IMAGES_DIR/$IMAGE"
|
|
||||||
msg_info "$(translate 'Importing image:') $IMAGE"
|
|
||||||
TEMP_DISK_FILE=$(mktemp)
|
|
||||||
|
|
||||||
qm importdisk "$VMID" "$FULL_PATH" "$STORAGE" 2>&1 | while read -r line; do
|
|
||||||
if [[ "$line" =~ transferred ]]; then
|
|
||||||
PERCENT=$(echo "$line" | grep -oP "\(\d+\.\d+%\)" | tr -d '()%')
|
|
||||||
echo -ne "\r${TAB}${BL}-$(translate 'Importing image:') $IMAGE-${CL} ${PERCENT}%"
|
|
||||||
elif [[ "$line" =~ successfully\ imported\ disk ]]; then
|
|
||||||
echo "$line" | grep -oP "(?<=successfully imported disk ').*(?=')" > "$TEMP_DISK_FILE"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
echo -ne "\n"
|
|
||||||
IMPORT_STATUS=${PIPESTATUS[0]}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if [ "$IMPORT_STATUS" -eq 0 ]; then
|
|
||||||
msg_ok "$(translate 'Image imported successfully')"
|
|
||||||
IMPORTED_DISK=$(cat "$TEMP_DISK_FILE")
|
|
||||||
rm -f "$TEMP_DISK_FILE"
|
|
||||||
|
|
||||||
if [ -n "$IMPORTED_DISK" ]; then
|
|
||||||
EXISTING_DISKS=$(qm config "$VMID" | grep -oP "${INTERFACE}\d+" | sort -n)
|
|
||||||
NEXT_SLOT=0
|
|
||||||
[[ -n "$EXISTING_DISKS" ]] && NEXT_SLOT=$(( $(echo "$EXISTING_DISKS" | tail -n1 | sed "s/${INTERFACE}//") + 1 ))
|
|
||||||
|
|
||||||
SSD_OPTION=""
|
|
||||||
if [ "$INTERFACE" != "virtio" ]; then
|
|
||||||
whiptail --yesno "$(translate 'Do you want to use SSD emulation for this disk?')" 10 60 && SSD_OPTION=",ssd=1"
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_info "$(translate 'Configuring disk')"
|
|
||||||
if qm set "$VMID" --${INTERFACE}${NEXT_SLOT} "$IMPORTED_DISK${SSD_OPTION}" &>/dev/null; then
|
|
||||||
msg_ok "$(translate 'Image') $IMAGE $(translate 'configured as') ${INTERFACE}${NEXT_SLOT}"
|
|
||||||
whiptail --yesno "$(translate 'Do you want to make this disk bootable?')" 10 60 && {
|
|
||||||
msg_info "$(translate 'Configuring disk as bootable')"
|
|
||||||
if qm set "$VMID" --boot c --bootdisk ${INTERFACE}${NEXT_SLOT} &>/dev/null; then
|
|
||||||
msg_ok "$(translate 'Disk configured as bootable')"
|
|
||||||
else
|
|
||||||
msg_error "$(translate 'Could not configure the disk as bootable')"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
else
|
|
||||||
msg_error "$(translate 'Could not configure disk') ${INTERFACE}${NEXT_SLOT} $(translate 'for VM') $VMID"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
msg_error "$(translate 'Could not find the imported disk')"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
msg_error "$(translate 'Could not import') $IMAGE"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
msg_ok "$(translate 'All selected images have been processed')"
|
|
||||||
msg_success "$(translate "Press Enter to return to menu...")"
|
|
||||||
read -r
|
|
||||||
@@ -1,256 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
|
||||||
# ==========================================================
|
|
||||||
# Author : MacRimi
|
|
||||||
# Revision : @Blaspt (USB passthrough via udev rule with persistent /dev/coral)
|
|
||||||
# Copyright : (c) 2024 MacRimi
|
|
||||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
|
||||||
# Version : 1.1
|
|
||||||
# Last Updated: 16/05/2025
|
|
||||||
# ==========================================================
|
|
||||||
# Description:
|
|
||||||
# This script automates the configuration and installation of
|
|
||||||
# Coral TPU and iGPU support in Proxmox VE containers. It:
|
|
||||||
# - Configures a selected LXC container for hardware acceleration
|
|
||||||
# - Installs and sets up Coral TPU drivers on the Proxmox host
|
|
||||||
# - Installs necessary drivers inside the container
|
|
||||||
# - Manages required system and container restarts
|
|
||||||
#
|
|
||||||
# Supports Coral USB and Coral M.2 (PCIe) devices.
|
|
||||||
# Includes USB passthrough enhancement using persistent udev alias (/dev/coral).
|
|
||||||
# ==========================================================
|
|
||||||
|
|
||||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
|
||||||
BASE_DIR="/usr/local/share/proxmenux"
|
|
||||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
||||||
VENV_PATH="/opt/googletrans-env"
|
|
||||||
|
|
||||||
if [[ -f "$UTILS_FILE" ]]; then
|
|
||||||
source "$UTILS_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
load_language
|
|
||||||
initialize_cache
|
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
|
|
||||||
select_container() {
|
|
||||||
CONTAINERS=$(pct list | awk 'NR>1 {print $1, $3}' | xargs -n2)
|
|
||||||
if [ -z "$CONTAINERS" ]; then
|
|
||||||
msg_error "$(translate 'No containers available in Proxmox.')"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
CONTAINER_ID=$(whiptail --title "$(translate 'Select Container')" \
|
|
||||||
--menu "$(translate 'Select the LXC container:')" 20 70 10 $CONTAINERS 3>&1 1>&2 2>&3)
|
|
||||||
|
|
||||||
if [ -z "$CONTAINER_ID" ]; then
|
|
||||||
msg_error "$(translate 'No container selected. Exiting.')"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! pct list | awk 'NR>1 {print $1}' | grep -qw "$CONTAINER_ID"; then
|
|
||||||
msg_error "$(translate 'Container with ID') $CONTAINER_ID $(translate 'does not exist. Exiting.')"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_ok "$(translate 'Container selected:') $CONTAINER_ID"
|
|
||||||
}
|
|
||||||
|
|
||||||
validate_container_id() {
|
|
||||||
if [ -z "$CONTAINER_ID" ]; then
|
|
||||||
msg_error "$(translate 'Container ID not defined. Make sure to select a container first.')"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if pct status "$CONTAINER_ID" | grep -q "running"; then
|
|
||||||
msg_info "$(translate 'Stopping the container before applying configuration...')"
|
|
||||||
pct stop "$CONTAINER_ID"
|
|
||||||
msg_ok "$(translate 'Container stopped.')"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
add_udev_rule_for_coral_usb_() {
|
|
||||||
RULE_FILE="/etc/udev/rules.d/99-coral-usb.rules"
|
|
||||||
RULE_CONTENT='SUBSYSTEM=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="9302", MODE="0666", TAG+="uaccess"'
|
|
||||||
|
|
||||||
if [[ ! -f "$RULE_FILE" ]] || ! grep -qF "$RULE_CONTENT" "$RULE_FILE"; then
|
|
||||||
echo "$RULE_CONTENT" > "$RULE_FILE"
|
|
||||||
udevadm control --reload-rules && udevadm trigger
|
|
||||||
msg_ok "$(translate 'Udev rule for Coral USB added and rules reloaded.')"
|
|
||||||
else
|
|
||||||
msg_ok "$(translate 'Udev rule for Coral USB already exists.')"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
add_udev_rule_for_coral_usb() {
|
|
||||||
RULE_FILE="/etc/udev/rules.d/99-coral-usb.rules"
|
|
||||||
RULE_CONTENT='# Coral USB Accelerator
|
|
||||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="9302", MODE="0666", TAG+="uaccess", SYMLINK+="coral"
|
|
||||||
# Coral Dev Board / Mini PCIe
|
|
||||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="1a6e", ATTRS{idProduct}=="089a", MODE="0666", TAG+="uaccess", SYMLINK+="coral"'
|
|
||||||
|
|
||||||
if [[ ! -f "$RULE_FILE" ]] || ! grep -q "18d1.*9302\|1a6e.*089a" "$RULE_FILE"; then
|
|
||||||
echo "$RULE_CONTENT" > "$RULE_FILE"
|
|
||||||
udevadm control --reload-rules && udevadm trigger
|
|
||||||
msg_ok "$(translate 'Udev rules for Coral USB devices added and rules reloaded.')"
|
|
||||||
else
|
|
||||||
msg_ok "$(translate 'Udev rules for Coral USB devices already exist.')"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
add_mount_if_needed() {
|
|
||||||
local DEVICE="$1"
|
|
||||||
local DEST="$2"
|
|
||||||
local CONFIG_FILE="$3"
|
|
||||||
if [ -e "$DEVICE" ] && ! grep -q "lxc.mount.entry: $DEVICE" "$CONFIG_FILE"; then
|
|
||||||
echo "lxc.mount.entry: $DEVICE $DEST none bind,optional,create=$( [ -c "$DEVICE" ] && echo file || echo dir )" >> "$CONFIG_FILE"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
configure_lxc_hardware() {
|
|
||||||
validate_container_id
|
|
||||||
CONFIG_FILE="/etc/pve/lxc/${CONTAINER_ID}.conf"
|
|
||||||
if [ ! -f "$CONFIG_FILE" ]; then
|
|
||||||
msg_error "$(translate 'Configuration file for container') $CONTAINER_ID $(translate 'not found.')"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Privileged container
|
|
||||||
if grep -q "^unprivileged: 1" "$CONFIG_FILE"; then
|
|
||||||
msg_info "$(translate 'The container is unprivileged. Changing to privileged...')"
|
|
||||||
sed -i "s/^unprivileged: 1/unprivileged: 0/" "$CONFIG_FILE"
|
|
||||||
STORAGE_TYPE=$(pct config "$CONTAINER_ID" | grep "^rootfs:" | awk -F, '{print $2}' | cut -d'=' -f2)
|
|
||||||
if [[ "$STORAGE_TYPE" == "dir" ]]; then
|
|
||||||
STORAGE_PATH=$(pct config "$CONTAINER_ID" | grep "^rootfs:" | awk '{print $2}' | cut -d',' -f1)
|
|
||||||
chown -R root:root "$STORAGE_PATH"
|
|
||||||
fi
|
|
||||||
msg_ok "$(translate 'Container changed to privileged.')"
|
|
||||||
else
|
|
||||||
msg_ok "$(translate 'The container is already privileged.')"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
sed -i '/^dev[0-9]\+:/d' "$CONFIG_FILE"
|
|
||||||
|
|
||||||
# Enable nesting feature
|
|
||||||
if ! grep -q "features: nesting=1" "$CONFIG_FILE"; then
|
|
||||||
echo "features: nesting=1" >> "$CONFIG_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# iGPU support
|
|
||||||
if ! grep -q "c 226:0 rwm" "$CONFIG_FILE"; then
|
|
||||||
echo "lxc.cgroup2.devices.allow: c 226:0 rwm # iGPU" >> "$CONFIG_FILE"
|
|
||||||
echo "lxc.cgroup2.devices.allow: c 226:128 rwm # iGPU" >> "$CONFIG_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
add_mount_if_needed "/dev/dri" "dev/dri" "$CONFIG_FILE"
|
|
||||||
add_mount_if_needed "/dev/dri/renderD128" "dev/dri/renderD128" "$CONFIG_FILE"
|
|
||||||
add_mount_if_needed "/dev/dri/card0" "dev/dri/card0" "$CONFIG_FILE"
|
|
||||||
|
|
||||||
# Framebuffer support
|
|
||||||
if ! grep -q "c 29:0 rwm # Framebuffer" "$CONFIG_FILE"; then
|
|
||||||
echo "lxc.cgroup2.devices.allow: c 29:0 rwm # Framebuffer" >> "$CONFIG_FILE"
|
|
||||||
fi
|
|
||||||
add_mount_if_needed "/dev/fb0" "dev/fb0" "$CONFIG_FILE"
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------
|
|
||||||
# Coral USB passthrough (via udev + /dev/coral)
|
|
||||||
# ----------------------------------------------------------
|
|
||||||
add_udev_rule_for_coral_usb
|
|
||||||
if ! grep -Pq "^lxc.cgroup2.devices.allow: c 189:\* rwm # Coral USB$" "$CONFIG_FILE"; then
|
|
||||||
echo "lxc.cgroup2.devices.allow: c 189:* rwm # Coral USB" >> "$CONFIG_FILE"
|
|
||||||
fi
|
|
||||||
add_mount_if_needed "/dev/coral" "dev/coral" "$CONFIG_FILE"
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------
|
|
||||||
# Coral M.2 (PCIe) support
|
|
||||||
# ----------------------------------------------------------
|
|
||||||
if lspci | grep -iq "Global Unichip"; then
|
|
||||||
if ! grep -Pq "^lxc.cgroup2.devices.allow: c 245:0 rwm # Coral M2 Apex$" "$CONFIG_FILE"; then
|
|
||||||
echo "lxc.cgroup2.devices.allow: c 245:0 rwm # Coral M2 Apex" >> "$CONFIG_FILE"
|
|
||||||
fi
|
|
||||||
add_mount_if_needed "/dev/apex_0" "dev/apex_0" "$CONFIG_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
msg_ok "$(translate 'Coral TPU and iGPU configuration added to container') $CONTAINER_ID."
|
|
||||||
}
|
|
||||||
|
|
||||||
install_coral_in_container() {
|
|
||||||
msg_info2 "$(translate 'Installing iGPU and Coral TPU drivers inside the container...')"
|
|
||||||
tput sc
|
|
||||||
LOG_FILE=$(mktemp)
|
|
||||||
|
|
||||||
pct start "$CONTAINER_ID"
|
|
||||||
|
|
||||||
CORAL_M2=$(lspci | grep -i "Global Unichip")
|
|
||||||
if [[ -n "$CORAL_M2" ]]; then
|
|
||||||
DRIVER_OPTION=$(whiptail --title "$(translate 'Select driver version')" \
|
|
||||||
--menu "$(translate 'Choose the driver version for Coral M.2:\n\nCaution: Maximum mode generates more heat.')" 15 60 2 \
|
|
||||||
1 "libedgetpu1-std ($(translate 'standard performance'))" \
|
|
||||||
2 "libedgetpu1-max ($(translate 'maximum performance'))" 3>&1 1>&2 2>&3)
|
|
||||||
|
|
||||||
case "$DRIVER_OPTION" in
|
|
||||||
1) DRIVER_PACKAGE="libedgetpu1-std" ;;
|
|
||||||
2) DRIVER_PACKAGE="libedgetpu1-max" ;;
|
|
||||||
*) DRIVER_PACKAGE="libedgetpu1-std" ;;
|
|
||||||
esac
|
|
||||||
else
|
|
||||||
DRIVER_PACKAGE="libedgetpu1-std"
|
|
||||||
fi
|
|
||||||
|
|
||||||
script -q -c "pct exec \"$CONTAINER_ID\" -- bash -c '
|
|
||||||
set -e
|
|
||||||
echo \"- Updating package lists...\"
|
|
||||||
apt-get update
|
|
||||||
echo \"- Installing iGPU drivers...\"
|
|
||||||
apt-get install -y va-driver-all ocl-icd-libopencl1 intel-opencl-icd vainfo intel-gpu-tools
|
|
||||||
chgrp video /dev/dri && chmod 755 /dev/dri
|
|
||||||
adduser root video && adduser root render
|
|
||||||
|
|
||||||
echo \"- Installing Coral TPU dependencies...\"
|
|
||||||
apt-get install -y gnupg python3 python3-pip python3-venv
|
|
||||||
|
|
||||||
echo \"- Adding Coral TPU repository...\"
|
|
||||||
curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/coral-edgetpu.gpg
|
|
||||||
echo \"deb [signed-by=/usr/share/keyrings/coral-edgetpu.gpg] https://packages.cloud.google.com/apt coral-edgetpu-stable main\" | tee /etc/apt/sources.list.d/coral-edgetpu.list
|
|
||||||
|
|
||||||
echo \"- Updating package lists again...\"
|
|
||||||
apt-get update
|
|
||||||
echo \"- Installing Coral TPU driver ($DRIVER_PACKAGE)...\"
|
|
||||||
apt-get install -y $DRIVER_PACKAGE
|
|
||||||
'" "$LOG_FILE"
|
|
||||||
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
tput rc
|
|
||||||
tput ed
|
|
||||||
rm -f "$LOG_FILE"
|
|
||||||
msg_ok "$(translate 'iGPU and Coral TPU drivers installed inside the container.')"
|
|
||||||
else
|
|
||||||
msg_error "$(translate 'Failed to install iGPU and Coral TPU drivers inside the container.')"
|
|
||||||
cat "$LOG_FILE"
|
|
||||||
rm -f "$LOG_FILE"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
select_container
|
|
||||||
show_proxmenux_logo
|
|
||||||
configure_lxc_hardware
|
|
||||||
install_coral_in_container
|
|
||||||
|
|
||||||
msg_ok "$(translate 'Configuration completed.')"
|
|
||||||
echo -e
|
|
||||||
msg_success "$(translate "Press Enter to return to menu...")"
|
|
||||||
read -r
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
|
|
||||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
|
||||||
# ==========================================================
|
|
||||||
# Author : MacRimi
|
|
||||||
# Copyright : (c) 2024 MacRimi
|
|
||||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
|
||||||
# Version : 1.0
|
|
||||||
# Last Updated: 28/01/2025
|
|
||||||
# ==========================================================
|
|
||||||
# Description:
|
|
||||||
# This script installs the Coral TPU drivers on the Proxmox VE host.
|
|
||||||
# It ensures that necessary packages are installed and compiles the
|
|
||||||
# Coral TPU drivers for proper functionality.
|
|
||||||
# ==========================================================
|
|
||||||
|
|
||||||
|
|
||||||
# Configuration ============================================
|
|
||||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
|
||||||
BASE_DIR="/usr/local/share/proxmenux"
|
|
||||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
||||||
VENV_PATH="/opt/googletrans-env"
|
|
||||||
|
|
||||||
if [[ -f "$UTILS_FILE" ]]; then
|
|
||||||
source "$UTILS_FILE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
load_language
|
|
||||||
initialize_cache
|
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
|
|
||||||
|
|
||||||
# Prompt before installation
|
|
||||||
pre_install_prompt() {
|
|
||||||
if ! whiptail --title "$(translate 'Coral TPU Installation')" --yesno "$(translate 'Installing Coral TPU drivers requires rebooting the server after installation. Do you want to proceed?')" 10 70; then
|
|
||||||
msg_warn "$(translate 'Installation cancelled by user.')"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Verify and configure repositories on the host
|
|
||||||
verify_and_add_repos() {
|
|
||||||
msg_info "$(translate 'Configuring necessary repositories on the host...')"
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
if ! grep -q "pve-no-subscription" /etc/apt/sources.list /etc/apt/sources.list.d/* 2>/dev/null; then
|
|
||||||
echo "deb http://download.proxmox.com/debian/pve $(lsb_release -sc) pve-no-subscription" | tee /etc/apt/sources.list.d/pve-no-subscription.list
|
|
||||||
msg_ok "$(translate 'pve-no-subscription repository added.')"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! grep -q "non-free-firmware" /etc/apt/sources.list; then
|
|
||||||
echo "deb http://deb.debian.org/debian $(lsb_release -sc) main contrib non-free-firmware
|
|
||||||
deb http://deb.debian.org/debian $(lsb_release -sc)-updates main contrib non-free-firmware
|
|
||||||
deb http://security.debian.org/debian-security $(lsb_release -sc)-security main contrib non-free-firmware" | tee -a /etc/apt/sources.list
|
|
||||||
msg_ok "$(translate 'non-free-firmware repositories added.')"
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_ok "$(translate 'Added repositories')"
|
|
||||||
sleep 2
|
|
||||||
|
|
||||||
msg_info "$(translate 'Verifying repositories...')"
|
|
||||||
apt-get update &>/dev/null
|
|
||||||
|
|
||||||
msg_ok "$(translate 'Verified and updated repositories.')"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to install Coral TPU drivers on the host
|
|
||||||
install_coral_host() {
|
|
||||||
show_proxmenux_logo
|
|
||||||
verify_and_add_repos
|
|
||||||
|
|
||||||
apt-get install -y git devscripts dh-dkms dkms pve-headers-$(uname -r) >/dev/null 2>&1
|
|
||||||
|
|
||||||
cd /tmp
|
|
||||||
rm -rf gasket-driver
|
|
||||||
git clone https://github.com/google/gasket-driver.git
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
msg_error "$(translate 'Error: Could not clone the repository.')"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd gasket-driver/
|
|
||||||
debuild -us -uc -tc -b
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
msg_error "$(translate 'Error: Failed to build driver packages.')"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
dpkg -i ../gasket-dkms_*.deb
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
msg_error "$(translate 'Error: Failed to install the driver packages.')"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
msg_success "$(translate 'Coral TPU drivers installed successfully on the host.')"
|
|
||||||
echo -e
|
|
||||||
}
|
|
||||||
|
|
||||||
# Prompt for reboot after installation
|
|
||||||
restart_prompt() {
|
|
||||||
if whiptail --title "$(translate 'Coral TPU Installation')" --yesno "$(translate 'The installation requires a server restart to apply changes. Do you want to restart now?')" 10 70; then
|
|
||||||
msg_warn "$(translate 'Restarting the server...')"
|
|
||||||
reboot
|
|
||||||
else
|
|
||||||
echo -e
|
|
||||||
msg_success "$(translate "Press Enter to return to menu...")"
|
|
||||||
read -r
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pre_install_prompt
|
|
||||||
install_coral_host
|
|
||||||
restart_prompt
|
|
||||||
@@ -35,13 +35,13 @@ initialize_cache
|
|||||||
|
|
||||||
case $OPTION in
|
case $OPTION in
|
||||||
1)
|
1)
|
||||||
bash "$LOCAL_SCRIPTS/configure_igpu_lxc.sh"
|
bash "$LOCAL_SCRIPTS/gpu_tpu/configure_igpu_lxc.sh"
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
2)
|
2)
|
||||||
bash "$LOCAL_SCRIPTS/install_coral_lxc.sh"
|
bash "$LOCAL_SCRIPTS/gpu_tpu/install_coral_lxc.sh"
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# ==========================================================
|
|
||||||
# ProxMenux - A menu-driven script for Proxmox VE management
|
|
||||||
# ==========================================================
|
|
||||||
# Author : MacRimi
|
|
||||||
# Copyright : (c) 2024 MacRimi
|
|
||||||
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
|
|
||||||
# Version : 1.0
|
|
||||||
# Last Updated: 28/01/2025
|
|
||||||
# ==========================================================
|
|
||||||
|
|
||||||
|
|
||||||
# Configuration ============================================
|
|
||||||
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
|
||||||
BASE_DIR="/usr/local/share/proxmenux"
|
|
||||||
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
||||||
VENV_PATH="/opt/googletrans-env"
|
|
||||||
|
|
||||||
if [[ -f "$UTILS_FILE" ]]; then
|
|
||||||
source "$UTILS_FILE"
|
|
||||||
fi
|
|
||||||
load_language
|
|
||||||
initialize_cache
|
|
||||||
# ==========================================================
|
|
||||||
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
OPTION=$(whiptail --title "$(translate "Disk and Storage Manager Menu")" --menu "$(translate "Select an option:")" 20 70 10 \
|
|
||||||
"1" "$(translate "Add Disk Passthrough to a VM")" \
|
|
||||||
"2" "$(translate "Add Disk") Passthrough $(translate "to a CT")" \
|
|
||||||
"3" "$(translate "Import Disk Image to a VM")" \
|
|
||||||
"4" "$(translate "Mount point to CT")" \
|
|
||||||
"5" "$(translate "Mount disk on HOST")" \
|
|
||||||
"6" "$(translate "Unmount disk from HOST")" \
|
|
||||||
"7" "$(translate "Format disk")" \
|
|
||||||
"8" "$(translate "Return to Main Menu")" 3>&1 1>&2 2>&3)
|
|
||||||
|
|
||||||
case $OPTION in
|
|
||||||
1)
|
|
||||||
msg_info2 "$(translate "Running script: Add Disk Passthrough to a VM")..."
|
|
||||||
bash "$LOCAL_SCRIPTS/storage/disk-passthrough.sh"
|
|
||||||
;;
|
|
||||||
2)
|
|
||||||
msg_info2 "$(translate "Running script: Add Disk Passthrough to a CT")..."
|
|
||||||
bash "$LOCAL_SCRIPTS/storage/disk-passthrough_ct.sh"
|
|
||||||
;;
|
|
||||||
3)
|
|
||||||
msg_info2 "$(translate "Running script: Import Disk Image to a VM")..."
|
|
||||||
bash "$LOCAL_SCRIPTS/storage/import-disk-image.sh"
|
|
||||||
;;
|
|
||||||
4)
|
|
||||||
msg_info2 "$(translate "Running script: Mount point to CT")..."
|
|
||||||
bash "$LOCAL_SCRIPTS/storage/mount-point-to-ct.sh"
|
|
||||||
;;
|
|
||||||
5)
|
|
||||||
msg_info2 "$(translate "Running script: Mount disk on HOST")..."
|
|
||||||
bash "$LOCAL_SCRIPTS/storage/mount-disk-on-host.sh"
|
|
||||||
;;
|
|
||||||
6)
|
|
||||||
msg_info2 "$(translate "Running script: Unmount disk from HOST")..."
|
|
||||||
bash "$LOCAL_SCRIPTS/storage/unmount-disk-from-host.sh"
|
|
||||||
;;
|
|
||||||
7)
|
|
||||||
msg_info2 "$(translate "Running script: Format disk")..."
|
|
||||||
bash "$LOCAL_SCRIPTS/storage/format-disk.sh"
|
|
||||||
;;
|
|
||||||
8)
|
|
||||||
exec bash "$LOCAL_SCRIPTS/menus/main_menu.sh"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
exec bash "$LOCAL_SCRIPTS/menus/main_menu.sh"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user