Compare commits

...

3 Commits

Author SHA1 Message Date
Prophet731 08ab36fdd3 chore(release): 1.5.1
Publish Release / release (push) Failing after 7s
Patch release: fix package upgrade/downgrade reporting a successful
HTTP 200 as a failure, and repair the per-resource modify calls
(cores field name + 201 acceptance) on VirtFusion v7.

Tested against WHMCS 9.0.3 + VirtFusion v7.0.0 Build 9.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 12:04:41 -05:00
Prophet731 bf1e0dc6a9 docs: add VirtFusion OpenAPI spec (v7) under docs/
Vendored copy of https://docs.virtfusion.com/api/openapi.yaml for offline
reference when auditing API behavior (success codes, request/response shapes).
Current production target is VirtFusion v7.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 11:59:25 -05:00
Prophet731 9d57ee6150 fix(changepackage): treat HTTP 200 as success and repair resource modify calls
VirtFusion v7's PUT /servers/{id}/package/{pkg} returns HTTP 200 (with an
{info:[...]} body), not 204. changePackage() only accepted 204, so every
successful package change fell through to the default case and reported
"Update package request failed. VirtFusion API returned HTTP 200" — the
exact error seen in production. The early return also skipped the
memory/CPU/traffic modify loop entirely.

- Accept 200 (and keep 204) as success; log the info array so operator can
  see skipped changes (e.g. "primary disk not updated... lower than current").
- modifyResource(): send cpuCores as the spec-required "cores" body field
  (wrong field name omitted the required property → CPU changes rejected).
- modifyResource(): accept 201 alongside 200/204 — VF v7 returns 201 Created
  on modify, mirroring the existing rename-endpoint fix.
- Surface modifyResource() failures in the package-change loop instead of
  swallowing them.

Disk-downgrade safety is unchanged and confirmed: no disk flag is sent, the
modify allowlist excludes storage, no disk-modify endpoint exists, and VF
itself refuses to shrink the primary disk.

Verified against the VirtFusion v7 OpenAPI spec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 11:59:17 -05:00
4 changed files with 8402 additions and 5 deletions
+16
View File
@@ -2,6 +2,22 @@
All notable changes to the VirtFusion Direct Provisioning Module for WHMCS. All notable changes to the VirtFusion Direct Provisioning Module for WHMCS.
## [1.5.1] - 2026-06-02
> **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.** `ChangePackage` issues `PUT /servers/{id}/package/{packageId}`, and VirtFusion v7 answers a successful change with **HTTP 200** (carrying an `info[]` 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 returned `info[]` 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 name `cpuCores`, but the `/servers/{id}/modify/cpuCores` endpoint requires the field `cores` — 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 as `cores`, 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 any `modifyResource()` 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.yaml` for offline API reference when auditing endpoint behavior.
## [1.5.0] - 2026-04-28 ## [1.5.0] - 2026-04-28
> **Tested against:** WHMCS 9.0.3 and VirtFusion v7.0.0 Build 9. > **Tested against:** WHMCS 9.0.3 and VirtFusion v7.0.0 Build 9.
+8359
View File
File diff suppressed because one or more lines are too long
@@ -789,12 +789,20 @@ class Module
return false; return false;
} }
$ctx['request']->addOption(CURLOPT_POSTFIELDS, json_encode([$resource => $value])); // The /modify/{resource} endpoints name their body field differently from our
// internal resource key: cpuCores is sent as "cores" (memory/traffic match 1:1).
// Sending the wrong field name omits the required property and the change is rejected.
$fieldMap = ['memory' => 'memory', 'cpuCores' => 'cores', 'traffic' => 'traffic'];
$field = $fieldMap[$resource];
$ctx['request']->addOption(CURLOPT_POSTFIELDS, json_encode([$field => $value]));
$data = $ctx['request']->put($ctx['cp']['url'] . '/servers/' . $ctx['serverId'] . '/modify/' . $resource); $data = $ctx['request']->put($ctx['cp']['url'] . '/servers/' . $ctx['serverId'] . '/modify/' . $resource);
Log::insert(__FUNCTION__ . ':' . $resource, $ctx['request']->getRequestInfo(), $data); Log::insert(__FUNCTION__ . ':' . $resource, $ctx['request']->getRequestInfo(), $data);
$httpCode = $ctx['request']->getRequestInfo('http_code'); // VF v7 returns 201 (Created) on a successful modify; older builds returned 200/204.
if ($httpCode == 200 || $httpCode == 204) { // Accept all three so we cover the version range (mirrors the rename-endpoint fix).
$httpCode = (int) $ctx['request']->getRequestInfo('http_code');
if ($httpCode == 200 || $httpCode == 201 || $httpCode == 204) {
return json_decode($data) ?: (object) ['success' => true]; return json_decode($data) ?: (object) ['success' => true];
} }
@@ -274,8 +274,18 @@ class ModuleFunctions extends Module
Log::insert(__FUNCTION__, $request->getRequestInfo(), $data); Log::insert(__FUNCTION__, $request->getRequestInfo(), $data);
switch ($request->getRequestInfo('http_code')) { switch ((int) $request->getRequestInfo('http_code')) {
case 200:
// VirtFusion v7 returns 200 (with an {info:[...]} body) on a package change;
// older builds returned 204. The info array reports what was/wasn't synced
// from the new package — e.g. "primary disk not updated. It either matches or
// is lower than the current value" (the panel never shrinks a disk). Log it so
// an operator can see when a requested change was skipped.
if (isset($data->info) && is_array($data->info)) {
Log::insert(__FUNCTION__ . ':info', [], $data->info);
}
break;
case 204: case 204:
break; break;
case 404: case 404:
@@ -310,7 +320,11 @@ class ModuleFunctions extends Module
if ($resource === 'memory' && $value < 1024) { if ($resource === 'memory' && $value < 1024) {
$value = $value * 1024; $value = $value * 1024;
} }
$this->modifyResource($params['serviceid'], $resource, $value); if ($this->modifyResource($params['serviceid'], $resource, $value) === false) {
// A single resource tweak failing shouldn't fail the whole package
// change, but the failure must not be silent — log it for the operator.
Log::insert(__FUNCTION__ . ':modifyFailed', ['resource' => $resource, 'value' => $value], 'modifyResource returned false');
}
} }
} }
} }