control.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. <?php
  2. /**
  3. * The control file of ZenAgent Node of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
  6. * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author liyuchun <liyuchun@easycorp.ltd>
  8. * @package qa
  9. * @version $Id$
  10. * @link https://www.zentao.net
  11. */
  12. class zanode extends control
  13. {
  14. /**
  15. * __construct
  16. *
  17. * @access public
  18. * @return void
  19. */
  20. public function __construct()
  21. {
  22. parent::__construct();
  23. $this->zanode->setMenu();
  24. }
  25. /**
  26. * 执行节点介绍页。
  27. * View ZenAgent Node instruction.
  28. *
  29. * @access public
  30. * @return void
  31. */
  32. public function instruction()
  33. {
  34. $this->view->title = $this->lang->zanode->instruction;
  35. $this->display();
  36. }
  37. /**
  38. * 执行节点列表页。
  39. * Browse ZenAgent Node page.
  40. *
  41. * @param string $browseType
  42. * @param string $param
  43. * @param string $orderBy
  44. * @param int $recTotal
  45. * @param int $recPerPage
  46. * @param int $pageID
  47. * @access public
  48. * @return void
  49. */
  50. public function browse($browseType = 'all', $param = '', $orderBy = 't1.id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
  51. {
  52. $browseType = strtolower($browseType);
  53. /* 加载分页器。*/
  54. /* Load pager. */
  55. $this->app->loadClass('pager', true);
  56. $queryID = $browseType == 'bysearch' ? (int)$param : 0;
  57. $pager = pager::init($recTotal, $recPerPage, $pageID);
  58. /* 构建搜索表单。*/
  59. /* Build the search form. */
  60. $hosts = $this->loadModel('zahost')->getPairs('host');
  61. $actionURL = $this->createLink('zanode', 'browse', "browseType=bySearch&queryID=myQueryID");
  62. $this->config->zanode->search['actionURL'] = $actionURL;
  63. $this->config->zanode->search['queryID'] = $queryID;
  64. $this->config->zanode->search['onMenuBar'] = 'no';
  65. $this->config->zanode->search['params']['host']['values'] = array('' => '') + $hosts;
  66. $this->loadModel('search')->setSearchParams($this->config->zanode->search);
  67. $hiddenHost = $this->zahost->hiddenHost();
  68. if($hiddenHost)
  69. {
  70. foreach(array('type', 'cpuCores', 'memory', 'diskSize', 'hostName') as $disableField)
  71. {
  72. unset($this->config->zanode->dtable->fieldList[$disableField]);
  73. unset($this->config->zanode->search['fields'][$disableField]);
  74. unset($this->config->zanode->search['params'][$disableField]);
  75. }
  76. unset($this->config->zanode->search['fields']['host']);
  77. unset($this->config->zanode->search['params']['host']);
  78. foreach($this->lang->zanode->statusList as $statusKey => $statusValue)
  79. {
  80. if(!in_array($statusKey, array('online', 'offline'))) unset($this->lang->zanode->statusList[$statusKey]);
  81. }
  82. $this->config->zanode->search['params']['status'] = array('operator' => '=', 'control' => 'select', 'values' => array('' => '') + $this->lang->zanode->statusList);
  83. $this->config->zanode->dtable->fieldList['actions']['menu'] = array('edit', 'destroy');
  84. $this->loadModel('search')->setSearchParams($this->config->zanode->search);
  85. }
  86. $this->view->title = $this->lang->zanode->common;
  87. $this->view->users = $this->loadModel('user')->getPairs('noletter|nodeleted');
  88. $this->view->nodeList = $this->zanode->getListByQuery($browseType, $queryID, $orderBy, $pager);
  89. $this->view->hiddenHost = $hiddenHost;
  90. $this->view->pager = $pager;
  91. $this->view->param = $param;
  92. $this->view->orderBy = $orderBy;
  93. $this->view->browseType = $browseType;
  94. $this->display();
  95. }
  96. /**
  97. * 在宿主机详情页中展示执行节点列表。
  98. * Browse ZenAgent Node list in zahost view.
  99. *
  100. * @param int $hostID
  101. * @param string $orderBy
  102. * @access public
  103. * @return void
  104. */
  105. public function nodeList($hostID, $orderBy = 'id_desc')
  106. {
  107. if(!commonModel::hasPriv('zanode', 'browse')) $this->loadModel('common')->deny('zanode', 'browse', false);
  108. $this->view->title = $this->lang->zanode->common;
  109. $this->view->nodeList = $this->zanode->getListByHost($hostID, $orderBy);
  110. $this->view->orderBy = $orderBy;
  111. $this->view->hostID = $hostID;
  112. $this->view->sortLink = $this->createLink('zanode', 'nodeList', "hostID={$hostID}&orderBy={orderBy}");
  113. $this->display();
  114. }
  115. /**
  116. * 创建执行节点。
  117. * Create node.
  118. *
  119. * @param int $hostID
  120. * @access public
  121. * @return void
  122. */
  123. public function create($hostID = 0)
  124. {
  125. if(!empty($_POST))
  126. {
  127. $data = $this->zanodeZen->prepareCreateExtras();
  128. $nodeID = $this->zanode->create($data);
  129. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  130. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => inlink('view', "id=$nodeID")));
  131. }
  132. $this->view->title = $this->lang->zanode->create;
  133. $this->view->hostPairs = array('' => '') + $this->loadModel('zahost')->getPairs($this->session->product);
  134. $this->view->hiddenHost = $this->loadModel('zahost')->hiddenHost();
  135. $this->view->hostID = $hostID;
  136. return $this->display();
  137. }
  138. /**
  139. * 编辑执行节点。
  140. * Edit node.
  141. *
  142. * @param int $id
  143. * @access public
  144. * @return void
  145. */
  146. public function edit($id)
  147. {
  148. if($_POST)
  149. {
  150. $hostInfo = form::data($this->config->zanode->form->edit)
  151. ->add('editedBy', $this->app->user->account)
  152. ->add('editedDate', helper::now())
  153. ->get();
  154. $this->config->zanode->create->requiredFields = 'name';
  155. $checkResult = $this->zanode->checkFields4Create($hostInfo);
  156. if(!$checkResult) return $this->sendError(dao::getError());
  157. $changes = $this->zanode->update($id, $hostInfo);
  158. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  159. if($changes)
  160. {
  161. $actionID = $this->loadModel('action')->create('zanode', $id, 'Edited');
  162. if(!empty($changes)) $this->action->logHistory($actionID, $changes);
  163. }
  164. if(isInModal()) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true));
  165. return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => inlink('browse')));
  166. }
  167. $zanode = $this->zanode->getNodeByID($id);
  168. $this->view->title = $this->lang->zanode->editAction;
  169. $this->view->zanode = $zanode;
  170. if($zanode->type == 'node')
  171. {
  172. $this->view->host = $this->zanode->getHostByID($zanode->parent);
  173. $this->view->image = $this->zanode->getImageByID($zanode->image);
  174. }
  175. $this->view->hiddenHost = $this->loadModel('zahost')->hiddenHost();
  176. $this->display();
  177. }
  178. /**
  179. * 执行节点详情。
  180. * View Node.
  181. *
  182. * @param int $id
  183. * @access public
  184. * @return void
  185. */
  186. public function view($id)
  187. {
  188. $node = $this->zanode->getNodeByID($id);
  189. $vnc = $this->zanode->getVncUrl($node);
  190. $this->view->url = $node->ip . ":" . $node->hzap;
  191. $this->view->host = !empty($vnc->hostIP) ? $vnc->hostIP:'';
  192. $this->view->token = !empty($vnc->token) ? $vnc->token:'';
  193. $this->view->title = $this->lang->zanode->view;
  194. $this->view->zanode = $node;
  195. $this->view->snapshotList = $this->zanode->getSnapshotList($id);
  196. $this->view->initBash = sprintf(zget($this->config->zanode->versionToOs, $node->osName, '') != '' ? $this->config->zanode->initPosh : $this->config->zanode->initBash, $node->secret, getWebRoot(true));
  197. $this->view->actions = $this->loadModel('action')->getList('zanode', $id);
  198. $this->view->users = $this->loadModel('user')->getPairs('noletter');
  199. $this->view->hiddenHost = $this->loadModel('zahost')->hiddenHost();
  200. $this->display();
  201. }
  202. /**
  203. * 开始执行节点。
  204. * Start Node.
  205. *
  206. * @param int $nodeID
  207. * @access public
  208. * @return void
  209. */
  210. public function start($nodeID)
  211. {
  212. $this->zanodeZen->handleNode($nodeID, 'boot');
  213. }
  214. /**
  215. * 关闭执行节点。
  216. * Shutdown Node.
  217. *
  218. * @param int $nodeID
  219. * @access public
  220. * @return void
  221. */
  222. public function close($nodeID)
  223. {
  224. $this->zanodeZen->handleNode($nodeID, 'destroy');
  225. }
  226. /**
  227. * 休眠执行节点。
  228. * Suspend Node.
  229. *
  230. * @param int $nodeID
  231. * @access public
  232. * @return void
  233. */
  234. public function suspend($nodeID)
  235. {
  236. $this->zanodeZen->handleNode($nodeID, 'suspend');
  237. }
  238. /**
  239. * 重启执行节点。
  240. * Reboot Node.
  241. *
  242. * @param int $nodeID
  243. * @access public
  244. * @return void
  245. */
  246. public function reboot($nodeID)
  247. {
  248. $this->zanodeZen->handleNode($nodeID, 'reboot');
  249. }
  250. /**
  251. * 恢复执行节点。
  252. * Resume Node.
  253. *
  254. * @param int $nodeID
  255. * @access public
  256. * @return void
  257. */
  258. public function resume($nodeID)
  259. {
  260. $this->zanodeZen->handleNode($nodeID, 'resume');
  261. }
  262. /**
  263. * 导出镜像。
  264. * Create custom image.
  265. *
  266. * @param int $nodeID
  267. * @access public
  268. * @return void
  269. */
  270. public function createImage($nodeID = 0)
  271. {
  272. if($_POST)
  273. {
  274. $imageData = form::data()->get();
  275. $this->zanode->createImage($nodeID, $imageData);
  276. if(dao::isError()) return $this->sendError(dao::getError());
  277. return $this->sendSuccess(array('load' => true));
  278. }
  279. $task = '';
  280. $node = $this->zanode->getNodeByID($nodeID);
  281. $customImage = $this->zanode->getCustomImage($nodeID, 'created,inprogress');
  282. if($customImage) $task = $this->zanodeZen->getTaskStatus($node, $customImage->id, 'exportVm');
  283. $this->view->task = $task;
  284. $this->view->node = $node;
  285. $this->view->rate = isset($task->rate) ? $task->rate : 0;
  286. $this->display();
  287. }
  288. /**
  289. * 创建快照。
  290. * Create snapshot.
  291. *
  292. * @param int $nodeID
  293. * @access public
  294. * @return void
  295. */
  296. public function createSnapshot($nodeID = 0)
  297. {
  298. if($_POST)
  299. {
  300. $node = $this->zanode->getNodeByID($nodeID);
  301. $snapshot = $this->zanodeZen->prepareCreateSnapshotExtras($node);
  302. $this->zanode->createSnapshot($node, $snapshot);
  303. if(dao::isError()) return $this->sendError(dao::getError());
  304. return $this->sendSuccess(array('load' => true));
  305. }
  306. $this->view->node = $this->zanode->getNodeByID($nodeID);
  307. $this->display();
  308. }
  309. /**
  310. * 编辑快照。
  311. * Edit Snapshot.
  312. *
  313. * @param int $snapshotID
  314. * @access public
  315. * @return void
  316. */
  317. public function editSnapshot($snapshotID)
  318. {
  319. $snapshot = $this->zanode->getImageByID($snapshotID);
  320. if($_POST)
  321. {
  322. $formData = form::data()->get();
  323. if(is_numeric($formData->name)) return $this->sendError(array('name' => sprintf($this->lang->error->code, $this->lang->zanode->name)));
  324. $this->zanode->editSnapshot($snapshotID, $formData);
  325. if(dao::isError()) return $this->sendError(dao::getError());
  326. $this->loadModel('action')->create('zanode', $snapshot->host, 'editSnapshot', '', $snapshot->localName ? $snapshot->localName : $snapshot->name);
  327. return $this->sendSuccess(array('load' => inLink('view', "id=$snapshot->host")));
  328. }
  329. $this->view->snapshot = $snapshot;
  330. $this->display();
  331. }
  332. /**
  333. * 删除快照。
  334. * Delete Snapshot.
  335. *
  336. * @param int $snapshotID
  337. * @access public
  338. * @return void
  339. */
  340. public function deleteSnapshot($snapshotID)
  341. {
  342. $result = $this->zanode->deleteSnapshot($snapshotID);
  343. if($result !== true) return $this->sendError($result, true);
  344. return $this->sendSuccess(array('message' => $this->lang->zanode->actionSuccess, 'load' => true));
  345. }
  346. /**
  347. * 销毁执行节点。
  348. * Desctroy node.
  349. *
  350. * @param int $nodeID
  351. * @access public
  352. * @return void
  353. */
  354. public function destroy($nodeID)
  355. {
  356. $error = $this->zanode->destroy($nodeID);
  357. if(!empty($error)) return $this->sendError($error);
  358. return $this->sendSuccess(array('message' => $this->lang->zanode->actionSuccess, 'load' => inlink('browse')));
  359. }
  360. /**
  361. * 远程操控执行节点。
  362. * Bring up novmc management view.
  363. *
  364. * @param int $nodeID
  365. * @access public
  366. * @return void
  367. */
  368. public function getVNC($nodeID)
  369. {
  370. $node = $this->zanode->getNodeByID($nodeID);
  371. $vnc = $this->zanode->getVncUrl($node);
  372. /* 记录操作日志。*/
  373. /* Add action log. */
  374. if(!empty($vnc->token)) $this->loadModel('action')->create('zanode', $nodeID, 'getVNC');
  375. $this->view->title = $this->lang->zanode->getVNC;
  376. $this->view->url = $node->ip . ":" . $node->hzap;
  377. $this->view->host = !empty($vnc->hostIP) ? $vnc->hostIP:'';
  378. $this->view->token = !empty($vnc->token) ? $vnc->token:'';
  379. $this->display();
  380. }
  381. /**
  382. * 快照列表。
  383. * Browse snapshot.
  384. *
  385. * @param int $nodeID
  386. * @param string $browseType
  387. * @param string $orderBy
  388. * @param int $recTotal
  389. * @param int $recPerPage
  390. * @param int $pageID
  391. * @access public
  392. * @return void
  393. */
  394. public function browseSnapshot($nodeID, $browseType = 'all', $orderBy = 'id', $recTotal = 0, $recPerPage = 20, $pageID = 1)
  395. {
  396. $this->app->loadLang('zahost');
  397. $this->app->loadClass('pager', true);
  398. $pager = pager::init($recTotal, $recPerPage, $pageID);
  399. $this->view->title = $this->lang->zanode->browseSnapshot;
  400. $this->view->nodeID = $nodeID;
  401. $this->view->node = $this->zanode->getNodeByID($nodeID);
  402. $this->view->snapshotList = $this->zanode->getSnapshotList($nodeID, $orderBy, $pager);
  403. $this->view->users = $this->loadModel('user')->getPairs('noletter');
  404. $this->view->pager = $pager;
  405. $this->view->orderBy = $orderBy;
  406. $this->view->browseType = $browseType;
  407. $this->display();
  408. }
  409. /**
  410. * 还原快照。
  411. * Restore node.
  412. *
  413. * @param int $nodeID
  414. * @param int $snapshotID
  415. * @access public
  416. * @return void
  417. */
  418. public function restoreSnapshot($nodeID, $snapshotID)
  419. {
  420. $this->zanode->restoreSnapshot($nodeID, $snapshotID);
  421. if(dao::isError()) return $this->sendError(dao::getError(), true);
  422. return $this->sendSuccess(array('message' => $this->lang->zanode->actionSuccess, 'load' => true));
  423. }
  424. /**
  425. * 获取镜像列表。
  426. * AJAX: Get template pairs by api.
  427. *
  428. * @param int $hostID
  429. * @access public
  430. * @return void
  431. */
  432. public function ajaxGetImages($hostID)
  433. {
  434. $options = array();
  435. $templatePairs = $this->loadModel('zahost')->getImagePairs($hostID);
  436. foreach($templatePairs as $key => $template) $options[] = array('text' => $template, 'value' => $key);
  437. return print(json_encode($options));
  438. }
  439. /**
  440. * 获取镜像信息。
  441. * AJAX: Get template info.
  442. *
  443. * @param int $imageID
  444. * @access public
  445. * @return void
  446. */
  447. public function ajaxGetImage($imageID)
  448. {
  449. $template = $this->loadModel('zahost')->getImageByID($imageID);
  450. return print(json_encode($template));
  451. }
  452. /**
  453. * 获取导出镜像的状态。
  454. * AJAX: Get task status.
  455. *
  456. * @param int $nodeID
  457. * @param int $taskID
  458. * @param string $type
  459. * @param string $status
  460. * @access public
  461. * @return void
  462. */
  463. public function ajaxGetTaskStatus($nodeID, $taskID = 0, $type = '', $status = '')
  464. {
  465. $node = $this->zanode->getNodeByID($nodeID);
  466. $result = $this->zanodeZen->getTaskStatus($node, $taskID, $type, $status);
  467. return print(json_encode($result));
  468. }
  469. /**
  470. * 更新导出镜像状态。
  471. * AJAX: Update image.
  472. *
  473. * @param int $imageID
  474. * @access public
  475. * @return void
  476. */
  477. public function ajaxUpdateImage($imageID = 0)
  478. {
  479. if($_POST)
  480. {
  481. $data = form::data()->get();
  482. $this->zanode->updateImageStatus($imageID, $data);
  483. if(dao::isError()) return $this->sendError(dao::getError());
  484. return $this->sendSuccess(array('load' => true));
  485. }
  486. }
  487. /**
  488. * 获取宿主机服务状态。
  489. * AJAX: Get service status.
  490. *
  491. * @param int $nodeID
  492. * @access public
  493. * @return void
  494. * @param int $hostID
  495. */
  496. public function ajaxGetServiceStatus($hostID)
  497. {
  498. $node = $this->zanode->getNodeById($hostID);
  499. $serviceStatus = $this->zanodeZen->getServiceStatus($node);
  500. if($node->status != 'running')
  501. {
  502. $serviceStatus['ZenAgent'] = 'unknown';
  503. $serviceStatus['ZTF'] = 'unknown';
  504. }
  505. $node->status = $node->status == 'online' ? 'ready' : $node->status;
  506. $serviceStatus['node'] = $node->status;
  507. return $this->send(array('result' => 'success', 'message' => '', 'data' => $serviceStatus));
  508. }
  509. /**
  510. * 安装服务。
  511. * AJAX: Install service by ajax.
  512. *
  513. * @param int $nodeID
  514. * @param string $service
  515. * @access public
  516. * @return void
  517. */
  518. public function ajaxInstallService($nodeID, $service)
  519. {
  520. $node = $this->zanode->getNodeById($nodeID);
  521. $result = $this->zanodeZen->installService($node, $service);
  522. return $this->send(array('result' => 'success', 'message' => '', 'data' => $result));
  523. }
  524. /**
  525. * 获取ZTF脚本。
  526. * AJAX: Get ZTF script.
  527. *
  528. * @param string $type
  529. * @param int $objectID
  530. * @access public
  531. * @return void
  532. */
  533. public function ajaxGetZTFScript($type = 'product', $objectID = 0)
  534. {
  535. $script = array();
  536. if($type == '') $script = $this->zanode->getAutomationByID($objectID);
  537. if($type == 'product') $script = $this->zanode->getAutomationByProduct($objectID);
  538. return $this->send(array('result' => 'success', 'data' => $script));
  539. }
  540. /**
  541. * 执行ZTF脚本。
  542. * AJAX: Run ZTF script.
  543. *
  544. * @param int $scriptID
  545. * @access public
  546. * @return void
  547. */
  548. public function ajaxRunZTFScript($scriptID = 0)
  549. {
  550. if($_POST)
  551. {
  552. $caseIdList = $_POST['caseIdList'];
  553. $runIdList = empty($_POST['runIDList']) ? array() : $_POST['runIDList'];
  554. $script = $this->zanode->getAutomationByID($scriptID);
  555. $cases = $this->loadModel('testcase')->getByList($caseIdList);
  556. $case2RunMap = array();
  557. foreach($caseIdList as $index => $caseID) $case2RunMap[$caseID] = empty($runIDList[$index]) ? 0 : $runIDList[$index];
  558. foreach($cases as $id => $case)
  559. {
  560. if($case->auto != 'auto') continue;
  561. if(empty($script->node)) continue;
  562. $resultID = $this->loadModel('testtask')->initResult($case2RunMap[$id], $id, $case->version, $script->node);
  563. if(!dao::isError()) $this->zanode->runZTFScript($script->id, $id, $resultID);
  564. }
  565. if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
  566. return $this->send(array('result' => 'success', 'message' => 'success'));
  567. }
  568. }
  569. /**
  570. * 获取执行节点。
  571. * AJAX:Get nodes.
  572. *
  573. * @access public
  574. * @return void
  575. */
  576. public function ajaxGetNodes()
  577. {
  578. $nodeList = $this->zanode->getPairs();
  579. return print(html::select("node", $nodeList, '', "class='form-control picker-select'"));
  580. }
  581. }