model.php 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166
  1. <?php
  2. /**
  3. * The model file of CNE(Cloud Native Engine) 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 Jianhua Wang <wangjianhua@easycorp.ltd>
  8. * @package CNE
  9. * @link https://www.zentao.net
  10. */
  11. class cneModel extends model
  12. {
  13. public $error;
  14. /**
  15. * Construct function: set api headers.
  16. *
  17. * @param string $appName
  18. * @access public
  19. * @return void
  20. */
  21. public function __construct($appName = '')
  22. {
  23. parent::__construct($appName);
  24. $this->error = new stdclass();
  25. global $config, $app;
  26. $config->CNE->api->headers[] = "{$config->CNE->api->auth}: {$config->CNE->api->token}";
  27. $config->cloud->api->headers[] = "{$config->cloud->api->auth}: {$config->cloud->api->token}";
  28. if($config->cloud->api->switchChannel && $app->session->cloudChannel)
  29. {
  30. $config->cloud->api->channel = $app->session->cloudChannel;
  31. $config->CNE->api->channel = $app->session->cloudChannel;
  32. }
  33. }
  34. /**
  35. * 更新实例配置。例如:cpu、内存大小、LDAP设置...
  36. * Update instance config. For example: cpu, memory size, LDAP settings...
  37. *
  38. * @link https://yapi.qc.oop.cc/project/21/interface/api/725
  39. * @param object $instance
  40. * @param object $settings
  41. * @access public
  42. * @return bool
  43. */
  44. public function updateConfig($instance, $settings = null)
  45. {
  46. $apiParams = array();
  47. $apiParams['cluster'] = '';
  48. $apiParams['namespace'] = $instance->spaceData->k8space;
  49. $apiParams['name'] = $instance->k8name;
  50. $apiParams['channel'] = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel;
  51. $apiParams['chart'] = $instance->chart;
  52. if(isset($instance->version)) $apiParams['version'] = $instance->version;
  53. if(isset($settings->force_restart)) $apiParams['force_restart'] = $settings->force_restart;
  54. if(isset($settings->settings)) $apiParams['settings'] = $settings->settings;
  55. if(isset($settings->settings_map)) $apiParams['settings_map'] = $settings->settings_map;
  56. if(isset($settings->settings_snippets)) $apiParams['settings_snippets'] = $settings->settings_snippets;
  57. $apiUrl = "/api/cne/app/settings";
  58. $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers);
  59. if($result && $result->code == 200) return true;
  60. return false;
  61. }
  62. /**
  63. * 校验证书。
  64. * Valid Certificate.
  65. *
  66. * @param string $certName
  67. * @param string $pem
  68. * @param string $key
  69. * @param string $domain
  70. * @access public
  71. * @return object
  72. */
  73. public function validateCert($certName, $pem, $key, $domain)
  74. {
  75. $apiParams = array();
  76. $apiParams['name'] = $certName;
  77. $apiParams['certificate_pem'] = $pem;
  78. $apiParams['private_key_pem'] = $key;
  79. $apiUrl = "/api/cne/system/tls/validator";
  80. $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers);
  81. if($result && $result->code != 200) return $result;
  82. $match = false;
  83. foreach($result->data->sans as $domainPattern)
  84. {
  85. if(stripos($domainPattern, $domain) !== false)
  86. {
  87. $match = true;
  88. break;
  89. }
  90. }
  91. if(!$match)
  92. {
  93. $result->code = 40004;
  94. $result->message = zget($this->lang->CNE->errorList, 40004);
  95. }
  96. return $result;
  97. }
  98. /**
  99. * 更新证书。
  100. * Upload cert.
  101. *
  102. * @param object $cert
  103. * @param string $channel
  104. * @access public
  105. * @return object
  106. */
  107. public function uploadCert($cert, $channel = '')
  108. {
  109. $apiParams = array();
  110. $apiParams['cluster'] = '';
  111. $apiParams['channel'] = empty($channel) ? $this->config->CNE->api->channel : $channel;
  112. $apiParams['name'] = $cert->name;
  113. $apiParams['certificate_pem'] = $cert->certificate_pem;
  114. $apiParams['private_key_pem'] = $cert->private_key_pem;
  115. return $this->apiPost('/api/cne/system/tls/upload', $apiParams, $this->config->CNE->api->headers);
  116. }
  117. /**
  118. * 获取证书信息。
  119. * Get cert info.
  120. *
  121. * @param string $certName
  122. * @param string $channel
  123. * @access public
  124. * @return object|null success: return cert info, fail: return null.
  125. */
  126. public function certInfo($certName, $channel = '')
  127. {
  128. $apiParams = array();
  129. $apiParams['cluster'] = '';
  130. $apiParams['channel'] = empty($channel) ? $this->config->CNE->api->channel : $channel;
  131. $apiParams['name'] = $certName;
  132. $apiUrl = "/api/cne/system/tls/info";
  133. $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers);
  134. if($result && $result->code == 200) return $result->data;
  135. return null;
  136. }
  137. /**
  138. * 获取实例的默认账号密码。
  139. * Get default username and password of app.
  140. *
  141. * @param object $instance
  142. * @param string $component
  143. * @access public
  144. * @return object|null
  145. */
  146. public function getDefaultAccount($instance, $component = '')
  147. {
  148. $apiUrl = '/api/cne/app/account?channel='. (empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel);
  149. $apiParams = array();
  150. $apiParams['name'] = $instance->k8name;
  151. $apiParams['namespace'] = $instance->spaceData->k8space;
  152. $apiParams['cluster'] = '';
  153. if($component) $apiParams['component'] = $component;
  154. $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers, $this->config->CNE->api->host);
  155. if(!isset($result->code) || $result->code != 200) return null;
  156. $account = $result->data;
  157. if(isset($account->username) && $account->username && isset($account->password) && $account->password) return $account;
  158. return null;
  159. }
  160. /**
  161. * 获取域名后缀。
  162. * Get suffix domain.
  163. *
  164. * @access public
  165. * @return string
  166. */
  167. public function sysDomain()
  168. {
  169. $customDomain = $this->loadModel('setting')->getItem('owner=system&module=common&section=domain&key=customDomain');
  170. if($customDomain) return $customDomain;
  171. if(getenv('APP_DOMAIN')) return getenv('APP_DOMAIN');
  172. if(!empty($this->config->CNE->app->domain)) return $this->config->CNE->app->domain;
  173. return '';
  174. }
  175. /**
  176. * 获取实例的域名。
  177. * Get domain.
  178. *
  179. * @param object $instance
  180. * @param string $component
  181. * @access public
  182. * @return object|null
  183. */
  184. public function getDomain($instance, $component = '')
  185. {
  186. $apiUrl = '/api/cne/app/domain?channel='. (empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel);
  187. $apiParams = array();
  188. $apiParams['name'] = $instance->k8name;
  189. $apiParams['namespace'] = $instance->spaceData->k8space;
  190. $apiParams['cluster'] = '';
  191. if($component) $apiParams['component'] = $component;
  192. $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers, $this->config->CNE->api->host);
  193. if(!isset($result->code) || $result->code != 200) return null;
  194. return empty($result->data->internal_host) ? null : $result->data;
  195. }
  196. /**
  197. * 获取CNE平台的集群度量。
  198. * Get cluster metrics of CNE platform.
  199. *
  200. * @access public
  201. * @return object
  202. */
  203. public function cneMetrics()
  204. {
  205. $metrics = new stdclass();
  206. $metrics->cpu = new stdclass();
  207. $metrics->cpu->usage = 0;
  208. $metrics->cpu->capacity = 0;
  209. $metrics->cpu->allocatable = 0;
  210. $metrics->cpu->rate = 0;
  211. $metrics->memory = new stdclass();
  212. $metrics->memory->usage = 0;
  213. $metrics->memory->capacity = 0;
  214. $metrics->memory->allocatable = 0;
  215. $metrics->memory->rate = 0;
  216. $statistics = new stdclass();
  217. $statistics->status = 'unknown';
  218. $statistics->node_count = 0;
  219. $statistics->metrics = $metrics;
  220. $result = $this->apiGet('/api/cne/statistics/cluster', array('cluster' => ''), $this->config->CNE->api->headers);
  221. if($result->code != 200) return $statistics;
  222. $nodes = $this->apiGet('/api/cne/cluster/nodes', array('cluster' => ''), $this->config->CNE->api->headers);
  223. if($nodes->code != 200) return $statistics;
  224. $readyNode = 0;
  225. $nodeError = '';
  226. foreach($nodes->data as $node)
  227. {
  228. if($node->ready)
  229. {
  230. $readyNode++;
  231. }
  232. else
  233. {
  234. if(empty($node->issues)) continue;
  235. $nodeError .= sprintf($this->lang->system->nodeNotice, $node->name, implode(',', array_unique($node->issues))) . "\n";
  236. }
  237. }
  238. $statistics = $result->data;
  239. $statistics->node_count = count($nodes->data);
  240. $statistics->ready_count = $readyNode;
  241. $statistics->nodeError = $nodeError;
  242. $statistics->metrics->cpu->usage = max(round($statistics->metrics->cpu->usage, 4), 0);
  243. $statistics->metrics->cpu->capacity = max(round($statistics->metrics->cpu->capacity, 4), $statistics->metrics->cpu->usage);
  244. $statistics->metrics->cpu->allocatable = round($statistics->metrics->cpu->allocatable, 4);
  245. $statistics->metrics->cpu->rate = $statistics->metrics->cpu->capacity > 0 ? round( $statistics->metrics->cpu->usage / $statistics->metrics->cpu->capacity * 100, 2) : 0;
  246. $statistics->metrics->cpu->rate = min($statistics->metrics->cpu->rate, 100);
  247. $statistics->metrics->memory->usage = max(round($statistics->metrics->memory->usage, 4), 0);
  248. $statistics->metrics->memory->capacity = max($statistics->metrics->memory->capacity, $statistics->metrics->memory->usage);
  249. $statistics->metrics->memory->rate = $statistics->metrics->memory->capacity > 0 ? round($statistics->metrics->memory->usage / $statistics->metrics->memory->capacity * 100, 2) : 0;
  250. $statistics->metrics->memory->rate = min($statistics->metrics->memory->rate, 100);
  251. return $statistics;
  252. }
  253. /**
  254. * Get the volumes metrics of the instance.
  255. *
  256. * @param object $instance
  257. * @return object
  258. */
  259. public function getVolumesMetrics($instance)
  260. {
  261. $metric = new stdclass;
  262. $metric->limit = 0;
  263. $metric->usage = 0;
  264. $metric->rate = 0;
  265. $volumes = $this->getAppVolumes($instance);
  266. if($volumes)
  267. {
  268. foreach($volumes as $volume)
  269. {
  270. if(!$volume->is_block_device) return $metric;
  271. $metric->limit = $volume->size;
  272. $metric->usage = $volume->actual_size;
  273. break;
  274. }
  275. }
  276. $metric->rate = $metric->limit != 0 ? round($metric->usage / $metric->limit * 100, 2) : 0.01;
  277. return $metric;
  278. }
  279. /**
  280. * 获取磁盘配置信息。
  281. * Get the disk settings.
  282. *
  283. * @param object $instance
  284. * @return object
  285. * @param bool|string $component
  286. */
  287. public function getDiskSettings($instance, $component = false)
  288. {
  289. $diskSetting = new stdclass;
  290. $diskSetting->resizable = false;
  291. $diskSetting->size = 0;
  292. $diskSetting->used = 0;
  293. $diskSetting->limit = 0;
  294. $diskSetting->name = '';
  295. $diskSetting->requestSize = 0;
  296. $volumes = $this->getAppVolumes($instance, $component);
  297. if($volumes)
  298. {
  299. foreach($volumes as $volume)
  300. {
  301. if(!$volume->is_block_device) return $diskSetting;
  302. $diskSetting->resizable = true;
  303. $diskSetting->size = ceil($volume->size / 1073741824);
  304. $diskSetting->used = ceil($volume->actual_size / 1073741824);
  305. $diskSetting->limit = floor($volume->max_increase_size / 1073741824);
  306. $diskSetting->name = $volume->setting_keys->size->path;
  307. $diskSetting->requestSize = ceil($volume->request_size / 1073741824);
  308. break;
  309. }
  310. }
  311. return $diskSetting;
  312. }
  313. /**
  314. * 获取平台实例的度量。
  315. * Get instance metrics.
  316. *
  317. * @param array $instances
  318. * @param bool $volumesMetrics
  319. * @access public
  320. * @return array
  321. */
  322. public function instancesMetrics($instances, $volumesMetrics = true)
  323. {
  324. $instancesMetrics = array();
  325. $apiData = array('cluster' => '', 'apps' => array());
  326. foreach($instances as $instance)
  327. {
  328. if($instance->source == 'external') continue;
  329. $appData = new stdclass();
  330. $appData->name = $instance->k8name;
  331. $appData->namespace = $instance->spaceData->k8space;
  332. $apiData['apps'][] = $appData;
  333. $instanceMetric = new stdclass();
  334. $instanceMetric->id = $instance->id;
  335. $instanceMetric->name = $instance->k8name;
  336. $instanceMetric->namespace = $instance->spaceData->k8space;
  337. $instanceMetric->cpu = new stdclass();
  338. $instanceMetric->cpu->limit = 0;
  339. $instanceMetric->cpu->usage = 0;
  340. $instanceMetric->cpu->rate = 0;
  341. $instanceMetric->memory = new stdclass();
  342. $instanceMetric->memory->limit = 0;
  343. $instanceMetric->memory->usage = 0;
  344. $instanceMetric->memory->rate = 0;
  345. if($volumesMetrics) $instanceMetric->disk = $this->getVolumesMetrics($instance);
  346. $instancesMetrics[$instance->k8name] = $instanceMetric;
  347. }
  348. $result = $this->apiPost('/api/cne/statistics/app', $apiData, $this->config->CNE->api->headers);
  349. if(!isset($result->code) || $result->code != 200)return array_combine(helper::arrayColumn($instancesMetrics, 'id'), $instancesMetrics);
  350. foreach($result->data as $k8sMetric)
  351. {
  352. if(!isset($k8sMetric->metrics)) continue;
  353. $instancesMetrics[$k8sMetric->name]->cpu->usage = isset($k8sMetric->metrics->cpu) && isset($k8sMetric->metrics->cpu->usage) ? round($k8sMetric->metrics->cpu->usage, 4) : 0;
  354. $instancesMetrics[$k8sMetric->name]->cpu->usage = max($instancesMetrics[$k8sMetric->name]->cpu->usage, 0);
  355. $instancesMetrics[$k8sMetric->name]->cpu->limit = isset($k8sMetric->metrics->cpu) && isset($k8sMetric->metrics->cpu->limit) ? round($k8sMetric->metrics->cpu->limit, 4) : 0;
  356. $instancesMetrics[$k8sMetric->name]->cpu->limit = max($instancesMetrics[$k8sMetric->name]->cpu->limit, $instancesMetrics[$k8sMetric->name]->cpu->usage);
  357. $instancesMetrics[$k8sMetric->name]->cpu->rate = $instancesMetrics[$k8sMetric->name]->cpu->limit > 0 ? round($instancesMetrics[$k8sMetric->name]->cpu->usage / $instancesMetrics[$k8sMetric->name]->cpu->limit * 100, 2) : 0;
  358. $instancesMetrics[$k8sMetric->name]->memory->usage = isset($k8sMetric->metrics->memory) && isset($k8sMetric->metrics->memory->usage) ? $k8sMetric->metrics->memory->usage : 0;
  359. $instancesMetrics[$k8sMetric->name]->memory->usage = max($instancesMetrics[$k8sMetric->name]->memory->usage, 0);
  360. $instancesMetrics[$k8sMetric->name]->memory->limit = isset($k8sMetric->metrics->memory) && isset($k8sMetric->metrics->memory->limit) ? $k8sMetric->metrics->memory->limit : 0;
  361. $instancesMetrics[$k8sMetric->name]->memory->limit = max( $instancesMetrics[$k8sMetric->name]->memory->limit, $instancesMetrics[$k8sMetric->name]->memory->usage);
  362. $instancesMetrics[$k8sMetric->name]->memory->rate = $instancesMetrics[$k8sMetric->name]->memory->limit > 0 ? round($instancesMetrics[$k8sMetric->name]->memory->usage / $instancesMetrics[$k8sMetric->name]->memory->limit * 100, 2) : 0;
  363. }
  364. return array_combine(helper::arrayColumn($instancesMetrics, 'id'), $instancesMetrics);
  365. }
  366. /**
  367. * 备份一个应用实例。
  368. * Backup a instance with account.
  369. *
  370. * @param object $instance
  371. * @param string $account
  372. * @param string $mode |manual|system|upgrade|downgrade
  373. * @access public
  374. * @return object
  375. */
  376. public function backup($instance, $account = '', $mode = '')
  377. {
  378. $apiParams = new stdclass;
  379. $apiParams->username = $account ?: $this->app->user->account;
  380. $apiParams->cluster = '';
  381. $apiParams->namespace = $instance->spaceData->k8space;
  382. $apiParams->name = $instance->k8name;
  383. $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel;
  384. if(!empty($mode)) $apiParams->mode = $mode;
  385. $apiUrl = "/api/cne/app/backup";
  386. return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers);
  387. }
  388. /**
  389. * 获取备份的进度。
  390. * Get the status of backup progress.
  391. *
  392. * @param object $instance
  393. * @param string $backupName
  394. * @access public
  395. * @return object
  396. */
  397. public function getBackupStatus($instance, $backupName)
  398. {
  399. $apiParams = new stdclass;
  400. $apiParams->cluster = '';
  401. $apiParams->namespace = $instance->spaceData->k8space;
  402. $apiParams->name = $instance->k8name;
  403. $apiParams->backup_name = $backupName;
  404. $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel;
  405. $apiUrl = "/api/cne/app/backup/status";
  406. return $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers);
  407. }
  408. /**
  409. * 获取备份列表。
  410. * Get the backup list.
  411. *
  412. * @param object $instance
  413. * @access public
  414. * @return object
  415. */
  416. public function getBackupList($instance)
  417. {
  418. $apiParams = new stdclass;
  419. $apiParams->cluster = '';
  420. $apiParams->namespace = $instance->spaceData->k8space;
  421. $apiParams->name = $instance->k8name;
  422. $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel;
  423. $apiUrl = "/api/cne/app/backups";
  424. return $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers);
  425. }
  426. /**
  427. * 删除一个备份.
  428. * Delete backup.
  429. *
  430. * @param object $instance
  431. * @param string $backupName
  432. * @access public
  433. * @return object
  434. */
  435. public function deleteBackup($instance, $backupName)
  436. {
  437. $apiParams = new stdclass;
  438. $apiParams->cluster = '';
  439. $apiParams->namespace = $instance->spaceData->k8space;
  440. $apiParams->name = $instance->k8name;
  441. $apiParams->backup_name = $backupName;
  442. $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel;
  443. $apiUrl = "/api/cne/app/backup/remove";
  444. return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers);
  445. }
  446. /**
  447. * 恢复一个备份。
  448. * Restore from the backup.
  449. *
  450. * @param object $instance
  451. * @param string $backupName
  452. * @param string $account
  453. * @access public
  454. * @return object
  455. */
  456. public function restore($instance, $backupName, $account = '')
  457. {
  458. $apiParams = new stdclass;
  459. $apiParams->username = $account ?: $this->app->user->account;
  460. $apiParams->cluster = '';
  461. $apiParams->namespace = $instance->spaceData->k8space;
  462. $apiParams->name = $instance->k8name;
  463. $apiParams->backup_name = $backupName;
  464. $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel;
  465. $apiUrl = "/api/cne/app/restore";
  466. return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers);
  467. }
  468. /**
  469. * 获取备份恢复的状态。
  470. * Get the status of restore progress.
  471. *
  472. * @param object $instance
  473. * @param string $backupName
  474. * @access public
  475. * @return object
  476. */
  477. public function getRestoreStatus($instance, $backupName)
  478. {
  479. $apiParams = new stdclass;
  480. $apiParams->cluster = '';
  481. $apiParams->namespace = $instance->spaceData->k8space;
  482. $apiParams->name = $instance->k8name;
  483. $apiParams->restore_name = $backupName;
  484. $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel;
  485. $apiUrl = "/api/cne/app/restore/status";
  486. return $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers);
  487. }
  488. /**
  489. * 启动一个应用实例。
  490. * Start an app instance.
  491. *
  492. * @param object $apiParams
  493. * @access public
  494. * @return object
  495. */
  496. public function startApp($apiParams)
  497. {
  498. if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel;
  499. $apiUrl = "/api/cne/app/start";
  500. return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers);
  501. }
  502. /**
  503. * 停止一个应用实例。
  504. * Stop an app instance.
  505. *
  506. * @param object $apiParams
  507. * @access public
  508. * @return object
  509. */
  510. public function stopApp($apiParams)
  511. {
  512. if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel;
  513. $apiUrl = "/api/cne/app/stop";
  514. return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers);
  515. }
  516. /**
  517. * 安装应用。
  518. * Install app.
  519. *
  520. * @param object $apiParams
  521. * @access public
  522. * @return object
  523. */
  524. public function installApp($apiParams)
  525. {
  526. if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel;
  527. $apiUrl = "/api/cne/app/install";
  528. return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers);
  529. }
  530. /**
  531. * 卸载应用。
  532. * Uninstall an app instance.
  533. *
  534. * @param object $apiParams
  535. * @access public
  536. * @return object
  537. */
  538. public function uninstallApp($apiParams)
  539. {
  540. if(empty($apiParams->name)) return null;
  541. if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel;
  542. $apiUrl = "/api/cne/app/uninstall";
  543. return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers);
  544. }
  545. /**
  546. * 获取应用组件列表
  547. * Get app components.
  548. *
  549. * @link https://yapi.qc.oop.cc/project/21/interface/api/1043
  550. * @param object $instance
  551. * @return object|null
  552. */
  553. public function getComponents($instance)
  554. {
  555. $apiParams = new stdClass();
  556. $apiParams->cluster = '';
  557. $apiParams->namespace = $instance->spaceData->k8space;
  558. $apiParams->name = $instance->k8name;
  559. return $this->apiGet('/api/cne/app/components', $apiParams, $this->config->CNE->api->headers);
  560. }
  561. /**
  562. * 获取应用 pod 列表
  563. * Get app pods.
  564. *
  565. * @link https://yapi.qc.oop.cc/project/21/interface/api/189
  566. * @param object $instance 应用实例对象
  567. * @param string $component 组件名称
  568. * @return object|null
  569. */
  570. public function getPods($instance, $component = '')
  571. {
  572. $apiParams = new stdClass();
  573. $apiParams->cluster = '';
  574. $apiParams->namespace = $instance->spaceData->k8space;
  575. $apiParams->name = $instance->k8name;
  576. !empty($component) && $apiParams->component = $component;
  577. return $this->apiGet('/api/cne/app/pods', $apiParams, $this->config->CNE->api->headers);
  578. }
  579. /**
  580. * 获取应用事件列表。
  581. * Get app events.
  582. *
  583. * @param object $instance
  584. * @param string $component
  585. * @return object|null
  586. */
  587. public function getEvents($instance, $component = '')
  588. {
  589. $apiParams = new stdClass();
  590. $apiParams->cluster = '';
  591. $apiParams->namespace = $instance->spaceData->k8space;
  592. $apiParams->name = $instance->k8name;
  593. !empty($component) && $apiParams->component = $component;
  594. return $this->apiGet('/api/cne/app/events', $apiParams, $this->config->CNE->api->headers);
  595. }
  596. /**
  597. * 获取应用的安装日志。
  598. * Get app install logs.
  599. *
  600. * @param ?object $instance
  601. * @access public
  602. * @return object
  603. * @param string $component
  604. * @param string $pod
  605. * @param string $container
  606. * @param bool $previous
  607. */
  608. public function getAppLogs($instance, $component = '', $pod = '', $container = '', $previous = false)
  609. {
  610. if(!isset($this->app->user->account))
  611. {
  612. $this->app->user = new stdClass();
  613. $this->app->user->account = $this->dao->select('*')->from(TABLE_USER)->where('deleted')->eq(0)->fetch('account');
  614. }
  615. $defaultSpace = $this->loadModel('space')->defaultSpace($this->app->user->account);
  616. $apiParams = new stdClass();
  617. $apiParams->cluster = '';
  618. $apiParams->namespace = !empty($instance->spaceData->k8space) ? $instance->spaceData->k8space : $defaultSpace->k8space;
  619. $apiParams->name = $instance->k8name;
  620. $apiParams->tail = 500;
  621. !empty($component) && $apiParams->component = $component;
  622. !empty($pod) && $apiParams->pod_name = $pod;
  623. !empty($container) && $apiParams->container_name = $container;
  624. $previous && $apiParams->previous = $previous;
  625. return $this->apiGet('/api/cne/app/logs', $apiParams, $this->config->CNE->api->headers);
  626. }
  627. /**
  628. * 查询应用的数据卷。
  629. * Get app volumes.
  630. *
  631. * @link https://yapi.qc.oop.cc/project/21/interface/api/168
  632. * @param object $instance
  633. * @param bool|string $component true|'mysql'
  634. * @return object|array|false
  635. */
  636. public function getAppVolumes($instance, $component = false)
  637. {
  638. $apiParams = new stdclass();
  639. $apiParams->cluster = '';
  640. $apiParams->namespace = $instance->spaceData->k8space;
  641. $apiParams->name = $instance->k8name;
  642. $apiParams->channel = $this->config->CNE->api->channel;
  643. if($component === true) $apiParams->component = 'mysql';
  644. if(!empty($component) && is_string($component)) $apiParams->component = $component;
  645. $apiUrl = "/api/cne/app/volumes";
  646. $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers);
  647. if(!$result || $result->code != 200) return false;
  648. return $result->data;
  649. }
  650. /**
  651. * 按实例获取设置映射。
  652. * Get settings mapping by instance.
  653. *
  654. * @param object $instance
  655. * @param array $mappings
  656. * @access public
  657. * @return object|null
  658. */
  659. public function getSettingsMapping($instance, $mappings = array())
  660. {
  661. if(empty($mappings)) $mappings = array(
  662. array(
  663. "key" => "admin_username",
  664. "type" => "helm",
  665. "path" => "auth.username"
  666. ),
  667. array(
  668. "key" => "z_username",
  669. "path" => "z_username",
  670. "type" => "secret"
  671. ),
  672. array(
  673. "key" => "z_password",
  674. "path" => "z_password",
  675. "type" => "secret"
  676. ),
  677. array(
  678. "key" => "api_token",
  679. "path" => "api_token",
  680. "type" => "secret"
  681. )
  682. );
  683. $apiParams = new stdclass();
  684. $apiParams->cluster = '';
  685. $apiParams->namespace = $instance->spaceData->k8space;
  686. $apiParams->name = $instance->k8name;
  687. $apiParams->mappings = $mappings;
  688. $apiUrl = "/api/cne/app/settings/mapping";
  689. $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers);
  690. if($result && $result->code != 200) return null;
  691. return $result->data;
  692. }
  693. /**
  694. * 获取应用配置和资源。
  695. * Get app config and resource.
  696. *
  697. * @param object $instance
  698. * @access public
  699. * @return object|false
  700. */
  701. public function getAppConfig($instance)
  702. {
  703. $apiParams = new stdclass();
  704. $apiParams->cluster = '';
  705. $apiParams->namespace = $instance->spaceData->k8space;
  706. $apiParams->name = $instance->k8name;
  707. $apiParams->channel = $this->config->CNE->api->channel;
  708. $apiUrl = "/api/cne/app/settings/common";
  709. $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers);
  710. if($result && $result->code != 200) return false;
  711. $resources = new stdclass();
  712. $resources->cpu = 0;
  713. $resources->memory = 0;
  714. $result->data->min = zget($result->data, 'oversold', $resources);
  715. $result->data->max = zget($result->data, 'resources', $resources);
  716. return $result->data;
  717. }
  718. /**
  719. * 获取应用实例状态。
  720. * Query status of an app instance.
  721. *
  722. * @param object $instance
  723. * @access public
  724. * @return object
  725. */
  726. public function queryStatus($instance)
  727. {
  728. $apiParams = new stdclass();
  729. $apiParams->cluster = '';
  730. $apiParams->name = $instance->k8name;
  731. $apiParams->chart = $instance->chart;
  732. $apiParams->namespace = $instance->spaceData->k8space;
  733. $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel;
  734. $apiUrl = "/api/cne/app/status";
  735. $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers);
  736. if($result && $result->code == 200) return $result;
  737. return $result;
  738. }
  739. /**
  740. * 批量获取应用实例状态。
  741. * Query status of instance list.
  742. *
  743. * @param array $instanceList
  744. * @access public
  745. * @return array
  746. */
  747. public function batchQueryStatus($instanceList)
  748. {
  749. $apiParams = new stdclass();
  750. $apiParams->cluster = '';
  751. $apiParams->apps = array();
  752. foreach($instanceList as $instance)
  753. {
  754. $app = new stdclass();
  755. $app->name = $instance->k8name;
  756. $app->chart = $instance->chart;
  757. $app->namespace = $instance->spaceData->k8space;
  758. $app->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel;
  759. $apiParams->apps[] = $app;
  760. }
  761. $apiUrl = "/api/cne/app/status/multi";
  762. $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers);
  763. if(empty($result) || $result->code != 200) return array();
  764. $statusList = array();
  765. foreach($result->data as $status) $statusList[$status->name] = $status;
  766. return $statusList;
  767. }
  768. /**
  769. * 获取应用的数据库列表。
  770. * Get all database list of app.
  771. *
  772. * @param object $instance
  773. * @access public
  774. * @return array
  775. */
  776. public function appDBList($instance)
  777. {
  778. $apiUrl = "/api/cne/app/dbs";
  779. $apiParams = array();
  780. $apiParams['cluster'] = '';
  781. $apiParams['name'] = $instance->k8name;
  782. $apiParams['namespace'] = $instance->spaceData->k8space;
  783. $apiParams['channel'] = $this->config->CNE->api->channel;
  784. $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers);
  785. if(empty($result) || $result->code != 200 || empty($result->data)) return array();
  786. $dbList = $result->data;
  787. return array_combine(helper::arrayColumn($dbList, 'name'), $dbList);
  788. }
  789. /**
  790. * 获取应用数据库的详细信息。
  791. * Get detail of app database.
  792. *
  793. * @param object $instance
  794. * @param string $dbName
  795. * @access public
  796. * @return object|false
  797. */
  798. public function appDBDetail($instance, $dbName)
  799. {
  800. $apiParams = array();
  801. $apiParams['cluster'] = '';
  802. $apiParams['name'] = $instance->k8name;
  803. $apiParams['namespace'] = $instance->spaceData->k8space;
  804. $apiParams['db'] = $dbName;
  805. $apiParams['channel'] = $this->config->CNE->api->channel;
  806. $apiUrl = "/api/cne/app/dbs/detail";
  807. $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers);
  808. if(empty($result) || $result->code != 200 || empty($result->data)) return false;
  809. return $result->data;
  810. }
  811. /**
  812. * 获取数据库配置。
  813. * Get database detail.
  814. *
  815. * @param string $dbService
  816. * @param string $namespace
  817. * @access public
  818. * @return object|false
  819. */
  820. public function dbDetail($dbService, $namespace)
  821. {
  822. $apiUrl = "/api/cne/component/dbservice/detail";
  823. $apiParams = array('name' => $dbService, 'namespace' => $namespace, 'channel' => $this->config->CNE->api->channel);
  824. $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers);
  825. if(empty($result) || $result->code != 200 || empty($result->data)) return false;
  826. return $result->data;
  827. }
  828. /**
  829. * 获取数据库列表。
  830. * Get all database list.
  831. *
  832. * @access public
  833. * @return array
  834. */
  835. public function allDBList()
  836. {
  837. $apiUrl = "/api/cne/component/dbservice";
  838. $apiParams = array('global' => 'true', 'namespace' => $this->config->k8space, 'channel' => $this->config->CNE->api->channel);
  839. $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers);
  840. if(empty($result) || $result->code != 200 || empty($result->data)) return array();
  841. $dbList = $result->data;
  842. return array_combine(helper::arrayColumn($dbList, 'name'), $dbList);
  843. }
  844. /**
  845. * 获取共享数据库列表。
  846. * Get shared database list.
  847. *
  848. * @param string $dbType
  849. * @access public
  850. * @return array
  851. */
  852. public function sharedDBList($dbType = 'mysql')
  853. {
  854. $apiUrl = "/api/cne/component/gdb";
  855. $apiParams = array('kind' => $dbType, 'namespace' => 'default', 'channel' => $this->config->CNE->api->channel);
  856. $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers);
  857. if(empty($result) || $result->code != 200 || empty($result->data)) return array();
  858. $dbList = $result->data;
  859. return array_combine(helper::arrayColumn($dbList, 'name'), $dbList);
  860. }
  861. /**
  862. * 校验数据库名称和用户是否可用。
  863. * Validate database name and user.
  864. *
  865. * @param string $dbService
  866. * @param string $dbUser
  867. * @param string $dbName
  868. * @param string $namespace
  869. * @access public
  870. * @return object
  871. */
  872. public function validateDB($dbService, $dbUser, $dbName, $namespace)
  873. {
  874. $apiParams = array();
  875. $apiParams['name'] = $dbService;
  876. $apiParams['user'] = $dbUser;
  877. $apiParams['database'] = $dbName;
  878. $apiParams['namespace'] = $namespace;
  879. $apiUrl = "/api/cne/component/gdb/validation";
  880. $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers);
  881. if($result && $result->code == 200) return $result->data->validation;
  882. $validation = new stdclass();
  883. $validation->user = true;
  884. $validation->database = true;
  885. return $validation;
  886. }
  887. /**
  888. * 通过Get方式调用API。
  889. * Get method of API.
  890. *
  891. * @param string $url
  892. * @param array|object $data
  893. * @param array $header example: array("key1:value1", "key2:value2")
  894. * @param string $host
  895. * @access public
  896. * @return object
  897. */
  898. public function apiGet($url, $data, $header = array(), $host = '')
  899. {
  900. $requestUri = ($host ? $host : $this->config->CNE->api->host) . $url;
  901. $requestUri .= (strpos($url, '?') !== false ? '&' : '?') . http_build_query($data, '', '&', PHP_QUERY_RFC3986);
  902. $result = json_decode(commonModel::http($requestUri, $data, array(CURLOPT_CUSTOMREQUEST => 'GET'), $header, 'json', 'GET', 20));
  903. if($result && $result->code == 200) return $result;
  904. if($result) return $this->translateError($result);
  905. return $this->cneServerError();
  906. }
  907. /**
  908. * 通过Post方式调用API。
  909. * Post method of API.
  910. *
  911. * @param string $url
  912. * @param array|object $data
  913. * @param array $header example: array("key1:value1", "key2:value2")
  914. * @param string $host
  915. * @access public
  916. * @return object
  917. */
  918. public function apiPost($url, $data, $header = array(), $host = '')
  919. {
  920. $requestUri = ($host ? $host : $this->config->CNE->api->host) . $url;
  921. $result = json_decode(commonModel::http($requestUri, $data, array(CURLOPT_CUSTOMREQUEST => 'POST'), $header, 'json', 'POST', 20));
  922. if($result && in_array($result->code, array(200, 201)))
  923. {
  924. $result->code = 200;
  925. return $result;
  926. }
  927. if($result) return $this->translateError($result);
  928. return $this->cneServerError();
  929. }
  930. /**
  931. * 返回API服务器错误对象。
  932. * Return error object of api server.
  933. *
  934. * @access protected
  935. * @return object
  936. */
  937. protected function cneServerError()
  938. {
  939. $error = new stdclass();
  940. $error->code = 600;
  941. $error->message = $this->lang->CNE->serverError;
  942. return $error;
  943. }
  944. /**
  945. * 翻译错误信息。
  946. * Translate error message for multi language.
  947. *
  948. * @param object $apiResult
  949. * @access protected
  950. * @return object
  951. */
  952. protected function translateError(&$apiResult)
  953. {
  954. $this->error->code = $apiResult->code;
  955. $this->error->message = zget($this->lang->CNE->errorList, $apiResult->code, $this->lang->CNE->serverError); // Translate CNE api error message to multi language.
  956. if($this->config->debug)
  957. {
  958. if(isset($apiResult->code)) $this->error->message .= " [{$apiResult->code}]:";
  959. if(isset($apiResult->message)) $this->error->message .= " [{$apiResult->message}]";
  960. }
  961. $apiResult->message = $this->error->message;
  962. return $this->error;
  963. }
  964. /**
  965. * app资源调度尝试。
  966. * Try allocate for apps.
  967. *
  968. * @param array $apps
  969. * @access public
  970. * @return object
  971. * @param mixed[] $resources
  972. */
  973. public function tryAllocate($resources)
  974. {
  975. $apiParams = new stdclass();
  976. $apiParams->requests = $resources;
  977. $apiUrl = "/api/cne/system/resource/try-allocate";
  978. return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers);
  979. }
  980. /**
  981. * 升级禅道DevOps平台版。
  982. * Upgrade the quickon system.
  983. *
  984. * @param string $edition oss|open|biz|max|ipd
  985. * @return object|false
  986. */
  987. public function upgrade($edition = 'oss')
  988. {
  989. $numArgs = func_num_args();
  990. if($numArgs == 0) $edition = $this->config->edition;
  991. if($edition == 'open') $edition = 'oss';
  992. $version = $this->loadModel('system')->getLatestRelease();
  993. if(!$version) return false;
  994. $apiParams = array(
  995. 'channel' => getenv('CLOUD_DEFAULT_CHANNEL') ?: 'stable',
  996. 'version' => $version->version,
  997. 'product' => $edition
  998. );
  999. $apiUrl = "/api/cne/system/update";
  1000. return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers);
  1001. }
  1002. /**
  1003. * 获取备份的详细信息。
  1004. * Get backup detail.
  1005. *
  1006. * @param object $instance
  1007. * @param string $backupName
  1008. * @access public
  1009. * @return object|false
  1010. */
  1011. public function backupDetail($instance, $backupName)
  1012. {
  1013. if(empty($instance->k8name) || empty($instance->spaceData)) return false;
  1014. $apiUrl = "/api/cne/app/backup/detail";
  1015. $apiParams = array('name' => $instance->k8name, 'namespace' => $instance->spaceData->k8space, 'backup_name' => $backupName);
  1016. $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers);
  1017. if(empty($result) || $result->code != 200 || empty($result->data)) return false;
  1018. return $result->data;
  1019. }
  1020. }