68 Commits

Author SHA1 Message Date
Luke S Thompson
a4b90f8d84 v1.2.17: VNC & Hyperscalers! 2025-10-19 09:49:08 +11:00
Luke S Thompson
472e9c8266 samesite=None for PVE Cookie (#167) 2025-10-18 22:22:35 +11:00
Luke S Thompson
cbf686b787 ss: New Action; Green CTA; Tidier Text 2025-10-18 21:53:21 +11:00
Luke S Thompson
e3f2491b56 VNC prepared now Green; Cookie = Secure (#167) 2025-10-18 21:36:28 +11:00
Luke S Thompson
5acc32fb2b Explain noVNC debug logging (#167) 2025-10-18 20:21:19 +11:00
Luke S Thompson
f614863547 Add "Check Status" Client action 2025-10-18 19:50:15 +11:00
Luke S Thompson
49a5d7f317 Delete cookie before setting it (#167) 2025-10-18 17:47:46 +11:00
Luke S Thompson
a81013bbc2 Explain about PVEAuthCookie (#167) 2025-10-18 17:41:04 +11:00
Luke S Thompson
5432eaad80 Clarify how to access noVNC (#167) 2025-10-18 12:11:43 +11:00
Luke S Thompson
63f56f8eea Cores/CPUs columns 2->3 chars (#167) 2025-10-17 12:17:41 +11:00
Luke S Thompson
cc302ed650 Try fix max-RAM issue (#167) 2025-10-17 12:01:30 +11:00
Luke S Thompson
2d8888138f v1.2.16: Minor Adjustments 2025-10-15 13:42:41 +11:00
Luke S Thompson
8d3c6e4abd Improved text layout (Admin GUI) 2025-10-15 13:37:49 +11:00
Luke S Thompson
f1f16e0826 Link to repo for Available Update 2025-10-15 13:31:41 +11:00
Luke S Thompson
fb9b730355 Minor wording tweaks (Plan add/edit) 2025-10-14 13:10:29 +11:00
Luke S Thompson
98270007e5 Guest Plan & PVE GUI button formatting 2025-10-13 13:42:41 +11:00
Luke S Thompson
3585a6cc1c Import & Support notes into highlights 2025-09-03 11:29:16 +10:00
Luke S Thompson
e266fa8c9d Replace Wiki link w/ README 2025-08-30 08:08:29 +10:00
Luke S Thompson
f4c3f0de0e v1.2.15: Little Adjustments 2025-08-29 10:51:35 +10:00
Luke S Thompson
470b1e15d2 Retain SQL data on-deactivate (fix #160) 2025-08-27 12:08:49 +10:00
Luke S Thompson
38a0e9f935 Update CHANGELOG.md 2025-08-27 10:52:04 +10:00
Luke S Thompson
e221503cc8 NIC #2 info to multiple lines 2025-08-27 10:51:37 +10:00
Luke S Thompson
7851db7cad Rename function (fix #159) 2025-08-27 10:45:48 +10:00
Luke S Thompson
efe73f8a28 Updated Logs/Tasks image 2025-08-19 13:11:02 +10:00
Luke S Thompson
f612c84897 VMID into PVE Tasks/Logs table 2025-08-19 13:10:14 +10:00
Luke S Thompson
ea985a2d37 Final module pretty name update 2025-08-19 12:54:10 +10:00
Luke S Thompson
60d0a67d40 Update menu imagery (new-only) 2025-08-19 10:39:22 +10:00
Luke S Thompson
aa54e51c7b Re-arrange Log columns; replace SS 2025-08-19 10:06:10 +10:00
Luke S Thompson
0f64b5b835 Add the Cluster History log (SS) 2025-08-19 09:58:03 +10:00
Luke S Thompson
b054965528 Re-order Admin GUI tabs/panes; new SS 2025-08-19 09:55:08 +10:00
Luke S Thompson
0634a17cdc v1.2.14 (fix #50, fix #154, fix #155, fix #157) 2025-08-19 08:42:37 +10:00
Luke S Thompson
fb08f8ac36 New screenshot 2025-08-18 18:34:46 +10:00
Luke S Thompson
86fbffd0b6 Consoles to bottom of menu 2025-08-18 18:31:42 +10:00
Luke S Thompson
1e01f1b1a9 Improve labels for power actions 2025-08-18 18:30:16 +10:00
Luke S Thompson
ecb6a4aa51 Improve Client Area (fix #154, fix #155) 2025-08-18 18:02:23 +10:00
Luke S Thompson
335ff949be Move docs into new folder 2025-08-18 17:19:12 +10:00
Luke S Thompson
3d9bff7e9c Rename one & add another 2025-08-18 17:16:19 +10:00
Luke S Thompson
5d2dfc273e Add Server Test screenshot 2025-08-18 17:09:04 +10:00
Luke S Thompson
7ee297e562 Move images into new folder 2025-08-18 17:01:55 +10:00
Luke S Thompson
22809ce9b3 Add new screenshot 2025-08-18 16:49:05 +10:00
Luke S Thompson
4ae70047ab add Product Save screenshot 2025-08-18 16:47:53 +10:00
Luke S Thompson
b8266f7f8c Shorten name of "WHMCS Server" type 2025-08-18 14:58:45 +10:00
Luke S Thompson
fe6c1bae56 Delete pvewhmcs-v1-2-13.zip 2025-08-13 15:52:44 +10:00
Luke S Thompson
1718d17e5a POST to GET request (#152) 2025-08-13 15:51:07 +10:00
Luke S Thompson
f1e701ac02 Remove trailing / (#152) 2025-08-13 15:48:01 +10:00
Luke S Thompson
5d97d34ab1 v1.2.13 (#151 and #152) 2025-08-13 15:38:11 +10:00
Luke S Thompson
5624ef1bac Change to standardised button (#152) 2025-08-13 15:29:32 +10:00
Luke S Thompson
a6e98b75a9 PVE AdminLink (GUI) fix #152 2025-08-13 15:23:24 +10:00
Luke S Thompson
4af6008317 whmcs.json file/logo; conn. test name (fix #151) 2025-08-13 13:37:21 +10:00
Luke S Thompson
2d798d1a0e v1.2.12 (fix #105, #139, #148, #149, #150) 2025-08-12 14:02:12 +10:00
Luke S Thompson
655ee29e10 Explicit $0.00 x2 on Service Add (#135) 2025-08-11 13:24:35 +10:00
Luke S Thompson
5a7c823c40 Fix C'LOG re: Virtio/E1000 2025-08-05 15:26:41 +10:00
Luke S Thompson
caa173cef4 Final serviceid to vmid (fix #146) 2025-08-05 15:25:54 +10:00
Luke S Thompson
0fd26ef72a /cluster/nextid for #136 & #145 2025-08-05 08:30:27 +10:00
Luke S Thompson
deedc53eb0 Minor tweaks 2025-08-02 15:03:15 +10:00
Luke S Thompson
d14ee3ce0e Final images for now (5 total)
WHMCS Marketplace only includes 3x by default
2025-08-02 12:21:41 +10:00
Luke S Thompson
5f8534e1a9 Module Config pane: minor text updates 2025-08-02 12:14:05 +10:00
Luke S Thompson
ec1f4fa6e7 New H3 for Custom Fields 2025-08-02 12:05:01 +10:00
Luke S Thompson
9d30365d5e Link to classdocs 2025-08-02 11:54:06 +10:00
Luke S Thompson
05e21eb441 Update flow into <ol> 2025-08-02 11:47:12 +10:00
Luke S Thompson
c7474af62a Fix tables 2025-08-02 11:41:31 +10:00
Luke S Thompson
03adc10597 Improved formatting 2025-08-02 11:36:26 +10:00
Luke S Thompson
e4fe986a6b Heading tidy-up etc 2025-08-02 11:21:18 +10:00
Luke S Thompson
69787b823c 'nodes' column (whmcs_id) #127 README 2025-08-02 11:15:34 +10:00
Luke S Thompson
171eadce0d Add 2nd & 3rd screenshots 2025-08-02 09:44:10 +10:00
Luke S Thompson
28921ab03d NIC default Virtio, was E1000 2025-08-02 09:36:38 +10:00
Luke S Thompson
ad6aac64f8 SQL prep for #105 2025-08-02 09:30:11 +10:00
Luke S Thompson
8e4a3c56d0 v1.3.x SQL tweak; README polish 2025-08-02 09:20:48 +10:00
31 changed files with 852 additions and 238 deletions

View File

@@ -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
View File

@@ -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.**

View File

@@ -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
```

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

BIN
_images/zClusterGuests.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

BIN
_images/zClusterHistory.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 KiB

BIN
_images/zConfiguration.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

BIN
_images/zConsoleReady.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

BIN
_images/zModuleDebug.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

BIN
_images/zPatchAvailable.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

BIN
_images/zProductISOetc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

BIN
_images/zProductSave.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

BIN
_images/zQEMUplanAdd.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 KiB

BIN
_images/zServerListLink.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 KiB

BIN
_images/zServerTestOK.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
_images/zVMIDimport.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

BIN
_images/zVMclientGUI.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

BIN
_images/zVNCprepared.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -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`)
);

View File

@@ -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 &gt; Products/Services &gt; 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.'&amp;tab=vmplans&amp;action=editplan&amp;id='.$vm->id.'&amp;vmtype='.$vm->vmtype.'"><img height="16" width="16" border="0" alt="Edit" src="images/edit.gif"></a>
<a href="'.pvewhmcs_BASEURL.'&amp;tab=vmplans&amp;action=removeplan&amp;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;
}
?>

View File

@@ -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:&nbsp;{$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:&nbsp;{$vm_config['netmask4']}<br/>Gateway:&nbsp;{$vm_config['gateway4']}</td>
</tr>
<tr>
<td><strong>OS/etc</strong> (System)</td>
<td>Kernel:&nbsp;{$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']}&nbsp;socket/s,&nbsp;{$vm_config['cores']}&nbsp;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']}&nbsp;{$vm_config['cores']}&nbsp;core/s&nbsp;on&nbsp;{$vm_config['sockets']}&nbsp;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:&nbsp;{$vm_config['ostype']}</td>
</tr>
<tr>
<td><strong>IPv4</strong> (Network)</td><td><strong>{$vm_config['ipv4']}</strong><br/>Mask:&nbsp;{$vm_config['netmask4']}<br/>Gateway:&nbsp;{$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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@@ -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;
}
?>
?>

View File

@@ -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.'&nbsp;:&nbsp;'.$plan->title ;
$plans[$plan->id] = '(' . $plan->vmtype . ')&nbsp;' . $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);

View 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\/"
}
]
}

View File

@@ -1 +1 @@
1.2.10
1.2.17

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB