CreateVmJob.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. <?php
  2. namespace ModulesGarden\ProxmoxAddon\App\Jobs\Vps\Reinstall;
  3. use MGProvision\Proxmox\v2\models\FirewallRule;
  4. use MGProvision\Proxmox\v2\models\Kvm;
  5. use MGProvision\Proxmox\v2\models\Node;
  6. use MGProvision\Proxmox\v2\ProxmoxApiException;
  7. use MGProvision\Proxmox\v2\repository\ClusterResourcesRepository;
  8. use MGProvision\Proxmox\v2\repository\FileRepository;
  9. use ModulesGarden\ProxmoxAddon\App\Events\Vps\LxcUpdateEvent;
  10. use ModulesGarden\ProxmoxAddon\App\Events\Vps\QemuUpdateEvent;
  11. use ModulesGarden\ProxmoxAddon\App\Events\Vps\VmReinstalledEvent;
  12. use ModulesGarden\ProxmoxAddon\App\Jobs\Vps\BaseJob;
  13. use ModulesGarden\ProxmoxAddon\App\Models\Job;
  14. use ModulesGarden\ProxmoxAddon\App\Models\VmIpAddress;
  15. use ModulesGarden\ProxmoxAddon\App\Services\Vps\AgentService;
  16. use ModulesGarden\ProxmoxAddon\App\Services\Vps\ContainerService;
  17. use ModulesGarden\ProxmoxAddon\App\Services\Vps\HighAvailabilityClusterService;
  18. use ModulesGarden\ProxmoxAddon\App\Services\Vps\HostingService;
  19. use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
  20. use function ModulesGarden\ProxmoxAddon\Core\Helper\fire;
  21. use function ModulesGarden\ProxmoxAddon\Core\Helper\queue;
  22. use function ModulesGarden\ProxmoxAddon\Core\Helper\sl;
  23. class CreateVmJob extends BaseJob
  24. {
  25. use ProductService;
  26. use HostingService;
  27. /**
  28. * @var HighAvailabilityClusterService
  29. */
  30. protected $highAvailabilityClusterService;
  31. protected function initServices()
  32. {
  33. $this->highAvailabilityClusterService = new HighAvailabilityClusterService();
  34. $this->containerService = new ContainerService();
  35. $this->agentService = new AgentService();
  36. }
  37. public function handle($text = null)
  38. {
  39. $this->initParams();
  40. $this->initServices();
  41. //is done
  42. if ($this->isTask() && $this->getTask()->isDone()) {
  43. //update password
  44. if ($this->getModelData()['password'] ) {
  45. if($this->params['customfields']['cipassword']){
  46. $this->customFieldUpdate('cipassword', $this->getModelData()['password']);
  47. $this->params['customfields']['cipassword'] = decrypt($this->getModelData()['password']);
  48. }else{
  49. $this->hosting()->update(["password" => $this->getModelData()['password']]);
  50. $this->params['password'] = decrypt($this->getModelData()['password']);
  51. }
  52. sl("whmcsParams")->setParams($this->params);
  53. \ModulesGarden\Servers\ProxmoxVps\Core\Helper\sl("whmcsParams")->setParams($this->params);
  54. }
  55. //reinstalled event
  56. if ($this->configuration()->isLxc()) {
  57. fire(new LxcUpdateEvent($this->vm()));
  58. } elseif ($this->configuration()->isQemu()) {
  59. //Reset IP addresses usage
  60. VmIpAddress::ofHostingId($this->getWhmcsParamByKey("serviceid"))
  61. ->update([
  62. 'net' => null
  63. ]);
  64. $this->deleteNetwork();
  65. if(!$this->vm()->isRunning()){
  66. $this->deleteNetwork();
  67. }
  68. fire(new QemuUpdateEvent($this->vm()));
  69. //Agent
  70. try{
  71. if($this->agentService->isEnabled()){
  72. if(!$this->vm()->isRunning()){
  73. $this->log->info(sprintf("VM %s - Start", $this->vm()->getVmid()));
  74. $this->vm()->start();
  75. $this->sleep(40);
  76. return false;
  77. }
  78. $this->vm()->agent()->ping();
  79. $this->agentService ->getUserAndUpdate();
  80. $this->agentService ->passwordUpdate();
  81. $this->agentService ->configureNetwork();
  82. }
  83. }catch (ProxmoxApiException $ex){
  84. if(preg_match("/not running/", $ex->getMessage())){
  85. $this->log->info($ex->getMessage());
  86. }else{
  87. $this->log->error($ex->getMessage());
  88. }
  89. //sleep
  90. $this->sleep(30);
  91. return false;
  92. }
  93. }
  94. //restoreFirewallRules
  95. $this->restoreFirewallRules();
  96. fire(new VmReinstalledEvent($this->vm()));
  97. return true;
  98. } else if ($this->isTask() && $this->getTask()->isRunning()) {
  99. $this->sleep(20);
  100. return false;
  101. } else if ($this->isTask() && $this->getTask()->isFalied()) {
  102. if ($this->configuration()->isBackupVmBeforeReinstall()) {
  103. $this->log->error($this->getTask()->getExitstatus());
  104. $this->restoreJob();
  105. $this->model->setStatus(Job::STATUS_FAILED);
  106. return;
  107. }
  108. throw new \Exception($this->getTask()->getExitstatus());
  109. } //create vm
  110. else if (!$this->isTask() && $this->configuration()->isLxc()) {
  111. try {
  112. $container = $this->getParentModelData()['container'];
  113. unset($container['lxc'], $container['parent']);
  114. //pool
  115. if ($this->configuration()->getPool())
  116. {
  117. $container['pool'] = $this->configuration()->getPool();
  118. }
  119. $node = new Node($this->vm()->getNode());
  120. $node->setApi($this->api());
  121. $taskId = $node->lxc()->create($container);
  122. //save task id
  123. $this->putModelDataAndSave(["taskId" => $taskId, "node" => $this->vm()->getNode()]);
  124. //task history
  125. $this->createTaskHistory($taskId, "Create");
  126. } catch (\Exception $ex) {
  127. $this->log->error($ex->getMessage());
  128. $this->restoreJob();
  129. return false;
  130. }
  131. //clone vm
  132. } else if (!$this->isTask() && $this->configuration()->isQemu()) {
  133. try {
  134. $osTemplate = $this->getModelData()['osTemplate'];
  135. //Support for configurable options i.e vmname|OS Name
  136. if (is_string($osTemplate) && !preg_match('/\//', $osTemplate)) {
  137. $templateNode = $this->vm()->getNode();
  138. $clusterRepository = new ClusterResourcesRepository();
  139. $clusterRepository->setApi($this->api());
  140. $clusterRepository->findByNodes([$templateNode])
  141. ->findKvmTemplate();
  142. foreach ($clusterRepository->fetch() as $resurce) {
  143. if ($resurce->getName() == $osTemplate && $templateNode == $resurce->getNode()) {
  144. $templateVmid = $resurce->getVmid();
  145. break;
  146. }
  147. }
  148. if (!$templateVmid) {
  149. throw new \Exception(sprintf("Unable to find KVM template: %s on node: %s", $osTemplate, $templateNode));
  150. }
  151. //Support for configurable options like nodename/vmid|OS Name
  152. } elseif (preg_match('/\//', $osTemplate)) {
  153. list($templateNode, $templateVmid) = explode("/", $osTemplate);
  154. }
  155. //init container
  156. $container = [
  157. "newid" => $this->vm()->getVmid(),
  158. "full" => $this->configuration()->getCloneMode(),
  159. "target" => $this->vm()->getNode()
  160. ];
  161. //description
  162. if ($this->configuration()->getDescription()) {
  163. $container['description'] = $this->containerService->description();
  164. }
  165. //hostname
  166. $hostname = $this->containerService->hostname();
  167. if ($hostname) {
  168. $container['name'] = $hostname;
  169. }
  170. //Storage
  171. if (!$this->configuration()->isCloneOnTheSameStorage() && $this->configuration()->getDiskStorage() && $this->configuration()->getCloneMode() == "1") {
  172. $container['storage'] = $this->configuration()->getDiskStorage();
  173. }
  174. //pool
  175. if ($this->configuration()->getPool()) {
  176. $container['pool'] = $this->configuration()->getPool();
  177. }
  178. //Create
  179. $template = new Kvm($templateNode, $templateVmid);
  180. $template->setApi($this->api());
  181. $taskId = $template->cloneVm($container);
  182. //save task id
  183. $this->putModelDataAndSave(["taskId" => $taskId, "node" => $this->vm()->getNode(), "templateNode" => $templateNode]);
  184. //task history
  185. $this->createTaskHistory($taskId, "Create");
  186. } catch (\Exception $ex) {
  187. if ($this->configuration()->isBackupVmBeforeReinstall()) {
  188. $this->log->error($ex->getMessage());
  189. $this->restoreJob();
  190. $this->model->setStatus(Job::STATUS_FAILED);
  191. return;
  192. }
  193. throw $ex;
  194. }
  195. }
  196. $this->sleep(20);
  197. return false;
  198. }
  199. private function restoreJob()
  200. {
  201. //create restore job
  202. $storage = $this->configuration()->getBackupStorage() ? $this->configuration()->getBackupStorage() : 'local';
  203. $fileRepository = new FileRepository();
  204. $fileRepository->findBackup($this->vm())
  205. ->findByStorages([$storage]);
  206. if (!$fileRepository->count()) {
  207. return;
  208. }
  209. queue(RestoreVm::class, [], null, "hosting", $this->getWhmcsParamByKey("serviceid"));
  210. $this->model->setStatus(Job::STATUS_CANCELLED)->save();
  211. return false;
  212. }
  213. private function deleteNetwork(){
  214. $deleteNetwork = [];
  215. foreach ($this->vm()->getNetworkDevices() as $networkDevice){
  216. if(VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))->ofNet($networkDevice->getId())->count()){
  217. continue;
  218. }
  219. $deleteNetwork[]=$networkDevice->getId();
  220. }
  221. if(!empty($deleteNetwork)){
  222. $this->vm()->deleteConfig(implode(",",$deleteNetwork));
  223. }
  224. }
  225. protected function restoreFirewallRules(){
  226. foreach ($this->getModelData()['firewallRules'] as $rule){
  227. $firewallRule = new FirewallRule();
  228. $firewallRule->setApi($this->api());
  229. $firewallRule->setPath($this->vm()->getPath() . "/firewall/rules/");
  230. $firewallRule->setAttributes($rule);
  231. $firewallRule->create();
  232. }
  233. }
  234. }