CloneQemuJob.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. <?php
  2. namespace ModulesGarden\ProxmoxAddon\App\Jobs\Vps;
  3. use Illuminate\Database\Capsule\Manager as DB;
  4. use MGProvision\Proxmox\v2\Api;
  5. use MGProvision\Proxmox\v2\models\Kvm;
  6. use MGProvision\Proxmox\v2\ProxmoxApiException;
  7. use MGProvision\Proxmox\v2\repository\ClusterResourcesRepository;
  8. use ModulesGarden\ProxmoxAddon\App\Enum\Vps\CustomField;
  9. use ModulesGarden\ProxmoxAddon\App\Events\Vps\QemuUpdateEvent;
  10. use ModulesGarden\ProxmoxAddon\App\Events\Vps\VmCreatedEvent;
  11. use ModulesGarden\ProxmoxAddon\App\Factory\Ssh2Factory;
  12. use ModulesGarden\ProxmoxAddon\App\Models\CloudInitScript;
  13. use ModulesGarden\ProxmoxAddon\App\Models\TaskHistory;
  14. use ModulesGarden\ProxmoxAddon\App\Models\VmIpAddress;
  15. use ModulesGarden\ProxmoxAddon\App\Providers\SnippetProvider;
  16. use ModulesGarden\ProxmoxAddon\App\Repositories\ServerConfigurationRepository;
  17. use ModulesGarden\ProxmoxAddon\App\Services\CloudInitScriptConveter;
  18. use ModulesGarden\ProxmoxAddon\App\Services\Vps\ProductService;
  19. use ModulesGarden\ProxmoxAddon\App\Services\Vps\UserService;
  20. use ModulesGarden\ProxmoxAddon\App\Enum\Vps\ConfigurableOption;
  21. use function ModulesGarden\ProxmoxAddon\Core\Helper\fire;
  22. class CloneQemuJob extends BaseJob
  23. {
  24. use ProductService;
  25. use UserService;
  26. public function handle()
  27. {
  28. $this->initParams();
  29. $this->initServices();
  30. $this->setHostingId($this->getWhmcsParamByKey("serviceid"));
  31. //create task validation
  32. if ($this->isDone())
  33. {
  34. $this->qemuUpdate();
  35. if($this->agentUpdate()){
  36. fire(new VmCreatedEvent($this->vm()));
  37. return true;
  38. }
  39. return false;
  40. }
  41. elseif ($this->isTaskRunning())
  42. {
  43. //sleep
  44. $this->sleep(5);
  45. return false;
  46. }
  47. try
  48. {
  49. Api::beginTransaction();
  50. DB::beginTransaction();
  51. //node
  52. $node = $this->getWhmcsCustomField(CustomField::NODE) ? $this->getWhmcsCustomField(CustomField::NODE) :$this->getNode()->getNode();
  53. //os template
  54. $osTemplate = $this->getWhmcsConfigOption(ConfigurableOption::OS_TEMPLATE, $this->configuration()->getOsTemplate() );
  55. //Support for configurable options i.e vmname|OS Name
  56. if (is_string($osTemplate) && !preg_match('/\//', $osTemplate))
  57. {
  58. $clusterRepository = new ClusterResourcesRepository();
  59. $clusterRepository->setApi($this->api());
  60. if(!$this->configuration()->isOsTemplatesInAllNodes()){
  61. $clusterRepository->findByNodes([$node]);
  62. }
  63. $clusterRepository->findKvmTemplate();
  64. foreach ($clusterRepository->fetch() as $resurce)
  65. {
  66. if ($resurce->getName() == $osTemplate)
  67. {
  68. $templateVmid = $resurce->getVmid();
  69. $templateNode = $resurce->getNode();
  70. break;
  71. }
  72. }
  73. if (!$templateVmid)
  74. {
  75. throw new \Exception(sprintf("Unable to find KVM template: %s on node: %s", $osTemplate, $templateNode ));
  76. }
  77. //Support for configurable options like nodename/vmid|OS Name
  78. }
  79. else
  80. {
  81. if (preg_match('/\//', $osTemplate))
  82. {
  83. list($templateNode, $templateVmid) = explode("/", $osTemplate);
  84. }
  85. }
  86. //vmid
  87. $vmid = $this->nextVmid();
  88. $this->customFieldUpdate("vmid", $vmid);
  89. $this->customFieldUpdate("node", $node);
  90. //init container
  91. $container = [
  92. "newid" => $vmid,
  93. "full" => $this->configuration()->getCloneMode(),
  94. "target" => $node
  95. ];
  96. //description
  97. if ($this->configuration()->getDescription())
  98. {
  99. $container['description'] = $this->containerService->description();
  100. }
  101. //hostname
  102. $hostname = $this->containerService->hostname();
  103. if ($hostname)
  104. {
  105. $container['name'] = $hostname;
  106. }
  107. //Storage
  108. if (!$this->configuration()->isCloneOnTheSameStorage() && $this->configuration()->getDiskStorage() && $this->configuration()->getCloneMode() == "1")
  109. {
  110. $container['storage'] = $this->configuration()->getDiskStorage();
  111. }
  112. if($this->getWhmcsConfigOption(ConfigurableOption::STORAGE)){
  113. list($storage,$diskSize) = explode(":", $this->getWhmcsConfigOption(ConfigurableOption::STORAGE),2);
  114. $container['storage'] = $storage;
  115. }
  116. //pool
  117. if ($this->configuration()->getPool())
  118. {
  119. $container['pool'] = $this->configuration()->getPool();
  120. }
  121. //bwlimit
  122. if($this->configuration()->getBwLimit()){
  123. $container['bwlimit'] = $this->configuration()->getBwLimit();
  124. }
  125. //Create
  126. $template = new Kvm($templateNode, $templateVmid);
  127. $template->setApi($this->api());
  128. $taskId = $template->cloneVm($container);
  129. DB::commit();
  130. }
  131. catch (\Exception $ex)
  132. {
  133. DB::rollBack();
  134. Api::commit();
  135. $this->failed($ex->getMessage());
  136. throw $ex;
  137. }
  138. //task history
  139. $task = new TaskHistory();
  140. $task->fill([
  141. 'hosting_id' => $this->getWhmcsParamByKey("serviceid"),
  142. 'upid' => $taskId,
  143. 'name' => sprintf("VM %s - %s", $vmid, "Clone"),
  144. 'vmid' => $template->getVmid(),
  145. 'node' => $template->getNode(),
  146. 'status' => 0
  147. ])->save();
  148. //save task id
  149. $this->putModelDataAndSave(["taskId" => $taskId, "node" => $template->getNode(), "templateNode" => $templateNode]);
  150. //sleep
  151. $this->sleep();
  152. return false;
  153. }
  154. private function deleteNetwork(){
  155. $deleteNetwork = [];
  156. foreach ($this->vm()->getNetworkDevices() as $networkDevice){
  157. if(VmIpAddress::ofHostingId($this->getWhmcsParamByKey('serviceid'))->ofNet($networkDevice->getId())->count()){
  158. continue;
  159. }
  160. $deleteNetwork[]=$networkDevice->getId();
  161. }
  162. if(!empty($deleteNetwork)){
  163. $this->vm()->deleteConfig(implode(",",$deleteNetwork));
  164. }
  165. }
  166. protected function qemuUpdate(){
  167. if(!$this->vm()->isRunning()){
  168. $this->deleteNetwork();
  169. }
  170. if($this->configuration()->isAdditionalDisk() && !$this->additionalDiskService->hasDisk() ){
  171. $this->additionalDiskService->create();
  172. }
  173. fire(new QemuUpdateEvent($this->vm()));
  174. }
  175. protected function agentUpdate(){
  176. try{
  177. if($this->agentService->isEnabled()){
  178. if(!$this->vm()->isRunning()){
  179. $this->log->info(sprintf("VM %s - Start", $this->vm()->getVmid()));
  180. $this->vm()->start();
  181. $this->sleep(5);
  182. return false;
  183. }
  184. $this->vm()->agent()->ping();
  185. $this->agentService ->getUserAndUpdate();
  186. $this->agentService ->passwordUpdate();
  187. $this->agentService ->configureNetwork();
  188. }
  189. return true;
  190. }catch (ProxmoxApiException $ex){
  191. if(preg_match("/not running/", $ex->getMessage())){
  192. $this->log->info($ex->getMessage());
  193. }else{
  194. $this->log->error($ex->getMessage());
  195. }
  196. //sleep
  197. $this->sleep(5);
  198. return false;
  199. }
  200. }
  201. }