Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4b90f8d84 | ||
|
|
472e9c8266 | ||
|
|
cbf686b787 | ||
|
|
e3f2491b56 | ||
|
|
5acc32fb2b | ||
|
|
f614863547 | ||
|
|
49a5d7f317 | ||
|
|
a81013bbc2 | ||
|
|
5432eaad80 | ||
|
|
63f56f8eea | ||
|
|
cc302ed650 | ||
|
|
2d8888138f | ||
|
|
8d3c6e4abd | ||
|
|
f1f16e0826 | ||
|
|
fb9b730355 | ||
|
|
98270007e5 | ||
|
|
3585a6cc1c | ||
|
|
e266fa8c9d | ||
|
|
f4c3f0de0e | ||
|
|
470b1e15d2 | ||
|
|
38a0e9f935 | ||
|
|
e221503cc8 | ||
|
|
7851db7cad | ||
|
|
efe73f8a28 | ||
|
|
f612c84897 | ||
|
|
ea985a2d37 | ||
|
|
60d0a67d40 | ||
|
|
aa54e51c7b | ||
|
|
0f64b5b835 | ||
|
|
b054965528 | ||
|
|
0634a17cdc | ||
|
|
fb08f8ac36 | ||
|
|
86fbffd0b6 | ||
|
|
1e01f1b1a9 | ||
|
|
ecb6a4aa51 | ||
|
|
335ff949be | ||
|
|
3d9bff7e9c | ||
|
|
5d2dfc273e | ||
|
|
7ee297e562 | ||
|
|
22809ce9b3 | ||
|
|
4ae70047ab | ||
|
|
b8266f7f8c | ||
|
|
fe6c1bae56 | ||
|
|
1718d17e5a | ||
|
|
f1e701ac02 | ||
|
|
5d97d34ab1 | ||
|
|
5624ef1bac | ||
|
|
a6e98b75a9 | ||
|
|
4af6008317 | ||
|
|
2d798d1a0e | ||
|
|
655ee29e10 | ||
|
|
5a7c823c40 | ||
|
|
caa173cef4 | ||
|
|
0fd26ef72a | ||
|
|
deedc53eb0 | ||
|
|
d14ee3ce0e | ||
|
|
5f8534e1a9 | ||
|
|
ec1f4fa6e7 | ||
|
|
9d30365d5e | ||
|
|
05e21eb441 | ||
|
|
c7474af62a | ||
|
|
03adc10597 | ||
|
|
e4fe986a6b | ||
|
|
69787b823c | ||
|
|
171eadce0d | ||
|
|
28921ab03d | ||
|
|
ad6aac64f8 | ||
|
|
8e4a3c56d0 |
77
CHANGELOG.md
@@ -5,6 +5,83 @@ All notable changes to Proxmox VE for WHMCS will be documented in this file.
|
||||
|
||||
https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/milestones
|
||||
|
||||
## [1.2.17] - 2025-10-19 - _"VNC & Hyperscale!"_
|
||||
|
||||
### 💅 Polish
|
||||
- Max Memory: Ensure you can set more than 128GB (#169)
|
||||
- Max CPUs/Cores: Expand column to allow for 100+ (#169)
|
||||
- VNC Prepared: Green background with clearer wording (#167)
|
||||
- Check Status: Allow for client-driven status checks (#168)
|
||||
|
||||
### 🐛 Bug Fix
|
||||
- noVNC: Delete PVEAuthCookie before setting it (#167)
|
||||
- noVNC: PVEAuthCookie is secure & samesite=None (#167)
|
||||
- SQL -> Plans: Expand several fields (future-proof) (#169)
|
||||
|
||||
## [1.2.16] - 2025-10-15 - _"Minor Adjustments"_
|
||||
|
||||
### 💅 Polish
|
||||
- WHMCS Parameter: RequiresServer set to true
|
||||
- Plan Add/Edit: Text descriptions updated
|
||||
- Update Available: Hyperlinked to repo
|
||||
- Admin GUI: Textual layout updates
|
||||
- Servers: PVE Button updated text
|
||||
- README: Final resting milestone
|
||||
|
||||
## [1.2.15] - 2025-08-29 - _"Little Adjustments"_
|
||||
|
||||
### 💅 Polish
|
||||
- NIC #2: Split info (MAC, link status, etc) to multiple lines
|
||||
- SQL Expansion: Prepare for Nodes/ISOs/TPLs/Logs/SSH Keys/etc
|
||||
- Deactivation Keeps Data: No table drops on de-activate (#160)
|
||||
|
||||
### 🐛 Bug Fix
|
||||
- Function Rename: hash_encryption to pvewhmcs_hash_encryption (#159)
|
||||
|
||||
## [1.2.14] - 2025-08-19 - _"Client Area tidy"_
|
||||
|
||||
### 🚀 Feature
|
||||
- Cluster Tasks: Show the cluster history in Admin GUI (#50)
|
||||
|
||||
### 💅 Polish
|
||||
- Admin Area, Server Test: Renamed to "Proxmox VE" for brevity
|
||||
- Admin Area, Pane Titles: Renamed most panes to make it simpler
|
||||
- Client Area: Improved layout and formatting of Guest Info (#155)
|
||||
- Client Area: Improved naming and ordering of Actions menu (#157)
|
||||
- Client Area: Updated 64x64px icons for Running/Suspended/Offline
|
||||
|
||||
### 🐛 Bug Fix
|
||||
- Client Area, Swap %: "NaN%" replaced with "0%" for QEMU (#154)
|
||||
|
||||
## [1.2.13] - 2025-08-13 - _"Little Things"_
|
||||
|
||||
### 💅 Polish
|
||||
- Connection Test: Module shows as "Proxmox VE for WHMCS" (#151)
|
||||
- Apps/Integrations: Now shown with logo & some info (whmcs.json)
|
||||
- WHMCS Admin > Servers: Added a PVE GUI link for each node (#152)
|
||||
|
||||
## [1.2.12] - 2025-08-12 - _"Adjustments"_
|
||||
|
||||
### 🚀 Feature
|
||||
- Cluster / Guest Resources: Add into the Admin GUI (#139)
|
||||
|
||||
### 💅 Polish
|
||||
- Unprivileged CT: At-create-only security option (#105)
|
||||
- Client Area: Running/Suspended/Stopped new icons (#149)
|
||||
|
||||
### 🐛 Bug Fix
|
||||
- Blanket $0.00: Apply fixed nil amount properly (#148)
|
||||
- Import Guest QEMU not KVM: Proper value stored (#150)
|
||||
|
||||
## [1.2.11] - 2025-08-05 - _"Start VMID OK"_
|
||||
|
||||
### 💅 Polish
|
||||
- Virtio Networking: Default set, instead of Intel E1000
|
||||
|
||||
### 🐛 Bug Fix
|
||||
- Start VMID: Change method to `/cluster/nextid` (#145)
|
||||
- Actions & Client Area: Final changes to VMID (#146)
|
||||
|
||||
## [1.2.10] - 2025-07-31 - _"Import Friendly"_
|
||||
|
||||
### 🚀 Feature
|
||||
|
||||
265
README.md
@@ -1,14 +1,14 @@
|
||||
# Proxmox VE for WHMCS (Module) Provision & Manage
|
||||
|
||||
<img alt="Logo for the Proxmox VE for WHMCS module" src="zLOGO.png">
|
||||
<img alt="Logo for the Proxmox VE for WHMCS module" src="_images/logo-pvewhmcs.png">
|
||||
|
||||
**Salvation, a free and open-source solution for beloved PVE!** If you love it, REVIEW & SHARE IT! ❤️
|
||||
**Salvation, a free and open-source solution for beloved PVE!** If you love it, REVIEW & SHARE IT! Cheers. ❤️
|
||||
|
||||
TNC Dev are looking for a co-developer to assist with finishing the project overhaul.
|
||||
If you have proven and public git-logged experience, or similar, please say g'day.
|
||||
|
||||
Please note: We are only looking for high-quality applicants with spare time.
|
||||
As it stands, we won't have much spare dev time for PVEWHMCS in 2025.
|
||||
As it stands, we won't have much spare dev time for this Module in 2025.
|
||||
|
||||
- Configure VM/CT plans with custom CPU/RAM/VLAN/On-boot/Bandwidth/etc
|
||||
- Automatically Provision VMs & CTs in **Proxmox VE** from **WHMCS** easily
|
||||
@@ -17,15 +17,22 @@
|
||||
- Statistics/Graphing is available in the Client Area for services :)
|
||||
- Leverage the power of QEMU & LXC with PVE's convenience
|
||||
- Import existing VM/CT Guest from Proxmox into WHMCS
|
||||
- Specify PVE VMID start & integrate to your schema
|
||||
- Choose PVE VMID start & integrate to your schema
|
||||
- Supports 128GB+ RAM & 128+ CPU cores per Guest!
|
||||
|
||||
Repo: https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/
|
||||
https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/
|
||||
|
||||
**Client Area GUI - Landing:**
|
||||
|
||||
<img alt="Client Area GUI showing management of a powered-on VM" src="_images/zVMclientGUI.png">
|
||||
|
||||
**Admin Area GUI - Landing:**
|
||||
|
||||
<img alt="Admin Area GUI for the Module, showing the Nodes & Guests" src="_images/zClusterGuests.png">
|
||||
|
||||
# ❤️ RTFM: Read the Manual & Review the Module!
|
||||
|
||||
**Please read the entire README.md file before getting started with Proxmox VE for WHMCS.** Thanks!
|
||||
|
||||
We're pretty much done overhauling the Module to suit our needs at The Network Crew Pty Ltd & Merlot Digital.
|
||||
**Please read the entire README.md file before getting started with Proxmox VE for WHMCS (`pvewhmcs`).**
|
||||
|
||||
> **Please review the module!** https://marketplace.whmcs.com/product/6935-proxmox-ve-for-whmcs#reviews
|
||||
>
|
||||
@@ -41,14 +48,16 @@ We're pretty much done overhauling the Module to suit our needs at The Network C
|
||||
- **(Proxmox)** 2 users (API & VNC)
|
||||
- **(Proxmox)** VE v8.x.x (current)
|
||||
|
||||
Please note specific VNC & Network requirements below - read 100% of the README.md. :-)
|
||||
|
||||
# ✅ MODULE: Installation & Configuration
|
||||
|
||||
> [!WARNING]
|
||||
> **DON'T SKIP ANY PART OF THIS README.md - please don't raise pointless Issues - thank you!**
|
||||
> **DON'T SKIP ANY PART OF THIS README.md & please don't raise pointless Issues - thank you!**
|
||||
|
||||
## 📋 1. PREP: Upload & Configure the Module
|
||||
|
||||
Check the System Requirements above, and resolve any blockers to using Proxmox VE for WHMCS.
|
||||
**First, read the above System Requirements, and resolve any blockers to using Proxmox VE for WHMCS.**
|
||||
|
||||
### 👥 PVE: User x2 Requirement (API & VNC users)
|
||||
|
||||
@@ -56,7 +65,7 @@ Check the System Requirements above, and resolve any blockers to using Proxmox V
|
||||
|
||||
**You must have a root account to use the Module at all.** Configured via WHMCS > Servers.
|
||||
|
||||
This is configured in the pam realm. We plan to allow selection in v1.3.x.
|
||||
This is configured in the `pam` realm.
|
||||
|
||||
#### Credentials: VNC user for Console Access only
|
||||
|
||||
@@ -64,9 +73,11 @@ Additionally, to improve security, for VNC you must also have a Restricted User.
|
||||
|
||||
Configured in the _Module_ as detailed below, once you've added/restricted it in PVE.
|
||||
|
||||
### 🏃♂️ INSTALL: Getting ready to use the Module!
|
||||
### 🏃♂️ Installing the WHMCS Module `pvewhmcs`
|
||||
|
||||
First up, get the basics sorted out:
|
||||
<img alt="WHMCS Server testing OK for a Proxmox VE (pvewhmcs) server/node" src="_images/zServerTestOK.png">
|
||||
|
||||
**First up, get the basics sorted out:**
|
||||
|
||||
0. Upload the Module to your WHMCS installation, ensuring correct permissions/ownership.
|
||||
1. Activate it via WHMCS > Addon Modules > Proxmox VE for WHMCS > Activate.
|
||||
@@ -74,33 +85,46 @@ First up, get the basics sorted out:
|
||||
3. Make sure your Proxmox host has a valid SSL Certificate installed.
|
||||
4. Ensure you've TCP/8006 connectivity between WHMCS & PVE.
|
||||
|
||||
Once you've done all of that, in order to get the module working properly, you need to:
|
||||
**Once you've done all of that, in order to get the module working properly, you need to:**
|
||||
|
||||
0. Proxmox VE > Create an additional VNC-only user, per instructions below
|
||||
1. WHMCS Admin > Config > Servers > Add (Advanced) > PVE Host/s (User: `root`; IPv4: `PVE's`; no port suffix!)
|
||||
2. WHMCS Admin > Addons > Proxmox VE for WHMCS > Module Config > VNC Secret (see below)
|
||||
3. WHMCS Admin > Addons > Proxmox VE for WHMCS > Add KVM/LXC Plan/s
|
||||
3. WHMCS Admin > Addons > Proxmox VE for WHMCS > Add QEMU/LXC Plan/s
|
||||
4. WHMCS Admin > Addons > Proxmox VE for WHMCS > Add an IPv4 Pool
|
||||
5. WHMCS Admin > Config > Products/Services > New Service (create offering)
|
||||
6. " " > Newly-added Service > Tab 3 > **SAVE** (links Module Plan to WHMCS Service type)
|
||||
7. (Optional) WHMCS Admin > Addons > Proxmox VE for WHMCS > Import Guest
|
||||
|
||||
#### Admin GUI: QEMU Plan :: Creation interface
|
||||
|
||||
<img alt="Plan Creation GUI for adding a new QEMU VM Plan" src="_images/zQEMUplanAdd.png">
|
||||
|
||||
#### Admin GUI: WHMCS Product/Service "Module" SAVE!
|
||||
|
||||
<img alt="Pane/tab where you need to SAVE the module Plan & Pool against the WHMCS Service" src="_images/zProductSave.png">
|
||||
|
||||
#### Admin GUI: WHMCS Servers > Links direct to PVE GUI
|
||||
|
||||
<img alt="WHMCS Admin > Configuration > Servers interface, showing link button to Proxmox GUI, labelled with the PVE hostname" src="_images/zServerListLink.png">
|
||||
|
||||
## 🥽 2. noVNC: Console Tunnel (Client Area)
|
||||
|
||||
After forking the module, we considered how to improve security of Console Tunneling via WHMCS. We decided to implement a routing method which uses a secondary user in Proxmox VE with very restrictive permissions.
|
||||
|
||||
This is due to be re-built again to further enhance security.
|
||||
**This is due to be re-built again in 2026 to further enhance security.**
|
||||
|
||||
### How to offer VNC via WHMCS Client Area
|
||||
### How to offer VNC via WHMCS Client Area!
|
||||
|
||||
1. Install & configure the module properly
|
||||
2. Follow the PVE User Requirement info below
|
||||
3. Public IPv4 for PVE (or proxy to private)
|
||||
4. PVE and WHMCS on the same Domain Name*
|
||||
5. Have valid PTR/rDNS for the PVE Address
|
||||
3. Routed IPv4 for PVE (or TLS-proxy to LAN)
|
||||
4. PVE and WHMCS on the same 1x Domain Name*
|
||||
5. Have valid PTR/rDNS set on the PVE Address
|
||||
|
||||
If proxying, that is your responsibility to diagnose.
|
||||
|
||||
Else, PVE must be WAN-accessible and all other configs/reqs satisfied.
|
||||
> **If proxying, that is your sole responsibility to configure & diagnose.**
|
||||
>
|
||||
> Otherwise, PVE must be WAN-accessible and all other configs/reqs satisfied.
|
||||
|
||||
### Creating the VNC User within Proxmox VE
|
||||
|
||||
@@ -114,13 +138,35 @@ Else, PVE must be WAN-accessible and all other configs/reqs satisfied.
|
||||
> Do NOT set less restrictive permissions. The above is designed for interim security.
|
||||
>
|
||||
> **However, if you wish for proper security: wait for VNC to be further improved.**
|
||||
>
|
||||
> **Note**: Custom WHMCS install folders like /clients/ are not yet VNC-supported. #114
|
||||
|
||||
<img alt="Client Area GUI showing the reply which links off to the VNC Console/Client" src="_images/zConsoleReady.png">
|
||||
|
||||
### Important info about Console Access
|
||||
|
||||
noVNC has been overhauled. It isn't guaranteed, nor the project at all. :-)
|
||||
**noVNC has been overhauled. It isn't guaranteed, nor the project at all. :-)**
|
||||
|
||||
- Note #1 = You must use different Subdomains on the same Domain Name, for the cookie (anti-CSRF).
|
||||
- Note #2 = If your Domain Name has a 2-part TLD (ie. co.uk) then you will need to fork & amend `novnc_router.php` - ideally we/someone will optimise this to better cater to all formats.
|
||||
Once you have it configured, clicking noVNC in Client Area provides direct link - click it:
|
||||
|
||||
<img alt="Client Area is ready for you to click into noVNC terminal console" src="_images/zVNCprepared.png">
|
||||
|
||||
**Here are most of the critical requirements for VNC tunnelling:**
|
||||
|
||||
1. PVE must be at an IPv4 which has PTR the exact same as PVE's hostname.
|
||||
2. You must use different Subdomains on the 1x Domain Name, for the cookie (anti-CSRF).
|
||||
3. If your Domain Name has a 2-part TLD (ie. co.uk) then you will need to fork & amend `novnc_router.php` - ideally we/someone will optimise this down the track.
|
||||
4. You must configure a VNC Secret in the Module Settings, after creating it in PVE.
|
||||
5. You must have a stable and "relatively" static IPv4 fixed/routed WAN address for each PVE host. **CGNAT, Cellular & other "fast DHCP" style configurations cannot be worked with due to a variety of external network issues.** We will not support anything except a perfectly-configured `pvewhmcs`. Thank you!
|
||||
6. Cookies must be properly usable and not manipulated by htaccess or similar rules, to ensure that `PVEAuthCookie` is properly set in-browser, for same-domain cross-subdomain access.
|
||||
|
||||
<img alt="Admin GUI of the Module Config (VNC Secret, Start VMID, Debug Log y/n)" src="_images/zConfiguration.png">
|
||||
|
||||
> [!TIP]
|
||||
> **To troubleshoot noVNC errors like "Connection Closed (1006)":**
|
||||
>
|
||||
> Load noVNC with `logging=debug` added to the query string, ie. `vnc.html?logging=debug`<br>
|
||||
> _Or in Settings change Logging to debug-level, then open JS Console before reloading noVNC._
|
||||
|
||||
## 🌐 3. Networking: IPv4 Pools, IPv6, vmbr/SDN
|
||||
|
||||
@@ -128,21 +174,29 @@ noVNC has been overhauled. It isn't guaranteed, nor the project at all. :-)
|
||||
|
||||
Please make sure you create an IPv4 Pool with sufficient scope/size to be able to deploy addresses within it to your guest VMs and CTs. Else it won't be able to create a Service for you.
|
||||
|
||||
**Private IPs for PVE Hosts:** Note that VNC may be problematic without work due to the strict requirements introduced in Proxmox v8.0 (strict same-site attribute).
|
||||
#### Private IPs for PVE Hosts
|
||||
|
||||
### IPv6: SLAAC default, 2nd vNIC
|
||||
Note that VNC may be problematic without work due to the strict requirements introduced in Proxmox v8.0 (strict same-site attribute). Just as SSL/TLS Certificates are no longer trusted for Public IP Addresses, there is increasing work to make the web secure-by-default which makes VNC/etc safer.
|
||||
|
||||
Per The-Network-Crew/Proxmox-VE-for-WHMCS#33 there's SLAAC/DHCP/off available (2x vNICs) (May 2024).
|
||||
#### Existing Guest Imports from PVE
|
||||
|
||||
You can of course add different config via PVE/`pvesh` manually, if you need to specify a prefix.
|
||||
Take note that during the Guest Import process, there is no association ensured to an IP Pool, rather we take your inputs and use them verbatim due to existing/current nature of the Guest's configuration.
|
||||
|
||||
### IPv6: SLAAC default (via 2nd vNIC)
|
||||
|
||||
Available options:
|
||||
1. **SLAAC** (2nd vNIC)
|
||||
2. **DHCP** (2nd vNIC)
|
||||
3. **Off** (v4-only)
|
||||
|
||||
You may add different config via PVE/`pvesh` manually of course, if you need to specify a prefix etc.
|
||||
|
||||
### vmbr / SDN: Config type
|
||||
|
||||
This depends on your configuration on the PVE Host/s - bridge (vmbr0 etc) or software-defined (SDN).
|
||||
|
||||
**If normal (bridged)** - use `vmbr` as the Network, then use `0` as the Interface ID - this makes up `vmbr0`.
|
||||
|
||||
**If SDN (Software Defined Network)** - use SDN Name for Network, leave Interface ID blank (= no suffix).
|
||||
- **If normal (bridged)** - use `vmbr` as the Network, then use `0` as the Interface ID - this makes up `vmbr0`.
|
||||
- **If SDN (Software Defined Network)** - use SDN Name for Network, leave Interface ID blank (= no suffix).
|
||||
|
||||
## ⚙️ 4. VM/CT PLANS: Setting everything up
|
||||
|
||||
@@ -151,18 +205,20 @@ These steps explain the unique requirements for QEMU & LXC guests.
|
||||
**Custom Fields:** Values need to go in Name & Select Options.<br>
|
||||
This needs configuring for each `WHMCS Admin > Products & Services` entry.
|
||||
|
||||
<img alt="Custom Fields for the Service/Product set the ISO/Template/etc." src="_images/zProductISOetc.png">
|
||||
|
||||
### VM Option 1: QEMU, PVE Template VM Clone
|
||||
|
||||
Firstly, create the Template VM in PVE. You need its unique PVE ID.
|
||||
|
||||
Use that ID in the Custom Field `KVMTemplate`, as in `ID|Name`.
|
||||
|
||||
> Note: `ID` is the Unique ID that your Template VM has in PVE.<br>
|
||||
> Note: `Name` is what will be displayed to your Clients in WHMCS.
|
||||
> **Note**: `ID` is the Unique ID that your Template VM has in PVE.<br>
|
||||
> **Note**: `Name` is what will be displayed to your Clients in WHMCS.
|
||||
|
||||
### VM Option 2: QEMU, WHMCS Plan + PVE ISO
|
||||
|
||||
Firstly, create the Plan in WHMCS Module. Then, WHMCS Config > Services.
|
||||
Firstly, create the Plan in WHMCS Module. Then too in WHMCS Config > Services.
|
||||
|
||||
> Under the Service, you need to add a Custom Field `ISO` with the full location.<br>
|
||||
> This ISO must be located on the PVE Host, and not on the WHMCS installation side.
|
||||
@@ -178,37 +234,65 @@ Firstly, store the Template in PVE. You need its storage, folder & File Name.
|
||||
|
||||
You can associate an existing PVE Guest through the WHMCS Module too, like this:
|
||||
|
||||
<img alt="Importing GUI for linking to existing PVE Guest" src="zVMIDimport.png">
|
||||
<img alt="Importing GUI for linking to existing PVE Guest" src="_images/zVMIDimport.png">
|
||||
|
||||
#### ZFS etc: Comfigure to suit isolated TPL
|
||||
> [!CAUTION]
|
||||
> All module-imported services need to be checked and amended to ensure configs such as Billing Cycle, Price, Discount, Assigned IPs, NS1/2, etc, are properly set!
|
||||
|
||||
### Custom Fields: Important Notes (ZFS/CTs)
|
||||
|
||||
#### ZFS etc: Configure to suit isolated TPLs
|
||||
|
||||
- `local` is the name of the file-system that you have the Template on
|
||||
- `vztmpl` is the directoty name per convention, with the ISO within
|
||||
- `ubuntu-99.99-...` etc is the Template file name, exactly as-is
|
||||
|
||||
ie. If using ZFS for Templates, substitute local with volume name.
|
||||
If using ZFS for Templates, substitute `local` with the volume name.
|
||||
|
||||
#### Password: Configure the CT's root user
|
||||
|
||||
Make a 2nd Custom Field `Password` for the CT's root user.
|
||||
Create a 2nd Custom Field `Password` for the Container's root user on all CT Services.
|
||||
|
||||
## 🔄 5. PATCH: Updating the Module
|
||||
|
||||
**Check:** `WHMCS Admin > Addon Modules > Proxmox VE for WHMCS > Support/Health`
|
||||
### Regularly check for updates
|
||||
|
||||
You should download any new version & upload it over the top, then login to WHMCS Admin.
|
||||
**WHMCS Admin -> Addon Modules -> Proxmox VE for WHMCS -> Support/Health**
|
||||
|
||||
### Updating to a newer release!
|
||||
|
||||
1. Download the new version
|
||||
2. Upload it over the top (FTP)
|
||||
3. Login to WHMCS Admin
|
||||
4. Verify all working OK
|
||||
5. **Watch the repo!**
|
||||
|
||||
> **Logging in _should_ trigger the self-upgrade procedure for the SQL database.**
|
||||
>
|
||||
> (**Beta in v1.2.x:** for now, verify yourself that updates were successful)
|
||||
|
||||
### SQL: Keeping your DB up-to-date
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Since v1.3.0, logging into WHMCS Admin & opening the module should run any needed SQL Ops.
|
||||
>
|
||||
> v1.2.9 & below, consult the **UPDATE-SQL.md** file, open your SQL DB & run statements.
|
||||
> v1.2.9 & below, consult the **_docs/UPDATE-SQL.md** file, open your SQL DB & run statements.
|
||||
|
||||
Then you're done with each update! :-)
|
||||
Then you're done with each update!
|
||||
|
||||
_**Note**: db.sql file currently contains new tables for v1.3.x releases as well_
|
||||
|
||||
<img alt="Admin GUI of the Support/Health page (an available update is highlighted)" src="_images/zPatchAvailable.png">
|
||||
|
||||
## 🆘 6. HELP: Best-effort Support
|
||||
|
||||
> [!WARNING]
|
||||
> We will not support ANY set-ups which do not follow ALL of the set-up processes 100%.
|
||||
>
|
||||
> Read the ENTIRE README, understand it, follow it, and submit detailed Issues.
|
||||
>
|
||||
> Else, do not expect any form of Support. Respect our time. Thank you!
|
||||
|
||||
### Before raising a GitHub Issue, please check:
|
||||
|
||||
1. The Wiki.
|
||||
@@ -222,6 +306,8 @@ Then you're done with each update! :-)
|
||||
|
||||
**Logs:** We work to ensure that Proxmox VE for WHMCS passes through error details to you.
|
||||
|
||||
Hence, we ask that you are as verbose and thorough as possible when reporting Issues. Thanks!
|
||||
|
||||
#### All Logs & Debug Logging too
|
||||
|
||||
- **(Logs: PHP)** `error_log` contents
|
||||
@@ -229,6 +315,8 @@ Then you're done with each update! :-)
|
||||
- **(Logs: Config)** WHMCS Display/Log Errors = ON
|
||||
- **(Logs: PVE)** Logs from Proxmox Host/s (`pveproxy` etc)
|
||||
|
||||
<img alt="Admin GUI of the WHMCS Module Debug Log interface" src="_images/zModuleDebug.png">
|
||||
|
||||
#### Other Requirements for Support
|
||||
|
||||
- **(Visibility)** Screenshots of the issue
|
||||
@@ -237,16 +325,18 @@ Then you're done with each update! :-)
|
||||
- **(Network)** Proof WHMCS Server can talk to PVE OK
|
||||
- **(PEBKAC)** _PROOF THAT YOU'VE FOLLOWED THIS README!_
|
||||
|
||||
The more info/context you provide up-front, the quicker & easier it will be!
|
||||
**The more info & context you provide up-front, the quicker & easier it will be!**
|
||||
|
||||
\* Debug: Also enable Debug Logging in Proxmox VE for WHMCS > Settings, as needed.
|
||||
|
||||
> [!TIP]
|
||||
> **Please note that this is FOSS and Support is not guaranteed at all.**<br>
|
||||
>
|
||||
> **If you don't read, listen or actively try, no help is given.**
|
||||
> **If you don't read, listen or actively try, no help will be provided.**
|
||||
>
|
||||
> https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/issues/new/choose
|
||||
|
||||
https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/issues/new/choose
|
||||
<img alt="Admin GUI showing the Cluster History (PVE Task) log" src="_images/zClusterHistory.png">
|
||||
|
||||
# 💅 FEATURES: Upcoming PVE bling
|
||||
|
||||
@@ -254,67 +344,56 @@ There are new features deployed into PVE upstream which are exciting and may be
|
||||
|
||||
**PVE Roadmap:** https://pve.proxmox.com/wiki/Roadmap
|
||||
|
||||
### Proxmox v9.0 beta
|
||||
### Proxmox v9.x
|
||||
|
||||
1. VM snapshots on thick LVM, snapshots as volume chains
|
||||
2. Fabrics for software networking (SDN) Open/OSPF/Ceph/VPN
|
||||
3. Major upgrade to Debian Trixie (testing status in 2025)
|
||||
|
||||
### Proxmox v8.4
|
||||
### Proxmox v8.x
|
||||
|
||||
1. Live migrate with mediated devices.
|
||||
2. Support for external backup providers.
|
||||
3. Host dir's, share with guests (virtiofs).
|
||||
|
||||
### Proxmox v8.3
|
||||
|
||||
1. Software-defined Networking/Firewall.
|
||||
2. Better guest importing from OVA/OVF.
|
||||
3. Webhook target for system alerting.
|
||||
4. Better change detection for PBS.
|
||||
|
||||
### Proxmox v8.2
|
||||
|
||||
1. Import Wizard for Guests.
|
||||
2. Unattended PVE Install (answer file).
|
||||
3. Backup Fleecing (local disk as data block buffer).
|
||||
4. Firewall Preview (based on nftables).
|
||||
|
||||
### Proxmox v8.1
|
||||
|
||||
1. Secure Boot support.
|
||||
2. Software Defined Networking (SDN).
|
||||
3. New flexible notification system (SMTP & Gotify).
|
||||
4. MAC Organizationally Unique Identifier (OUI) BC:24:11: prefix!
|
||||
|
||||
### Proxmox v8.0
|
||||
|
||||
1. Create, manage and assign resource mappings for PCI and USB devices for use in virtual machines (VMs) via API and web UI.
|
||||
2. (DONE) Add virtual machine CPU models based on the x86-64 psABI Micro-Architecture Levels and use the widely supported x86-64-v2-AES as default for new VMs created via the web UI.
|
||||
1. Live migrate with mediated devices
|
||||
2. Support for external Backup providers
|
||||
3. Host dir's, share with guests (virtiofs)
|
||||
4. Firewall into Software-defined Networking
|
||||
5. Webhook target for system alerting
|
||||
6. Better change detection for PBS
|
||||
7. (✅) Import Wizard for VMware/etc Guests
|
||||
8. Unattended PVE Install (via answer file)
|
||||
9. Backup Fleecing (local disk as data block buffer)
|
||||
10. Secure Boot support
|
||||
11. (✅) Software Defined Networking (SDN)
|
||||
12. New flexible notification system (SMTP & Gotify)
|
||||
13. MAC Organizationally Unique Identifier (OUI) BC:24:11: prefix!
|
||||
14. Create, manage & assign resource mappings for PCI & USB devices for use in VMs via API and GUI
|
||||
15. (✅) Add CPUs (x86-64 psABI Micro-Architecture Levels) & adopt default x86-64-v2-AES
|
||||
|
||||
### Proxmox 7.x
|
||||
|
||||
1. Cross-cluster guest migrations
|
||||
2. Cluster Resource Scheduling (CRS) launched
|
||||
3. Re-balance CRS on fresh start-up, not just recovery
|
||||
3. Re-balance CRS on fresh start-up, not just on-recovery
|
||||
4. CRM into HA Manager, as a node maintenance switch
|
||||
5. Proxmox Offline Mirror (POM) launched
|
||||
|
||||
# 🖥️ INC: Libraries & Dependencies
|
||||
|
||||
- **(MIT)** PHP Client for PVE2 API (Dec 5th, 2022) https://github.com/CpuID/pve2-api-php-client
|
||||
- **(GPLv2)** TigerVNC VncViewer.jar (v1.15.0 in repo) https://sourceforge.net/projects/tigervnc/files/stable/
|
||||
- **(MPLv2)** noVNC HTML5 Viewer (v1.6.0 in repo) https://github.com/novnc/noVNC
|
||||
- **(GPLv3)** SPICE HTML5 Viewer (v0.3 in repo) https://gitlab.freedesktop.org/spice/spice-html5
|
||||
- **(MIT)** IPv4/SN Validation (August 2012) https://github.com/tapmodo/php-ipv4/
|
||||
| License | Dependency | In-use Ver. | Link to Repository, etc.|
|
||||
|---------|------------|-------------|-------------------------|
|
||||
| **(MIT)** | PHP Client for PVE2 API | **2022/Dec/05** | https://github.com/CpuID/pve2-api-php-client |
|
||||
| **(GPLv2)** | TigerVNC VncViewer.jar | **v1.15.0** | https://sourceforge.net/projects/tigervnc/files/stable/ |
|
||||
| **(MPLv2)** | noVNC HTML5 Viewer | **v1.6.0** | https://github.com/novnc/noVNC/ |
|
||||
| **(GPLv3)** | SPICE HTML5 Viewer | **v0.3** | https://gitlab.freedesktop.org/spice/spice-html5/ |
|
||||
| **(MIT)** | IPv4/SN Validation | **August 2012** | https://github.com/tapmodo/php-ipv4/ |
|
||||
|
||||
# 📄 DIY: Documentation & Resources
|
||||
|
||||
- **(Proxmox API)** https://pve.proxmox.com/pve-docs/api-viewer/
|
||||
- **(TigerVNC)** https://github.com/TigerVNC/tigervnc/wiki
|
||||
- **(noVNC)** https://github.com/novnc/noVNC/wiki
|
||||
- **(WHMCS)** https://developers.whmcs.com/
|
||||
- **(x86-64-ABI)** https://gitlab.com/x86-psABIs/x86-64-ABI/-/jobs/artifacts/master/raw/x86-64-ABI/abi.pdf?job=build
|
||||
| Developer | Link to Documentation, etc. |
|
||||
|-----------|-----------------------------|
|
||||
| **(PVE API)** | https://pve.proxmox.com/pve-docs/api-viewer/ |
|
||||
| **(TigerVNC)** | https://github.com/TigerVNC/tigervnc/wiki |
|
||||
| **(noVNC)** | https://github.com/novnc/noVNC/wiki |
|
||||
| **(WHMCS)** | https://developers.whmcs.com & https://classdocs.whmcs.com |
|
||||
| **(psABIs)** | https://gitlab.com/x86-psABIs/x86-64-ABI/-/jobs/artifacts/master/raw/x86-64-ABI/abi.pdf?job=build |
|
||||
|
||||
# 🤬 ABUSE: Zero Tolerance (ZT)
|
||||
|
||||
@@ -328,13 +407,11 @@ If you cannot accept this, do not download nor use the code. Complaints, nasty r
|
||||
|
||||
# 🎉 FOSS: Open-source Contributions
|
||||
|
||||
If you'd like to contribute to the Module, please open a Pull on GitHub >> The-Network-Crew/Proxmox-VE-for-WHMCS
|
||||
|
||||
_The original module was written in 2 months by @cybercoder for sale online in 2016, though didn't sell any copies so they kindly open-sourced it and removed the licensing requirement._
|
||||
If you'd like to contribute to the Module, please open a Pull on GitHub >> The-Network-Crew/Proxmox-VE-for-WHMCS >> cheers! _The original module was written in 2 months by @cybercoder for sale online in 2016, though didn't sell any copies so they kindly open-sourced it and removed the licensing requirement._
|
||||
|
||||
**Thank you to psyborg® for the module's logo design! We love it.**
|
||||
|
||||
FOSS is only possible thanks to dedicated people around the world!
|
||||
FOSS is only possible thanks to dedicated people around the world! :-)
|
||||
|
||||
**See [CONTRIBUTORS.md](https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/blob/master/CONTRIBUTORS.md) for those who've made PVEWHMCS possible.**
|
||||
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# SQL Statements for Updates (nav to DB first)
|
||||
|
||||
## v1.2.14 & onwards...
|
||||
|
||||
> [!NOTE]
|
||||
> As we transition to auto-updating, you can interpret manual queries in the `pvewhmcs_upgrade` function.
|
||||
>
|
||||
> It is located in the /modules/addons/pvewhmcs/pvewhmcs.php file near-ish the top. Thank you.
|
||||
|
||||
## v1.2.10 to v1.2.12
|
||||
|
||||
```
|
||||
ALTER TABLE mod_pvewhmcs_plans ADD COLUMN `unpriv` int(1) unsigned DEFAULT 0;
|
||||
```
|
||||
|
||||
## v1.2.8 to v1.2.10
|
||||
|
||||
```
|
||||
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
BIN
_images/zClusterGuests.png
Normal file
|
After Width: | Height: | Size: 138 KiB |
BIN
_images/zClusterHistory.png
Normal file
|
After Width: | Height: | Size: 469 KiB |
BIN
_images/zConfiguration.png
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
_images/zConsoleReady.png
Normal file
|
After Width: | Height: | Size: 119 KiB |
BIN
_images/zModuleDebug.png
Normal file
|
After Width: | Height: | Size: 226 KiB |
BIN
_images/zPatchAvailable.png
Normal file
|
After Width: | Height: | Size: 218 KiB |
BIN
_images/zProductISOetc.png
Normal file
|
After Width: | Height: | Size: 162 KiB |
BIN
_images/zProductSave.png
Normal file
|
After Width: | Height: | Size: 179 KiB |
BIN
_images/zQEMUplanAdd.png
Normal file
|
After Width: | Height: | Size: 291 KiB |
BIN
_images/zServerListLink.png
Normal file
|
After Width: | Height: | Size: 381 KiB |
BIN
_images/zServerTestOK.png
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
_images/zVMIDimport.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
_images/zVMclientGUI.png
Normal file
|
After Width: | Height: | Size: 294 KiB |
BIN
_images/zVNCprepared.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
@@ -25,7 +25,7 @@ CREATE TABLE IF NOT EXISTS `mod_pvewhmcs_iso` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`title` varchar(255) NOT NULL,
|
||||
`storage` varchar(20) NOT NULL DEFAULT 'local',
|
||||
`iso-name` varchar(255) NOT NULL,
|
||||
`iso_name` varchar(255) NOT NULL,
|
||||
`nodes` int(11) DEFAULT '0',
|
||||
`created` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
@@ -50,10 +50,16 @@ CREATE TABLE IF NOT EXISTS `mod_pvewhmcs_nodes` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`pve_id` int(11) NOT NULL,
|
||||
`pve_name` varchar(255) NOT NULL,
|
||||
`whmcs_id` int(11) NOT NULL,
|
||||
`title` varchar(255) NOT NULL,
|
||||
`ip` varchar(100) NOT NULL,
|
||||
`capacity` int(5) NOT NULL DEFAULT '20',
|
||||
`pve_ver` varchar(20) NOT NULL DEFAULT '9.0.0',
|
||||
`status` varchar(20) NOT NULL DEFAULT 'active',
|
||||
`max_guests` int(5) NOT NULL DEFAULT '20',
|
||||
`health` text DEFAULT NULL,
|
||||
`load_avg` varchar(100) DEFAULT NULL,
|
||||
`load_crs` varchar(255) DEFAULT NULL,
|
||||
`notifiers` text DEFAULT NULL,
|
||||
`resources` text DEFAULT NULL,
|
||||
`supports` varchar(255) NOT NULL DEFAULT 'vm,ct',
|
||||
`templates` varchar(1000) NOT NULL DEFAULT '',
|
||||
@@ -65,14 +71,14 @@ CREATE TABLE IF NOT EXISTS `mod_pvewhmcs_plans` (
|
||||
`title` varchar(255) CHARACTER SET utf8 NOT NULL,
|
||||
`vmtype` varchar(8) NOT NULL,
|
||||
`ostype` varchar(8) DEFAULT NULL,
|
||||
`cpus` tinyint(2) unsigned DEFAULT NULL,
|
||||
`cpus` smallint(4) unsigned DEFAULT NULL,
|
||||
`cpuemu` varchar(30) CHARACTER SET utf8 DEFAULT NULL,
|
||||
`cores` tinyint(2) unsigned DEFAULT NULL,
|
||||
`cores` smallint(4) unsigned DEFAULT NULL,
|
||||
`cpulimit` smallint(5) unsigned DEFAULT NULL,
|
||||
`cpuunits` smallint(5) unsigned DEFAULT NULL,
|
||||
`memory` smallint(5) unsigned NOT NULL,
|
||||
`swap` smallint(5) unsigned DEFAULT NULL,
|
||||
`disk` smallint(5) unsigned DEFAULT NULL,
|
||||
`memory` int(10) unsigned NOT NULL,
|
||||
`swap` int(10) unsigned DEFAULT NULL,
|
||||
`disk` int(10) unsigned DEFAULT NULL,
|
||||
`diskformat` varchar(10) DEFAULT NULL,
|
||||
`diskcache` varchar(20) DEFAULT NULL,
|
||||
`disktype` varchar(20) DEFAULT NULL,
|
||||
@@ -80,23 +86,24 @@ CREATE TABLE IF NOT EXISTS `mod_pvewhmcs_plans` (
|
||||
`diskio` varchar(20) DEFAULT '0',
|
||||
`netmode` varchar(10) DEFAULT NULL,
|
||||
`bridge` varchar(20) NOT NULL DEFAULT 'vmbr',
|
||||
`vmbr` tinyint(1) unsigned DEFAULT NULL,
|
||||
`vmbr` tinyint(3) unsigned DEFAULT NULL,
|
||||
`netmodel` varchar(10) DEFAULT NULL,
|
||||
`netrate` varchar(5) DEFAULT '0',
|
||||
`netrate` int(10) DEFAULT '0',
|
||||
`firewall` tinyint(1) unsigned NOT NULL DEFAULT 0,
|
||||
`bw` int(6) unsigned DEFAULT 0,
|
||||
`bw` int(10) unsigned DEFAULT 0,
|
||||
`kvm` tinyint(1) unsigned DEFAULT 0,
|
||||
`onboot` tinyint(1) unsigned DEFAULT 0,
|
||||
`vlanid` varchar(10) DEFAULT NULL,
|
||||
`vlanid` int(10) DEFAULT NULL,
|
||||
`ipv6` varchar(10) DEFAULT 'auto',
|
||||
`balloon` varchar(10) DEFAULT '0',
|
||||
`balloon` int(10) DEFAULT '0',
|
||||
`unpriv` tinyint(1) unsigned DEFAULT 0,
|
||||
`ssh-keys` varchar(100) DEFAULT '',
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS `mod_pvewhmcs_ssh_keys` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`title` varchar(255) NOT NULL DEFAULT '',
|
||||
`ssh-key` text NOT NULL,
|
||||
`ssh_key` text NOT NULL,
|
||||
`created` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
@@ -36,7 +36,7 @@ function pvewhmcs_config() {
|
||||
$configarray = array(
|
||||
"name" => "Proxmox VE for WHMCS",
|
||||
"description" => "Proxmox VE (Virtual Environment) & WHMCS, integrated & open-source! Provisioning & Management of VMs/CTs.".is_pvewhmcs_outdated(),
|
||||
"version" => "1.2.10",
|
||||
"version" => pvewhmcs_version(),
|
||||
"author" => "The Network Crew Pty Ltd",
|
||||
'language' => 'English'
|
||||
);
|
||||
@@ -45,7 +45,7 @@ function pvewhmcs_config() {
|
||||
|
||||
// VERSION: also stored in repo/version (for update-available checker)
|
||||
function pvewhmcs_version(){
|
||||
return "1.2.10";
|
||||
return "1.2.17";
|
||||
}
|
||||
|
||||
// WHMCS MODULE: ACTIVATION of the ADDON MODULE
|
||||
@@ -79,15 +79,18 @@ function pvewhmcs_activate() {
|
||||
// WHMCS MODULE: DEACTIVATION
|
||||
function pvewhmcs_deactivate() {
|
||||
// Drop all module-related tables
|
||||
Capsule::statement('drop table mod_pvewhmcs_ip_addresses,mod_pvewhmcs_ip_pools,mod_pvewhmcs_plans,mod_pvewhmcs_vms,mod_pvewhmcs');
|
||||
// NOTE: Disabled/Deleted via #160
|
||||
// Capsule::statement('drop table mod_pvewhmcs_ip_addresses,mod_pvewhmcs_ip_pools,mod_pvewhmcs_plans,mod_pvewhmcs_vms,mod_pvewhmcs');
|
||||
|
||||
// Return the assumed result (change?)
|
||||
return array('status'=>'success','description'=>'Proxmox VE for WHMCS successfully deactivated and all related tables deleted.');
|
||||
return array('status'=>'success','description'=>'Proxmox VE for WHMCS successfully deactivated. Database tables/data retained.');
|
||||
}
|
||||
|
||||
// WHMCS MODULE: Upgrade
|
||||
function pvewhmcs_upgrade($vars) {
|
||||
// This function gets passed the old ver once post-update, hence lt check
|
||||
$currentlyInstalledVersion = $vars['version'];
|
||||
|
||||
// SQL Operations for v1.2.9/10 version
|
||||
if (version_compare($currentlyInstalledVersion, '1.2.10', 'lt')) {
|
||||
$schema = Capsule::schema();
|
||||
@@ -110,6 +113,47 @@ function pvewhmcs_upgrade($vars) {
|
||||
->update(['vmid' => Capsule::raw('id')]);
|
||||
}
|
||||
}
|
||||
|
||||
// SQL Operations for v1.2.12 version
|
||||
if (version_compare($currentlyInstalledVersion, '1.2.12', 'lt')) {
|
||||
$schema = Capsule::schema();
|
||||
|
||||
// Add the column "unpriv" to the mod_pvewhmcs_plans table
|
||||
if (!$schema->hasColumn('mod_pvewhmcs_plans', 'unpriv')) {
|
||||
$schema->table('mod_pvewhmcs_plans', function ($table) {
|
||||
$table->integer('unpriv')->default(0)->after('balloon');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// SQL Operations for v1.2.17 version
|
||||
if (version_compare($currentlyInstalledVersion, '1.2.17', 'lt')) {
|
||||
try {
|
||||
Capsule::schema()->table('mod_pvewhmcs_plans', function ($table) {
|
||||
$table->smallInteger('cpus')->unsigned()->nullable()->change();
|
||||
$table->smallInteger('cores')->unsigned()->nullable()->change();
|
||||
$table->integer('memory')->unsigned()->default(0)->change();
|
||||
$table->integer('swap')->unsigned()->nullable()->change();
|
||||
$table->integer('disk')->unsigned()->nullable()->change();
|
||||
$table->tinyInteger('vmbr')->unsigned()->nullable()->change();
|
||||
$table->integer('netrate')->default(0)->change();
|
||||
$table->integer('bw')->unsigned()->default(0)->change();
|
||||
$table->integer('vlanid')->nullable()->change();
|
||||
$table->integer('balloon')->default(0)->change();
|
||||
$table->tinyInteger('unpriv')->unsigned()->default(0)->change();
|
||||
});
|
||||
} catch (\Throwable $e) {
|
||||
// Debug logging (same style as ClientArea)
|
||||
if (Capsule::table('mod_pvewhmcs')->where('id', '1')->value('debug_mode') == 1) {
|
||||
logModuleCall(
|
||||
'pvewhmcs',
|
||||
__FUNCTION__,
|
||||
'Attempting v1.2.17 database upgrade failed.',
|
||||
$e->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UPDATE CHECKER: live vs repo
|
||||
@@ -137,7 +181,7 @@ function pvewhmcs_output($vars) {
|
||||
// Check for update and report if available
|
||||
if (!empty(is_pvewhmcs_outdated())) {
|
||||
$_SESSION['pvewhmcs']['infomsg']['title']='Proxmox VE for WHMCS: New version available!' ;
|
||||
$_SESSION['pvewhmcs']['infomsg']['message']='Please visit the GitHub repository > Releases page. https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/releases' ;
|
||||
$_SESSION['pvewhmcs']['infomsg']['message']='<a href="https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/releases/latest" target="_blank">https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/releases/latest</a>' ;
|
||||
}
|
||||
|
||||
// Print Messages to GUI before anything else
|
||||
@@ -155,19 +199,20 @@ function pvewhmcs_output($vars) {
|
||||
|
||||
// Set the active tab based on the GET parameter, default to 'vmplans'
|
||||
if (!isset($_GET['tab'])) {
|
||||
$_GET['tab'] = 'vmplans';
|
||||
$_GET['tab'] = 'nodes';
|
||||
}
|
||||
|
||||
// Start the HTML output for the Admin GUI
|
||||
echo '
|
||||
<div id="clienttabs">
|
||||
<ul class="nav nav-tabs admin-tabs">
|
||||
<li class="'.($_GET['tab']=="vmplans" ? "active" : "").'"><a id="tabLink1" data-toggle="tab" role="tab" href="#plans">VM/CT Plans</a></li>
|
||||
<li class="'.($_GET['tab']=="ippools" ? "active" : "").'"><a id="tabLink2" data-toggle="tab" role="tab" href="#ippools">IPv4 Pools</a></li>
|
||||
<li class="'.($_GET['tab']=="nodes" ? "active" : "").'"><a id="tabLink3" data-toggle="tab" role="tab" href="#nodes">Nodes / Cluster</a></li>
|
||||
<li class="'.($_GET['tab']=="actions" ? "active" : "").'"><a id="tabLink4" data-toggle="tab" role="tab" href="#actions">Actions / Logs</a></li>
|
||||
<li class="'.($_GET['tab']=="health" ? "active" : "").'"><a id="tabLink5" data-toggle="tab" role="tab" href="#health">Support / Health</a></li>
|
||||
<li class="'.($_GET['tab']=="config" ? "active" : "").'"><a id="tabLink6" data-toggle="tab" role="tab" href="#config">Module Config</a></li>
|
||||
<li class="'.($_GET['tab']=="nodes" ? "active" : "").'"><a id="tabLink1" data-toggle="tab" role="tab" href="#nodes">Nodes & Guests</a></li>
|
||||
<li class="'.($_GET['tab']=="vmplans" ? "active" : "").'"><a id="tabLink2" data-toggle="tab" role="tab" href="#plans">Plans: VM & CT</a></li>
|
||||
<li class="'.($_GET['tab']=="ippools" ? "active" : "").'"><a id="tabLink3" data-toggle="tab" role="tab" href="#ippools">IPv4 Pools</a></li>
|
||||
<li class="'.($_GET['tab']=="actions" ? "active" : "").'"><a id="tabLink4" data-toggle="tab" role="tab" href="#actions">Actions</a></li>
|
||||
<li class="'.($_GET['tab']=="support" ? "active" : "").'"><a id="tabLink5" data-toggle="tab" role="tab" href="#support">Support</a></li>
|
||||
<li class="'.($_GET['tab']=="config" ? "active" : "").'"><a id="tabLink6" data-toggle="tab" role="tab" href="#config">Config</a></li>
|
||||
<li class="'.($_GET['tab']=="logs" ? "active" : "").'"><a id="tabLink7" data-toggle="tab" role="tab" href="#logs">Logs</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content admin-tabs">
|
||||
@@ -193,7 +238,154 @@ function pvewhmcs_output($vars) {
|
||||
save_lxc_plan() ;
|
||||
}
|
||||
|
||||
// VM/CT PLANS tab in ADMIN GUI
|
||||
// NODES / GUESTS tab in ADMIN GUI
|
||||
echo '<div id="nodes" class="tab-pane '.($_GET['tab']=="nodes" ? "active" : "").'" >' ;
|
||||
echo ('<strong><h2>Cluster Members</h2></strong>');
|
||||
|
||||
// Fetch all enabled Servers that use pvewhmcs
|
||||
$servers = Capsule::table('tblservers')
|
||||
->where('type', '=', 'pvewhmcs')
|
||||
->where('disabled', '=', 0)
|
||||
->orderBy('id', 'asc')
|
||||
->get();
|
||||
|
||||
// Catch no-servers case early
|
||||
if ($servers->isEmpty()) {
|
||||
echo '<div class="alert alert-warning">No enabled WHMCS servers found for module type <code>pvewhmcs</code>. Add/enable a server in <em>Setup > Products/Services > Servers</em>.</div>';
|
||||
} else {
|
||||
foreach ($servers as $srv) {
|
||||
// Decrypt server password (same approach as ClientArea)
|
||||
$api_data = array('password2' => $srv->password);
|
||||
$serverpassword = localAPI('DecryptPassword', $api_data);
|
||||
$serverip = $srv->ipaddress;
|
||||
$serverusername = $srv->username;
|
||||
$serverlabel = !empty($srv->name) ? $srv->name : ('Server #'.$srv->id);
|
||||
|
||||
// Login + get cluster/resources
|
||||
$proxmox = new PVE2_API($serverip, $serverusername, "pam", $serverpassword['password']);
|
||||
if (!$proxmox->login()) {
|
||||
echo '<div class="alert alert-danger">Unable to log in to PVE API on '.htmlspecialchars($serverip).'. Check credentials / connectivity.</div>';
|
||||
continue;
|
||||
}
|
||||
|
||||
$cluster_resources = $proxmox->get('/cluster/resources'); // returns nodes, qemu, lxc, storage, pools, etc.
|
||||
|
||||
// Debug logging (same style as ClientArea)
|
||||
if (Capsule::table('mod_pvewhmcs')->where('id', '1')->value('debug_mode') == 1) {
|
||||
logModuleCall(
|
||||
'pvewhmcs',
|
||||
__FUNCTION__,
|
||||
'CLUSTER RESOURCES ['.$serverlabel.']:',
|
||||
json_encode($cluster_resources)
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_array($cluster_resources) || empty($cluster_resources)) {
|
||||
echo '<div class="alert alert-info">No resources returned.</div>';
|
||||
continue;
|
||||
}
|
||||
|
||||
// Split resources
|
||||
$nodes = [];
|
||||
$guests = []; // qemu + lxc
|
||||
foreach ($cluster_resources as $res) {
|
||||
if (!isset($res['type'])) {
|
||||
continue;
|
||||
}
|
||||
if ($res['type'] === 'node') {
|
||||
$nodes[] = $res;
|
||||
} elseif ($res['type'] === 'qemu' || $res['type'] === 'lxc') {
|
||||
$guests[] = $res;
|
||||
}
|
||||
}
|
||||
|
||||
// -------- Nodes table --------
|
||||
echo '<table class="datatable" border="0" cellpadding="3" cellspacing="1" width="100%">';
|
||||
echo '<tbody><tr>
|
||||
<th>Node</th>
|
||||
<th>Version</th>
|
||||
<th>Status</th>
|
||||
<th>IPv4</th>
|
||||
<th>CPU %</th>
|
||||
<th>RAM %</th>
|
||||
<th>Uptime</th>
|
||||
</tr>';
|
||||
|
||||
foreach ($nodes as $n) {
|
||||
$n_cpu_pct = isset($n['cpu']) ? round($n['cpu'] * 100, 2) : 0;
|
||||
$n_mem_pct = (isset($n['maxmem']) && $n['maxmem'] > 0)
|
||||
? intval(($n['mem'] ?? 0) * 100 / $n['maxmem'])
|
||||
: 0;
|
||||
$n_uptime = isset($n['uptime']) ? time2format($n['uptime']) : '—';
|
||||
$n_status = isset($n['status']) ? $n['status'] : 'unknown';
|
||||
$n_name = isset($n['node']) ? $n['node'] : '(node)';
|
||||
$n_version = $proxmox->get_version();
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td><strong>'.htmlspecialchars($n_name).'</strong></td>';
|
||||
echo '<td>'.htmlspecialchars($n_version).'</td>';
|
||||
echo '<td>'.htmlspecialchars($n_status).'</td>';
|
||||
echo '<td>'.htmlspecialchars($serverip).'</td>';
|
||||
echo '<td>'.$n_cpu_pct.'</td>';
|
||||
echo '<td>'.$n_mem_pct.'</td>';
|
||||
echo '<td>'.htmlspecialchars($n_uptime).'</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
echo '</tbody></table>';
|
||||
|
||||
// -------- Active Guests (running only) --------
|
||||
echo '<h2 style="margin-top:16px;">Active Guests</h2>';
|
||||
echo '<table class="datatable" border="0" cellpadding="3" cellspacing="1" width="100%">';
|
||||
echo '<tbody><tr>
|
||||
<th>VMID</th>
|
||||
<th>Name</th>
|
||||
<th>Status</th>
|
||||
<th>Type</th>
|
||||
<th>Node</th>
|
||||
<th>CPU %</th>
|
||||
<th>RAM %</th>
|
||||
<th>Disk %</th>
|
||||
<th>Uptime</th>
|
||||
</tr>';
|
||||
|
||||
foreach ($guests as $g) {
|
||||
// Only running guests for the "active" overview
|
||||
if (!isset($g['status']) || $g['status'] !== 'running') {
|
||||
continue;
|
||||
}
|
||||
$g_node = $g['node'] ?? '—';
|
||||
$g_type = $g['type'] ?? '—';
|
||||
$g_vmid = isset($g['vmid']) ? (int)$g['vmid'] : 0;
|
||||
$g_name = $g['name'] ?? '';
|
||||
$g_uptime = isset($g['uptime']) ? time2format($g['uptime']) : '—';
|
||||
$g_cpu_pct = isset($g['cpu']) ? round($g['cpu'] * 100, 2) : 0;
|
||||
$g_mem_pct = (isset($g['maxmem']) && $g['maxmem'] > 0)
|
||||
? intval(($g['mem'] ?? 0) * 100 / $g['maxmem'])
|
||||
: 0;
|
||||
$g_dsk_pct = (isset($g['maxdisk']) && $g['maxdisk'] > 0)
|
||||
? intval(($g['disk'] ?? 0) * 100 / $g['maxdisk'])
|
||||
: 0;
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td><strong>'.$g_vmid.'</strong></td>';
|
||||
echo '<td><strong>'.htmlspecialchars($g_name).'</strong></td>';
|
||||
echo '<td>'.htmlspecialchars($g['status']).'</td>';
|
||||
echo '<td>'.htmlspecialchars($g_type).'</td>';
|
||||
echo '<td>'.htmlspecialchars($g_node).'</td>';
|
||||
echo '<td>'.$g_cpu_pct.'</td>';
|
||||
echo '<td>'.$g_mem_pct.'</td>';
|
||||
echo '<td>'.$g_dsk_pct.'</td>';
|
||||
echo '<td>'.htmlspecialchars($g_uptime).'</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
echo '</tbody></table>';
|
||||
|
||||
echo '<hr style="margin:24px 0;">';
|
||||
}
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
// VM / CT PLANS tab in ADMIN GUI
|
||||
echo '
|
||||
<div id="plans" class="tab-pane '.($_GET['tab']=="vmplans" ? "active" : "").'">
|
||||
<div class="btn-group" role="group" aria-label="...">
|
||||
@@ -237,7 +429,7 @@ function pvewhmcs_output($vars) {
|
||||
lxc_plan_add() ;
|
||||
}
|
||||
|
||||
// List of VM/CT Plans
|
||||
// List of VM / CT Plans
|
||||
if ($_GET['action']=='planlist') {
|
||||
echo '
|
||||
<table class="datatable" border="0" cellpadding="3" cellspacing="1" width="100%">
|
||||
@@ -263,6 +455,7 @@ function pvewhmcs_output($vars) {
|
||||
<th>Net Rate</th>
|
||||
<th>Net BW</th>
|
||||
<th>IPv6</th>
|
||||
<th>Unpriv.</th>
|
||||
<th>Actions</th>
|
||||
</tr>';
|
||||
foreach (Capsule::table('mod_pvewhmcs_plans')->get() as $vm) {
|
||||
@@ -287,6 +480,7 @@ function pvewhmcs_output($vars) {
|
||||
echo '<td>'.$vm->netrate . PHP_EOL .'</td>';
|
||||
echo '<td>'.$vm->bw . PHP_EOL .'</td>';
|
||||
echo '<td>'.$vm->ipv6 . PHP_EOL .'</td>';
|
||||
echo '<td>'.$vm->unpriv . PHP_EOL .'</td>';
|
||||
echo '<td>
|
||||
<a href="'.pvewhmcs_BASEURL.'&tab=vmplans&action=editplan&id='.$vm->id.'&vmtype='.$vm->vmtype.'"><img height="16" width="16" border="0" alt="Edit" src="images/edit.gif"></a>
|
||||
<a href="'.pvewhmcs_BASEURL.'&tab=vmplans&action=removeplan&id='.$vm->id.'" onclick="return confirm(\'Plan will be deleted, continue?\')"><img height="16" width="16" border="0" alt="Edit" src="images/delete.gif"></a>
|
||||
@@ -336,34 +530,21 @@ function pvewhmcs_output($vars) {
|
||||
</div>
|
||||
';
|
||||
|
||||
// NODES / CLUSTER tab in ADMIN GUI
|
||||
echo '<div id="nodes" class="tab-pane '.($_GET['tab']=="nodes" ? "active" : "").'" >' ;
|
||||
echo ('<strong><h2>PVE: /cluster/resources</h2></strong>');
|
||||
echo ('Coming in v1.3.x');
|
||||
echo ('<strong><h2>PVE: Cluster Action Viewer</h2></strong>');
|
||||
echo ('Coming in v1.3.x');
|
||||
echo ('<strong><h2>PVE: Failed Actions (emailed)</h2></strong>');
|
||||
echo ('Coming in v1.3.x<br><br>');
|
||||
echo ('<strong><a href=\'https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/milestones\' target=\'_blank\'>View the milestones/versions on GitHub</a></strong>');
|
||||
echo '</div>';
|
||||
|
||||
// ACTIONS / LOGS tab in ADMIN GUI
|
||||
// ACTIONS tab in ADMIN GUI
|
||||
echo '<div id="actions" class="tab-pane '.($_GET['tab']=="actions" ? "active" : "").'" >' ;
|
||||
echo ('<strong><h2>WHMCS: Module Logging</h2></strong>');
|
||||
echo ('<u><a href=\'/admin/index.php?rp=/admin/logs/module-log\'>Click here</a></u><br>(Module Config > Debug Mode = ON)');
|
||||
echo ('<strong><h2>Module: Action History</h2></strong>');
|
||||
echo ('Coming in v1.3.x');
|
||||
echo ('<strong><h2>Module: Failed Actions</h2></strong>');
|
||||
echo ('Coming in v1.3.x<br><strong><a href=\'https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/milestones\' target=\'_blank\'>View the milestones/versions on GitHub</a></strong>');
|
||||
echo ('Coming in v1.3.x<br><br><strong><a href=\'https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/milestones\' target=\'_blank\'>View the milestones/versions on GitHub</a></strong>');
|
||||
echo '</div>';
|
||||
|
||||
// SUPPORT / HEALTH tab in ADMIN GUI
|
||||
echo ('<div id="health" class="tab-pane '.($_GET['tab']=="health" ? "active" : "").'" >') ;
|
||||
echo ('<b>❤️ Proxmox for WHMCS is open-source and free to use & improve on!</b><br><a href="https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/" target="_blank">https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/</a><br><br>');
|
||||
echo ('<b style="color:darkgreen;">Your 5-star review on WHMCS Marketplace will help the module grow!</b><br>*****: <a href="https://marketplace.whmcs.com/product/6935-proxmox-ve-for-whmcs" target="_blank">https://marketplace.whmcs.com/product/6935-proxmox-ve-for-whmcs</a><br><br>');
|
||||
// SUPPORT tab in ADMIN GUI
|
||||
echo ('<div id="support" class="tab-pane '.($_GET['tab']=="support" ? "active" : "").'" >') ;
|
||||
echo ('<strong><h2>System Environment</h2></strong><b>Proxmox VE for WHMCS</b> v' . pvewhmcs_version() . ' (GitHub reports latest as <b>v' . get_pvewhmcs_latest_version() . '</b>)' . '<br><b>PHP</b> v' . phpversion() . ' running on <b>' . $_SERVER['SERVER_SOFTWARE'] . '</b> Web Server (' . $_SERVER['SERVER_NAME'] . ')<br><br>');
|
||||
echo ('<b>❤️ PVEWHMCS is open-source and free to use & improve on!</b><br><a href="https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/" target="_blank">https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/</a><br><br>');
|
||||
echo ('<b style="color:darkgreen;">Your 5-star review on WHMCS Marketplace will help the module grow!</b><br>*****: <a href="https://marketplace.whmcs.com/product/6935-proxmox-ve-for-whmcs" target="_blank">https://marketplace.whmcs.com/product/6935-proxmox-ve-for-whmcs</a><br><br>');
|
||||
echo ('<strong><h2>Issues: Common Causes</h2></strong>1. Save your Package (Plan/Pool)! (configproducts.php?action=edit&id=...#tab=3)<br>2. Where possible, we pass-through the exact error to WHMCS Admin. Check it for info!<br><br>');
|
||||
echo ('<strong><h2>Module Technical Support</h2></strong>Our README contains a wealth of information:<br><a href="https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/" target="_blank">https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/</a><br>Please only raise an <a href="https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/issues/new" target="_blank"><u>Issue</u></a> on GitHub - inc. logs - if you\'ve properly tried.<br>Help is not guaranteed (FOSS). We will need your assistance. <b>Thank you!</b><br><br>');
|
||||
echo ('<strong><h2>Module Technical Support</h2></strong>Our README contains a wealth of information:<br><a href="https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/" target="_blank">https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/</a><br>Please only raise an <a href="https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/issues/new" target="_blank"><u>Issue</u></a> on GitHub - inc. logs - if you\'ve properly tried.<br><br><b>Help is not guaranteed (FOSS). We will need your assistance.</b> Thank you!<br><br>');
|
||||
echo '</div>';
|
||||
|
||||
// Config Tab
|
||||
@@ -375,20 +556,20 @@ function pvewhmcs_output($vars) {
|
||||
<tr>
|
||||
<td class="fieldlabel">VNC Secret</td>
|
||||
<td class="fieldarea">
|
||||
<input type="text" size="35" name="vnc_secret" id="vnc_secret" value="'.$config->vnc_secret.'"> Password of "vnc"@"pve" user. Mandatory for VNC proxying. See the <a href="https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/wiki" target="_blank">Wiki</a> for more info.
|
||||
<input type="text" size="35" name="vnc_secret" id="vnc_secret" value="'.$config->vnc_secret.'"> Password of "vnc"@"pve" user. Mandatory for VNC proxying. (See the <a href="https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS/" target="_blank">README</a> for more info)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fieldlabel">VMID Start</td>
|
||||
<td class="fieldarea">
|
||||
<input type="text" size="35" name="start_vmid" id="start_vmid" value="'.$config->start_vmid.'"> Starting PVE VMID. Default is 100. Module will increment this until vacant VMID found.
|
||||
<input type="text" size="35" name="start_vmid" id="start_vmid" value="'.$config->start_vmid.'"> Starting VMID (PVE). Default is 100. (Module will increment this until vacant VMID is found)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fieldlabel">Debug Mode</td>
|
||||
<td class="fieldlabel">Debug?</td>
|
||||
<td class="fieldarea">
|
||||
<label class="checkbox-inline">
|
||||
<input type="checkbox" name="debug_mode" value="1" '. ($config->debug_mode=="1" ? "checked" : "").'> Whether or not you want Debug Logging enabled (WHMCS Module Log for Debugging >> /admin/logs/module-log)
|
||||
<input type="checkbox" name="debug_mode" value="1" '. ($config->debug_mode=="1" ? "checked" : "").'> Whether or not you want Debug Logging enabled - must also enable WHMCS Module Log (WHMCS debug) & then view <u><a href="/admin/index.php?rp=/admin/logs/module-log">at this link here.</a></u>
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -399,9 +580,122 @@ function pvewhmcs_output($vars) {
|
||||
</div>
|
||||
</form>
|
||||
';
|
||||
|
||||
echo '</div>';
|
||||
|
||||
// LOGS tab in ADMIN GUI
|
||||
echo '<div id="logs" class="tab-pane ' . (isset($_GET['tab']) && $_GET['tab'] === 'logs' ? 'active' : '') . '">';
|
||||
echo '<strong><h2>Cluster History</h2></strong>';
|
||||
|
||||
try {
|
||||
// If a client exists already, reuse it; else initialise once from the first enabled pvewhmcs server
|
||||
if (!isset($proxmox)) {
|
||||
$srv = Capsule::table('tblservers')
|
||||
->where('type', 'pvewhmcs')
|
||||
->where('disabled', 0)
|
||||
->orderBy('id', 'asc')
|
||||
->first();
|
||||
|
||||
if (!$srv) {
|
||||
throw new Exception('No enabled WHMCS server found for module type pvewhmcs.');
|
||||
}
|
||||
|
||||
$dec = localAPI('DecryptPassword', ['password2' => $srv->password]);
|
||||
$serverpassword = $dec['password'] ?? '';
|
||||
if (!$serverpassword) {
|
||||
throw new Exception('Could not decrypt Proxmox server password.');
|
||||
}
|
||||
|
||||
$proxmox = new PVE2_API($srv->ipaddress, $srv->username, 'pam', $serverpassword);
|
||||
if (!$proxmox->login()) {
|
||||
throw new Exception('Login to Proxmox API failed.');
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch recent cluster-wide tasks once
|
||||
$limit = 150;
|
||||
$tasks = $proxmox->get('/cluster/tasks', ['limit' => $limit]);
|
||||
|
||||
// Optional debug logging
|
||||
if (Capsule::table('mod_pvewhmcs')->where('id', '1')->value('debug_mode') == 1) {
|
||||
logModuleCall('pvewhmcs', 'ADMIN LOGS: /cluster/tasks', 'limit=' . $limit, json_encode($tasks));
|
||||
}
|
||||
|
||||
if (!is_array($tasks) || empty($tasks)) {
|
||||
echo '<div class="alert alert-info">No recent cluster tasks were returned.</div>';
|
||||
} else {
|
||||
// Sort newest first (defensive)
|
||||
usort($tasks, function ($a, $b) {
|
||||
return (intval($b['starttime'] ?? 0)) <=> (intval($a['starttime'] ?? 0));
|
||||
});
|
||||
|
||||
echo '<table class="datatable" border="0" cellpadding="3" cellspacing="1" width="100%">';
|
||||
echo '<tbody><tr>
|
||||
<th>Task</th>
|
||||
<th>VMID</th>
|
||||
<th>Status</th>
|
||||
<th>Node</th>
|
||||
<th>User</th>
|
||||
<th>Duration</th>
|
||||
<th>Start</th>
|
||||
<th>End</th>
|
||||
</tr>';
|
||||
|
||||
foreach ($tasks as $t) {
|
||||
$node = $t['node'] ?? '—';
|
||||
$type = $t['type'] ?? '';
|
||||
$user = $t['user'] ?? '';
|
||||
$upid = $t['upid'] ?? '';
|
||||
|
||||
// Derive VMID:
|
||||
// 1) Prefer numeric $t['id'] when available
|
||||
// 2) Otherwise parse from UPID ("...:type:<vmid>:user@realm:")
|
||||
$vmid = '—';
|
||||
if (isset($t['id']) && preg_match('/^\d+$/', (string)$t['id'])) {
|
||||
$vmid = (string)$t['id'];
|
||||
} elseif (is_string($upid) && $upid !== '') {
|
||||
// UPID format: UPID:node:pid:pstart:starttime:type:vmid:user@realm:
|
||||
if (preg_match('/^UPID:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:([^:]*):/', $upid, $m)) {
|
||||
if ($m[1] !== '' && ctype_digit($m[1])) {
|
||||
$vmid = $m[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$startTs = (int)($t['starttime'] ?? 0);
|
||||
$endTs = isset($t['endtime']) ? (int)$t['endtime'] : null;
|
||||
|
||||
$start = $startTs ? date('Y-m-d H:i:s', $startTs) : '—';
|
||||
$end = $endTs ? date('Y-m-d H:i:s', $endTs) : '—';
|
||||
|
||||
$durSec = $startTs ? (is_null($endTs) ? (time() - $startTs) : max(0, $endTs - $startTs)) : null;
|
||||
$durH = is_null($durSec)
|
||||
? '—'
|
||||
: sprintf('%02d:%02d:%02d', intdiv($durSec, 3600), intdiv($durSec % 3600, 60), $durSec % 60);
|
||||
|
||||
$status = $t['status'] ?? (is_null($endTs) ? 'running' : '');
|
||||
$badge = ($status === 'OK')
|
||||
? '✅'
|
||||
: ((preg_match('/(error|fail|aborted|unknown)/i', (string)$status)) ? '❌' : '⏳');
|
||||
|
||||
echo '<tr>';
|
||||
echo '<td><strong>' . htmlspecialchars($type) . '</strong></td>';
|
||||
echo '<td>' . htmlspecialchars($vmid) . '</td>';
|
||||
echo '<td>' . $badge . ' ' . htmlspecialchars($status) . '</td>';
|
||||
echo '<td><strong>' . htmlspecialchars($node) . '</strong></td>';
|
||||
echo '<td>' . htmlspecialchars($user) . '</td>';
|
||||
echo '<td>' . htmlspecialchars($durH) . '</td>';
|
||||
echo '<td>' . htmlspecialchars($start) . '</td>';
|
||||
echo '<td>' . htmlspecialchars($end) . '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
echo '</tbody></table>';
|
||||
// Always close the tab-pane div
|
||||
echo '</div>';
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
echo '<div class="alert alert-danger">Could not retrieve PVE Cluster history: '
|
||||
. htmlspecialchars($e->getMessage()) . '</div>';
|
||||
}
|
||||
echo '</div>';
|
||||
// End of tabbed content
|
||||
|
||||
@@ -423,7 +717,7 @@ function import_guest() {
|
||||
$subnetmask = trim($_POST['import_subnet']);
|
||||
$gateway = trim($_POST['import_gateway']);
|
||||
$hostname = trim($_POST['import_hostname']);
|
||||
$vtype = ($_POST['import_vtype'] === 'lxc') ? 'lxc' : 'kvm';
|
||||
$vtype = ($_POST['import_vtype'] === 'lxc') ? 'lxc' : 'qemu';
|
||||
|
||||
// Validate Client ID
|
||||
$client = Capsule::table('tblclients')->where('id', $userid)->where('status', 'Active')->first();
|
||||
@@ -447,8 +741,8 @@ function import_guest() {
|
||||
'regdate' => date('Y-m-d'),
|
||||
'domain' => $hostname,
|
||||
'paymentmethod' => 'banktransfer',
|
||||
'firstpaymentamount' => $product->paytype == 'free' ? 0 : $product->monthly,
|
||||
'amount' => $product->paytype == 'free' ? 0 : $product->monthly,
|
||||
'firstpaymentamount' => '0.00',
|
||||
'amount' => '0.00',
|
||||
'billingcycle' => 'Monthly',
|
||||
'nextduedate' => date('Y-m-d'),
|
||||
'nextinvoicedate' => date('Y-m-d'),
|
||||
@@ -524,8 +818,8 @@ function import_guest() {
|
||||
echo '</select></td></tr>';
|
||||
|
||||
// Guest Type dropdown
|
||||
echo '<tr><td class="fieldlabel">VM/CT</td><td class="fieldarea"><select name="import_vtype" required>';
|
||||
echo '<option value="kvm">(VM) QEMU</option>';
|
||||
echo '<tr><td class="fieldlabel">VM / CT</td><td class="fieldarea"><select name="import_vtype" required>';
|
||||
echo '<option value="qemu">(VM) QEMU</option>';
|
||||
echo '<option value="lxc">(CT) LXC</option>';
|
||||
echo '</select></td></tr>';
|
||||
|
||||
@@ -670,7 +964,7 @@ function kvm_plan_add() {
|
||||
<option value="Opteron_G4">(AMD) Opteron_G4</option>
|
||||
<option value="Opteron_G5">(AMD) Opteron_G5</option>
|
||||
</select>
|
||||
CPU emulation type. Default is x86-64 psABI v2-AES
|
||||
Emulation type. Default is x86-64 psABI v2-AES.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -678,14 +972,14 @@ function kvm_plan_add() {
|
||||
<td class="fieldlabel">CPU - Sockets</td>
|
||||
<td class="fieldarea">
|
||||
<input type="text" size="8" name="cpus" id="cpus" value="1" required>
|
||||
The number of CPU Sockets. 1 - 4.
|
||||
The number of CPU Sockets (typically 1-4).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fieldlabel">CPU - Cores</td>
|
||||
<td class="fieldarea">
|
||||
<input type="text" size="8" name="cores" id="cores" value="1" required>
|
||||
The number of CPU Cores per socket. 1 - 32.
|
||||
The number of CPU Cores per Socket (1-N).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -706,21 +1000,21 @@ function kvm_plan_add() {
|
||||
<td class="fieldlabel">RAM - Memory</td>
|
||||
<td class="fieldarea">
|
||||
<input type="text" size="8" name="memory" id="memory" value="2048" required>
|
||||
RAM space in Megabyte e.g 1024 = 1GB (default is 2GB)
|
||||
RAM space in Megabytes e.g 1024 = 1GB (default is 2GB)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fieldlabel">RAM - Balloon</td>
|
||||
<td class="fieldarea">
|
||||
<input type="text" size="8" name="balloon" id="balloon" value="0" required>
|
||||
Balloon space in Megabyte e.g 1024 = 1GB (0 = disabled)
|
||||
Balloon space in Megabytes e.g 1024 = 1GB (0 = disabled)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fieldlabel">Disk - Capacity</td>
|
||||
<td class="fieldarea">
|
||||
<input type="text" size="8" name="disk" id="disk" value="10240" required>
|
||||
HDD/SSD storage space in Gigabyte e.g 1024 = 1TB (default is 10GB)
|
||||
HDD/SSD storage in Gigabytes e.g 1024 = 1TB (default is 10GB)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -731,7 +1025,7 @@ function kvm_plan_add() {
|
||||
<option selected="" value="qcow2">QEMU Image (qcow2)</option>
|
||||
<option value="vmdk">VMware Image (vmdk)</option>
|
||||
</select>
|
||||
Recommend "QEMU/qcow2" (so it can make Snapshots)
|
||||
Recommend "QEMU/qcow2" (so it can take Snapshots)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -774,11 +1068,11 @@ function kvm_plan_add() {
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fieldlabel">NIC - Type</td>
|
||||
<td class="fieldlabel">Network - NIC Type</td>
|
||||
<td class="fieldarea">
|
||||
<select class="form-control select-inline" name="netmodel">
|
||||
<option selected="" value="e1000">Intel E1000 (Reliable)</option>
|
||||
<option value="virtio">VirtIO (Paravirtualized)</option>
|
||||
<option value="e1000">Intel E1000 (Stable but slower)</option>
|
||||
<option selected="" value="virtio">VirtIO (Paravirtualised)</option>
|
||||
<option value="rtl8139">Realtek RTL8139</option>
|
||||
<option value="vmxnet3">VMware vmxnet3</option>
|
||||
</select>
|
||||
@@ -986,7 +1280,7 @@ function kvm_plan_edit($id) {
|
||||
<option value="Opteron_G4" ' . ($plan->cpuemu == "Opteron_G4" ? "selected" : "") . '>(AMD) Opteron_G4</option>
|
||||
<option value="Opteron_G5" ' . ($plan->cpuemu == "Opteron_G5" ? "selected" : "") . '>(AMD) Opteron_G5</option>
|
||||
</select>
|
||||
CPU emulation type. Default is x86-64 psABI v2-AES
|
||||
Emulation type. Default is x86-64 psABI v2-AES.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -994,14 +1288,14 @@ function kvm_plan_edit($id) {
|
||||
<td class="fieldlabel">CPU - Sockets</td>
|
||||
<td class="fieldarea">
|
||||
<input type="text" size="8" name="cpus" id="cpus" value="'.$plan->cpus.'" required>
|
||||
The number of CPU sockets. 1 - 4.
|
||||
The number of CPU Sockets (typically 1-4).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fieldlabel">CPU - Cores</td>
|
||||
<td class="fieldarea">
|
||||
<input type="text" size="8" name="cores" id="cores" value="'.$plan->cores.'" required>
|
||||
The number of CPU cores per socket. 1 - 32.
|
||||
The number of CPU Cores per Socket (1-N).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -1029,14 +1323,14 @@ function kvm_plan_edit($id) {
|
||||
<td class="fieldlabel">RAM - Balloon</td>
|
||||
<td class="fieldarea">
|
||||
<input type="text" size="8" name="balloon" id="balloon" required value="'.$plan->balloon.'">
|
||||
Balloon space in Megabyte e.g 1024 = 1GB (0 = disabled)
|
||||
Balloon space in Megabytes e.g 1024 = 1GB (0 = disabled)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fieldlabel">Disk - Capacity</td>
|
||||
<td class="fieldarea">
|
||||
<input type="text" size="8" name="disk" id="disk" required value="'.$plan->disk.'">
|
||||
HDD/SSD storage space in Gigabytes e.g 1024 = 1TB
|
||||
HDD/SSD storage in Gigabytes e.g 1024 = 1TB
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -1047,7 +1341,7 @@ function kvm_plan_edit($id) {
|
||||
<option value="qcow2" '. ($plan->diskformat=="qcow2" ? "selected" : "").'>QEMU image (qcow2)</option>
|
||||
<option value="vmdk" '. ($plan->diskformat=="vmdk" ? "selected" : "").'>VMware image (vmdk)</option>
|
||||
</select>
|
||||
Recommend "QEMU/qcow2 format" (to make Snapshots)
|
||||
Recommend "QEMU/qcow2 format" (so it can take Snapshots)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -1090,11 +1384,11 @@ function kvm_plan_edit($id) {
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fieldlabel">NIC - Type</td>
|
||||
<td class="fieldlabel">Network - NIC Type</td>
|
||||
<td class="fieldarea">
|
||||
<select class="form-control select-inline" name="netmodel">
|
||||
<option value="e1000" '. ($plan->netmodel=="e1000" ? "selected" : "").'>Intel E1000 (Reliable)</option>
|
||||
<option value="virtio" '. ($plan->netmodel=="virtio" ? "selected" : "").'>VirtIO (Paravirt)</option>
|
||||
<option value="e1000" '. ($plan->netmodel=="e1000" ? "selected" : "").'>Intel E1000 (Stable but slower)</option>
|
||||
<option value="virtio" '. ($plan->netmodel=="virtio" ? "selected" : "").'>VirtIO (Paravirtualised)</option>
|
||||
<option value="rtl8139" '. ($plan->netmodel=="rtl8139" ? "selected" : "").'>Realtek RTL8139</option>
|
||||
<option value="vmxnet3" '. ($plan->netmodel=="vmxnet3" ? "selected" : "").'>VMware vmxnet3</option>
|
||||
</select>
|
||||
@@ -1302,6 +1596,16 @@ function lxc_plan_add() {
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fieldlabel">
|
||||
Unpriv.
|
||||
</td>
|
||||
<td class="fieldarea">
|
||||
<label class="checkbox-inline">
|
||||
<input type="checkbox" name="unpriv" value="0"> Specifies whether a CT will be unprivileged. (Recommended) Set at-create only.
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="btn-container">
|
||||
@@ -1437,6 +1741,16 @@ function lxc_plan_edit($id) {
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fieldlabel">
|
||||
Unpriv.
|
||||
</td>
|
||||
<td class="fieldarea">
|
||||
<label class="checkbox-inline">
|
||||
<input type="checkbox" value="1" name="unpriv" '. ($plan->unpriv=="1" ? "checked" : "").'> Specifies whether a CT will be unprivileged. (Recommended) Set at-create only.
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="btn-container">
|
||||
@@ -1568,6 +1882,7 @@ function save_lxc_plan() {
|
||||
'bw' => $_POST['bw'],
|
||||
'ipv6' => $_POST['ipv6'],
|
||||
'onboot' => $_POST['onboot'],
|
||||
'unpriv' => $_POST['unpriv'],
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -1604,6 +1919,7 @@ function update_lxc_plan() {
|
||||
'bw' => $_POST['bw'],
|
||||
'ipv6' => $_POST['ipv6'],
|
||||
'onboot' => $_POST['onboot'],
|
||||
'unpriv' => $_POST['unpriv'],
|
||||
]
|
||||
);
|
||||
$_SESSION['pvewhmcs']['infomsg']['title']='LXC Plan updated.' ;
|
||||
@@ -1768,4 +2084,38 @@ function removeip($id,$pool_id) {
|
||||
$_SESSION['pvewhmcs']['infomsg']['title']='IPv4 Address deleted.' ;
|
||||
$_SESSION['pvewhmcs']['infomsg']['message']='Deleted selected item successfully.' ;
|
||||
}
|
||||
|
||||
function time2format($s) {
|
||||
$d = intval( $s / 86400 );
|
||||
if ($d < '10') {
|
||||
$d = '0' . $d;
|
||||
}
|
||||
$s -= $d * 86400;
|
||||
$h = intval( $s / 3600 );
|
||||
if ($h < '10') {
|
||||
$h = '0' . $h;
|
||||
}
|
||||
$s -= $h * 3600;
|
||||
$m = intval( $s / 60 );
|
||||
if ($m < '10') {
|
||||
$m = '0' . $m;
|
||||
}
|
||||
$s -= $m * 60;
|
||||
if ($s < '10') {
|
||||
$s = '0' . $s;
|
||||
}
|
||||
if ($d) {
|
||||
$str = $d . ' days ';
|
||||
}
|
||||
if ($h) {
|
||||
$str .= $h . ':';
|
||||
}
|
||||
if ($m) {
|
||||
$str .= $m . ':';
|
||||
}
|
||||
if ($s) {
|
||||
$str .= $s . '';
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
?>
|
||||
@@ -19,7 +19,6 @@
|
||||
<img src="/modules/servers/pvewhmcs/img/{$vm_status['status']}.png"/><br/>
|
||||
<span style="text-transform: uppercase"><strong><i>{$vm_status['status']}</i></strong></span><br/>
|
||||
Up: {$vm_status['uptime']}
|
||||
|
||||
</div>
|
||||
<div class="col col-md-7">
|
||||
<div class="row">
|
||||
@@ -57,28 +56,13 @@
|
||||
|
||||
<table class="table table-bordered table-striped">
|
||||
<tr>
|
||||
<td><strong>IP</strong> (Addressing)</td><td><strong>{$vm_config['ipv4']}</strong><br/>Subnet Mask: {$vm_config['netmask4']}<br/>Gateway: {$vm_config['gateway4']}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>OS/etc</strong> (System)</td>
|
||||
<td>Kernel: {$vm_config['ostype']}</td>
|
||||
<td><strong>Memory</strong> (RAM)</td>
|
||||
<td><strong>{$vm_config['memory']}MB</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Compute</strong> (CPU)</td>
|
||||
<td>{$vm_config['sockets']} socket/s, {$vm_config['cores']} core/s<br />
|
||||
Emulation: {$vm_config['cpu']}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Memory</strong> (RAM)</td>
|
||||
<td>{$vm_config['memory']}MB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>NIC</strong> (Interface #1)</td>
|
||||
<td>{($vm_config['net0']|replace:',':'<br/>')}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>NIC</strong> (Interface #2)</td>
|
||||
<td>{$vm_config['net1']}</td>
|
||||
<td><strong>{$vm_config['cpu']} {$vm_config['cores']} core/s on {$vm_config['sockets']} socket/s
|
||||
</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Storage</strong> (SSD/HDD)</td>
|
||||
@@ -91,6 +75,21 @@
|
||||
{($vm_config['virtio0']|replace:',':'<br/>')}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>OS/etc</strong> (System)</td>
|
||||
<td>Kernel: {$vm_config['ostype']}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>IPv4</strong> (Network)</td><td><strong>{$vm_config['ipv4']}</strong><br/>Mask: {$vm_config['netmask4']}<br/>Gateway: {$vm_config['gateway4']}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>NIC</strong> (Interface #1)</td>
|
||||
<td>{($vm_config['net0']|replace:',':'<br/>')}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>NIC</strong> (Interface #2)</td>
|
||||
<td>{($vm_config['net1']|replace:',':'<br/>')}</td>
|
||||
</tr>
|
||||
</table>
|
||||
{if ($smarty.get.a eq 'vmStat')}
|
||||
<h4>VM Statistics</h4>
|
||||
|
||||
BIN
modules/servers/pvewhmcs/img/logo.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 6.1 KiB |
@@ -21,6 +21,11 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Delete the authentication cookie, if it exists
|
||||
if (isset($_COOKIE['PVEAuthCookie'])) {
|
||||
unset($_COOKIE['PVEAuthCookie']);
|
||||
}
|
||||
|
||||
if (isset($_GET['pveticket']) && isset($_GET['host']) && isset($_GET['path']) && isset($_GET['vncticket'])) {
|
||||
// Take passed-in variables and re-assign for usage
|
||||
$pveticket = $_GET['pveticket'];
|
||||
@@ -33,7 +38,14 @@ if (isset($_GET['pveticket']) && isset($_GET['host']) && isset($_GET['path']) &&
|
||||
// Now extract just the domain parts we need (FUTURE: capacity/option for multi-part TLDs)
|
||||
$domainonly = preg_replace("/^(.*?)\.(.*)$/","$2",$whmcsdomain['path']);
|
||||
// Set the cookie as Proxmox will be expecting it, so it is WHMCS to VNC without further login
|
||||
setrawcookie('PVEAuthCookie', $pveticket, 0, '/', $domainonly);
|
||||
setrawcookie('PVEAuthCookie', $pveticket, [
|
||||
'expires' => 0,
|
||||
'path' => '/',
|
||||
'domain' => $domainonly,
|
||||
'secure' => true,
|
||||
'httponly' => false,
|
||||
'samesite' => 'None',
|
||||
]);
|
||||
|
||||
// Create the final noVNC URL with the re-encoded vncticket
|
||||
$hostname = gethostbyaddr($host);
|
||||
@@ -47,4 +59,4 @@ if (isset($_GET['pveticket']) && isset($_GET['host']) && isset($_GET['path']) &&
|
||||
echo 'Error: Missing required info to route your request. Please try again.';
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
?>
|
||||
@@ -34,6 +34,33 @@ use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
// Prepare to source Guest type
|
||||
global $guest;
|
||||
|
||||
// Fix the Server Test showing "Pvewhmcs" instead of pretty name
|
||||
// ref: https://developers.whmcs.com/provisioning-modules/meta-data-params/
|
||||
function pvewhmcs_MetaData() {
|
||||
return array(
|
||||
'DisplayName' => 'Proxmox VE',
|
||||
'APIVersion' => '1.1',
|
||||
'RequiresServer' => 'true',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* AdminLink: show a direct link to the Proxmox UI on :8006.
|
||||
* Falls back to server IP if hostname is empty.
|
||||
*/
|
||||
function pvewhmcs_AdminLink(array $params) {
|
||||
$host = $params['serverhostname'] ?: $params['serverip'];
|
||||
if (!$host) {
|
||||
// Nothing to link to – return the module page as a safe fallback
|
||||
return '<a href="addonmodules.php?module=pvewhmcs">Module Config</a>';
|
||||
}
|
||||
|
||||
$url = 'https://' . $host . ':8006';
|
||||
return '<form action="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '" method="get" target="_blank">
|
||||
<input type="submit" value="Log in to PVE" class="btn btn-sm btn-default" />
|
||||
</form>';
|
||||
}
|
||||
|
||||
// WHMCS CONFIG > SERVICES/PRODUCTS > Their Service > Tab #3 (Plan/Pool)
|
||||
function pvewhmcs_ConfigOptions() {
|
||||
// Retrieve PVE for WHMCS Cluster
|
||||
@@ -41,12 +68,12 @@ function pvewhmcs_ConfigOptions() {
|
||||
|
||||
// Retrieve Plans
|
||||
foreach (Capsule::table('mod_pvewhmcs_plans')->get() as $plan) {
|
||||
$plans[$plan->id]=$plan->vmtype.' : '.$plan->title ;
|
||||
$plans[$plan->id] = '(' . $plan->vmtype . ') ' . $plan->title ;
|
||||
}
|
||||
|
||||
// Retrieve IP Pools
|
||||
foreach (Capsule::table('mod_pvewhmcs_ip_pools')->get() as $ippool) {
|
||||
$ippools[$ippool->id]=$ippool->title ;
|
||||
$ippools[$ippool->id] = $ippool->title ;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -75,13 +102,13 @@ function pvewhmcs_ConfigOptions() {
|
||||
"FriendlyName" => "PVE Plan",
|
||||
"Type" => "dropdown",
|
||||
'Options' => $plans ,
|
||||
"Description" => "QEMU/LXC : Plan Name"
|
||||
"Description" => "(QEMU/LXC) Plan Name"
|
||||
),
|
||||
"IPPool" => array(
|
||||
"FriendlyName" => "IPv4 Pool",
|
||||
"Type" => "dropdown",
|
||||
'Options'=> $ippools,
|
||||
"Description" => "IPv4 : Allocation Pool"
|
||||
"Description" => "(IPv4) Allocation Pool"
|
||||
),
|
||||
);
|
||||
|
||||
@@ -258,6 +285,7 @@ function pvewhmcs_CreateAccount($params) {
|
||||
$vm_settings['net0'] .= ',tag=' . $plan->vlanid;
|
||||
}
|
||||
$vm_settings['onboot'] = $plan->onboot;
|
||||
$vm_settings['unprivileged'] = $plan->unpriv;
|
||||
$vm_settings['password'] = $params['customfields']['Password'];
|
||||
} else {
|
||||
////////////////////////////
|
||||
@@ -445,28 +473,49 @@ function pvewhmcs_CreateAccount($params) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the next available VMID starting from the given ID
|
||||
* @param PVE2_API $proxmox Proxmox API instance
|
||||
* @param string $node Node name
|
||||
* @param int $start_vmid Starting VMID to search from
|
||||
* @return int Next available VMID
|
||||
* @throws Exception if no VMID available within reasonable range
|
||||
* Find the next free VMID cluster-wide by probing /cluster/nextid.
|
||||
* Returns the first VMID >= $start_vmid for which /cluster/nextid?vmid=X returns X.
|
||||
*
|
||||
* @param PVE2_API $proxmox Proxmox API client
|
||||
* @param string $node Ignored (VMIDs are cluster-wide)
|
||||
* @param int $start_vmid Starting VMID from Module config
|
||||
* @return int
|
||||
* @throws Exception on unexpected API errors or if cap exceeded
|
||||
*/
|
||||
function pvewhmcs_find_next_available_vmid($proxmox, $node, $start_vmid) {
|
||||
$vmid = $start_vmid;
|
||||
$max_attempts = 1000;
|
||||
$attempts = 0;
|
||||
|
||||
while (!is_null($proxmox->get('/nodes/' . $node . '/qemu/' . $vmid . '/status/current')) ||
|
||||
!is_null($proxmox->get('/nodes/' . $node . '/lxc/' . $vmid . '/status/current'))) {
|
||||
$vmid++;
|
||||
$attempts++;
|
||||
if ($attempts > $max_attempts) {
|
||||
throw new Exception("Unable to find available VMID after $max_attempts attempts");
|
||||
$max_attempts = 1000; // Safety cap to avoid infinite loops
|
||||
$vmid = (int) $start_vmid; // Starting with configured VMID
|
||||
|
||||
for ($i = 0; $i < $max_attempts; $i++, $vmid++) {
|
||||
try {
|
||||
// Proxmox API: is this VMID vacant?
|
||||
// If vacant, servers echo it back in 'data'.
|
||||
$resp = $proxmox->get('/cluster/nextid', ['vmid' => $vmid]);
|
||||
|
||||
// Different PHP clients return either ['data' => '123'] or just '123'
|
||||
$data = (is_array($resp) && array_key_exists('data', $resp)) ? $resp['data'] : $resp;
|
||||
|
||||
if ((int) $data === $vmid) {
|
||||
return $vmid; // confirmed vacant
|
||||
}
|
||||
|
||||
// If the API returns a *different* number here, we ignore it and keep probing
|
||||
continue;
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
$msg = strtolower($e->getMessage());
|
||||
|
||||
// Occupied case looks like: "400 Parameter verification failed. vmid: VM 106 already exists"
|
||||
if (strpos($msg, 'already exists') !== false || strpos($msg, 'parameter verification failed') !== false) {
|
||||
continue; // try the next VMID
|
||||
}
|
||||
|
||||
// Any other error is unexpected; surface it.
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
return (int)$vmid;
|
||||
|
||||
throw new Exception("Unable to find a free VMID starting at {$start_vmid} after {$max_attempts} attempts");
|
||||
}
|
||||
|
||||
// PVE API FUNCTION, ADMIN: Test Connection with Proxmox node
|
||||
@@ -518,8 +567,8 @@ function pvewhmcs_SuspendAccount(array $params) {
|
||||
$guest=Capsule::table('mod_pvewhmcs_vms')->where('id','=',$params['serviceid'])->get()[0] ;
|
||||
$pve_cmdparam = array();
|
||||
// Log and fire request
|
||||
$logrequest = '/nodes/' . $first_node . '/' . $guest->vtype . '/' . $params['serviceid'] . '/status/stop';
|
||||
$response = $proxmox->post('/nodes/' . $first_node . '/' . $guest->vtype . '/' . $params['serviceid'] . '/status/stop' , $pve_cmdparam);
|
||||
$logrequest = '/nodes/' . $first_node . '/' . $guest->vtype . '/' . $guest->vmid . '/status/stop';
|
||||
$response = $proxmox->post('/nodes/' . $first_node . '/' . $guest->vtype . '/' . $guest->vmid . '/status/stop' , $pve_cmdparam);
|
||||
}
|
||||
// DEBUG - Log the request parameters before it's fired
|
||||
if (Capsule::table('mod_pvewhmcs')->where('id', '1')->value('debug_mode') == 1) {
|
||||
@@ -555,8 +604,8 @@ function pvewhmcs_UnsuspendAccount(array $params) {
|
||||
$guest=Capsule::table('mod_pvewhmcs_vms')->where('id','=',$params['serviceid'])->get()[0] ;
|
||||
$pve_cmdparam = array();
|
||||
// Log and fire request
|
||||
$logrequest = '/nodes/' . $first_node . '/' . $guest->vtype . '/' . $params['serviceid'] . '/status/start';
|
||||
$response = $proxmox->post('/nodes/' . $first_node . '/' . $guest->vtype . '/' . $params['serviceid'] . '/status/start');
|
||||
$logrequest = '/nodes/' . $first_node . '/' . $guest->vtype . '/' . $guest->vmid . '/status/start';
|
||||
$response = $proxmox->post('/nodes/' . $first_node . '/' . $guest->vtype . '/' . $guest->vmid . '/status/start');
|
||||
}
|
||||
// DEBUG - Log the request parameters before it's fired
|
||||
if (Capsule::table('mod_pvewhmcs')->where('id', '1')->value('debug_mode') == 1) {
|
||||
@@ -593,13 +642,13 @@ function pvewhmcs_TerminateAccount(array $params) {
|
||||
$guest=Capsule::table('mod_pvewhmcs_vms')->where('id', '=', $params['serviceid'])->get()[0];
|
||||
$pve_cmdparam = array();
|
||||
// Stop the service if it is not already stopped
|
||||
$guest_specific = $proxmox->get('/nodes/'.$first_node.'/'.$guest->vtype.'/'.$params['serviceid'].'/status/current');
|
||||
$guest_specific = $proxmox->get('/nodes/' . $first_node . '/' . $guest->vtype . '/' . $guest->vmid . '/status/current');
|
||||
if ($guest_specific['status'] != 'stopped') {
|
||||
$proxmox->post('/nodes/' . $first_node . '/' . $guest->vtype . '/' . $params['serviceid'] . '/status/stop' , $pve_cmdparam);
|
||||
$proxmox->post('/nodes/' . $first_node . '/' . $guest->vtype . '/' . $guest->vmid . '/status/stop' , $pve_cmdparam);
|
||||
sleep(30);
|
||||
}
|
||||
|
||||
if ($proxmox->delete('/nodes/'.$first_node.'/'.$guest->vtype.'/'.$params['serviceid'],array('skiplock'=>1))) {
|
||||
if ($proxmox->delete('/nodes/' . $first_node . '/' . $guest->vtype . '/' . $guest->vmid,array('skiplock'=>1))) {
|
||||
// Delete entry from module table once service terminated in PVE
|
||||
Capsule::table('mod_pvewhmcs_vms')->where('id', '=', $params['serviceid'])->delete();
|
||||
return "success";
|
||||
@@ -610,7 +659,7 @@ function pvewhmcs_TerminateAccount(array $params) {
|
||||
}
|
||||
|
||||
// GENERAL CLASS: WHMCS Decrypter
|
||||
class hash_encryption {
|
||||
class pvewhmcs_hash_encryption {
|
||||
/**
|
||||
* Hashed value of the user provided encryption key
|
||||
* @var string
|
||||
@@ -643,7 +692,7 @@ class hash_encryption {
|
||||
* @param boold $base64 Enable base64 en- / decoding
|
||||
* @return mixed
|
||||
*/
|
||||
function hash_encryption($key, $base64 = true) {
|
||||
function pvewhmcs_hash_encryption($key, $base64 = true) {
|
||||
|
||||
global $cc_encryption_hash;
|
||||
|
||||
@@ -770,7 +819,7 @@ class hash_encryption {
|
||||
*
|
||||
* @todo Add more random sources.
|
||||
* @access private
|
||||
* @see function hash_encryption
|
||||
* @see function pvewhmcs_hash_encryption
|
||||
* @return string Binary pseudo random string
|
||||
**/
|
||||
function _generate_iv() {
|
||||
@@ -809,7 +858,7 @@ function pvewhmcs_get_whmcs_server_password($enc_pass){
|
||||
$key1 = md5 (md5 ($cc_encryption_hash));
|
||||
$key2 = md5 ($cc_encryption_hash);
|
||||
$key = $key1.$key2;
|
||||
$hasher = new hash_encryption($key);
|
||||
$hasher = new pvewhmcs_hash_encryption($key);
|
||||
return $hasher->decrypt($enc_pass);
|
||||
}
|
||||
|
||||
@@ -827,13 +876,14 @@ function pvewhmcs_AdminCustomButtonArray() {
|
||||
// MODULE BUTTONS: Client Interface button regos
|
||||
function pvewhmcs_ClientAreaCustomButtonArray() {
|
||||
$buttonarray = array(
|
||||
"<img src='./modules/servers/pvewhmcs/img/novnc.png'/> noVNC (HTML5)" => "noVNC",
|
||||
"<img src='./modules/servers/pvewhmcs/img/tigervnc.png'/> TigerVNC (Java)" => "javaVNC",
|
||||
"<i class='fa fa-2x fa-flag-checkered'></i> Start Machine" => "vmStart",
|
||||
"<i class='fa fa-2x fa-sync'></i> Reboot Now" => "vmReboot",
|
||||
"<i class='fa fa-2x fa-flag-checkered'></i> Start" => "vmStart",
|
||||
"<i class='fa fa-2x fa-sync'></i> Reboot" => "vmReboot",
|
||||
"<i class='fa fa-2x fa-power-off'></i> Power Off" => "vmShutdown",
|
||||
"<i class='fa fa-2x fa-stop'></i> Hard Stop" => "vmStop",
|
||||
"<i class='fa fa-2x fa-chart-bar'></i> Statistics" => "vmStat",
|
||||
"<i class='fa fa-2x fa-search'></i> Check Status" => "vmCheck",
|
||||
"<img src='./modules/servers/pvewhmcs/img/novnc.png'/> noVNC (HTML5)" => "noVNC",
|
||||
"<img src='./modules/servers/pvewhmcs/img/tigervnc.png'/> TigerVNC (Java)" => "javaVNC",
|
||||
);
|
||||
return $buttonarray;
|
||||
}
|
||||
@@ -865,7 +915,7 @@ function pvewhmcs_ClientArea($params) {
|
||||
unset($nodes);
|
||||
|
||||
# Get and set VM variables
|
||||
$vm_config = $proxmox->get('/nodes/'.$first_node.'/'.$guest->vtype.'/'.$params['serviceid'] .'/config') ;
|
||||
$vm_config = $proxmox->get('/nodes/'.$first_node.'/'.$guest->vtype.'/'.$guest->vmid .'/config') ;
|
||||
$cluster_resources = $proxmox->get('/cluster/resources');
|
||||
$vm_status = null;
|
||||
|
||||
@@ -910,10 +960,10 @@ function pvewhmcs_ClientArea($params) {
|
||||
$ct_specific = $proxmox->get('/nodes/'.$first_node.'/lxc/'.$guest->vmid.'/status/current');
|
||||
if ($ct_specific['maxswap'] != 0) {
|
||||
$vm_status['swapusepercent'] = intval($ct_specific['swap'] * 100 / $ct_specific['maxswap']);
|
||||
} else {
|
||||
// Fall back to 0% usage to satisfy chart requirement
|
||||
$vm_status['swapusepercent'] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fall back to 0% usage to satisfy chart requirement
|
||||
$vm_status['swapusepercent'] = 0;
|
||||
}
|
||||
} else {
|
||||
// Handle the VM not found in the cluster resources (Optional)
|
||||
@@ -1076,7 +1126,7 @@ function pvewhmcs_noVNC($params) {
|
||||
// Construct the noVNC Router URL with the path already prepared now
|
||||
$url = '/modules/servers/pvewhmcs/novnc_router.php?host=' . $serverip . '&pveticket=' . urlencode($pveticket) . '&path=' . urlencode($path) . '&vncticket=' . urlencode($vncticket);
|
||||
// Build and deliver the noVNC Router hyperlink for access
|
||||
$vncreply = '<center><strong>Console (noVNC) prepared for usage. <a href="'.$url.'" target="_blanK">Click here</a> to open the noVNC window.</strong></center>' ;
|
||||
$vncreply = '<center style="background-color: green;"><strong style="color: white;">Console (noVNC) successfully prepared!<br><a href="'.$url.'" target="_blanK" style="color: Khaki;"><u>Click here to launch noVNC.</u></a></strong></center>' ;
|
||||
return $vncreply;
|
||||
} else {
|
||||
$vncreply = 'Failed to prepare noVNC. Please contact Technical Support.';
|
||||
@@ -1113,7 +1163,7 @@ function pvewhmcs_SPICE($params) {
|
||||
// Construct the SPICE Router URL with the path already prepared now
|
||||
$url = '/modules/servers/pvewhmcs/spice_router.php?host=' . $serverip . '&pveticket=' . urlencode($pveticket) . '&path=' . urlencode($path) . '&vncticket=' . urlencode($vncticket);
|
||||
// Build and deliver the SPICE Router hyperlink for access
|
||||
$vncreply = '<center><strong>Console (SPICE) prepared for usage. <a href="'.$url.'" target="_blanK">Click here</a> to open the noVNC window.</strong></center>' ;
|
||||
$vncreply = '<center style="background-color: green;"><strong>Console (SPICE) successfully prepared.<br><a href="'.$url.'" target="_blanK" style="color: Khaki;"><u>Click here</u></a> to launch SPICE.</strong></center>' ;
|
||||
return $vncreply;
|
||||
} else {
|
||||
$vncreply = 'Failed to prepare SPICE. Please contact Technical Support.';
|
||||
@@ -1150,7 +1200,7 @@ function pvewhmcs_javaVNC($params){
|
||||
$javaVNCparams[4] = $vm_vncproxy['ticket'] ;
|
||||
// URL preparation to deliver in hyperlink message
|
||||
$url = './modules/servers/pvewhmcs/tigervnc.php?'.http_build_query($javaVNCparams).'' ;
|
||||
$vncreply = '<center><strong>Console (TigerVNC) prepared for usage. <a href="'.$url.'" target="_blanK">Click here</a> to open the TigerVNC window.</strong></center>' ;
|
||||
$vncreply = '<center style="background-color: green;"><strong>Console (TigerVNC) successfully prepared.<br><a href="'.$url.'" target="_blanK" style="color: Khaki;"><u>Click here</u></a> to launch TigerVNC.</strong></center>' ;
|
||||
// echo '<script>window.open("modules/servers/pvewhmcs/tigervnc.php?'.http_build_query($javaVNCparams).'","VNC","location=0,toolbar=0,menubar=0,scrollbars=1,resizable=1,width=802,height=624")</script>';
|
||||
return $vncreply;
|
||||
} else {
|
||||
@@ -1339,6 +1389,11 @@ function pvewhmcs_vmStop($params) {
|
||||
}
|
||||
}
|
||||
|
||||
// CLIENT AREA: REFRESH TO CHECK STATUS ON-CLICK
|
||||
function pvewhmcs_vmCheck($params) {
|
||||
return "success";
|
||||
}
|
||||
|
||||
// NETWORKING FUNCTION: Convert subnet mask to CIDR
|
||||
function mask2cidr($mask){
|
||||
$long = ip2long($mask);
|
||||
|
||||
24
modules/servers/pvewhmcs/whmcs.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"schema": "1.0",
|
||||
"type": "whmcs-servers",
|
||||
"name": "pvewhmcs",
|
||||
"license": "open-source",
|
||||
"category": "provisioning",
|
||||
"description": {
|
||||
"name": "Proxmox VE for WHMCS",
|
||||
"tagline": "Seamless integration of Proxmox VE (PVE) VMs & CTs with WHMCS.",
|
||||
"long": ""
|
||||
},
|
||||
"logo": {
|
||||
"filename": "img/logo.png"
|
||||
},
|
||||
"support": {
|
||||
"docs_url": "https://github.com/The-Network-Crew/Proxmox-VE-for-WHMCS"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "The Network Crew Pty Ltd",
|
||||
"homepage": "https:\/\/tnc.works\/"
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
zVMIDimport.png
|
Before Width: | Height: | Size: 153 KiB |