Releases: EZSCALE/virtfusion-whmcs-module
v1.5.1
Tested against: WHMCS 9.0.3 and VirtFusion v7.0.0 Build 9.
Bug Fixes
-
Critical: package upgrades/downgrades reported "Update package request failed. VirtFusion API returned HTTP 200" even though the change succeeded.
ChangePackageissuesPUT /servers/{id}/package/{packageId}, and VirtFusion v7 answers a successful change with HTTP 200 (carrying aninfo[]body describing what was/wasn't synced from the new package) — but the success whitelist only accepted 204, so every real package change fell through to the default branch and surfaced a failure to WHMCS. Because that branch returns early, the follow-up Memory/CPU/Bandwidth tuning never ran either, and WHMCS recorded a failure for an operation VirtFusion had actually applied (state drift). Fixed by accepting 200 (and keeping 204 for older builds); the returnedinfo[]array is now logged so an operator can see when the panel skipped part of a change. -
Per-resource tuning during a package change silently failed on VirtFusion v7.
modifyResource()sent the CPU value under the field namecpuCores, but the/servers/{id}/modify/cpuCoresendpoint requires the fieldcores— the request omitted the required property and was rejected by the API. It also only accepted HTTP 200/204 as success, while v7 returns 201 Created on every/modify/*call (the same version shift already handled for the rename endpoint in 1.5.0). Both are fixed: CPU is now sent ascores, and 201 is added to the success whitelist for memory, CPU, and traffic. These failures had been masked by the HTTP 200 bug above (which returned before the tuning loop) and were swallowed silently — the loop now logs anymodifyResource()failure instead of discarding it.
Disk-downgrade safety (unchanged, confirmed): the module cannot shrink a primary disk and never could. It sends no disk flag on the package change,
modifyResource()excludes storage entirely, no disk-modify endpoint exists, and VirtFusion itself refuses to lower a primary disk ("primary disk not updated. It either matches or is lower than the current value"). A downgrade leaves the disk at its larger size — there is no data-loss path.
Documentation
- Vendored the VirtFusion v7 OpenAPI spec at
docs/openapi.yamlfor offline API reference when auditing endpoint behavior.
Full Changelog: v1.5.0...v1.5.1
v1.4.0
Features
-
Dynamic VPS stock control driven by live hypervisor capacity. Opt-in per product via WHMCS's native
tblproducts.stockcontroltoggle; when enabled, the module overwritestblproducts.qtywith the real number of VPSes the panel can still provision and WHMCS handles the "Out of Stock" badge, Add-to-Cart gating, and checkout refusal natively — no template work required. qty is derived by combining two authoritative sources:GET /packages/{packageId}for the per-VPS resource footprint (memory,cpuCores,primaryStorage,primaryStorageProfile,enabled)GET /compute/hypervisors/groups/{id}/resourcesfor live per-hypervisor free/allocated data
Algorithm sums
min(memory, cpu, storage)across eligible hypervisors (enabled AND commissioned AND !prohibit) for every group the product can be placed in (defaultconfigoption1plus every numeric value of aLocationconfigurable option), capped by the group-level IPv4 pool taken asmax()within a group to avoid double-counting. Storage matching is strict againstpackage.primaryStorageProfile; hypervisors without the named pool contribute 0. Confirmed-missing conditions (HTTP 404 on/packages/{id},package.enabled=false) force qty=0; transient failures leaveqtyUNTOUCHED to avoid false out-of-stock during API blips. -
Event-driven stock recalculation hooks:
AfterModuleCreate— refreshes qty after every VirtFusion provision (capacity just decreased). Bursts of parallel provisions coalesce via a 30 s shared rate-limit.AfterModuleTerminate— refreshes qty after every VirtFusion termination (capacity just increased). Shares the 30 s rate-limit with create.AfterCronJob— every-2-hour safety net that catches capacity changes made directly in the VirtFusion panel without going through WHMCS. Interval tunable viaSTOCK_CRON_INTERVAL_SECONDSinhooks.php.ClientAreaPageCart— opportunistic per-product refresh during the order flow, rate-limited to once per product per 60 s.
-
Order auto-accept after successful provision.
AfterModuleCreatecalls WHMCSAcceptOrder(withautosetup=falseso there's no double-provision) when the parent order is still in Pending status. Closes the gap for installs that rely on pending-order workflows for non-VF products but want VirtFusion provisions to auto-advance. Idempotent — already-accepted orders are skipped. -
Admin-triggered full recalculation. New
admin.php?action=stockRecalculateaction (POST + same-origin required) runsStockControl::recalculateAll()on demand and returns a JSON{productId: qty}map; the module log gets a compact summary ({total, updated, zeroed, skipped}) so it stays readable on stores with hundreds of products. -
Per-product safety buffer. New
stockSafetyBufferPctconfig option (configoption7, default 10) reserves X% of each resource'smaxduring stock calculation. Applied only to capped resources (unlimited resources withmax=0skip the buffer). Admins can override per product in the module settings; blank falls back to 10% so existing products get sensible headroom without any config change. -
Test Connection now probes
/compute/hypervisors/groups. A VirtFusion API token scoped only to/serverswould pass the existing/connectcheck but silently break nightly stock updates. The admin's Test Connection button now surfaces missing/computeread scope at config time with a specific error rather than as unexplained nightly silence.
Caching
- New cache keys:
pkg:{packageId}(10 min TTL, package definitions rarely change) andgrpres:{groupId}(120 s TTL, resources change minute-to-minute under load). Confirmed 404 responses are cached for 60 s so an admin re-creating a deleted package/group takes effect quickly.
Safety Properties
Module::fetchPackage()andModule::fetchGroupResources()return a tri-statearray | false | null:falsemeans "VirtFusion confirmed this doesn't exist → OOS is correct",nullmeans "we can't tell right now → don't touch existing qty". Without this distinction the module would either zero out inventory during transient API blips, or show inventory for deleted packages.\Throwablecatches on every stock-path entry point (not just\Exception) so aTypeErrorfrom a malformed API response can't escape the tri-state contract.- Stock-control is gated by
tblproducts.stockcontrol=1— products that opt out are never touched, even by the safety-net cron.
Full Changelog: v1.3.0...v1.4.0
v1.3.0
Bug Fixes
- Critical: decrypt() corruption of plaintext addon API keys.
Config::get()was calling WHMCS'sdecrypt()on the rawtbladdonmodules.valuefor the PowerDNS API key and accepting whatever non-empty result came back. WHMCS addon password-type fields are actually stored plaintext (unliketblservers.passwordwhich is encrypted), anddecrypt()on plaintext input returns ~4 bytes of binary garbage instead of empty. That garbage was ending up in theX-API-Key:header, producing a baffling 401 from PowerDNS and an empty zone list — which then surfaced as "no zone" for every IP in the client-area rDNS panel. Fix: only usedecrypt()'s output when it's printable ASCII; fall back to raw otherwise. Alsotrim()the chosen value so a stray paste-newline can't corrupt the header.
Features
- IPv6 subnet visibility + custom-host PTR flow. VirtFusion allocates v6 as whole subnets (e.g. a /64 routed to the VPS) rather than discrete host addresses. The module previously filtered these silently; now subnets appear as first-class rows in the client rDNS panel with a collapsible "Add host PTR" form. Ownership verification uses subnet containment (
IpUtil::ipv6InSubnet()viainet_pton+ bit masking) so any address inside one of the VPS's allocated subnets is writeable, while addresses outside them are rejected. FCrDNS / rate-limit / CSRF guards all still apply. - Diagnose-an-IP tool on the VirtFusion DNS addon admin page. Takes an IP input and runs the full PtrManager pipeline inline: config snapshot, fresh zone list (cache-bypassed), computed PTR name, matched zone, current PTR content. Every common failure mode (wrong key, wrong serverId, forgotten zone, mis-aligned RFC 2317 label, stale cache) produces a distinctive shape in that output, turning "support ticket" into "screenshot the diagnosis".
- Actionable auth-error messages.
Client::ping()now returns structured guidance on 401/403 (check API key,api-allow-from, whitespace) and 404 (checkserverId, it should be the literallocalhost), replacing the previous "authentication failed (check API key)" / "unexpected HTTP 404" which gave no clue which of several causes was actually biting.
Full Changelog: v1.2.0...v1.3.0
v1.2.0 — PowerDNS Reverse DNS Integration
This release adds an opt-in reverse DNS management subsystem for operators running PowerDNS, plus a round of security hardening and code-level documentation improvements.
Highlights
PowerDNS Reverse DNS (PTR) Integration
A new companion addon module (VirtFusionDns) lets the provisioning module automatically manage PTR records through the PowerDNS HTTP API — fully optional, with zero impact on existing deployments that don't activate it.
- Automatic PTR lifecycle — PTRs are created on server provisioning, updated on rename, and deleted on termination
- Client-area Reverse DNS panel — one editable PTR input per assigned IP on the service overview, with per-row status badges
- Admin services-tab widget — live PTR state plus Reconcile (additive) and Reconcile (force reset) buttons
- Daily additive reconciliation via WHMCS
DailyCronJob— creates any missing PTRs, never overwrites existing values - Forward-confirmed reverse DNS (FCrDNS) enforcement — PTR writes are rejected if the hostname's forward A/AAAA doesn't already resolve to the target IP, so rDNS is never left in a deliverability-harming mismatched state
- IPv4 + IPv6 support including full nibble-reversal for
ip6.arpazones - RFC 2317 classless delegation support — both CIDR-prefix (
0/26) and block-size (64/64) naming conventions are parsed and matched by IP range - Automatic NOTIFY after every successful PATCH so slaves pick up the SOA-bumped serial immediately (no waiting for the next scheduled refresh)
Security Hardening
New reusable guards on the Module base class, applied to the rDNS endpoints:
requirePost()— enforces POST for mutating endpoints (405 otherwise)requireSameOrigin()— validatesOrigin/Refereragainst the WHMCS host as a CSRF defense against cross-site form POSTsrequireServiceStatus()— filters bytblhosting.domainstatus(writes requireActive, reads allowActive+Suspended)
Every successful PTR edit is written to the WHMCS Module Log with {clientId, serviceId, ip} for audit traceability.
Merged Test Connection
The admin Test Connection button now validates both VirtFusion and PowerDNS in a single check when the DNS addon is active.
Fixed
IpUtil::parseClasslessZonenow rejects misaligned RFC 2317 zone names (e.g.,3/26.x.y.z.in-addr.arpa.— a /26 delegation must begin at a multiple of 64). Prevents silent writes into the wrong zone on misconfigured labels.
Documentation
- Extensive design-rationale commentary added across the module's support classes (
Cache,Curl,Log,Database,ServerResource,ConfigureService) and throughout the new PowerDNS subsystem README.mdgains a full Reverse DNS Addon (PowerDNS) section covering prerequisites, activation, settings, behaviour-by-event, RFC 2317 handling, and security postureCLAUDE.mdupdated with architecture notes and a PowerDNS API compatibility matrix
Installation / Upgrade
Existing installs can pull the latest module files as usual. The DNS addon is opt-in — deploying it is a no-op until an operator activates it. Set WHMCS once and it's reused for every rsync destination:
WHMCS=/path/to/whmcs
git clone https://github.com/EZSCALE/virtfusion-whmcs-module.git /tmp/vf \
&& rsync -ahP --delete /tmp/vf/modules/servers/VirtFusionDirect/ "$WHMCS/modules/servers/VirtFusionDirect/" \
&& rsync -ahP --delete /tmp/vf/modules/addons/VirtFusionDns/ "$WHMCS/modules/addons/VirtFusionDns/" \
&& rm -rf /tmp/vfThe second rsync line is only needed if you want to use the Reverse DNS addon. To activate it: WHMCS Admin → System Settings → Addon Modules → VirtFusion DNS → Activate, then Configure and enter the PowerDNS endpoint + API key. The README's Reverse DNS Addon (PowerDNS) section walks through the full setup.
No database migration is required — addon settings live in tbladdonmodules and are created on activation. The existing mod_virtfusion_direct table is unchanged.
Requirements for the DNS Addon
- PowerDNS Authoritative 4.x with HTTP API enabled (
webserver=yes,api=yes,api-key=...) api-allow-frommust include your WHMCS host's IP- All reverse zones you want to manage must already exist in PowerDNS — the addon never creates zones
- Recommended: set
soa_edit_api=INCREASEon each zone so PowerDNS auto-bumps the SOA serial on API writes
Full Changelog
See CHANGELOG.md · Compare: v1.1.0...v1.2.0
v1.1.0
Features
- Auto-create custom fields —
Initial Operating SystemandInitial SSH Keyfields are now created automatically on module load viaDatabase::ensureCustomFields(). No more manual SQL import.modify.sqlhas been removed. (d253bd4) - OS gallery, server rename, traffic chart, backups, VNC toggle, password reset, Redis caching, UX improvements (90a97c4)
- Laravel Pint code formatting with pre-commit hook, auto-installed via Composer (d253bd4)
Bug Fixes
- Restore OS template icons using correct VirtFusion path
/img/logo/(6528c8a) - Constrain OS icon sizing and remove background when image loads (6694a5e)
- Constrain category header icon images with overflow:hidden and max dimensions (64dcce3)
- Use unix timestamp for cache busting, generic server icon for Other category (504d292)
- Force generic icon on 'Other' category even when API provides linux_logo.png (3ca9eb6)
- OS gallery accordion auto-collapses other sections when one opens (a9565ff)
- OS gallery accordion layout and remove broken remote icon fetching (9cd737c)
- Remove dead code, update stale versions, tag-based release workflow (d3d75b4)
Code Quality
- Comprehensive try/catch — every DB operation and API call is now wrapped per project error handling rules (d253bd4)
- Full PHPDoc — class-level and method-level documentation on all PHP files (d253bd4)
- Dead code removal and project audit cleanup (1ab2ef4)
- Consolidate duplicate logic across codebase (0ade74d)
- Simplified README installation to a single copy-paste command
1.0.0
0.0.18
Full Changelog: 0.0.17...0.0.18
0.0.17
Release 0.0.17
0.0.16
Release 0.0.16
0.0.15
Release 0.0.15