Kvm.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. <?php
  2. /* * ********************************************************************
  3. * ProxmoxVPS product developed. (2016-10-05)
  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 MGProvision\Proxmox\v2\models;
  20. use MGProvision\Proxmox\v2\models\HardDisk;
  21. use MGProvision\Proxmox\v2\repository\CdRomRepository;
  22. use MGProvision\Proxmox\v2\repository\HardDiskRepostiory;
  23. use \MGProvision\Proxmox\v2\repository\IpConfigRepository;
  24. /**
  25. * Description of Kvm
  26. *
  27. * @author Pawel Kopec <pawelk@modulesgarden.com>
  28. * @version 1.0.0
  29. */
  30. class Kvm extends AbstractVm implements \MGProvision\Proxmox\v2\interfaces\KvmInterface
  31. {
  32. public function getVirtualization()
  33. {
  34. return 'qemu';
  35. }
  36. public function suspend()
  37. {
  38. return $this->api()->post("/nodes/{$this->node}/{$this->getVirtualization()}/{$this->vmid}/status/suspend");
  39. }
  40. public function cdrom()
  41. {
  42. foreach ($this->config() as $k => $c)
  43. {
  44. if (strpos($c, "media=cdrom") !== false && !preg_match('/cloudinit/', $c))
  45. {
  46. $c = explode(",", $c);
  47. $isoRaw = $c[0];
  48. $c = explode(":iso/", $isoRaw);
  49. $iso = end($c);
  50. $iso = ucwords(str_replace(array("-", "_", ".iso"), array(" ", " ", ""), $iso));
  51. return array(
  52. "iso" => $iso,
  53. "isoRaw" => $isoRaw,
  54. "bus" => $k
  55. );
  56. }
  57. }
  58. }
  59. public function getBootOrder()
  60. {
  61. $config = $this->config();
  62. //order=scsi0;ide1;scsi2
  63. if($config['boot'] && preg_match("/order/",$config['boot'])){
  64. list($key, $order) = explode("=", $config['boot']);
  65. return explode(";",$order);
  66. }
  67. $boot = array("c", "d", "n");
  68. if (isset($config['boot']))
  69. {
  70. $boot = str_split($config['boot']);
  71. }
  72. return $boot;
  73. }
  74. public function changeBootOrder($boot)
  75. {
  76. $data = array();
  77. $data['boot'] = $boot;
  78. $this->config = null;
  79. return $this->api()->put("/nodes/{$this->node}/qemu/{$this->vmid}/config", $data);
  80. }
  81. public function changeIso($iso)
  82. {
  83. $cdrom = $this->cdrom();
  84. if (!$cdrom['bus'])
  85. throw new \MGProvision\Proxmox\v2\ProxmoxApiException("CD-ROM volume not found");
  86. $data = array();
  87. $data[$cdrom['bus']] = "{$iso},media=cdrom";
  88. $this->config = null;
  89. return $this->api()->put("/nodes/{$this->node}/qemu/{$this->vmid}/config", $data);
  90. }
  91. public function cloneVm($container)
  92. {
  93. return $this->api()->post("/nodes/{$this->node}/qemu/{$this->vmid}/clone", $container);
  94. }
  95. public function getIso()
  96. {
  97. $result = array();
  98. foreach ($this->config() as $k => $c)
  99. {
  100. if (strpos($c, "media=cdrom") !== false && !preg_match('/cloudinit/', $c ))
  101. {
  102. $c = explode(",", $c);
  103. $isoRaw = $c[0];
  104. $c = explode(":iso/", $isoRaw);
  105. $iso = end($c);
  106. $iso = ucwords(str_replace(array("-", "_", ".iso"), array(" ", " ", ""), $iso));
  107. return array(
  108. "iso" => $iso,
  109. "isoRaw" => $isoRaw,
  110. "bus" => $k
  111. );
  112. }
  113. }
  114. }
  115. public function updateCdrom($iso)
  116. {
  117. $cdrom = $this->cdrom();
  118. if (!$cdrom['bus'])
  119. throw new \MGProvision\Proxmox\v2\ProxmoxApiException("CD-ROM volume not found");
  120. $data = array();
  121. $data[$cdrom['bus']] = "{$iso},media=cdrom";
  122. $this->config = null;
  123. return $this->api()->put("/nodes/{$this->node}/qemu/{$this->vmid}/config", $data);
  124. }
  125. public function findFreeNetworDeviceId()
  126. {
  127. $config = $this->config(true);
  128. for($i=0; $i<=50; $i++){
  129. if($config['net'.$i]){
  130. continue;
  131. }
  132. return $i;
  133. }
  134. }
  135. public function findFreeIde($type)
  136. {
  137. $i = 0;
  138. $type = strtolower($type);
  139. foreach ($this->config(true) as $k => $v)
  140. {
  141. if (preg_match("/{$type}/", $k))
  142. $i++;
  143. }
  144. return $i;
  145. }
  146. /**
  147. * @deprecated since version 2.4.0
  148. * @return array
  149. */
  150. public function getHdds()
  151. {
  152. $disks = array();
  153. $isPrimary = false;
  154. $config = $this->config();
  155. foreach ($config as $key => $val)
  156. {
  157. if (strpos($val, 'disk') !== false)
  158. {
  159. if (in_array($key, ['hotplug']))
  160. {
  161. continue;
  162. }
  163. $sets = explode(",", $val);
  164. $disks[$key] = array("bus" => $key, "location" => current($sets), "format" => "", "backup" => "", "size" => "", "isPrimary" => false);
  165. foreach ($sets as $set)
  166. {
  167. list($k, $v) = explode("=", $set);
  168. $disks[$key][$k] = $v;
  169. if ($k == "size")
  170. {
  171. if (preg_match('/M/', $v))
  172. {//MB => GB
  173. $disks[$key]['sizeRaw'] = (int) $v / 1024;
  174. }
  175. else if (preg_match('/T/', $v))
  176. {//T => GB
  177. $disks[$key]['sizeRaw'] = (int) $v * 1024;
  178. }
  179. else
  180. {//GB
  181. $disks[$key]['sizeRaw'] = (int) $v;
  182. }
  183. }
  184. }
  185. if (empty($disks[$key]['format']) && preg_match('/disk-[0-9]\./', $sets['0']))
  186. {
  187. $disks[$key]['format'] = preg_replace('/(.*)\./', '', $sets['0']);
  188. }
  189. if (isset($config['bootdisk']) && $key == $config['bootdisk'])
  190. {
  191. $disks[$key] ['isPrimary'] = true;
  192. $isPrimary = true;
  193. }
  194. else if (!isset($config['bootdisk']) && !$isPrimary && strpos($disks[$key] ['location'], 'disk-0') !== false)
  195. {
  196. $disks[$key] ['isPrimary'] = true;
  197. $isPrimary = true;
  198. }
  199. $matches = array();
  200. preg_match('/disk-[0-9]/', $disks[$key] ['location'], $matches);
  201. if ($matches[0])
  202. $disks[$key] ['name'] = $matches[0];
  203. }
  204. }
  205. ksort($disks);
  206. return $disks;
  207. }
  208. /**
  209. * @return HardDisk[]
  210. */
  211. public function getHardDisks()
  212. {
  213. $disks = array();
  214. $config = $this->config(true);
  215. $boot = (array) $this->getBootOrder();
  216. $bootDisk = reset($boot );
  217. foreach ($config as $id => $value)
  218. {
  219. if (in_array($id, ['hotplug','agent']))
  220. {
  221. continue;
  222. }
  223. if(preg_match("/unused/", $id)){
  224. continue;
  225. }
  226. if (!preg_match('/disk/', $value))
  227. {
  228. continue;
  229. }
  230. $hdd = (new HardDisk($id, $value))->setPath("/nodes/{$this->node}/qemu/{$this->vmid}/config");
  231. if (isset($config['bootdisk']))
  232. {
  233. $hdd->setMaster($config['bootdisk'] == $id);
  234. }elseif ($bootDisk ){
  235. $hdd->setMaster($bootDisk == $id);
  236. }
  237. $disks[] = $hdd;
  238. }
  239. return $disks;
  240. }
  241. /**
  242. * @return HardDisk[]
  243. */
  244. public function getUnusedHardDisks()
  245. {
  246. $disks = array();
  247. $config = $this->config(true);
  248. foreach ($config as $id => $value)
  249. {
  250. if (in_array($id, ['hotplug','agent']))
  251. {
  252. continue;
  253. }
  254. if(!preg_match("/unused/", $id)){
  255. continue;
  256. }
  257. if (!preg_match('/disk/', $value))
  258. {
  259. continue;
  260. }
  261. $hdd = (new HardDisk($id, $value))->setPath("/nodes/{$this->node}/qemu/{$this->vmid}/config");
  262. $disks[] = $hdd;
  263. }
  264. return $disks;
  265. }
  266. /**
  267. *
  268. * @return HardDisk
  269. * @throws \MGProvision\Proxmox
  270. */
  271. public function getMasterHardDisk()
  272. {
  273. $hdds = [];
  274. $configs = $this->config();
  275. $boot = (array) $this->getBootOrder();
  276. $bootDisk = reset($boot );
  277. foreach ($configs as $id => $config)
  278. {
  279. if (!HardDisk::isConfigValid($id, $config))
  280. {
  281. continue;
  282. }
  283. $hdd = new HardDisk($id, $config);
  284. $hdd->setPath("/nodes/{$this->node}/qemu/{$this->vmid}/config");
  285. if (isset($configs['bootdisk']))
  286. {
  287. $hdd->setMaster($configs['bootdisk'] == $id);
  288. }elseif ($bootDisk ){
  289. $hdd->setMaster($bootDisk == $id);
  290. }
  291. if ($hdd->isMaster())
  292. {
  293. return $hdd;
  294. }
  295. $hdds[] = $hdd;
  296. }
  297. foreach ($hdds as $hdd)
  298. {
  299. if(preg_match('/unused/', $hdd->getId())){
  300. continue;
  301. }
  302. return $hdd;
  303. }
  304. throw new \MGProvision\Proxmox\v2\ProxmoxApiException("Master Hard Disk not found");
  305. }
  306. public function resizeHdd(array $setting)
  307. {
  308. return $this->api()->put("/nodes/{$this->node}/qemu/{$this->vmid}/resize", $setting);
  309. }
  310. public function getMasterHddSize()
  311. {
  312. $hdds = $this->getHdds();
  313. foreach ($hdds as $hdd)
  314. {
  315. if ($hdd['isPrimary'])
  316. {
  317. return $hdd['sizeRaw'];
  318. }
  319. }
  320. throw new \MGProvision\Proxmox\v2\ProxmoxApiException("Master Disk no found!");
  321. }
  322. /**
  323. * @param $id
  324. * @return \MGProvision\Proxmox\v2\models\HardDisk
  325. * @throws \Exception
  326. */
  327. public function findHardDiskById($id)
  328. {
  329. foreach($this->getHardDisks() as $disk)
  330. {
  331. if($disk->getId() == $id)
  332. {
  333. return $disk;
  334. }
  335. }
  336. throw new \Exception('Cannot find disk');
  337. }
  338. public function getSlaveHddsSize($skip = null)
  339. {
  340. $size = 0;
  341. foreach ($this->getHdds() as $hdd)
  342. {
  343. if ($hdd['isPrimary'] || $skip == $hdd['bus'])
  344. continue;
  345. $size += $hdd['sizeRaw'];
  346. }
  347. return $size;
  348. }
  349. /**
  350. *
  351. * @param type $findBridge
  352. * @param type $force
  353. * @return \MGProvision\Proxmox\v2\models\NetworkDeviceKvm[]
  354. */
  355. public function getNetworkDevices($findBridge = null, $force = true)
  356. {
  357. $networks = array();
  358. foreach ($this->config($force) as $k => $v)
  359. {
  360. if (!preg_match('/net/', $k))
  361. continue;
  362. $network = new NetworkDeviceKvm($k, $v);
  363. if ($findBridge && $network->getBridge() !== $findBridge)
  364. continue;
  365. $networks[] = $network;
  366. }
  367. return $networks;
  368. }
  369. public function getMacAddresses($findBridge = null, $force = false)
  370. {
  371. $macs = array();
  372. foreach ($this->getNetworkDevices($findBridge, $force) as $network)
  373. {
  374. $macs[] = $network->getMacAddress();
  375. }
  376. return $macs;
  377. }
  378. /**
  379. *
  380. * @param \MGProvision\Proxmox\v2\models\NetworkDeviceKvm[] $networkDevices
  381. */
  382. public function updateNetworkDevices($networkDevices)
  383. {
  384. $container = array();
  385. foreach ($networkDevices as $networkDevice)
  386. {
  387. $container[$networkDevice->getId()] = $networkDevice->asConfig();
  388. }
  389. return $this->updateConfig($container);
  390. }
  391. public function getReinstallConfig()
  392. {
  393. $setting = array();
  394. foreach ($this->config(true) as $k => $v)
  395. {
  396. $setting[$k] = $v;
  397. }
  398. unset($setting['digest']);
  399. return $setting;
  400. }
  401. public function restore($archive)
  402. {
  403. try
  404. {
  405. if ($this->isRunning())
  406. {
  407. $this->stop();
  408. sleep(5);
  409. }
  410. }
  411. catch (\Exception $ex)
  412. {//error i.e.: Configuration file 'nodes/proxmox/lxc/117.conf' does not exist
  413. if ($ex->getCode() != 500)
  414. {
  415. throw $ex;
  416. }
  417. }
  418. $container = array(
  419. 'vmid' => $this->vmid,
  420. 'archive' => $archive,
  421. 'force' => 1,
  422. );
  423. return $this->api()->post("/nodes/{$this->node}/qemu", $container);
  424. }
  425. /**
  426. *
  427. * @return \MGProvision\Proxmox\v2\models\SnapshotKvm
  428. */
  429. public function snapshot($name = null)
  430. {
  431. $snap = new SnapshotKvm();
  432. $path = "/nodes/{$this->getNode()}/{$this->getVirtualization()}/{$this->getVmid()}/snapshot";
  433. if ($name !== null)
  434. {
  435. $path .= "/{$name}";
  436. }
  437. $snap->setPath($path);
  438. return $snap;
  439. }
  440. public function convertToTemplate()
  441. {
  442. return $this->api()->post("/nodes/{$this->node}/qemu/{$this->vmid}/template");
  443. }
  444. public function findNetworkDevice($macAddress)
  445. {
  446. foreach ($this->getNetworkDevices() as $nd)
  447. {
  448. if ($nd->getMacAddress() == $macAddress)
  449. {
  450. return $nd;
  451. }
  452. }
  453. return null;
  454. }
  455. public function deleteNetworkDevice(NetworkDeviceKvm $networkDevice)
  456. {
  457. $this->deleteConfig($networkDevice->getId());
  458. }
  459. /**
  460. *
  461. * @param HardDisk $hardDisks
  462. * @return array
  463. */
  464. public function updateHardDisks($hardDisks)
  465. {
  466. $container = array();
  467. foreach ($hardDisks as $hardDisk)
  468. {
  469. $container[$hardDisk->getId()] = $hardDisk->asConfig();
  470. }
  471. return $this->updateConfig($container);
  472. }
  473. /**
  474. *
  475. * @return IpConfigRepository
  476. */
  477. public function getIpConfig()
  478. {
  479. $repostiory = new IpConfigRepository;
  480. $repostiory->findByPath("/nodes/{$this->node}/qemu/{$this->vmid}/config");
  481. return $repostiory;
  482. }
  483. public function getCdRom()
  484. {
  485. $repostiory = new CdRomRepository();
  486. $repostiory->findByPath("/nodes/{$this->node}/qemu/{$this->vmid}/config");
  487. return $repostiory;
  488. }
  489. /**
  490. * @return Agent
  491. */
  492. public function agent()
  493. {
  494. return (new Agent())->setPath("/nodes/{$this->node}/qemu/{$this->vmid}/agent");
  495. }
  496. public function getCdRomRepository(){
  497. $repostiory = new CdRomRepository();
  498. $repostiory->findByPath("/nodes/{$this->node}/qemu/{$this->vmid}/config");
  499. return $repostiory;
  500. }
  501. public function hasCloudInit(){
  502. $repostiory = new CdRomRepository();
  503. $repostiory->findByPath("/nodes/{$this->node}/qemu/{$this->vmid}/config");
  504. return $repostiory->hasCloudInit();
  505. }
  506. /**
  507. * @return HardDiskRepostiory
  508. * @throws \MGProvision\Proxmox\v2\ProxmoxApiException
  509. */
  510. public function getHardDiskRepostiory(){
  511. $repository = new HardDiskRepostiory();
  512. $repository->setApi($this->api());
  513. $repository->findByPath($this->getPath() . '/config');
  514. return $repository;
  515. }
  516. }