Kvm.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  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. *
  243. * @return HardDisk
  244. * @throws \MGProvision\Proxmox
  245. */
  246. public function getMasterHardDisk()
  247. {
  248. $hdds = [];
  249. $configs = $this->config();
  250. $boot = (array) $this->getBootOrder();
  251. $bootDisk = reset($boot );
  252. foreach ($configs as $id => $config)
  253. {
  254. if (!HardDisk::isConfigValid($id, $config))
  255. {
  256. continue;
  257. }
  258. $hdd = new HardDisk($id, $config);
  259. $hdd->setPath("/nodes/{$this->node}/qemu/{$this->vmid}/config");
  260. if (isset($configs['bootdisk']))
  261. {
  262. $hdd->setMaster($configs['bootdisk'] == $id);
  263. }elseif ($bootDisk ){
  264. $hdd->setMaster($bootDisk == $id);
  265. }
  266. if ($hdd->isMaster())
  267. {
  268. return $hdd;
  269. }
  270. $hdds[] = $hdd;
  271. }
  272. foreach ($hdds as $hdd)
  273. {
  274. if(preg_match('/unused/', $hdd->getId())){
  275. continue;
  276. }
  277. return $hdd;
  278. }
  279. throw new \MGProvision\Proxmox\v2\ProxmoxApiException("Master Hard Disk not found");
  280. }
  281. public function resizeHdd(array $setting)
  282. {
  283. return $this->api()->put("/nodes/{$this->node}/qemu/{$this->vmid}/resize", $setting);
  284. }
  285. public function getMasterHddSize()
  286. {
  287. $hdds = $this->getHdds();
  288. foreach ($hdds as $hdd)
  289. {
  290. if ($hdd['isPrimary'])
  291. {
  292. return $hdd['sizeRaw'];
  293. }
  294. }
  295. throw new \MGProvision\Proxmox\v2\ProxmoxApiException("Master Disk no found!");
  296. }
  297. /**
  298. * @param $id
  299. * @return \MGProvision\Proxmox\v2\models\HardDisk
  300. * @throws \Exception
  301. */
  302. public function findHardDiskById($id)
  303. {
  304. foreach($this->getHardDisks() as $disk)
  305. {
  306. if($disk->getId() == $id)
  307. {
  308. return $disk;
  309. }
  310. }
  311. throw new \Exception('Cannot find disk');
  312. }
  313. public function getSlaveHddsSize($skip = null)
  314. {
  315. $size = 0;
  316. foreach ($this->getHdds() as $hdd)
  317. {
  318. if ($hdd['isPrimary'] || $skip == $hdd['bus'])
  319. continue;
  320. $size += $hdd['sizeRaw'];
  321. }
  322. return $size;
  323. }
  324. /**
  325. *
  326. * @param type $findBridge
  327. * @param type $force
  328. * @return \MGProvision\Proxmox\v2\models\NetworkDeviceKvm[]
  329. */
  330. public function getNetworkDevices($findBridge = null, $force = true)
  331. {
  332. $networks = array();
  333. foreach ($this->config($force) as $k => $v)
  334. {
  335. if (!preg_match('/net/', $k))
  336. continue;
  337. $network = new NetworkDeviceKvm($k, $v);
  338. if ($findBridge && $network->getBridge() !== $findBridge)
  339. continue;
  340. $networks[] = $network;
  341. }
  342. return $networks;
  343. }
  344. public function getMacAddresses($findBridge = null, $force = false)
  345. {
  346. $macs = array();
  347. foreach ($this->getNetworkDevices($findBridge, $force) as $network)
  348. {
  349. $macs[] = $network->getMacAddress();
  350. }
  351. return $macs;
  352. }
  353. /**
  354. *
  355. * @param \MGProvision\Proxmox\v2\models\NetworkDeviceKvm[] $networkDevices
  356. */
  357. public function updateNetworkDevices($networkDevices)
  358. {
  359. $container = array();
  360. foreach ($networkDevices as $networkDevice)
  361. {
  362. $container[$networkDevice->getId()] = $networkDevice->asConfig();
  363. }
  364. return $this->updateConfig($container);
  365. }
  366. public function getReinstallConfig()
  367. {
  368. $setting = array();
  369. foreach ($this->config(true) as $k => $v)
  370. {
  371. $setting[$k] = $v;
  372. }
  373. unset($setting['digest']);
  374. return $setting;
  375. }
  376. public function restore($archive)
  377. {
  378. try
  379. {
  380. if ($this->isRunning())
  381. {
  382. $this->stop();
  383. sleep(5);
  384. }
  385. }
  386. catch (\Exception $ex)
  387. {//error i.e.: Configuration file 'nodes/proxmox/lxc/117.conf' does not exist
  388. if ($ex->getCode() != 500)
  389. {
  390. throw $ex;
  391. }
  392. }
  393. $container = array(
  394. 'vmid' => $this->vmid,
  395. 'archive' => $archive,
  396. 'force' => 1,
  397. );
  398. return $this->api()->post("/nodes/{$this->node}/qemu", $container);
  399. }
  400. /**
  401. *
  402. * @return \MGProvision\Proxmox\v2\models\SnapshotKvm
  403. */
  404. public function snapshot($name = null)
  405. {
  406. $snap = new SnapshotKvm();
  407. $path = "/nodes/{$this->getNode()}/{$this->getVirtualization()}/{$this->getVmid()}/snapshot";
  408. if ($name !== null)
  409. {
  410. $path .= "/{$name}";
  411. }
  412. $snap->setPath($path);
  413. return $snap;
  414. }
  415. public function convertToTemplate()
  416. {
  417. return $this->api()->post("/nodes/{$this->node}/qemu/{$this->vmid}/template");
  418. }
  419. public function findNetworkDevice($macAddress)
  420. {
  421. foreach ($this->getNetworkDevices() as $nd)
  422. {
  423. if ($nd->getMacAddress() == $macAddress)
  424. {
  425. return $nd;
  426. }
  427. }
  428. return null;
  429. }
  430. public function deleteNetworkDevice(NetworkDeviceKvm $networkDevice)
  431. {
  432. $this->deleteConfig($networkDevice->getId());
  433. }
  434. /**
  435. *
  436. * @param HardDisk $hardDisks
  437. * @return array
  438. */
  439. public function updateHardDisks($hardDisks)
  440. {
  441. $container = array();
  442. foreach ($hardDisks as $hardDisk)
  443. {
  444. $container[$hardDisk->getId()] = $hardDisk->asConfig();
  445. }
  446. return $this->updateConfig($container);
  447. }
  448. /**
  449. *
  450. * @return IpConfigRepository
  451. */
  452. public function getIpConfig()
  453. {
  454. $repostiory = new IpConfigRepository;
  455. $repostiory->findByPath("/nodes/{$this->node}/qemu/{$this->vmid}/config");
  456. return $repostiory;
  457. }
  458. public function getCdRom()
  459. {
  460. $repostiory = new CdRomRepository();
  461. $repostiory->findByPath("/nodes/{$this->node}/qemu/{$this->vmid}/config");
  462. return $repostiory;
  463. }
  464. /**
  465. * @return Agent
  466. */
  467. public function agent()
  468. {
  469. return (new Agent())->setPath("/nodes/{$this->node}/qemu/{$this->vmid}/agent");
  470. }
  471. public function getCdRomRepository(){
  472. $repostiory = new CdRomRepository();
  473. $repostiory->findByPath("/nodes/{$this->node}/qemu/{$this->vmid}/config");
  474. return $repostiory;
  475. }
  476. public function hasCloudInit(){
  477. $repostiory = new CdRomRepository();
  478. $repostiory->findByPath("/nodes/{$this->node}/qemu/{$this->vmid}/config");
  479. return $repostiory->hasCloudInit();
  480. }
  481. /**
  482. * @return HardDiskRepostiory
  483. * @throws \MGProvision\Proxmox\v2\ProxmoxApiException
  484. */
  485. public function getHardDiskRepostiory(){
  486. $repository = new HardDiskRepostiory();
  487. $repository->setApi($this->api());
  488. $repository->findByPath($this->getPath() . '/config');
  489. return $repository;
  490. }
  491. }