* @package CNE * @link https://www.zentao.net */ class cneModel extends model { public $error; /** * Construct function: set api headers. * * @param string $appName * @access public * @return void */ public function __construct($appName = '') { parent::__construct($appName); $this->error = new stdclass(); global $config, $app; $config->CNE->api->headers[] = "{$config->CNE->api->auth}: {$config->CNE->api->token}"; $config->cloud->api->headers[] = "{$config->cloud->api->auth}: {$config->cloud->api->token}"; if($config->cloud->api->switchChannel && $app->session->cloudChannel) { $config->cloud->api->channel = $app->session->cloudChannel; $config->CNE->api->channel = $app->session->cloudChannel; } } /** * 更新实例配置。例如:cpu、内存大小、LDAP设置... * Update instance config. For example: cpu, memory size, LDAP settings... * * @link https://yapi.qc.oop.cc/project/21/interface/api/725 * @param object $instance * @param object $settings * @access public * @return bool */ public function updateConfig(object $instance, ?object $settings = null): bool { $apiParams = array(); $apiParams['cluster'] = ''; $apiParams['namespace'] = $instance->spaceData->k8space; $apiParams['name'] = $instance->k8name; $apiParams['channel'] = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; $apiParams['chart'] = $instance->chart; if(isset($instance->version)) $apiParams['version'] = $instance->version; if(isset($settings->force_restart)) $apiParams['force_restart'] = $settings->force_restart; if(isset($settings->settings)) $apiParams['settings'] = $settings->settings; if(isset($settings->settings_map)) $apiParams['settings_map'] = $settings->settings_map; if(isset($settings->settings_snippets)) $apiParams['settings_snippets'] = $settings->settings_snippets; $apiUrl = "/api/cne/app/settings"; $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); if($result && $result->code == 200) return true; return false; } /** * 校验证书。 * Valid Certificate. * * @param string $certName * @param string $pem * @param string $key * @param string $domain * @access public * @return object */ public function validateCert(string $certName, string $pem, string $key, string $domain) { $apiParams = array(); $apiParams['name'] = $certName; $apiParams['certificate_pem'] = $pem; $apiParams['private_key_pem'] = $key; $apiUrl = "/api/cne/system/tls/validator"; $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); if($result && $result->code != 200) return $result; $match = false; foreach($result->data->sans as $domainPattern) { if(stripos($domainPattern, $domain) !== false) { $match = true; break; } } if(!$match) { $result->code = 40004; $result->message = zget($this->lang->CNE->errorList, 40004); } return $result; } /** * 更新证书。 * Upload cert. * * @param object $cert * @param string $channel * @access public * @return object */ public function uploadCert(object $cert, string $channel = ''): ?object { $apiParams = array(); $apiParams['cluster'] = ''; $apiParams['channel'] = empty($channel) ? $this->config->CNE->api->channel : $channel; $apiParams['name'] = $cert->name; $apiParams['certificate_pem'] = $cert->certificate_pem; $apiParams['private_key_pem'] = $cert->private_key_pem; return $this->apiPost('/api/cne/system/tls/upload', $apiParams, $this->config->CNE->api->headers); } /** * 获取证书信息。 * Get cert info. * * @param string $certName * @param string $channel * @access public * @return object|null success: return cert info, fail: return null. */ public function certInfo(string $certName, string $channel = ''): ?object { $apiParams = array(); $apiParams['cluster'] = ''; $apiParams['channel'] = empty($channel) ? $this->config->CNE->api->channel : $channel; $apiParams['name'] = $certName; $apiUrl = "/api/cne/system/tls/info"; $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); if($result && $result->code == 200) return $result->data; return null; } /** * 获取实例的默认账号密码。 * Get default username and password of app. * * @param object $instance * @param string $component * @access public * @return object|null */ public function getDefaultAccount(object $instance, string $component = ''): ?object { $apiUrl = '/api/cne/app/account?channel='. (empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel); $apiParams = array(); $apiParams['name'] = $instance->k8name; $apiParams['namespace'] = $instance->spaceData->k8space; $apiParams['cluster'] = ''; if($component) $apiParams['component'] = $component; $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers, $this->config->CNE->api->host); if(!isset($result->code) || $result->code != 200) return null; $account = $result->data; if(isset($account->username) && $account->username && isset($account->password) && $account->password) return $account; return null; } /** * 获取域名后缀。 * Get suffix domain. * * @access public * @return string */ public function sysDomain(): string { $customDomain = $this->loadModel('setting')->getItem('owner=system&module=common§ion=domain&key=customDomain'); if($customDomain) return $customDomain; if(getenv('APP_DOMAIN')) return getenv('APP_DOMAIN'); if(!empty($this->config->CNE->app->domain)) return $this->config->CNE->app->domain; return ''; } /** * 获取实例的域名。 * Get domain. * * @param object $instance * @param string $component * @access public * @return object|null */ public function getDomain(object $instance, string $component = ''): ?object { $apiUrl = '/api/cne/app/domain?channel='. (empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel); $apiParams = array(); $apiParams['name'] = $instance->k8name; $apiParams['namespace'] = $instance->spaceData->k8space; $apiParams['cluster'] = ''; if($component) $apiParams['component'] = $component; $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers, $this->config->CNE->api->host); if(!isset($result->code) || $result->code != 200) return null; return empty($result->data->internal_host) ? null : $result->data; } /** * 获取CNE平台的集群度量。 * Get cluster metrics of CNE platform. * * @access public * @return object */ public function cneMetrics(): object { $metrics = new stdclass(); $metrics->cpu = new stdclass(); $metrics->cpu->usage = 0; $metrics->cpu->capacity = 0; $metrics->cpu->allocatable = 0; $metrics->cpu->rate = 0; $metrics->memory = new stdclass(); $metrics->memory->usage = 0; $metrics->memory->capacity = 0; $metrics->memory->allocatable = 0; $metrics->memory->rate = 0; $statistics = new stdclass(); $statistics->status = 'unknown'; $statistics->node_count = 0; $statistics->metrics = $metrics; $result = $this->apiGet('/api/cne/statistics/cluster', array('cluster' => ''), $this->config->CNE->api->headers); if($result->code != 200) return $statistics; $nodes = $this->apiGet('/api/cne/cluster/nodes', array('cluster' => ''), $this->config->CNE->api->headers); if($nodes->code != 200) return $statistics; $readyNode = 0; $nodeError = ''; foreach($nodes->data as $node) { if($node->ready) { $readyNode++; } else { if(empty($node->issues)) continue; $nodeError .= sprintf($this->lang->system->nodeNotice, $node->name, implode(',', array_unique($node->issues))) . "\n"; } } $statistics = $result->data; $statistics->node_count = count($nodes->data); $statistics->ready_count = $readyNode; $statistics->nodeError = $nodeError; $statistics->metrics->cpu->usage = max(round($statistics->metrics->cpu->usage, 4), 0); $statistics->metrics->cpu->capacity = max(round($statistics->metrics->cpu->capacity, 4), $statistics->metrics->cpu->usage); $statistics->metrics->cpu->allocatable = round($statistics->metrics->cpu->allocatable, 4); $statistics->metrics->cpu->rate = $statistics->metrics->cpu->capacity > 0 ? round( $statistics->metrics->cpu->usage / $statistics->metrics->cpu->capacity * 100, 2) : 0; $statistics->metrics->cpu->rate = min($statistics->metrics->cpu->rate, 100); $statistics->metrics->memory->usage = max(round($statistics->metrics->memory->usage, 4), 0); $statistics->metrics->memory->capacity = max($statistics->metrics->memory->capacity, $statistics->metrics->memory->usage); $statistics->metrics->memory->rate = $statistics->metrics->memory->capacity > 0 ? round($statistics->metrics->memory->usage / $statistics->metrics->memory->capacity * 100, 2) : 0; $statistics->metrics->memory->rate = min($statistics->metrics->memory->rate, 100); return $statistics; } /** * Get the volumes metrics of the instance. * * @param object $instance * @return object */ public function getVolumesMetrics(object $instance): object { $metric = new stdclass; $metric->limit = 0; $metric->usage = 0; $metric->rate = 0; $volumes = $this->getAppVolumes($instance); if($volumes) { foreach($volumes as $volume) { if(!$volume->is_block_device) return $metric; $metric->limit = $volume->size; $metric->usage = $volume->actual_size; break; } } $metric->rate = $metric->limit != 0 ? round($metric->usage / $metric->limit * 100, 2) : 0.01; return $metric; } /** * 获取磁盘配置信息。 * Get the disk settings. * * @param object $instance * @return object */ public function getDiskSettings(object $instance, bool|string $component = false): object { $diskSetting = new stdclass; $diskSetting->resizable = false; $diskSetting->size = 0; $diskSetting->used = 0; $diskSetting->limit = 0; $diskSetting->name = ''; $diskSetting->requestSize = 0; $volumes = $this->getAppVolumes($instance, $component); if($volumes) { foreach($volumes as $volume) { if(!$volume->is_block_device) return $diskSetting; $diskSetting->resizable = true; $diskSetting->size = ceil($volume->size / 1073741824); $diskSetting->used = ceil($volume->actual_size / 1073741824); $diskSetting->limit = floor($volume->max_increase_size / 1073741824); $diskSetting->name = $volume->setting_keys->size->path; $diskSetting->requestSize = ceil($volume->request_size / 1073741824); break; } } return $diskSetting; } /** * 获取平台实例的度量。 * Get instance metrics. * * @param array $instances * @param bool $volumesMetrics * @access public * @return array */ public function instancesMetrics(array $instances, bool $volumesMetrics = true): array { $instancesMetrics = array(); $apiData = array('cluster' => '', 'apps' => array()); foreach($instances as $instance) { if($instance->source == 'external') continue; $appData = new stdclass(); $appData->name = $instance->k8name; $appData->namespace = $instance->spaceData->k8space; $apiData['apps'][] = $appData; $instanceMetric = new stdclass(); $instanceMetric->id = $instance->id; $instanceMetric->name = $instance->k8name; $instanceMetric->namespace = $instance->spaceData->k8space; $instanceMetric->cpu = new stdclass(); $instanceMetric->cpu->limit = 0; $instanceMetric->cpu->usage = 0; $instanceMetric->cpu->rate = 0; $instanceMetric->memory = new stdclass(); $instanceMetric->memory->limit = 0; $instanceMetric->memory->usage = 0; $instanceMetric->memory->rate = 0; if($volumesMetrics) $instanceMetric->disk = $this->getVolumesMetrics($instance); $instancesMetrics[$instance->k8name] = $instanceMetric; } $result = $this->apiPost('/api/cne/statistics/app', $apiData, $this->config->CNE->api->headers); if(!isset($result->code) || $result->code != 200)return array_combine(helper::arrayColumn($instancesMetrics, 'id'), $instancesMetrics); foreach($result->data as $k8sMetric) { if(!isset($k8sMetric->metrics)) continue; $instancesMetrics[$k8sMetric->name]->cpu->usage = isset($k8sMetric->metrics->cpu) && isset($k8sMetric->metrics->cpu->usage) ? round($k8sMetric->metrics->cpu->usage, 4) : 0; $instancesMetrics[$k8sMetric->name]->cpu->usage = max($instancesMetrics[$k8sMetric->name]->cpu->usage, 0); $instancesMetrics[$k8sMetric->name]->cpu->limit = isset($k8sMetric->metrics->cpu) && isset($k8sMetric->metrics->cpu->limit) ? round($k8sMetric->metrics->cpu->limit, 4) : 0; $instancesMetrics[$k8sMetric->name]->cpu->limit = max($instancesMetrics[$k8sMetric->name]->cpu->limit, $instancesMetrics[$k8sMetric->name]->cpu->usage); $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; $instancesMetrics[$k8sMetric->name]->memory->usage = isset($k8sMetric->metrics->memory) && isset($k8sMetric->metrics->memory->usage) ? $k8sMetric->metrics->memory->usage : 0; $instancesMetrics[$k8sMetric->name]->memory->usage = max($instancesMetrics[$k8sMetric->name]->memory->usage, 0); $instancesMetrics[$k8sMetric->name]->memory->limit = isset($k8sMetric->metrics->memory) && isset($k8sMetric->metrics->memory->limit) ? $k8sMetric->metrics->memory->limit : 0; $instancesMetrics[$k8sMetric->name]->memory->limit = max( $instancesMetrics[$k8sMetric->name]->memory->limit, $instancesMetrics[$k8sMetric->name]->memory->usage); $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; } return array_combine(helper::arrayColumn($instancesMetrics, 'id'), $instancesMetrics); } /** * 备份一个应用实例。 * Backup a instance with account. * * @param object $instance * @param string $account * @param string $mode |manual|system|upgrade|downgrade * @access public * @return object */ public function backup(object $instance, string|null $account = '', string $mode = ''): object { $apiParams = new stdclass; $apiParams->username = $account ?: $this->app->user->account; $apiParams->cluster = ''; $apiParams->namespace = $instance->spaceData->k8space; $apiParams->name = $instance->k8name; $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; if(!empty($mode)) $apiParams->mode = $mode; $apiUrl = "/api/cne/app/backup"; return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); } /** * 获取备份的进度。 * Get the status of backup progress. * * @param object $instance * @param string $backupName * @access public * @return object */ public function getBackupStatus(object $instance, string $backupName): object { $apiParams = new stdclass; $apiParams->cluster = ''; $apiParams->namespace = $instance->spaceData->k8space; $apiParams->name = $instance->k8name; $apiParams->backup_name = $backupName; $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; $apiUrl = "/api/cne/app/backup/status"; return $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); } /** * 获取备份列表。 * Get the backup list. * * @param object $instance * @access public * @return object */ public function getBackupList(object $instance): object { $apiParams = new stdclass; $apiParams->cluster = ''; $apiParams->namespace = $instance->spaceData->k8space; $apiParams->name = $instance->k8name; $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; $apiUrl = "/api/cne/app/backups"; return $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); } /** * 删除一个备份. * Delete backup. * * @param object $instance * @param string $backupName * @access public * @return object */ public function deleteBackup(object $instance, string $backupName): object { $apiParams = new stdclass; $apiParams->cluster = ''; $apiParams->namespace = $instance->spaceData->k8space; $apiParams->name = $instance->k8name; $apiParams->backup_name = $backupName; $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; $apiUrl = "/api/cne/app/backup/remove"; return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); } /** * 恢复一个备份。 * Restore from the backup. * * @param object $instance * @param object $backupName * @param string $account * @access public * @return object */ public function restore(object $instance, string $backupName, string $account = ''): object { $apiParams = new stdclass; $apiParams->username = $account ?: $this->app->user->account; $apiParams->cluster = ''; $apiParams->namespace = $instance->spaceData->k8space; $apiParams->name = $instance->k8name; $apiParams->backup_name = $backupName; $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; $apiUrl = "/api/cne/app/restore"; return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); } /** * 获取备份恢复的状态。 * Get the status of restore progress. * * @param object $instance * @param string $backupName * @access public * @return object */ public function getRestoreStatus(object $instance, string $backupName): object { $apiParams = new stdclass; $apiParams->cluster = ''; $apiParams->namespace = $instance->spaceData->k8space; $apiParams->name = $instance->k8name; $apiParams->restore_name = $backupName; $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; $apiUrl = "/api/cne/app/restore/status"; return $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); } /** * 启动一个应用实例。 * Start an app instance. * * @param object $apiParams * @access public * @return object */ public function startApp(object $apiParams): ?object { if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel; $apiUrl = "/api/cne/app/start"; return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); } /** * 停止一个应用实例。 * Stop an app instance. * * @param object $apiParams * @access public * @return object */ public function stopApp(object $apiParams): ?object { if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel; $apiUrl = "/api/cne/app/stop"; return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); } /** * 安装应用。 * Install app. * * @param object $apiParams * @access public * @return object */ public function installApp(object $apiParams): ?object { if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel; $apiUrl = "/api/cne/app/install"; return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); } /** * 卸载应用。 * Uninstall an app instance. * * @param object $apiParams * @access public * @return object */ public function uninstallApp(object $apiParams): ?object { if(empty($apiParams->name)) return null; if(empty($apiParams->channel)) $apiParams->channel = $this->config->CNE->api->channel; $apiUrl = "/api/cne/app/uninstall"; return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); } /** * 获取应用组件列表 * Get app components. * * @link https://yapi.qc.oop.cc/project/21/interface/api/1043 * @param object $instance * @return object|null */ public function getComponents(object $instance): ?object { $apiParams = new stdClass(); $apiParams->cluster = ''; $apiParams->namespace = $instance->spaceData->k8space; $apiParams->name = $instance->k8name; return $this->apiGet('/api/cne/app/components', $apiParams, $this->config->CNE->api->headers); } /** * 获取应用 pod 列表 * Get app pods. * * @link https://yapi.qc.oop.cc/project/21/interface/api/189 * @param object $instance 应用实例对象 * @param string $component 组件名称 * @return object|null */ public function getPods(object $instance, string $component = ''): ?object { $apiParams = new stdClass(); $apiParams->cluster = ''; $apiParams->namespace = $instance->spaceData->k8space; $apiParams->name = $instance->k8name; !empty($component) && $apiParams->component = $component; return $this->apiGet('/api/cne/app/pods', $apiParams, $this->config->CNE->api->headers); } /** * 获取应用事件列表。 * Get app events. * * @param object $instance * @param string $component * @return object|null */ public function getEvents(object $instance, string $component = ''): ?object { $apiParams = new stdClass(); $apiParams->cluster = ''; $apiParams->namespace = $instance->spaceData->k8space; $apiParams->name = $instance->k8name; !empty($component) && $apiParams->component = $component; return $this->apiGet('/api/cne/app/events', $apiParams, $this->config->CNE->api->headers); } /** * 获取应用的安装日志。 * Get app install logs. * * @param ?object $instance * @access public * @return object */ public function getAppLogs(?object $instance, string $component = '', string $pod = '', string $container = '', bool $previous = false): ?object { if(!isset($this->app->user->account)) { $this->app->user = new stdClass(); $this->app->user->account = $this->dao->select('*')->from(TABLE_USER)->where('deleted')->eq(0)->fetch('account'); } $defaultSpace = $this->loadModel('space')->defaultSpace($this->app->user->account); $apiParams = new stdClass(); $apiParams->cluster = ''; $apiParams->namespace = !empty($instance->spaceData->k8space) ? $instance->spaceData->k8space : $defaultSpace->k8space; $apiParams->name = $instance->k8name; $apiParams->tail = 500; !empty($component) && $apiParams->component = $component; !empty($pod) && $apiParams->pod_name = $pod; !empty($container) && $apiParams->container_name = $container; $previous && $apiParams->previous = $previous; return $this->apiGet('/api/cne/app/logs', $apiParams, $this->config->CNE->api->headers); } /** * 查询应用的数据卷。 * Get app volumes. * * @link https://yapi.qc.oop.cc/project/21/interface/api/168 * @param object $instance * @param bool|string $component true|'mysql' * @return object|array|false */ public function getAppVolumes(object $instance, bool|string $component = false): object|array|false { $apiParams = new stdclass(); $apiParams->cluster = ''; $apiParams->namespace = $instance->spaceData->k8space; $apiParams->name = $instance->k8name; $apiParams->channel = $this->config->CNE->api->channel; if($component === true) $apiParams->component = 'mysql'; if(!empty($component) && is_string($component)) $apiParams->component = $component; $apiUrl = "/api/cne/app/volumes"; $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); if(!$result || $result->code != 200) return false; return $result->data; } /** * 按实例获取设置映射。 * Get settings mapping by instance. * * @param object $instance * @param array $mappings * @access public * @return object|null */ public function getSettingsMapping(object $instance, array $mappings = array()): ?object { if(empty($mappings)) $mappings = array( array( "key" => "admin_username", "type" => "helm", "path" => "auth.username" ), array( "key" => "z_username", "path" => "z_username", "type" => "secret" ), array( "key" => "z_password", "path" => "z_password", "type" => "secret" ), array( "key" => "api_token", "path" => "api_token", "type" => "secret" ) ); $apiParams = new stdclass(); $apiParams->cluster = ''; $apiParams->namespace = $instance->spaceData->k8space; $apiParams->name = $instance->k8name; $apiParams->mappings = $mappings; $apiUrl = "/api/cne/app/settings/mapping"; $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); if($result && $result->code != 200) return null; return $result->data; } /** * 获取应用配置和资源。 * Get app config and resource. * * @param object $instance * @access public * @return object|false */ public function getAppConfig(object $instance): object|false { $apiParams = new stdclass(); $apiParams->cluster = ''; $apiParams->namespace = $instance->spaceData->k8space; $apiParams->name = $instance->k8name; $apiParams->channel = $this->config->CNE->api->channel; $apiUrl = "/api/cne/app/settings/common"; $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); if($result && $result->code != 200) return false; $resources = new stdclass(); $resources->cpu = 0; $resources->memory = 0; $result->data->min = zget($result->data, 'oversold', $resources); $result->data->max = zget($result->data, 'resources', $resources); return $result->data; } /** * 获取应用实例状态。 * Query status of an app instance. * * @param object $instance * @access public * @return object */ public function queryStatus(object $instance): ?object { $apiParams = new stdclass(); $apiParams->cluster = ''; $apiParams->name = $instance->k8name; $apiParams->chart = $instance->chart; $apiParams->namespace = $instance->spaceData->k8space; $apiParams->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; $apiUrl = "/api/cne/app/status"; $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); if($result && $result->code == 200) return $result; return $result; } /** * 批量获取应用实例状态。 * Query status of instance list. * * @param array $instanceList * @access public * @return array */ public function batchQueryStatus(array $instanceList): array { $apiParams = new stdclass(); $apiParams->cluster = ''; $apiParams->apps = array(); foreach($instanceList as $instance) { $app = new stdclass(); $app->name = $instance->k8name; $app->chart = $instance->chart; $app->namespace = $instance->spaceData->k8space; $app->channel = empty($instance->channel) ? $this->config->CNE->api->channel : $instance->channel; $apiParams->apps[] = $app; } $apiUrl = "/api/cne/app/status/multi"; $result = $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); if(empty($result) || $result->code != 200) return array(); $statusList = array(); foreach($result->data as $status) $statusList[$status->name] = $status; return $statusList; } /** * 获取应用的数据库列表。 * Get all database list of app. * * @param object $instance * @access public * @return array */ public function appDBList(object $instance): array { $apiUrl = "/api/cne/app/dbs"; $apiParams = array(); $apiParams['cluster'] = ''; $apiParams['name'] = $instance->k8name; $apiParams['namespace'] = $instance->spaceData->k8space; $apiParams['channel'] = $this->config->CNE->api->channel; $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); if(empty($result) || $result->code != 200 || empty($result->data)) return array(); $dbList = $result->data; return array_combine(helper::arrayColumn($dbList, 'name'), $dbList); } /** * 获取应用数据库的详细信息。 * Get detail of app database. * * @param object $instance * @param string $dbName * @access public * @return object|false */ public function appDBDetail(object $instance, string $dbName): object|false { $apiParams = array(); $apiParams['cluster'] = ''; $apiParams['name'] = $instance->k8name; $apiParams['namespace'] = $instance->spaceData->k8space; $apiParams['db'] = $dbName; $apiParams['channel'] = $this->config->CNE->api->channel; $apiUrl = "/api/cne/app/dbs/detail"; $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); if(empty($result) || $result->code != 200 || empty($result->data)) return false; return $result->data; } /** * 获取数据库配置。 * Get database detail. * * @param string $dbService * @param string $namespace * @access public * @return object|false */ public function dbDetail(string $dbService, string $namespace): object|false { $apiUrl = "/api/cne/component/dbservice/detail"; $apiParams = array('name' => $dbService, 'namespace' => $namespace, 'channel' => $this->config->CNE->api->channel); $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); if(empty($result) || $result->code != 200 || empty($result->data)) return false; return $result->data; } /** * 获取数据库列表。 * Get all database list. * * @access public * @return array */ public function allDBList(): array { $apiUrl = "/api/cne/component/dbservice"; $apiParams = array('global' => 'true', 'namespace' => $this->config->k8space, 'channel' => $this->config->CNE->api->channel); $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); if(empty($result) || $result->code != 200 || empty($result->data)) return array(); $dbList = $result->data; return array_combine(helper::arrayColumn($dbList, 'name'), $dbList); } /** * 获取共享数据库列表。 * Get shared database list. * * @param string $dbType * @access public * @return array */ public function sharedDBList(string $dbType = 'mysql'): array { $apiUrl = "/api/cne/component/gdb"; $apiParams = array('kind' => $dbType, 'namespace' => 'default', 'channel' => $this->config->CNE->api->channel); $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); if(empty($result) || $result->code != 200 || empty($result->data)) return array(); $dbList = $result->data; return array_combine(helper::arrayColumn($dbList, 'name'), $dbList); } /** * 校验数据库名称和用户是否可用。 * Validate database name and user. * * @param string $dbService * @param string $dbUser * @param string $dbName * @param string $namespace * @access public * @return object */ public function validateDB(string $dbService, string $dbUser, string $dbName, string $namespace): object { $apiParams = array(); $apiParams['name'] = $dbService; $apiParams['user'] = $dbUser; $apiParams['database'] = $dbName; $apiParams['namespace'] = $namespace; $apiUrl = "/api/cne/component/gdb/validation"; $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); if($result && $result->code == 200) return $result->data->validation; $validation = new stdclass(); $validation->user = true; $validation->database = true; return $validation; } /** * 通过Get方式调用API。 * Get method of API. * * @param string $url * @param array|object $data * @param array $header example: array("key1:value1", "key2:value2") * @param string $host * @access public * @return object */ public function apiGet(string $url, array|object $data, array $header = array(), string $host = ''): object { $requestUri = ($host ? $host : $this->config->CNE->api->host) . $url; $requestUri .= (strpos($url, '?') !== false ? '&' : '?') . http_build_query($data, '', '&', PHP_QUERY_RFC3986); $result = json_decode(commonModel::http($requestUri, $data, array(CURLOPT_CUSTOMREQUEST => 'GET'), $header, 'json', 'GET', 20)); if($result && $result->code == 200) return $result; if($result) return $this->translateError($result); return $this->cneServerError(); } /** * 通过Post方式调用API。 * Post method of API. * * @param string $url * @param array|object $data * @param array $header example: array("key1:value1", "key2:value2") * @param string $host * @access public * @return object */ public function apiPost(string $url, array|object $data, array $header = array(), string $host = ''): object { $requestUri = ($host ? $host : $this->config->CNE->api->host) . $url; $result = json_decode(commonModel::http($requestUri, $data, array(CURLOPT_CUSTOMREQUEST => 'POST'), $header, 'json', 'POST', 20)); if($result && in_array($result->code, array(200, 201))) { $result->code = 200; return $result; } if($result) return $this->translateError($result); return $this->cneServerError(); } /** * 返回API服务器错误对象。 * Return error object of api server. * * @access protected * @return object */ protected function cneServerError(): object { $error = new stdclass(); $error->code = 600; $error->message = $this->lang->CNE->serverError; return $error; } /** * 翻译错误信息。 * Translate error message for multi language. * * @param object $apiResult * @access protected * @return object */ protected function translateError(object &$apiResult): object { $this->error->code = $apiResult->code; $this->error->message = zget($this->lang->CNE->errorList, $apiResult->code, $this->lang->CNE->serverError); // Translate CNE api error message to multi language. if($this->config->debug) { if(isset($apiResult->code)) $this->error->message .= " [{$apiResult->code}]:"; if(isset($apiResult->message)) $this->error->message .= " [{$apiResult->message}]"; } $apiResult->message = $this->error->message; return $this->error; } /** * app资源调度尝试。 * Try allocate for apps. * * @param array $apps * @access public * @return object */ public function tryAllocate(array $resources): object { $apiParams = new stdclass(); $apiParams->requests = $resources; $apiUrl = "/api/cne/system/resource/try-allocate"; return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); } /** * 升级禅道DevOps平台版。 * Upgrade the quickon system. * * @param string $edition oss|open|biz|max|ipd * @return object|false */ public function upgrade($edition = 'oss'): object|false { $numArgs = func_num_args(); if($numArgs == 0) $edition = $this->config->edition; if($edition == 'open') $edition = 'oss'; $version = $this->loadModel('system')->getLatestRelease(); if(!$version) return false; $apiParams = array( 'channel' => getenv('CLOUD_DEFAULT_CHANNEL') ?: 'stable', 'version' => $version->version, 'product' => $edition ); $apiUrl = "/api/cne/system/update"; return $this->apiPost($apiUrl, $apiParams, $this->config->CNE->api->headers); } /** * 获取备份的详细信息。 * Get backup detail. * * @param object $instance * @param string $backupName * @access public * @return object|false */ public function backupDetail(object $instance, string $backupName): object|false { if(empty($instance->k8name) || empty($instance->spaceData)) return false; $apiUrl = "/api/cne/app/backup/detail"; $apiParams = array('name' => $instance->k8name, 'namespace' => $instance->spaceData->k8space, 'backup_name' => $backupName); $result = $this->apiGet($apiUrl, $apiParams, $this->config->CNE->api->headers); if(empty($result) || $result->code != 200 || empty($result->data)) return false; return $result->data; } }