init
This commit is contained in:
commit
1bf67eef22
5 changed files with 491 additions and 0 deletions
2
README.md
Normal file
2
README.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# service-virtfusionservice
|
||||||
|
A WemX service integration with VirtFusion
|
439
Service.php
Normal file
439
Service.php
Normal file
|
@ -0,0 +1,439 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\VirtfusionService;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use App\Services\ServiceInterface;
|
||||||
|
use App\Models\Package;
|
||||||
|
use App\Models\Order;
|
||||||
|
use App\Models\ServiceAccount;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
|
||||||
|
class Service implements ServiceInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Unique key used to store settings
|
||||||
|
* for this service.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static $key = 'virtfusionserv';
|
||||||
|
|
||||||
|
public function __construct(Order $order)
|
||||||
|
{
|
||||||
|
$this->order = $order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDisplayName(): string
|
||||||
|
{
|
||||||
|
return settings('virtfusionserv::display_name', 'VirtFusion');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the meta data about this Server/Service
|
||||||
|
*
|
||||||
|
* @return object
|
||||||
|
*/
|
||||||
|
public static function metaData(): object
|
||||||
|
{
|
||||||
|
return (object)
|
||||||
|
[
|
||||||
|
'display_name' => 'VirtfusionService',
|
||||||
|
'author' => 'Shane C.',
|
||||||
|
'version' => '1.0.0',
|
||||||
|
'wemx_version' => ['dev', '>=1.8.0'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the default configuration values required to setup this service
|
||||||
|
* i.e host, api key, or other values. Use Laravel validation rules for
|
||||||
|
*
|
||||||
|
* Laravel validation rules: https://laravel.com/docs/10.x/validation
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function setConfig(): array
|
||||||
|
{
|
||||||
|
|
||||||
|
$doesNotEndWithSlash = function ($attribute, $value, $fail) {
|
||||||
|
if (preg_match('/\/$/', $value)) {
|
||||||
|
return $fail('Panel URL must not end with a slash "/". It should be like https://panel.example.com');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
"key" => "virtfusionserv::host",
|
||||||
|
"name" => "VirtFusion Panel Host/URL",
|
||||||
|
"description" => "The Host/URL of the VirtFusion panel i.e https://panel.example.com",
|
||||||
|
"type" => "url",
|
||||||
|
"rules" => ["required", "active_url", $doesNotEndWithSlash]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"key" => "encrypted::virtfusionserv::apikey",
|
||||||
|
"name" => "VirtFusion API Key",
|
||||||
|
"description" => "API Key to manage VirtFusion panel.",
|
||||||
|
"type" => "password",
|
||||||
|
"rules" => ["required"],
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the default package configuration values required when creatig
|
||||||
|
* new packages. i.e maximum ram usage, allowed databases and backups etc.
|
||||||
|
*
|
||||||
|
* Laravel validation rules: https://laravel.com/docs/10.x/validation
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function setPackageConfig(Package $package): array
|
||||||
|
{
|
||||||
|
|
||||||
|
$response = Service::api('get', '/packages');
|
||||||
|
if ($response->failed()) {
|
||||||
|
if (isset($response['errors'])) {
|
||||||
|
throw new Exception("[VirtFusion] " . json_encode($response['errors']));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($response['message'])) {
|
||||||
|
throw new Exception("[VirtFusion] " . $response['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$collectPackages = collect($response['data']);
|
||||||
|
$packages = $collectPackages->mapWithKeys(function ($item) {
|
||||||
|
if (!$item['enabled']) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$item['id'] => $item['name']];
|
||||||
|
});
|
||||||
|
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
"col" => "col-12",
|
||||||
|
"key" => "package",
|
||||||
|
"name" => "Package",
|
||||||
|
"description" => "Select the package to use for this service",
|
||||||
|
"type" => "select",
|
||||||
|
"options" => $packages->toArray(),
|
||||||
|
"save_on_change" => true,
|
||||||
|
"rules" => ['required'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"col" => "col-12",
|
||||||
|
"key" => "hypervisor_group_id",
|
||||||
|
"name" => "Hypervisor Group ID",
|
||||||
|
"description" => "Enter the Hypervisor Group ID to use for this service",
|
||||||
|
"type" => "number",
|
||||||
|
"save_on_change" => true,
|
||||||
|
"rules" => ['required', 'numeric'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"key" => "allowed_ips",
|
||||||
|
"name" => "Number of Allowed IPv4 IPs",
|
||||||
|
"description" => "Enter the number of allowed IPv4 IPs for this service",
|
||||||
|
"type" => "number",
|
||||||
|
"rules" => ['required', 'numeric'],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the checkout config that is required at checkout and is fillable by
|
||||||
|
* the client. Its important to properly sanatize all inputted data with rules
|
||||||
|
*
|
||||||
|
* Laravel validation rules: https://laravel.com/docs/10.x/validation
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function setCheckoutConfig(Package $package): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define buttons shown at order management page
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function setServiceButtons(Order $order): array
|
||||||
|
{
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = Service::api('post', "/users/{$order->user->id}/serverAuthenticationTokens/{$order->data['id']}");
|
||||||
|
if ($response->failed()) {
|
||||||
|
if (isset($response['errors'])) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($response['message'])) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$loginUrl = settings('virtfusionserv::host') . $response['data']['authentication']['endpoint_complete'];
|
||||||
|
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
"name" => "Panel Login",
|
||||||
|
"color" => "primary",
|
||||||
|
"href" => $loginUrl,
|
||||||
|
"target" => "_blank",
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is responsible for creating an instance of the
|
||||||
|
* service. This can be anything such as a server, vps or any other instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function create(array $data = [])
|
||||||
|
{
|
||||||
|
|
||||||
|
$order = $this->order;
|
||||||
|
$user = $this->order->user;
|
||||||
|
$package = $this->order->package;
|
||||||
|
|
||||||
|
if (!$order->hasExternalUser()) {
|
||||||
|
$response = Service::api('post', '/users', [
|
||||||
|
"name" => $user->first_name . ' ' . $user->last_name,
|
||||||
|
"email" => $user->email,
|
||||||
|
"extRelationId" => $user->id,
|
||||||
|
"sendMail" => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($response->failed() && $response->status() != 409) {
|
||||||
|
if (isset($response['errors'])) {
|
||||||
|
throw new Exception("[VirtFusion] " . json_encode($response['errors']));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($response['message'])) {
|
||||||
|
throw new Exception("[VirtFusion] " . $response['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response->status() == 409) {
|
||||||
|
|
||||||
|
$getUserRes = Service::api('get', "/users/{$user->id}/byExtRelation");
|
||||||
|
|
||||||
|
$virtFusionUser = $getUserRes['data'];
|
||||||
|
|
||||||
|
$order->createExternalUser([
|
||||||
|
'external_id' => $virtFusionUser['id'],
|
||||||
|
'username' => $user->email,
|
||||||
|
'password' => Str::random(16),
|
||||||
|
'data' => $virtFusionUser
|
||||||
|
]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$order->createExternalUser([
|
||||||
|
'external_id' => $response['data']['id'], // optional
|
||||||
|
'username' => $user->email,
|
||||||
|
'password' => $response['data']['password'],
|
||||||
|
'data' => $response['data'], // Additional data about the user as an array (optional)
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->email([
|
||||||
|
'subject' => 'Panel Account Created',
|
||||||
|
'content' => "Your account has been created on the vps panel. You can login using the following details: <br><br> Email: {$user->email} <br> Password: {$response['data']['password']}",
|
||||||
|
'button' => [
|
||||||
|
'name' => 'VPS Panel',
|
||||||
|
'url' => settings('virtfusionserv::host'),
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the server
|
||||||
|
$createSrvRes = Service::api('post', '/servers', [
|
||||||
|
"packageId" => $package->data('package'),
|
||||||
|
"userId" => $order->getExternalUser()->external_id,
|
||||||
|
"hypervisorId" => $package->data('hypervisor_group_id'),
|
||||||
|
"ipv4" => $package->data('allowed_ips', 1),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($createSrvRes->failed()) {
|
||||||
|
if (isset($response['errors'])) {
|
||||||
|
throw new Exception("[VirtFusion] " . json_encode($response['errors']));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($response['message'])) {
|
||||||
|
throw new Exception("[VirtFusion] " . $response['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$order->external_id = $createSrvRes['data']['id'];
|
||||||
|
$order->data = $createSrvRes['data'];
|
||||||
|
$order->save();
|
||||||
|
|
||||||
|
return $createSrvRes;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is responsible for upgrading or downgrading
|
||||||
|
* an instance of this service. This method is optional
|
||||||
|
* If your service doesn't support upgrading, remove this method.
|
||||||
|
*
|
||||||
|
* Optional
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function upgrade(Package $oldPackage, Package $newPackage)
|
||||||
|
{
|
||||||
|
$order = $this->order;
|
||||||
|
$response = Service::api('put', "/servers/{$order->data['id']}/package/{$newPackage->data('package')}");
|
||||||
|
if ($response->failed()) {
|
||||||
|
if (isset($response['errors'])) {
|
||||||
|
throw new Exception("[VirtFusion] " . json_encode($response['errors']));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($response['message'])) {
|
||||||
|
throw new Exception("[VirtFusion] " . $response['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is responsible for suspending an instance of the
|
||||||
|
* service. This method is called when a order is expired or
|
||||||
|
* suspended by an admin
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function suspend(array $data = [])
|
||||||
|
{
|
||||||
|
$order = $this->order;
|
||||||
|
$response = Service::api('post', "/servers/{$order->data['id']}/suspend");
|
||||||
|
if ($response->failed()) {
|
||||||
|
if (isset($response['errors'])) {
|
||||||
|
throw new Exception("[VirtFusion] " . json_encode($response['errors']));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($response['message'])) {
|
||||||
|
throw new Exception("[VirtFusion] " . $response['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is responsible for unsuspending an instance of the
|
||||||
|
* service. This method is called when a order is activated or
|
||||||
|
* unsuspended by an admin
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function unsuspend(array $data = [])
|
||||||
|
{
|
||||||
|
$order = $this->order;
|
||||||
|
$response = Service::api('post', "/servers/{$order->data['id']}/unsuspend");
|
||||||
|
if ($response->failed()) {
|
||||||
|
if (isset($response['errors'])) {
|
||||||
|
throw new Exception("[VirtFusion] " . json_encode($response['errors']));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($response['message'])) {
|
||||||
|
throw new Exception("[VirtFusion] " . $response['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is responsible for deleting an instance of the
|
||||||
|
* service. This can be anything such as a server, vps or any other instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function terminate(array $data = [])
|
||||||
|
{
|
||||||
|
$order = $this->order;
|
||||||
|
Service::api('delete', "/servers/{$order->data['id']}?delay=5");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is responsible automatically logging in to the
|
||||||
|
* panel when the user clicks the login button in the client area.
|
||||||
|
*
|
||||||
|
* @return redirect
|
||||||
|
*/
|
||||||
|
public function loginToPanel(Order $order)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$response = Service::api('post', "/users/{$order->user->id}/serverAuthenticationTokens/{$order->data['id']}");
|
||||||
|
if ($response->failed()) {
|
||||||
|
if (isset($response['errors'])) {
|
||||||
|
throw new Exception("[VirtFusion] " . json_encode($response['errors']));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($response['message'])) {
|
||||||
|
throw new Exception("[VirtFusion] " . $response['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return redirect(settings('virtfusionserv::host') . $response['data']['authentication']['endpoint_complete']);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return redirect()->back()->withError("Something went wrong, please try again later.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test API connection
|
||||||
|
*/
|
||||||
|
public static function testConnection()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// try to get list of packages through API request
|
||||||
|
$response = Service::api('get', '/connect');
|
||||||
|
} catch (Exception $error) {
|
||||||
|
// if try-catch fails, return the error with details
|
||||||
|
return redirect()->back()->withError("Failed to connect to VirtFusion. <br><br>{$error->getMessage()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no errors are logged, return a success message
|
||||||
|
return redirect()->back()->withSuccess("Successfully connected with VirtFusion");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function api($method, $endpoint, $data = [])
|
||||||
|
{
|
||||||
|
// validate the method
|
||||||
|
if (!in_array($method, ['get', 'post', 'put', 'delete', 'patch', 'head'])) {
|
||||||
|
throw new Exception("[VirtFusion] Invalid method: {$method}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// make the request
|
||||||
|
$url = settings('virtfusionserv::host') . '/api/v1' . $endpoint;
|
||||||
|
$response = Http::withHeaders([
|
||||||
|
'Authorization' => 'Bearer ' . settings('encrypted::virtfusionserv::apikey'),
|
||||||
|
'Accept' => 'application/json',
|
||||||
|
'Content-Type' => 'application/json',
|
||||||
|
])->$method($url, $data);
|
||||||
|
|
||||||
|
// dd($response, $response->json());
|
||||||
|
|
||||||
|
if ($response->failed()) {
|
||||||
|
// dd($response, $response->json());
|
||||||
|
|
||||||
|
if ($response->unauthorized() or $response->forbidden()) {
|
||||||
|
throw new Exception("[VirtFusion] This action is unauthorized! Confirm that API token has the right permissions");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($response->serverError()) {
|
||||||
|
throw new Exception("[VirtFusion] Internal Server Error: {$response->status()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
23
composer.json
Normal file
23
composer.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"name": "wemx/service-virtfusionservice",
|
||||||
|
"type": "laravel-module",
|
||||||
|
"description": "A service integration with VirtFusion",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Shane",
|
||||||
|
"email": "shane@scaffoe.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extra": {
|
||||||
|
"module-dir": "app/Services",
|
||||||
|
"laravel": {
|
||||||
|
"providers": [],
|
||||||
|
"aliases": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"App\\Services\\VirtfusionService\\": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
module.json
Normal file
11
module.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"name": "VirtfusionService",
|
||||||
|
"alias": "virtfusionservice",
|
||||||
|
"description": "",
|
||||||
|
"keywords": [],
|
||||||
|
"priority": 0,
|
||||||
|
"providers": [
|
||||||
|
"App\\Services\\VirtfusionService\\Providers\\VirtfusionServiceServiceProvider"
|
||||||
|
],
|
||||||
|
"files": []
|
||||||
|
}
|
16
package.json
Normal file
16
package.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"axios": "^0.21.4",
|
||||||
|
"dotenv": "^10.0.0",
|
||||||
|
"dotenv-expand": "^5.1.0",
|
||||||
|
"laravel-vite-plugin": "^0.6.0",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"postcss": "^8.3.7",
|
||||||
|
"vite": "^3.0.9"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue