ChangePackage.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. <?php
  2. /**********************************************************************
  3. * ProxmoxVPS developed. (26.03.19)
  4. * *
  5. *
  6. * CREATED BY MODULESGARDEN -> http://modulesgarden.com
  7. * CONTACT -> contact@modulesgarden.com
  8. *
  9. *
  10. * This software is furnished under a license and may be used and copied
  11. * only in accordance with the terms of such license and with the
  12. * inclusion of the above copyright notice. This software or any other
  13. * copies thereof may not be provided or otherwise made available to any
  14. * other person. No title to and ownership of the software is hereby
  15. * transferred.
  16. *
  17. *
  18. **********************************************************************/
  19. namespace ModulesGarden\Servers\ProxmoxVps\App\Http\Actions;
  20. use Illuminate\Database\Capsule\Manager as DB;
  21. use ModulesGarden\ProxmoxAddon\App\Events\Vps\LxcUpdateEvent;
  22. use ModulesGarden\ProxmoxAddon\App\Events\Vps\QemuUpdateEvent;
  23. use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Agent\ConfigureNetworkJob;
  24. use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\LoadBalancer as LoadBalancer;
  25. use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\MoveDiskJob;
  26. use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\RebootVmJob;
  27. use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Reinstall\BackupVmJob;
  28. use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Reinstall\CreateVmJob;
  29. use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Reinstall\DeleteVmJob;
  30. use ModulesGarden\ProxmoxAddon\App\Libs\Format;
  31. use ModulesGarden\ProxmoxAddon\App\Models\Job;
  32. use ModulesGarden\ProxmoxAddon\App\Models\ServerGroupItem;
  33. use ModulesGarden\ProxmoxAddon\App\Models\Whmcs\ToDoList;
  34. use ModulesGarden\ProxmoxAddon\App\Models\Whmcs\Upgrade;
  35. use ModulesGarden\ProxmoxAddon\App\Services\ApiService;
  36. use ModulesGarden\ProxmoxAddon\App\Services\EmailService;
  37. use ModulesGarden\ProxmoxAddon\App\Services\LoadBalancerService;
  38. use ModulesGarden\ProxmoxAddon\App\Services\Utility;
  39. use ModulesGarden\ProxmoxAddon\App\Services\Vps\HostingService;
  40. use ModulesGarden\ProxmoxAddon\App\Services\Vps\IpSetIpFilterService;
  41. use ModulesGarden\ProxmoxAddon\App\Services\Vps\NetworkService;
  42. use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
  43. use ModulesGarden\ProxmoxAddon\App\Services\Vps\UserService;
  44. use ModulesGarden\Servers\ProxmoxVps\App\Helpers\AppParams;
  45. use ModulesGarden\Servers\ProxmoxVps\App\Helpers\ProxmoxAddonValidator;
  46. use ModulesGarden\Servers\ProxmoxVps\Core\App\Controllers\Instances\AddonController;
  47. use ModulesGarden\Servers\ProxmoxVps\Core\UI\Traits\WhmcsParams;
  48. use function ModulesGarden\ProxmoxAddon\Core\Helper\fire;
  49. use function ModulesGarden\ProxmoxAddon\Core\Helper\queue;
  50. use function ModulesGarden\ProxmoxAddon\Core\Helper\sl;
  51. use ModulesGarden\ProxmoxAddon\App\Enum\Vps\ConfigurableOption;
  52. class ChangePackage extends AddonController
  53. {
  54. use WhmcsParams;
  55. use ApiService;
  56. use ProductService;
  57. use UserService;
  58. use HostingService;
  59. /**
  60. * @var NetworkService
  61. */
  62. private $networkService;
  63. /**
  64. * @var IpSetIpFilterService
  65. */
  66. private $ipSetIpFilterService;
  67. /**
  68. * @var EmailService
  69. */
  70. private $emailService;
  71. /**
  72. * ChangePackage constructor.
  73. * @param $networkService
  74. */
  75. public function __construct()
  76. {
  77. $this->networkService = new NetworkService();
  78. $this->ipSetIpFilterService = new IpSetIpFilterService();
  79. $this->emailService = new EmailService();
  80. }
  81. public function execute($params = null)
  82. {
  83. if(!ProxmoxAddonValidator::isInstalled()){
  84. return ProxmoxAddonValidator::failAsString();
  85. }
  86. (new AppParams())->initFromWhmcsParams();
  87. try
  88. {
  89. $this->manuallyUpgrade();
  90. //Disk
  91. $this->diskSizeValidation();
  92. $this->createReinstallJob();
  93. //Add IP Addresses
  94. if (!Utility::isIpManagerProxmoxVPSIntegration())
  95. {
  96. list($requestIPv4, $requestIPv6) = $this->networkService->getIpAddressesRequest();
  97. $bridge = $this->configuration()->getBridge();
  98. $this->networkService->hasIp($requestIPv4, $requestIPv6, $this->vm()->getNode(),$bridge)
  99. ->addIp($requestIPv4, $requestIPv6, $this->vm()->getNode(),$bridge);
  100. }
  101. //Unassing ip addresses and delete network
  102. if(!Utility::isIpManagerProxmoxVPSIntegration())
  103. {
  104. $this->networkService->unassignIpAddressesAndDeleteNetwork();
  105. }
  106. //Load Balancer
  107. if (!Job::waiting()->ofHostingId($this->getWhmcsParamByKey("serviceid"))->ofJob(LoadBalancer\UpgradeVmJob::class)->count() && $this->configuration()->isLoadBalancer() && in_array($this->configuration()->getLoadBalancerOnUpgrade(), ["block", "migrate"]))
  108. {
  109. $loadBalancer = new LoadBalancerService($this->getWhmcsParamByKey('serverid'));
  110. $loadBalancer->setApi($this->api());
  111. //Disk
  112. $disk = $this->configuration()->getDiskSize();
  113. Utility::unitFormat($disk, "gb", 'bytes');
  114. if($this->getWhmcsConfigOption(ConfigurableOption::STORAGE)){
  115. list($storage,$disk) = explode(":", $this->getWhmcsConfigOption(ConfigurableOption::STORAGE),2);
  116. Utility::unitFormat($disk, $this->configuration()->getDiskUnit(), 'bytes');
  117. }
  118. elseif ($this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE))
  119. {
  120. $disk = $this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE);
  121. Utility::unitFormat($disk, $this->configuration()->getDiskUnit(), 'bytes');
  122. }
  123. //RAM
  124. $ram = $this->configuration()->getMemory();
  125. Utility::unitFormat($ram, "mb", 'bytes');
  126. if ($this->getWhmcsConfigOption(ConfigurableOption::MEMORY))
  127. {
  128. $ram = $this->getWhmcsConfigOption(ConfigurableOption::MEMORY);
  129. Utility::unitFormat($ram, $this->configuration()->getMemoryUnit(), 'bytes');
  130. }
  131. if ($this->configuration()->isQemu())
  132. {
  133. $socket = $this->getWhmcsConfigOption(ConfigurableOption::SOCKETS,$this->configuration()->getSockets() );
  134. $cores = $this->getWhmcsConfigOption(ConfigurableOption::CORES_PER_SOCKET, $this->configuration()->getCores()) ;
  135. $cpu = $socket * $cores;
  136. }
  137. else if ($this->configuration()->isLxc())
  138. {
  139. $cpu = $this->getWhmcsConfigOption(ConfigurableOption::CORES, $this->configuration()->getCores()) ;
  140. }
  141. $loadBalancer->setExcludeVmid($this->vm()->getVmid());
  142. //Upgrade on current node
  143. if ($this->configuration()->getLoadBalancerOnUpgrade() == "block")
  144. {
  145. $loadBalancerNodes = $loadBalancer->findByNode($this->vm()->getNode());
  146. $loadBalancerNodes = $loadBalancerNodes->findByRam($ram)
  147. ->findByCpu($cpu)
  148. ->findByDisk($disk);
  149. if ($loadBalancerNodes->isEmpty())
  150. {
  151. throw new \Exception("Load Balancer: Cannot find free resources on node: " . $this->vm()->getNode());
  152. }
  153. }
  154. else
  155. {
  156. if ($this->configuration()->getLoadBalancerOnUpgrade() == "migrate")
  157. { //Allow to upgrade process, after previous migration vm to the server with free space.
  158. $loadBalancerNodes = $loadBalancer->findByNode($this->vm()->getNode());
  159. $loadBalancerNodes = $loadBalancerNodes->findByRam($ram)
  160. ->findByCpu($cpu)
  161. ->findByDisk($disk);
  162. if ($loadBalancerNodes->isEmpty())
  163. {
  164. if($this->configuration()->getServerGroup()){
  165. $nodes = ServerGroupItem::ofGroupIdsAndServerId($this->configuration()->getServerGroup(), $this->getWhmcsParamByKey('serverid'))
  166. ->pluck("node")
  167. ->toArray();
  168. if(empty($nodes)){
  169. throw new \InvalidArgumentException("LoadBalancer: Cannot find group for server #". $this->getWhmcsParamByKey('serverid'));
  170. }
  171. $loadBalancer->findByNodes($nodes);
  172. }
  173. $loadBalancerNodes = $loadBalancer->findByVmCreate();
  174. $nodesForUser = $loadBalancer->findNotUser($this->getWhmcsParamByKey('userid'));
  175. if (!$nodesForUser->isEmpty())
  176. {
  177. $loadBalancerNodes = $nodesForUser;
  178. }
  179. $targetNode = $loadBalancerNodes->findByRam($ram)
  180. ->findByCpu($cpu)
  181. ->findByDisk($disk)
  182. ->findByVms(1)
  183. ->nodeLowLoad();
  184. if ($this->configuration()->isLoadBalancerShutdownOnUpgrade())
  185. {
  186. $job = queue(LoadBalancer\ShutdownVmJob::class, ['hostingId' => $this->getWhmcsParamByKey('serviceid'), "targetNode" => $targetNode], null, "hosting", $this->getWhmcsParamByKey("serviceid"));
  187. }
  188. $job = queue(LoadBalancer\MigrateVmJob::class, ['hostingId' => $this->getWhmcsParamByKey('serviceid'), "targetNode" => $targetNode], $job->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
  189. queue(LoadBalancer\UpgradeVmJob::class, ['hostingId' => $this->getWhmcsParamByKey('serviceid'), "targetNode" => $targetNode], $job->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
  190. return true;
  191. }
  192. }
  193. }
  194. }
  195. if ($this->configuration()->isQemu())
  196. {
  197. $evnet = new QemuUpdateEvent($this->vm());
  198. $evnet->setChangeVmPassword(false);
  199. fire($evnet);
  200. }
  201. elseif ($this->configuration()->isLxc())
  202. {
  203. fire(new LxcUpdateEvent($this->vm()));
  204. }
  205. //hosting limit
  206. $this->saveUsageLimit();
  207. //move disk
  208. if($this->getWhmcsConfigOption(ConfigurableOption::STORAGE)){
  209. list($storage,$diskSize) = explode(":", $this->getWhmcsConfigOption(ConfigurableOption::STORAGE),2);
  210. $hdd = $this->vm()->getMasterHardDisk();
  211. if($hdd->getStorage() != $storage && !Job::waiting()->ofJob(MoveDiskJob::class)->ofHostingId($this->getWhmcsParamByKey("serviceid"))->count()){
  212. $parent = queue(MoveDiskJob::class, ['hostingId' => $this->getWhmcsParamByKey('serviceid')], null, "hosting", $this->getWhmcsParamByKey("serviceid"));
  213. }
  214. }
  215. if($this->configuration()->isAgentConfigureNetwork()){
  216. $parent = queue(ConfigureNetworkJob::class, ['hostingId' => $this->getWhmcsParamByKey('serviceid')], $parent->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
  217. }
  218. //reboot
  219. if ($this->configuration()->isRebootVmAfterChangePackage() &&
  220. $this->vm()->isRunning() &&
  221. !Job::waiting()->ofJob(RebootVmJob::class)->ofHostingId($this->getWhmcsParamByKey("serviceid"))->count())
  222. {
  223. $parent = queue(RebootVmJob::class, ['hostingId' => $this->getWhmcsParamByKey('serviceid')], $parent->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
  224. }
  225. //IP Filter
  226. if ($this->configuration()->isIpsetIpFilter())
  227. {
  228. $this->ipSetIpFilterService->create();
  229. }
  230. return "success";
  231. }
  232. catch (\Exception $ex)
  233. {
  234. return $ex->getMessage();
  235. }
  236. }
  237. private function manuallyUpgrade()
  238. {
  239. $scriptFile = substr($_SERVER['SCRIPT_NAME'], strrpos($_SERVER['SCRIPT_NAME'], DIRECTORY_SEPARATOR) + 1);
  240. if (!$this->configuration()->getUpgradeNotificationTemplateId() || $scriptFile == "clientsservices.php")
  241. {
  242. return;
  243. }
  244. if ($this->configuration()->isToDoList())
  245. {
  246. $title = sprintf('Manually Upgrade - Service ID: %s', $this->getWhmcsParamByKey('serviceid'));
  247. if (!ToDoList::ofTitle($title)->pending()->count())
  248. {
  249. $entity = new ToDoList();
  250. $entity->fill(
  251. [
  252. 'date' => date("Y-m-d H:i:s"),
  253. "duedate" => date("Y-m-d H:i:s"),
  254. 'title' => $title,
  255. "status" => "Pending",
  256. "description" => "An upgrade order has received its payment, automatic upgrades has been disabled and requires manually processing.",
  257. "admin" => 0,
  258. ]
  259. );
  260. $entity->save();
  261. }
  262. }
  263. //Send Admin notification
  264. $this->emailService->template($this->configuration()->getUpgradeNotificationTemplateId());
  265. global $customadminpath;
  266. $adminDir = $customadminpath ? $customadminpath : "admin";
  267. $adminAreaLink = $GLOBALS['CONFIG']['SystemURL'] . "/{$adminDir}";
  268. $hosting = $GLOBALS['CONFIG']['SystemURL'] . "/{$adminDir}/clientsservices.php?id=" . $this->getWhmcsParamByKey('serviceid');
  269. $emailVars = [
  270. "client_id" => $this->getWhmcsParamByKey('clientsdetails')['id'],
  271. "service_id" => $this->getWhmcsParamByKey('serviceid'),
  272. "service_product" => "<a href='{$hosting}/'>{$hosting}</a>",
  273. "service_domain" => $this->getWhmcsParamByKey('domain'),
  274. "whmcs_admin_link" => "<a href='{$adminAreaLink}/'>{$adminAreaLink}</a>",
  275. ];
  276. $this->emailService->vars($emailVars)->sendToAdmin();
  277. throw new \Exception("Automaticall upgrade has been disabled by admin");
  278. }
  279. private function createReinstallJob()
  280. {
  281. if (!$this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE))
  282. {
  283. return;
  284. }
  285. if (!Upgrade::ofHostingId($this->getWhmcsParamByKey('serviceid'))->pending()->today()->count())
  286. {
  287. return;
  288. }
  289. $pg = "tblproductconfiggroups";
  290. $pl = "tblproductconfiglinks";
  291. $po = "tblproductconfigoptions";
  292. $optionId = DB::table($po)
  293. ->select("{$po}.id")
  294. ->leftJoin($pg, "{$pg}.id", "=", "{$po}.gid")
  295. ->leftJoin($pl, "{$pl}.gid", "=", "{$pg}.id")
  296. ->where("{$pl}.pid", $this->getWhmcsParamByKey("pid"))
  297. ->where("{$po}.optionname", "like", "VM Template|%")
  298. ->value("id");
  299. if (!$optionId)
  300. {
  301. return;
  302. }
  303. if (!Upgrade::ofHostingId($this->getWhmcsParamByKey('serviceid'))->pending()->today()->ofOptionId($optionId)->count())
  304. {
  305. return;
  306. }
  307. if ($this->configuration()->isQemu())
  308. {
  309. if ($this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE)=== "0")
  310. {
  311. return;
  312. }
  313. }
  314. $arguments = [
  315. 'hostingId' => $this->getWhmcsParamByKey('serviceid'),
  316. "osTemplate" => $this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE),
  317. "password" => encrypt($this->getWhmcsParamByKey("password"))
  318. ];
  319. if ($this->configuration()->isBackupVmBeforeReinstall())
  320. {
  321. $job = queue(BackupVmJob::class, $arguments, null, "hosting", $this->getWhmcsParamByKey("serviceid"));
  322. }
  323. $job = queue(DeleteVmJob::class, $arguments, $job->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
  324. $job = queue(CreateVmJob::class, $arguments, $job->id, "hosting", $this->getWhmcsParamByKey("serviceid"));
  325. }
  326. protected function diskSizeValidation(){
  327. $diskSize = $this->configuration()->getDiskSize();
  328. if($this->getWhmcsConfigOption(ConfigurableOption::STORAGE)){
  329. list($storage,$diskSize) = explode(":", $this->getWhmcsConfigOption(ConfigurableOption::STORAGE),2);
  330. Utility::unitFormat($diskSize, $this->configuration()->getDiskUnit(), 'bytes');
  331. }
  332. elseif ($this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE))
  333. {
  334. $diskSize = $this->getWhmcsConfigOption(ConfigurableOption::DISK_SIZE);
  335. Utility::unitFormat($diskSize, $this->configuration()->getDiskUnit(), 'bytes');
  336. }else{
  337. Utility::unitFormat($diskSize, "gb", 'bytes');
  338. }
  339. $masterHddSize = $this->vm()->getMasterHddSize();
  340. Utility::unitFormat($masterHddSize, "gb", 'bytes');
  341. if ($diskSize < $masterHddSize)
  342. {
  343. throw new \Exception(sprintf('Downgrading disk size is restricted. Request Disk size: %s, VM disk size: %s',
  344. Format::convertBytes($diskSize), Format::convertBytes($masterHddSize)));
  345. }
  346. }
  347. }