model.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. <?php
  2. /**
  3. * The model file of zahost module 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 Wang Jianhua <wangjiahua@easycorp.ltd>
  8. * @package zahost
  9. * @version $Id$
  10. * @link https://www.zentao.net
  11. */
  12. class zahostModel extends model
  13. {
  14. /**
  15. * 根据 ID 获取宿主机。
  16. * Get host by id.
  17. *
  18. * @param int $hostID
  19. * @access public
  20. * @return object
  21. */
  22. public function getByID($hostID)
  23. {
  24. $host = $this->dao->select('*, id AS hostID')->from(TABLE_ZAHOST)->where('id')->eq($hostID)->fetch();
  25. if(!$host) return false;
  26. if(empty($host->heartbeat)) $host->heartbeat = '';
  27. if(time() - strtotime($host->heartbeat) > 60 && $host->status == 'online') $host->status = 'offline';
  28. return $host;
  29. }
  30. /**
  31. * 获取宿主机的键值对。
  32. * Get host pairs.
  33. *
  34. * @access public
  35. * @return array
  36. */
  37. public function getPairs()
  38. {
  39. return $this->dao->select('id, name')->from(TABLE_ZAHOST)->where('deleted')->eq('0')->andWhere('type')->eq('zahost')->orderBy('`group`')->fetchPairs();
  40. }
  41. /**
  42. * 获取宿主机的列表。
  43. * Get host list.
  44. *
  45. * @param string $browseType
  46. * @param int $param
  47. * @param string $orderBy
  48. * @param object $pager
  49. * @access public
  50. * @return array
  51. */
  52. public function getList($browseType = 'all', $param = 0, $orderBy = 'id_desc', $pager = null)
  53. {
  54. $query = '';
  55. if($browseType == 'bysearch')
  56. {
  57. /* Concatenate the conditions for the query. */
  58. if($this->session->zahostQuery == false) $this->session->set('zahostQuery', ' 1 = 1');
  59. if($param)
  60. {
  61. $this->session->set('zahostQuery', ' 1 = 1');
  62. $query = $this->loadModel('search')->getQuery($param);
  63. if($query)
  64. {
  65. $this->session->set('zahostQuery', $query->sql);
  66. $this->session->set('zahostForm', $query->form);
  67. }
  68. }
  69. $query = $this->session->zahostQuery;
  70. }
  71. $hostList = $this->dao->select('*, id AS hostID')->from(TABLE_ZAHOST)
  72. ->where('deleted')->eq('0')
  73. ->andWhere('type')->eq('zahost')
  74. ->beginIF($query)->andWhere($query)->fi()
  75. ->orderBy($orderBy)
  76. ->page($pager)
  77. ->fetchAll();
  78. foreach($hostList as $host)
  79. {
  80. if(empty($host->heartbeat)) $host->hertbeat = '';
  81. if(time() - strtotime($host->heartbeat) > 60 && $host->status == 'online') $host->status = 'offline';
  82. }
  83. return $hostList;
  84. }
  85. /**
  86. * 创建宿主机。
  87. * Create a host.
  88. *
  89. * @param object $hostInfo
  90. * @access public
  91. * @return int|bool
  92. */
  93. public function create($hostInfo)
  94. {
  95. $ping = $this->checkAddress($hostInfo->extranet);
  96. if(!$ping) dao::$errors['extranet'][] = $this->lang->zahost->netError;
  97. $this->dao->insert(TABLE_ZAHOST)->data($hostInfo)->autoCheck()
  98. ->batchCheck($this->config->zahost->create->requiredFields, 'notempty')
  99. ->batchCheck('cpuCores,diskSize', 'gt', 0)
  100. ->batchCheck('diskSize,memory', 'float')
  101. ->check('name', 'unique', "type='zahost'")
  102. ->exec();
  103. if(dao::isError()) return false;
  104. $hostID = $this->dao->lastInsertID();
  105. $this->loadModel('action')->create('zahost', $hostID, 'created');
  106. return $hostID;
  107. }
  108. /**
  109. * 更新宿主机。
  110. * Update a host.
  111. *
  112. * @param object $hostInfo
  113. * @access public
  114. * @return array|bool
  115. */
  116. public function update($hostInfo)
  117. {
  118. $oldHost = $this->getByID($hostInfo->id);
  119. $ping = $this->checkAddress($hostInfo->extranet);
  120. if(!$ping) dao::$errors['extranet'][] = $this->lang->zahost->netError;
  121. $this->dao->update(TABLE_ZAHOST)->data($hostInfo)->autoCheck()
  122. ->batchCheck($this->config->zahost->create->requiredFields, 'notempty')
  123. ->batchCheck('cpuCores,diskSize', 'gt', 0)
  124. ->batchCheck('diskSize,memory', 'float')
  125. ->check('name', 'unique', "id != $hostInfo->id and type in ('vhost', 'zahost')")
  126. ->where('id')->eq($hostInfo->id)
  127. ->exec();
  128. if(dao::isError()) return false;
  129. return common::createChanges($oldHost, $hostInfo);
  130. }
  131. /**
  132. * 检查宿主机的IP/域名是否能 ping 通。
  133. * Ping ip/domain.
  134. *
  135. * @param string $address
  136. * @access public
  137. * @return bool
  138. */
  139. public function ping($address)
  140. {
  141. if(strcasecmp(PHP_OS, 'WINNT') === 0)
  142. {
  143. exec("ping -n 1 {$address}", $outcome, $status);
  144. }
  145. else
  146. {
  147. exec("ping -c 1 {$address}", $outcome, $status);
  148. }
  149. return 0 == $status;
  150. }
  151. /**
  152. * 检查宿主机的IP/域名是否可用。
  153. * Telnet ip/domain.
  154. *
  155. * @param string $address
  156. * @access public
  157. * @return bool
  158. */
  159. public function checkAddress($address)
  160. {
  161. $address = str_replace(array('https://', 'http://'), '', $address);
  162. if(!filter_var($address, FILTER_VALIDATE_IP) && !filter_var(gethostbyname($address), FILTER_VALIDATE_IP)) return false;
  163. return true;
  164. }
  165. /**
  166. * 根据编号获取镜像。
  167. * Get image by ID.
  168. *
  169. * @param int $imageID
  170. * @access public
  171. * @return false|object
  172. */
  173. public function getImageByID($imageID)
  174. {
  175. return $this->dao->select('*')->from(TABLE_IMAGE)->where('id')->eq($imageID)->fetch();
  176. }
  177. /**
  178. * 根据镜像名称和宿主机编号获取镜像。
  179. * Get image by name and host.
  180. *
  181. * @param string $imageName
  182. * @param int $hostID
  183. * @access public
  184. * @return object|false
  185. */
  186. public function getImageByNameAndHostID($imageName, $hostID)
  187. {
  188. return $this->dao->select('*')->from(TABLE_IMAGE)->where('host')->eq($hostID)->andWhere('name')->eq($imageName)->fetch();
  189. }
  190. /**
  191. * 获取宿主机的镜像列表。
  192. * Get image list of host.
  193. *
  194. * @param int $hostID
  195. * @param string $orderBy
  196. * @param object $pager
  197. * @access public
  198. * @return array
  199. */
  200. public function getImageList($hostID, $orderBy = 'id', $pager = null)
  201. {
  202. $imageList = json_decode(commonModel::http($this->config->zahost->imageListUrl, array(), array()));
  203. if(empty($imageList)) return array();
  204. $downloadedImageList = $this->dao->select('*')->from(TABLE_IMAGE)->where('host')->eq($hostID)->orderBy($orderBy)->page($pager)->fetchAll('name');
  205. $refreshPageData = $this->zahostTao->insertImageList($imageList, $hostID, $downloadedImageList);
  206. if($refreshPageData) $downloadedImageList = $this->dao->select('*')->from(TABLE_IMAGE)->where('host')->eq($hostID)->orderBy($orderBy)->page($pager)->fetchAll('name');
  207. foreach($downloadedImageList as $image)
  208. {
  209. if($image->status == 'notDownloaded')
  210. {
  211. $image->cancelMisc = sprintf("title='%s' class='btn image-cancel image-cancel-%d %s'", $this->lang->zahost->cancel, $image->id, "disabled");
  212. $image->downloadMisc = sprintf("title='%s' class='btn image-download image-download-%d %s'", $this->lang->zahost->image->downloadImage, $image->id, "");
  213. }
  214. else
  215. {
  216. $image->cancelMisc = sprintf("title='%s' data-id='%s' class='btn image-cancel image-cancel-%d %s'", $this->lang->zahost->cancel, $image->id, $image->id, in_array($image->status, array("inprogress", "created")) ? "" : "disabled");
  217. $image->downloadMisc = sprintf("title='%s' data-id='%s' class='btn image-download image-download-%d %s'", $this->lang->zahost->image->downloadImage, $image->id, $image->id, in_array($image->status, array("completed", "inprogress", "created")) || $image->from == 'user' ? "disabled" : "");
  218. }
  219. }
  220. return $downloadedImageList;
  221. }
  222. /**
  223. * 获取镜像键值对。
  224. * Get image pairs by host.
  225. *
  226. * @param int $hostID
  227. * @access public
  228. * @return array
  229. */
  230. public function getImagePairs($hostID)
  231. {
  232. return $this->dao->select('id, name')->from(TABLE_IMAGE)->where('host')->eq($hostID)->andWhere('status')->eq('completed')->fetchPairs();
  233. }
  234. /**
  235. * 下载镜像。
  236. * Download image.
  237. *
  238. * @param object $image
  239. * @access public
  240. * @return bool
  241. */
  242. public function downloadImage($image)
  243. {
  244. $host = $this->getByID($image->host);
  245. $apiUrl = 'http://' . $host->extranet . ':' . $host->zap . '/api/v1/download/add';
  246. $apiParams = array();
  247. $apiParams['md5'] = $image->md5;
  248. $apiParams['url'] = $image->address;
  249. $apiParams['task'] = intval($image->id);
  250. $response = json_decode(commonModel::http($apiUrl, array($apiParams), array(CURLOPT_CUSTOMREQUEST => 'POST'), array("Authorization:$host->tokenSN"), 'json'));
  251. if($response && $response->code == 'success')
  252. {
  253. $this->dao->update(TABLE_IMAGE)->set('status')->eq('created')->where('id')->eq($image->id)->exec();
  254. return true;
  255. }
  256. dao::$errors[] = $this->lang->zahost->image->downloadImageFail;
  257. return false;
  258. }
  259. /**
  260. * 查询镜像的状态。
  261. * Query image download progress.
  262. *
  263. * @param object $image
  264. * @access public
  265. * @return object
  266. */
  267. public function queryDownloadImageStatus($image)
  268. {
  269. if(!empty($this->imageStatusList)) $result = $this->imageStatusList;
  270. if(empty($this->imageStatusList))
  271. {
  272. $host = $this->getByID($image->host);
  273. $apiUrl = 'http://' . $host->extranet . ':' . $host->zap . '/api/v1/task/getStatus';
  274. $result = $this->imageStatusList = json_decode(commonModel::http($apiUrl, array(), array(CURLOPT_CUSTOMREQUEST => 'POST'), array("Authorization:$host->tokenSN"), 'json'));
  275. if(!$result || $result->code != 'success') return $image;
  276. }
  277. $currentTask = $this->zahostTao->getCurrentTask($image->id, $result->data);
  278. if($currentTask)
  279. {
  280. $image->rate = $currentTask->rate;
  281. $image->status = $currentTask->status;
  282. if(!empty($result->data->inprogress) && $currentTask->task != $result->data->inprogress[0]->task && $currentTask->status == 'created') $image->status = 'pending';
  283. $this->dao->update(TABLE_IMAGE)->set('status')->eq($image->status)->set('path')->eq(zget($currentTask, 'path', ''))->where('id')->eq($image->id)->exec();
  284. $image->taskID = $currentTask->id;
  285. }
  286. else
  287. {
  288. $image->taskID = 0;
  289. }
  290. return $image;
  291. }
  292. /**
  293. * 取消镜像下载。
  294. * Send cancel download image command to HOST.
  295. *
  296. * @param object $image
  297. * @access public
  298. * @return bool
  299. */
  300. public function cancelDownload($image)
  301. {
  302. $image = $this->queryDownloadImageStatus($image);
  303. $host = $this->getByID($image->host);
  304. $apiUrl = 'http://' . $host->extranet . ':' . $host->zap . '/api/v1/download/cancel';
  305. $apiParams = array();
  306. $apiParams['id'] = intval($image->taskID);
  307. $response = json_decode(commonModel::http($apiUrl, $apiParams, array(CURLOPT_CUSTOMREQUEST => 'POST'), array("Authorization:$host->tokenSN"), 'json'));
  308. if($response && $response->code == 'success')
  309. {
  310. $this->dao->update(TABLE_IMAGE)->set('status')->eq('canceled')->where('id')->eq($image->id)->exec();
  311. return true;
  312. }
  313. dao::$errors[] = $this->lang->zahost->image->cancelDownloadFail;
  314. return false;
  315. }
  316. /**
  317. * 获取宿主机的执行节点。
  318. * Get zanode group by zahost.
  319. *
  320. * @access public
  321. * @return array
  322. */
  323. public function getNodeGroupHost()
  324. {
  325. return $this->dao->select('t1.id AS hostID, t2.*')->from(TABLE_ZAHOST)->alias('t1')
  326. ->leftJoin(TABLE_ZAHOST)->alias('t2')->on('t2.parent = t1.id')
  327. ->where('t2.deleted')->eq('0')
  328. ->andWhere('t1.deleted')->eq('0')
  329. ->fetchGroup('hostID', 'id');
  330. }
  331. /**
  332. * 判断按钮是否可点击。
  333. * Judge an action is clickable or not.
  334. *
  335. * @param object $object
  336. * @param string $action
  337. * @access public
  338. * @return bool
  339. */
  340. public static function isClickable($object, $action)
  341. {
  342. if($action == 'delete') return $object->canDelete;
  343. if($action == 'browseImage') return $object->status != 'wait';
  344. if($action == 'cancelDownload') return $object->status == 'notDownloaded' || !in_array($object->status, array('inprogress', 'created')) ? false : true;
  345. if($action == 'downloadImage') return in_array($object->status, array('completed', 'inprogress', 'created')) || $object->from == 'user' ? false : true;
  346. return true;
  347. }
  348. /**
  349. * 根据是否有宿主机,判断是否隐藏。
  350. * Judge an action is clickable or not.
  351. *
  352. * @access public
  353. * @return bool
  354. */
  355. public function hiddenHost()
  356. {
  357. $this->app->loadClass('pager', true);
  358. $pager = pager::init(0, 20, 1);
  359. return empty($this->getList('all', 0, 'id_desc', $pager));
  360. }
  361. }