|
| 1 | +--- |
| 2 | +name: cloudlinux-api |
| 3 | +description: Uses the Detain\Cloudlinux\Cloudlinux client (from detain/cloudlinux-licensing) for license operations — isLicensed(), license(), remove(), licenseList(), kcareList(), imunifyList(). Use when user says 'check license', 'activate IP', 'remove license', 'list licenses', or adds bin/ scripts. Do NOT use for Plugin hook wiring or EventDispatcher registration. |
| 4 | +--- |
| 5 | +# CloudLinux API |
| 6 | + |
| 7 | +## Critical |
| 8 | + |
| 9 | +- **Always** instantiate with `new Cloudlinux(CLOUDLINUX_LOGIN, CLOUDLINUX_KEY)` — never hard-code credentials. |
| 10 | +- **Always** `use Detain\Cloudlinux\Cloudlinux;` at the top of the file. |
| 11 | +- **Never** call the XML-RPC endpoint directly from new code — use the `Cloudlinux` client methods. |
| 12 | +- `isLicensed($ip, true)` returns an **array** of active type IDs; `isLicensed($ip)` (no second arg) returns bool. Pass `true` whenever you need to inspect which types are active. |
| 13 | +- `remove()` without a type ID removes **all** licenses on that IP. Always pass `$type` when you only want to remove one tier. |
| 14 | +- After every mutating call (`license()`, `remove()`), check `$response === false` for failure — the client returns `false`, not an exception, on API error. |
| 15 | +- Log every API call with `myadmin_log()` before and after; log with `request_log()` after mutation calls. |
| 16 | + |
| 17 | +## Instructions |
| 18 | + |
| 19 | +### Step 1 — Bootstrap (bin/ scripts) |
| 20 | + |
| 21 | +For standalone CLI scripts under `bin/`, load the environment with: |
| 22 | + |
| 23 | +```php |
| 24 | +#!/usr/bin/env php |
| 25 | +<?php |
| 26 | +use Detain\Cloudlinux\Cloudlinux; |
| 27 | + |
| 28 | +require_once __DIR__.'/../../../../include/functions.inc.php'; |
| 29 | +``` |
| 30 | + |
| 31 | +Verify `CLOUDLINUX_LOGIN` and `CLOUDLINUX_KEY` are defined constants after the require before proceeding. |
| 32 | + |
| 33 | +### Step 2 — Bootstrap (src/ helpers) |
| 34 | + |
| 35 | +For helper functions in `src/cloudlinux.inc.php`, use: |
| 36 | + |
| 37 | +```php |
| 38 | +<?php |
| 39 | +use Detain\Cloudlinux\Cloudlinux; |
| 40 | +``` |
| 41 | + |
| 42 | +No require needed — Composer autoload handles it at runtime via the plugin loader. |
| 43 | + |
| 44 | +### Step 3 — Instantiate the client |
| 45 | + |
| 46 | +Always create a fresh client per operation: |
| 47 | + |
| 48 | +```php |
| 49 | +$cl = new Cloudlinux(CLOUDLINUX_LOGIN, CLOUDLINUX_KEY); |
| 50 | +``` |
| 51 | + |
| 52 | +### Step 4 — Check if an IP is licensed |
| 53 | + |
| 54 | +```php |
| 55 | +$cl = new Cloudlinux(CLOUDLINUX_LOGIN, CLOUDLINUX_KEY); |
| 56 | +$response = $cl->isLicensed($ipAddress, true); // true = return array of active type IDs |
| 57 | +// $response is an array like [0 => 1, 1 => 16] or false/empty when unlicensed |
| 58 | +if (is_array($response) && in_array($typeId, array_values($response))) { |
| 59 | + // already has this type licensed |
| 60 | +} |
| 61 | +``` |
| 62 | + |
| 63 | +### Step 5 — Activate a license |
| 64 | + |
| 65 | +```php |
| 66 | +myadmin_log('licenses', 'info', 'Activating license for '.$ipAddress, __LINE__, __FILE__); |
| 67 | +$cl = new Cloudlinux(CLOUDLINUX_LOGIN, CLOUDLINUX_KEY); |
| 68 | +$response = $cl->license($ipAddress, $typeId); |
| 69 | +request_log('licenses', $custid, __FUNCTION__, 'cloudlinux', 'license', [$ipAddress, $typeId], $response, $serviceId); |
| 70 | +myadmin_log('licenses', 'info', 'Response: '.json_encode($response), __LINE__, __FILE__); |
| 71 | +if ($response === false) { |
| 72 | + // handle error |
| 73 | +} |
| 74 | +``` |
| 75 | + |
| 76 | +Type IDs: `1`=CloudLinux, `16`=KernelCare, `40`=ImunityAV+, `41`=Imunify360 single, `42`=up to 30 users, `43`=up to 250 users, `49`=unlimited. |
| 77 | + |
| 78 | +### Step 6 — Remove a license |
| 79 | + |
| 80 | +```php |
| 81 | +myadmin_log('cloudlinux', 'info', "Deactivate CloudLinux({$ipAddress}, {$type}) called", __LINE__, __FILE__); |
| 82 | +$cl = new Cloudlinux(CLOUDLINUX_LOGIN, CLOUDLINUX_KEY); |
| 83 | +if ($type == false) { |
| 84 | + $response = $cl->remove($ipAddress); // removes ALL types on this IP |
| 85 | +} else { |
| 86 | + $response = $cl->remove($ipAddress, $type); // removes only the given type |
| 87 | +} |
| 88 | +if (!isset($response['success']) || $response['success'] !== true) { |
| 89 | + // send failure email (see Common Issues below) |
| 90 | +} |
| 91 | +request_log('licenses', false, __FUNCTION__, 'cloudlinux', 'removeLicense', [$ipAddress, $type], $response); |
| 92 | +myadmin_log('cloudlinux', 'info', "Deactivate response: ".json_encode($response), __LINE__, __FILE__); |
| 93 | +``` |
| 94 | + |
| 95 | +### Step 7 — List all licenses |
| 96 | + |
| 97 | +Use the helper function already registered in `src/cloudlinux.inc.php`: |
| 98 | + |
| 99 | +```php |
| 100 | +function_requirements('get_cloudlinux_licenses'); |
| 101 | +$licenses = get_cloudlinux_licenses(); |
| 102 | +print_r($licenses); |
| 103 | +``` |
| 104 | + |
| 105 | +Or call directly: |
| 106 | + |
| 107 | +```php |
| 108 | +$cl = new Cloudlinux(CLOUDLINUX_LOGIN, CLOUDLINUX_KEY); |
| 109 | +$licenses = $cl->licenseList(); // all CloudLinux licenses |
| 110 | +$kcare = $cl->kcareList(); // KernelCare only |
| 111 | +$imunify = $cl->imunifyList(); // Imunify360 only |
| 112 | +``` |
| 113 | + |
| 114 | +### Step 8 — Failure email on deactivation error |
| 115 | + |
| 116 | +Mirror the pattern from `src/cloudlinux.inc.php:deactivate_cloudlinux()`: |
| 117 | + |
| 118 | +```php |
| 119 | +if (!isset($response['success']) || $response['success'] !== true) { |
| 120 | + $bodyRows = []; |
| 121 | + $bodyRows[] = 'License IP: '.$ipAddress.' unable to deactivate.'; |
| 122 | + $bodyRows[] = 'Deactivation Response: .'.json_encode($response); |
| 123 | + $subject = 'Cloudlinux License Deactivation Issue IP: '.$ipAddress; |
| 124 | + $smartyE = new TFSmarty(); |
| 125 | + $smartyE->assign('h1', 'Cloudlinux License Deactivation'); |
| 126 | + $smartyE->assign('body_rows', $bodyRows); |
| 127 | + $msg = $smartyE->fetch('email/client/client_email.tpl'); |
| 128 | + (new \MyAdmin\Mail())->multiMail($subject, $msg, false, 'client/client_email.tpl'); |
| 129 | +} |
| 130 | +``` |
| 131 | + |
| 132 | +## Examples |
| 133 | + |
| 134 | +**User says:** "Add a bin script to activate a CloudLinux license for a given IP" |
| 135 | + |
| 136 | +**Actions taken:** |
| 137 | +1. Create `bin/activate_cloudlinux.php` |
| 138 | +2. Add shebang + `use` + require bootstrap |
| 139 | +3. Instantiate client with constants |
| 140 | +4. Call `isLicensed()` to check first, then `license()` if needed |
| 141 | +5. Print result |
| 142 | + |
| 143 | +**Result:** |
| 144 | + |
| 145 | +```php |
| 146 | +#!/usr/bin/env php |
| 147 | +<?php |
| 148 | +use Detain\Cloudlinux\Cloudlinux; |
| 149 | + |
| 150 | +require_once __DIR__.'/../../../../include/functions.inc.php'; |
| 151 | + |
| 152 | +$ipAddress = $_SERVER['argv'][1]; |
| 153 | +$typeId = isset($_SERVER['argv'][2]) ? (int)$_SERVER['argv'][2] : 1; |
| 154 | + |
| 155 | +$cl = new Cloudlinux(CLOUDLINUX_LOGIN, CLOUDLINUX_KEY); |
| 156 | +$existing = $cl->isLicensed($ipAddress, true); |
| 157 | +if (is_array($existing) && in_array($typeId, array_values($existing))) { |
| 158 | + echo "IP {$ipAddress} already has type {$typeId} licensed.\n"; |
| 159 | + exit(0); |
| 160 | +} |
| 161 | +$response = $cl->license($ipAddress, $typeId); |
| 162 | +if ($response === false) { |
| 163 | + echo "Error licensing {$ipAddress}.\n"; |
| 164 | + exit(1); |
| 165 | +} |
| 166 | +print_r($response); |
| 167 | +echo "Success licensing {$ipAddress} type {$typeId}.\n"; |
| 168 | +``` |
| 169 | + |
| 170 | +--- |
| 171 | + |
| 172 | +**User says:** "Write a helper to deactivate KernelCare for an IP" |
| 173 | + |
| 174 | +**Result:** Add to `src/cloudlinux.inc.php`: |
| 175 | + |
| 176 | +```php |
| 177 | +function deactivate_kcare($ipAddress) |
| 178 | +{ |
| 179 | + return deactivate_cloudlinux($ipAddress, 16); |
| 180 | +} |
| 181 | +``` |
| 182 | + |
| 183 | +(delegates to the existing `deactivate_cloudlinux()` with type `16`.) |
| 184 | + |
| 185 | +## Common Issues |
| 186 | + |
| 187 | +**`Call to undefined constant CLOUDLINUX_LOGIN`** |
| 188 | +The `include/functions.inc.php` bootstrap was not loaded, or it was loaded but the settings have not been initialized. In bin/ scripts, verify the require path resolves: `realpath(__DIR__.'/../../../../include/functions.inc.php')` should exist. In src/ helpers called via plugin loader, `function_requirements()` must have been called first. |
| 189 | + |
| 190 | +**`$response === false` on `license()` or `remove()`** |
| 191 | +The XML-RPC call failed (network, bad credentials, or IP already in that state). Check `CLOUDLINUX_LOGIN` and `CLOUDLINUX_KEY` constants are correct. Run `php bin/cloudlinux_check.php <ip>` to verify connectivity. The client does not throw — it returns `false`. |
| 192 | + |
| 193 | +**`isLicensed()` returns `false` but IP is definitely licensed** |
| 194 | +You called `isLicensed($ip)` without the `true` second argument — it returns bool. Use `isLicensed($ip, true)` to get the array of active type IDs. |
| 195 | + |
| 196 | +**`in_array($typeId, $response)` always false even though licensed** |
| 197 | +Use `in_array($typeId, array_values($response))` — the response array may have non-sequential keys. |
| 198 | + |
| 199 | +**`Class 'TFSmarty' not found` in deactivation error email** |
| 200 | +The function is being called outside the MyAdmin request context. `TFSmarty` is only available after the full MyAdmin bootstrap. In CLI/bin scripts, skip the email and only log with `myadmin_log()`. |
0 commit comments