| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555 |
- <?php
- /**********************************************************************
- * ProxmoxVPS developed. (26.03.19)
- * *
- *
- * CREATED BY MODULESGARDEN -> http://modulesgarden.com
- * CONTACT -> contact@modulesgarden.com
- *
- *
- * This software is furnished under a license and may be used and copied
- * only in accordance with the terms of such license and with the
- * inclusion of the above copyright notice. This software or any other
- * copies thereof may not be provided or otherwise made available to any
- * other person. No title to and ownership of the software is hereby
- * transferred.
- *
- *
- **********************************************************************/
- namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Actions;
- use MGProvision\Proxmox\v2\models\Kvm;
- use MGProvision\Proxmox\v2\models\Node;
- use MGProvision\Proxmox\v2\repository\ClusterResourcesRepository;
- use ModulesGarden\ProxmoxAddon as addon;
- use ModulesGarden\ProxmoxAddon\App\Configuration\Addon\Update\AddonUpgradeService;
- use ModulesGarden\ProxmoxAddon\App\Models\VmIpAddress;
- use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
- use ModulesGarden\ProxmoxAddon\App\Services\Utility;
- use ModulesGarden\ProxmoxAddon\App\Services\Vps\HostingService;
- use ModulesGarden\ProxmoxAddon\App\Services\Vps\NetworkService;
- use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
- use ModulesGarden\ProxmoxAddon\App\Services\Vps\UserService;
- use ModulesGarden\ProxmoxAddon\Core\Queue\Models\Job;
- use ModulesGarden\Servers\ProxmoxVps\App\Enum\CustomField;
- use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
- use ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator;
- use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController;
- use ModulesGarden\Servers\ProxmoxVps\Core\Models\Whmcs\Server;
- use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
- use ModulesGarden\Servers\ProxmoxVps\App\Enum\ConfigurableOption;
- class CreateAccount extends AddonController
- {
- use WhmcsParams;
- use ProductService;
- use ApiService;
- use UserService;
- use HostingService;
- use addon\App\Traits\Vps\SnippetTrait;
- private $errors = [];
- /**
- * @var AddonUpgradeService
- */
- private $addonUpgradeService;
- /**
- * @var Kvm|null
- */
- private $templateVm;
- public function execute($params = null)
- {
- if(!ProxmoxAddonValidator::isInstalled()){
- return ProxmoxAddonValidator::failAsString();
- }
- (new AppParams())->initFromWhmcsParams();
- $this->addonUpgradeService = new AddonUpgradeService();
- $this->addonUpgradeService->run();
- try
- {
- //init nameservers
- $this->initNameServers();
- //Validate
- $this->validate();
- //Clone validate
- if ($this->configuration()->isQemu())
- {
- $this->cloneValidate();
- }
- //Check free resources
- $this->checkResources();
- //update hostname
- if($params['customfields']['proxmoxHostname']){
- $this->hosting()->domain = $params['customfields']['proxmoxHostname'];
- $this->hosting()->save();
- }
- //throw errors
- if ($this->errors)
- {
- throw new \Exception(implode(", ", $this->errors));
- }
- //Create User
- if (!$this->isUser())
- {
- $this->userCreate();
- }elseif($this->isUser() ){
- $this->createUserIfNotExist($this->getUser());
- }
- //Assing ip
- if (!Utility::isIpManagerProxmoxVPSIntegration())
- {
- if ($this->isCustomIpRequest() && $this->hasCustomIp())
- {
- $this->addCustomIp();
- }
- else
- {
- $networkService = new NetworkService();
- list($requestIPv4, $requestIPv6) = $networkService->getIpAddressesRequest();
- $node = $this->getNode()->getNode();
- $networkService->hasIp($requestIPv4, $requestIPv6, $node)
- ->addIp($requestIPv4, $requestIPv6, $node);
- $this->customFieldUpdate(CustomField::NODE, $node);
- }
- }
- //automaticaly configure administartor username for window
- if($this->templateVm instanceof Kvm &&
- $this->configuration()->isAgent() &&
- $this->configuration()->isAgentServicePassword() &&
- !$this->configuration()->isAgentTemplateUser() &&
- preg_match('/w/', $this->templateVm->config()['ostype'])){
- $ciuser = $this->templateVm->config()['ciuser'];
- $this->hosting()->update(['username' => $ciuser ?: 'Administrator' ]);
- }
- elseif($this->configuration()->isQemu() && $this->configuration()->getCiuser()){
- $this->hosting()->update(['username' =>$this->configuration()->getCiuser() ]);
- }
- //hosting limit
- $this->saveUsageLimit();
- //Create task
- if ($this->configuration()->isLxc())
- {
- $taskName = addon\App\Jobs\Vps\CreateLxcJob::class;
- }
- else
- {
- if ($this->configuration()->isQemu())
- {
- $taskName = addon\App\Jobs\Vps\CreateQemuJob::class;
- $osTemplate = $this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE, $this->configuration()->getOsTemplate());
- if (!empty($osTemplate) && $osTemplate != "0")
- {
- $taskName = addon\App\Jobs\Vps\CloneQemuJob::class;
- }
- }
- }
- $arguments = [
- 'hostingId' => $this->getWhmcsParamByKey('serviceid')
- ];
- if($this->configuration()->isQemu() && $this->hasSnippet()){
- $parent = addon\Core\Helper\queue(addon\App\Jobs\Vps\CreateSnippet::class, $arguments, null, "hosting", $this->getWhmcsParamByKey("serviceid"));
- }
- addon\Core\Helper\queue($taskName, $arguments, $parent->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
- return "success";
- }
- catch (\Exception $ex)
- {
- if (addon\App\Models\ModuleSettings::isDebug())
- {
- logModuleCall(
- 'ProxmoxVps',
- __CLASS__,
- [],
- null,
- $ex->getMessage() . " " . $ex->getTraceAsString()
- );
- }
- return $ex->getMessage();
- }
- }
- private function validate()
- {
- //vmid
- if ($this->getWhmcsCustomField(CustomField::VMID))
- {
- $this->errors[] = "Custom Field \"VMID\" is not empty";
- }
- //node
- if ($this->getWhmcsCustomField(CustomField::NODE))
- {
- $this->errors[] = "Custom Field \"Node\" is not empty";
- }
- if (!in_array($this->configuration()->getVirtualization(), ["qemu", "lxc"]))
- {
- $this->errors[] = 'Unknown virtualization type: ' . $this->configuration()->getVirtualization();
- }
- //Network bridge
- if (!$this->configuration()->getBridge())
- {
- $this->errors[] = "''Bridge' - is empty";
- }
- //lxc
- if ($this->configuration()->isLxc())
- {
- //OS Template
- if (!$this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE, $this->configuration()->getOsTemplate()) )
- {
- $this->errors[] = "'OS Template' - is empty";
- }
- //Storage
- if (!$this->configuration()->getStorage())
- {
- $this->errors[] = "'Default Storage' - is empty";
- }
- $taskName = addon\App\Jobs\Vps\CreateLxcJob::class . '@handle';
- }
- else
- {
- if ($this->configuration()->isQemu())
- {
- //searchdomain
- if ($this->configuration()->getSearchdomain() && !preg_match('/^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$/', $this->configuration()->getSearchdomain()))
- {
- $this->errors[] = sprintf('DNS Domain \'%s\' is invalid', $this->configuration()->getSearchdomain());
- }
- //SSH Key
- if ($this->getWhmcsParamByKey('customfields')['sshkeys'] && !preg_match('/ssh\-/', $this->getWhmcsParamByKey('customfields')['sshkeys']))
- {
- $this->errors[] = ' SSH Public Key is invalid';
- }
- $taskName = addon\App\Jobs\Vps\CreateQemuJob::class . '@handle';
- $osTemplate = $this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE, $this->configuration()->getOsTemplate() );
- //clone
- if (!empty($osTemplate) && $osTemplate != "0")
- {
- $taskName = addon\App\Jobs\Vps\CloneQemuJob::class . '@handle';
- }
- }
- }
- $query = Job::where("job", $taskName)->whereIn("status", ['waiting', "running", ""])->where("rel_id", $this->getWhmcsParamByKey("serviceid"))->where("rel_type", "hosting")
- ->orWhere("job", $taskName)->where("status", 'error')->where("rel_id", $this->getWhmcsParamByKey("serviceid"))->where("rel_type", "hosting")->where("retry_count","<",100);
- if ( $query->count() )
- {
- $this->errors[] = "Job 'create' already exist";
- }
- //Name servers
- if ($this->configuration()->isLxc() || $this->configuration()->isCloudInitServiceNameservers())
- {
- $ns = [];
- for ($i = 1; $i <= 2; $i++)
- {
- $n = trim($this->hosting()->{"ns{$i}"});
- if (!empty($n) && !filter_var($n, FILTER_VALIDATE_IP))
- {
- $n = gethostbyname($n);
- }
- if (!empty($n) && !filter_var($n, FILTER_VALIDATE_IP))
- {
- $ns[] = "'{$n}'";
- }
- }
- if (!empty($ns))
- {
- $this->errors[] = sprintf(" Name Server value: %s does not look like a valid IP Address", implode(", ", $ns));
- }
- }
- //Disk size
- $diskSize = $this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE);
- if ($diskSize && $this->configuration()->getDiskUnit() == "mb" && $diskSize < 1024)
- {
- $this->errors[] = sprintf("Disk size of %sMB cannot be created", $diskSize);
- }
- $rate = $this->getWhmcsConfigOption(addon\App\Enum\Vps\ConfigurableOption::NETWORK_RATE) ? $this->getWhmcsConfigOption(addon\App\Enum\Vps\ConfigurableOption::NETWORK_RATE) :$this->configuration()->getRate();
- if ($rate && !is_numeric($rate))
- {
- $this->errors[] = sprintf("Network Rate - invalid format: %s ", $rate) ;
- }
- }
- private function initNameServers()
- {
- $this->setHostingId($this->getWhmcsParamByKey("serviceid"));
- if ($this->configuration()->isServerNameservers())
- {
- $server = Server::select('id', 'nameserver1ip', 'nameserver2ip')->findOrFail($this->getWhmcsParamByKey('serverid'));
- $this->hosting()->ns1 = trim($server->nameserver1ip);
- $this->hosting()->ns2 = trim($server->nameserver2ip);
- $this->hosting()->save();
- }
- else
- {
- if ($this->configuration()->isLxc() || $this->configuration()->isCloudInitServiceNameservers())
- {
- $domain = $this->getWhmcsCustomField(CustomField::HOSTNAME, $this->getWhmcsParamByKey('domain'));
- $update = [];
- for ($i = 1; $i <= 2; $i++)
- {
- $n = trim($this->hosting()->{"ns{$i}"});
- if (!empty($n) && !filter_var($n, FILTER_VALIDATE_IP))
- {
- $host = preg_match('/\./', $n) ? $n : "{$n}.{$domain}";
- $n = gethostbyname($host);
- if (!$n || !filter_var($n, FILTER_VALIDATE_IP))
- {
- throw new \Exception(sprintf("Nameserver '%s' cannot be resolved", $host));
- }
- }
- if (!empty($n) && filter_var($n, FILTER_VALIDATE_IP))
- {
- $update['ns' . $i] = $n;
- $this->hosting()->{"ns{$i}"} = $n;
- }
- }
- if ($update)
- {
- $this->hosting()->update($update);
- }
- }
- }
- }
- private function isCustomIpRequest()
- {
- //if there is custom ip on dedicated ip or assinged ips
- $model = $this->getWhmcsParamByKey('model');
- if (!$model)
- {
- $model = \WHMCS\Service\Service::where("id", $this->getWhmcsParamByKey('serviceid'))->first();
- }
- if (!$model->dedicatedip && !$model->assignedips)
- {
- return false;
- }
- $ips = $this->getCustomIp();
- if (!$ips)
- {
- return false;
- }
- foreach ($ips as $k => $ip)
- {
- if (!filter_var((string)$ip, FILTER_VALIDATE_IP))
- {
- throw new \Exception(sprintf("IP Address '%s' is not valid", $ip));
- }
- }
- return true;
- }
- private function getCustomIp()
- {
- $ips = [];
- $model = $this->getWhmcsParamByKey('model');
- if (!$model)
- {
- $model = \WHMCS\Service\Service::where("id", $this->getWhmcsParamByKey('serviceid'))->first();
- }
- if ($model->dedicatedip)
- {
- $ips[] = $model->dedicatedip;
- }
- if ($model->assignedips)
- {
- $ex = explode(PHP_EOL, $model->assignedips);
- foreach ($ex as $ip)
- {
- if (!$ip)
- {
- continue;
- }
- $ips[] = str_replace(["\r", "\n"], ["", ""], $ip);
- }
- }
- return array_diff($ips, [""]);
- }
- private function hasCustomIp()
- {
- $nodeName = $this->getNode()->getNode();
- $ipAddresses = $this->getCustomIp();
- $virtualization = $this->configuration()->isQemu() ? "KVM" : "LXC";
- $ipCollections = addon\App\Models\IpAddress::where('hosting_id', '0')
- ->where('private', '0')
- ->whereIn('ip', $ipAddresses)
- ->whereIn('sid', [$this->getWhmcsParamByKey('serverid'), '0'])
- ->whereIn('visualization', [$virtualization, 'Auto'])
- ->whereIn('node', [$nodeName, '0', ""]);
- $count = $ipCollections->count();
- return $count == count($ipAddresses);
- }
- private function addCustomIp()
- {
- $nodeName = $this->getNode()->getNode();
- $ipAddresses = $this->getCustomIp();
- $virtualization = $this->configuration()->isQemu() ? "KVM" : "LXC";
- addon\App\Models\IpAddress::where('hosting_id', '0')
- ->where('private', '0')
- ->whereIn('ip', $ipAddresses)
- ->whereIn('sid', [$this->getWhmcsParamByKey('serverid'), '0'])
- ->whereIn('visualization', [$virtualization, 'Auto'])
- ->whereIn('node', [$nodeName, '0', ""])
- ->update(["hosting_id" => $this->getWhmcsParamByKey('serviceid'), 'last_check' => Utility::timeStamp()]);
- //get ips
- $collection = addon\App\Models\IpAddress::where('hosting_id', $this->getWhmcsParamByKey('serviceid'))
- ->whereNotIn('ip', function ($query)
- {
- $query->select('ip')->from((new VmIpAddress)->getTable());
- });
- foreach ($collection->get() as $ip)
- {
- /*@var $ip VmIpAddress */
- $newIp = new VmIpAddress();
- $ipData = $ip->toArray();
- $ipData['hosting_id'] = $this->getWhmcsParamByKey('serviceid');
- $ipData['server_id'] = $this->getWhmcsParamByKey('serverid');
- $newIp->fill($ipData)->save();
- }
- return $this;
- }
- private function checkResources()
- {
- if (!$this->configuration()->isCheckResources())
- {
- return;
- }
- //get free space
- $storage = $this->configuration()->isQemu() ? $this->configuration()->getDiskStorage() : $this->configuration()->getStorage();
- $resurces = $this->getNode()->getFreeSpace($storage);
- //Memory
- if ($this->getWhmcsConfigOption(ConfigurableOption::MEMORY))
- {
- $memoryBytes = $this->getWhmcsConfigOption(ConfigurableOption::MEMORY);
- Utility::unitFormat($memoryBytes, $this->configuration()->getMemoryUnit(), 'bytes');
- }
- else
- {
- $memoryBytes = $this->configuration()->getMemory();
- Utility::unitFormat($memoryBytes, "mb", 'bytes');
- }
- //Validation
- if ($memoryBytes && $resurces['memory'] && $memoryBytes > $resurces['memory'])
- {
- $this->errors[] = sprintf("Unable to allocate %s of Memory. Memory available: %s",
- addon\App\Libs\Format::convertBytes($memoryBytes), addon\App\Libs\Format::convertBytes($resurces['memory']));
- }
- //SWAP
- if ($this->configuration()->isLxc())
- {
- if ($this->getWhmcsConfigOption(ConfigurableOption::SWAP))
- {
- $swapBytes = $this->getWhmcsConfigOption(ConfigurableOption::SWAP);
- Utility::unitFormat($swapBytes, strtolower($this->configuration()->getSwapUnit()), 'bytes');
- }
- else
- {
- $swapBytes = $this->configuration()->getSwap();
- Utility::unitFormat($swapBytes, "mb", 'bytes');
- }
- //Validation
- if ($swapBytes && $resurces['swap'] && $swapBytes > $resurces['swap'])
- {
- $this->errors[] = sprintf("Unable to allocate %s of SWAP. SWAP available: %s",
- addon\App\Libs\Format::convertBytes($swapBytes), addon\App\Libs\Format::convertBytes($resurces['swap']));
- }
- }
- //Disk
- if ($this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE))
- {
- $diskBytes = $this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE);
- Utility::unitFormat($diskBytes, $this->configuration()->getDiskUnit(), 'bytes');
- }
- else
- {
- $diskBytes = $this->configuration()->getDiskSize();
- Utility::unitFormat($diskBytes, "gb", 'bytes');
- }
- //Validation
- if ($diskBytes && $resurces['storage'] && $diskBytes > $resurces['storage'])
- {
- $this->errors[] = sprintf("Unable to allocate %s of Disk Space. Disk Space available: %s",
- addon\App\Libs\Format::convertBytes($diskBytes), addon\App\Libs\Format::convertBytes($resurces['storage']));
- }
- }
- private function cloneValidate()
- {
- $osTemplate = $this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE, $this->configuration()->getOsTemplate() );
- if (empty($osTemplate) && $osTemplate == "0")
- {
- return;
- }
- //Support for configurable options i.e vmname|OS Name
- if (is_string($osTemplate) && !preg_match('/\//', $osTemplate))
- {
- $templateNode = $this->getNode()->getNode();
- $clusterRepository = new ClusterResourcesRepository();
- $clusterRepository->setApi($this->api());
- if(!$this->configuration()->isOsTemplatesInAllNodes()){
- $clusterRepository->findByNodes([$templateNode]);
- }
- $clusterRepository->findKvmTemplate();
- foreach ($clusterRepository->fetch() as $resurce)
- {
- if ($resurce->getName() == $osTemplate )
- {
- $templateVmid = $resurce->getVmid();
- $templateNode = $resurce->getNode();
- break;
- }
- }
- if (!$templateVmid)
- {
- $this->errors[] = sprintf("Unable to find KVM template: %s on node: %s", $osTemplate, $this->getNode()->getNode());
- return;
- }
- //Support for configurable options like nodename/vmid|OS Name
- }
- else
- {
- if (preg_match('/\//', $osTemplate))
- {
- list($templateNode, $templateVmid) = explode("/", $osTemplate);
- }
- }
- if (!in_array($templateNode, (array)$this->api()->get_node_list()))
- {
- $this->errors[] = sprintf("Unable to find node %s on cluster %s", $templateNode, $this->api()->getPveHostname());
- return;
- }
- //template exist on node?
- $node = new Node($templateNode);
- $node->setApi($this->api());
- if (!$node->hasKvm($templateVmid))
- {
- $this->errors[] = sprintf("KVM template VMID '%s' does not exist on node '%s'", $templateVmid, $templateNode);
- return;
- }
- //Disk size validation
- $this->templateVm = new Kvm($templateNode, $templateVmid);
- $this->templateVm->setApi($this->api());
- //Disk
- $diskSize = $this->configuration()->getDiskSize();
- if ($this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE))
- {
- $diskSize = $this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE);
- Utility::unitFormat($diskSize, $this->configuration()->getDiskUnit(), 'bytes');
- }else{
- Utility::unitFormat($diskSize, "gb", 'bytes');
- }
- if ($this->templateVm->getMasterHardDisk()->getBytes() > $diskSize)
- {
- $this->errors[] = sprintf('Downgrading disk size is restricted. Request Disk size: %s, VM disk size: %s', addon\App\Libs\Format::convertBytes($diskSize), addon\App\Libs\Format::convertBytes($this->templateVm->getMasterHardDisk()->getBytes()));
- }
- }
- }
|