* @package instance * @version $Id$ * @link https://www.qucheng.com */ class instance extends control { /** * Construct function. * * @param string $moduleName * @param string $methodName * @access public * @return void */ public function __construct($moduleName = '', $methodName = '') { parent::__construct($moduleName, $methodName); $this->loadModel('action'); $this->loadModel('cne'); $this->loadModel('store'); } /** * Show instance view. * * @param int $id * @param int $recTotal * @param int $recPerPage * @param int $page * @access public * @return void */ public function view($id, $type = 'store', $tab ='baseinfo' ) { if(!commonModel::hasPriv('space', 'browse')) $this->loadModel('common')->deny('space', 'browse', false); if($type === 'store') { $this->storeView($id, $tab); } else { $instance = $this->loadModel('gitea')->getByID($id); $instance->status = ''; $instance->source = 'user'; $instance->externalID = $instance->id; $instance->runDuration = 0; $instance->appName = $instance->type; $instance->createdAt = $instance->createdDate; $instanceMetric = new stdclass(); $instanceMetric->cpu = 0; $instanceMetric->memory = 0; $this->view->title = $instance->name; $this->view->instance = $instance; $this->view->cloudApp = array(); $this->view->seniorAppList = array(); $this->view->actions = $this->loadModel('action')->getList($instance->type, $id); $this->view->defaultAccount = ''; $this->view->instanceMetric = $instanceMetric; $this->view->currentResource = ''; $this->view->customItems = array(); $this->view->backupList = array(); $this->view->hasRestoreLog = false; $this->view->latestBackup = array(); $this->view->dbList = array(); $this->view->domain = ''; } $this->view->users = $this->loadModel('user')->getPairs('noletter'); $this->view->tab = $tab; $this->view->type = $type; $this->display(); } /** * Show instance view. * * @param int $id * @param int $recTotal * @param int $recPerPage * @param int $page * @access public * @return void */ protected function storeView($id, $tab ='baseinfo' ) { if(!commonModel::hasPriv('space', 'browse')) $this->loadModel('common')->deny('space', 'browse', false); $this->loadModel('system'); $this->app->loadLang('system'); $instance = $this->instance->getByID($id); if(empty($instance)) return print(js::alert($this->lang->instance->instanceNotExists) . js::locate($this->createLink('space', 'browse'))); $instance->latestVersion = $this->store->appLatestVersion($instance->appID, $instance->version); $instance = $this->instance->freshStatus($instance); $instanceMetric = $this->cne->instancesMetrics(array($instance)); $instanceMetric = $instanceMetric[$instance->id]; $this->lang->switcherMenu = $this->instance->getSwitcher($instance); $backupList = array(); $latestBackup = new stdclass; if($tab == 'backup') $backupList = $this->instance->backupList($instance); if(count($backupList)) $latestBackup = reset($backupList); $hasRestoreLog = false; foreach($backupList as $backup) { $backup->latest_restore_time = 0; $backup->latest_restore_status = ''; foreach($backup->restores as $restore) { $hasRestoreLog = true; if($restore->create_time > $backup->latest_restore_time) { $backup->latest_restore_time = $restore->create_time; $backup->latest_restore_status = $restore->status; } } } $dbList = $this->cne->appDBList($instance); $currentResource = $this->cne->getAppConfig($instance); $customItems = $this->cne->getCustomItems($instance); if($instance->status == 'running') $this->instanceZen->saveAuthInfo($instance); if(in_array(strtolower($instance->appName), $this->config->instance->devopsApps)) { $url = strstr(getWebRoot(true), ':', true) . '://' . $instance->domain; $pipeline = $this->loadModel('pipeline')->getByUrl($url); $instance->externalID = $pipeline->id; } $this->view->title = $instance->appName; $this->view->instance = $instance; $this->view->cloudApp = $this->loadModel('store')->getAppInfoByChart($instance->chart, $instance->channel, false); $this->view->seniorAppList = $tab == 'baseinfo' ? $this->instance->seniorAppList($instance, $instance->channel) : array(); $this->view->actions = $this->loadModel('action')->getList('instance', $id); $this->view->defaultAccount = $this->cne->getDefaultAccount($instance); $this->view->instanceMetric = $instanceMetric; $this->view->currentResource = $currentResource; $this->view->customItems = $customItems; $this->view->backupList = $backupList; $this->view->hasRestoreLog = $hasRestoreLog; $this->view->latestBackup = $latestBackup; $this->view->dbList = $dbList; $this->view->domain = $this->cne->getDomain($instance); $this->view->tab = $tab; } /** * Display or save auto backup settings. * * @param int $instanceID * @access public * @return void */ public function backupSettings($instanceID) { $instance = $this->instance->getByID($instanceID); if($_POST) { $this->instance->saveAutoBackupSettings($instance); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $backupSettings = $this->instance->getAutoBackupSettings($instanceID); $startTime = strtotime($backupSettings->backupTime); if($startTime < time()) $startTime = strtotime("+1 day $backupSettings->backupTime"); if($backupSettings->autoBackup) { $startBackupMessage = sprintf($this->lang->instance->backup->firstStartTime, $instance->name, date('Y-m-d H:i:s', $startTime)); return $this->send(array('result' => 'success', 'message' => $startBackupMessage)); } return $this->send(array('result' => 'success', 'message' => $this->lang->instance->backup->disableAutoBackup)); } $backupSettings = $this->instance->getAutoBackupSettings($instanceID); $this->view->title = $this->lang->instance->backup->autoBackup; $this->view->instance = $instance; $this->view->backupSettings = $backupSettings; $this->display(); } /** * Display or save auto restore settings. * * @param int $instanceID * @access public * @return void */ public function restoreSettings($instanceID) { $instance = $this->instance->getByID($instanceID); if($_POST) { $this->instance->saveAutoRestoreSettings($instance); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $restoreSettings = $this->instance->getAutoRestoreSettings($instanceID); $startTime = strtotime($restoreSettings->restoreTime); if($startTime < time()) $startTime = strtotime("+1 day $restoreSettings->restoreTime"); if($restoreSettings->autoRestore) { $startRestoreMessage = sprintf($this->lang->instance->restore->firstStartTime, $instance->name, date('Y-m-d H:i:s', $startTime)); return $this->send(array('result' => 'success', 'message' => $startRestoreMessage)); } return $this->send(array('result' => 'success', 'message' => $this->lang->instance->restore->disableAutoRestore)); } $this->view->title = $this->lang->instance->restore->autoRestore; $this->view->instance = $instance; $this->view->restoreSettings = $this->instance->getAutoRestoreSettings($instanceID); $this->display(); } /** * Cron task of auto backup. * * @param string $key * @access public * @return void */ public function autoBackup($key) { if($this->config->instance->enableAutoRestore) return; // Only one of auto backup and auto restore can be enabled. $this->app->saveLog('Run auto backup at: ' . date('Y-md-d H:i:s')); if($key != helper::readKey()) return; $this->instance->autoBackup(); } /** * Cron task of auto restore. * * @param string $key * @access public * @return void */ public function autoRestore($key) { if(!$this->config->instance->enableAutoRestore) return; // Only one of auto backup and auto restore can be enabled. $this->app->saveLog('Run auto restore at: ' . date('Y-md-d H:i:s')); if($key != helper::readKey()) return; $this->instance->autoRestore(); } /** * Edit instance app name. * * @param int $id * @access public * @return void */ public function setting($id) { if(!commonModel::hasPriv('instance', 'manage')) $this->loadModel('common')->deny('instance', 'manage', false); $currentResource = new stdclass; $instance = $this->instance->getByID($id); $currentResource = $this->cne->getAppConfig($instance); if(!empty($_POST)) { $newInstance = fixer::input('post')->trim('name')->get(); $memoryKb = $newInstance->memory_kb; unset($newInstance->memory_kb); if(intval($currentResource->max->memory / 1024) != $memoryKb) { /* Check free memory size is enough or not. */ $clusterResource = $this->cne->cneMetrics(); $freeMemory = intval($clusterResource->metrics->memory->allocatable * 0.9); // Remain 10% memory for system. if($memoryKb * 1024 > $freeMemory) $this->send(array('result' => 'fail', 'message' => $this->lang->instance->errors->notEnoughResource)); /* Request CNE to adjust memory size. */ if(!$this->instance->updateMemorySize($instance, $memoryKb * 1024)) { $this->send(array('result' => 'fail', 'message' => dao::getError())); } } $this->instance->updateByID($id, $newInstance); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); if($newInstance->name != $instance->name) { $this->action->create('instance', $instance->id, 'editname', '', json_encode(array('result' => array('result' => 'success'), 'data' => array('oldName' => $instance->name, 'newName' => $newInstance->name)))); } return $this->send(array('result' => 'success', 'load' => true, 'closeModal' => true)); } $this->view->currentResource = $currentResource; $this->view->instance = $instance; $this->display(); } /** * Upgrade to senior serial. * * @param int $instanceID * @param int $seniorAppID * @param string $confirm * @access public * @return void */ public function toSenior($instanceID, $seniorAppID, $confirm = 'no') { $instance = $this->instance->getByID($instanceID); $cloudApp = $this->store->getAppInfo($seniorAppID, $instance->channel, false); if(empty($cloudApp)) return $this->send(array('result' => 'fail', 'message' => $this->lang->instance->errors->noAppInfo)); if($confirm == 'yes') { $success = $this->instance->upgradeToSenior($instance, $cloudApp); if($success) $this->send(array('result' => 'success', 'message' => '', 'locate' => $this->inLink('view', "id=$instance->id"))); $this->send(array('result' => 'fail', 'message' => dao::getError())); } $this->view->title = $this->lang->instance->upgradeToSenior; $this->view->instance = $instance; $this->view->cloudApp = $cloudApp; $this->display(); } /** * Upgrade instnace * * @param int $id * @access public * @return mixed */ public function upgrade($id) { if(!commonModel::hasPriv('instance', 'manage')) $this->loadModel('common')->deny('instance', 'manage', false); $instance = $this->instance->getByID($id); $instance->latestVersion = $this->store->appLatestVersion($instance->appID, $instance->version); if($_POST) { if(empty($instance->latestVersion)) return $this->send(array('result' => 'fail', 'message' => $this->lang->instance->noHigherVersion, 'closeModal' => true)); $postData = fixer::input('post')->get(); if($postData->confirm == 'yes') $success = $this->instance->upgrade($instance, $instance->latestVersion->version, $instance->latestVersion->app_version); $logExtra = array('result' => 'success', 'data' => array('oldVersion' => $instance->appVersion, 'newVersion' => $instance->latestVersion->app_version)); if(!$success) { $logExtra['result'] = 'fail'; $this->action->create('instance', $instance->id, 'upgrade', '', json_encode($logExtra)); return $this->send(array('result' => 'fail', 'message' => !empty($logExtra['message']) ? $logExtra['message'] : $this->lang->instance->notices['upgradeFail'], 'closeModal' => true)); } $this->action->create('instance', $instance->id, 'upgrade', '', json_encode($logExtra)); return $this->send(array('result' => 'success', 'message' => $this->lang->instance->notices['upgradeSuccess'], 'load' => $this->createLink('instance', 'view', "id=$id"), 'closeModal' => true)); } $this->view->title = $this->lang->instance->upgrade . $instance->name; $this->view->instance = $instance; $this->display(); } /** * 访问一个应用。 * Visit a app. * * @param int $id * @param int $externalID * @access public * @return void */ public function visit(int $id, int $externalID = 0): void { if(!commonModel::hasPriv('space', 'browse')) $this->loadModel('common')->deny('space', 'browse', false); if(!$externalID) { $instance = $this->instance->getByID($id); $url = $this->instance->url($instance); } else { $pipeline = $this->loadModel('pipeline')->getByID($externalID); $url = $pipeline->url; } $this->locate($url); } /** * 创建手工配置外部应用。 * Create a external app. * * @param string $type * @access public * @return viod */ public function createExternalApp(string $type) { if(!commonModel::hasPriv('instance', 'manage')) $this->loadModel('common')->deny('instance', 'manage', false); $this->app->loadModuleConfig('sonarqube'); $this->app->loadLang('pipeline'); $externalApp = form::data($this->config->sonarqube->form->create) ->add('type', $type) ->add('private',md5(rand(10,113450))) ->add('createdBy', $this->app->user->account) ->add('createdDate', helper::now()) ->trim('url,account,password') ->skipSpecial('url,token,account,password') ->remove('token,appType') ->get(); $externalApp->url = rtrim($externalApp->url, '/'); if(!$this->instance->checkAppNameUnique($externalApp->name)) return $this->send(array('result' => false, 'message' => array('name' => sprintf($this->lang->error->repeat, $this->lang->pipeline->name, $externalApp->name)))); $appID = $this->loadModel('pipeline')->create($externalApp); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $this->loadModel('action')->create($type, $appID, 'created'); return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('space', 'browse'))); } /** * 编辑手工配置外部应用。 * Edit a external app. * * @param int $externalID * @access public * @return viod */ public function editExternalApp(int $externalID) { if(!commonModel::hasPriv('instance', 'manage')) $this->loadModel('common')->deny('instance', 'manage', false); $oldApp = $this->loadModel('pipeline')->getByID($externalID); if($_POST) { $this->pipeline->update($externalID); $app = $this->pipeline->getByID($externalID); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); $this->loadModel('action'); $actionID = $this->action->create($app->type, $externalID, 'edited'); $changes = common::createChanges($oldApp, $app); $this->action->logHistory($actionID, $changes); return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => true, 'closeModal' => true)); } $this->app->loadLang('space'); $this->app->loadLang('sonarqube'); $this->view->app = $oldApp; $this->display(); } /** * 删除一个外部应用。 * Delete a external app. * * @param int $externalID * @access public * @return viod */ public function deleteExternalApp(int $externalID) { if(!commonModel::hasPriv('instance', 'manage')) $this->loadModel('common')->deny('instance', 'manage', false); $oldApp = $this->loadModel('pipeline')->getByID($externalID); $actionID = $this->pipeline->delete($externalID, $oldApp->type); if(!$actionID) { $response['result'] = 'fail'; $response['callback'] = sprintf('zui.Modal.alert("%s");', $this->lang->pipeline->delError); return $this->send($response); } $app = $this->pipeline->getByID($externalID); $changes = common::createChanges($oldApp, $app); $this->loadModel('action')->logHistory($actionID, $changes); $response['load'] = true; $response['message'] = zget($this->lang->instance->notices, 'uninstallSuccess'); $response['result'] = 'success'; return $this->send($response); } /** * (Not used at present.) Install app by custom settings. * * @param int $id * @access public * @return void */ public function customInstall($id) { // Disable custom installation in version 1.0. $storeUrl = $this->createLink('store', 'appview', "id=$id"); return js::execute("window.parent.location.href='{$storeUrl}';"); } /** * Install app. * * @param int $appID * @access public * @return void */ public function install($appID) { if(!commonModel::hasPriv('instance', 'manage')) $this->loadModel('common')->deny('instance', 'manage', false); $cloudApp = $this->store->getAppInfo($appID); if(empty($cloudApp)) return $this->send(array('result' => 'fail', 'message' => $this->lang->instance->errors->noAppInfo)); if(empty($this->config->demoAccounts)) { $clusterResource = $this->cne->cneMetrics(); $freeMemory = intval($clusterResource->metrics->memory->allocatable * 0.9); // Remain 10% memory for system. if($cloudApp->memory > $freeMemory) { $cloudApp = $cloudApp; $gapMemory = helper::formatKB(intval(($cloudApp->memory - $freeMemory))); $requiredMemory = helper::formatKB(intval($cloudApp->memory)); $freeMemory = helper::formatKB(intval($freeMemory)); return $this->send(array('result' => 'fail', 'message' => sprintf($this->lang->instance->errors->notEnoughMemory, $cloudApp->alias, $requiredMemory, $freeMemory, $gapMemory))); } } $versionList = $this->store->appVersionList($cloudApp->id); $mysqlList = $this->cne->sharedDBList('mysql'); $pgList = $this->cne->sharedDBList('postgresql'); if(!empty($_POST)) { $customData = fixer::input('post') ->trim('customName')->setDefault('customName', '') ->trim('customDomain')->setDefault('customDomain', '') ->trim('version')->setDefault('version', '') ->trim('dbType')->setDefault('dbType', 'unsharedDB') ->trim('dbService') ->setDefault('app_version', '') ->get(); if($customData->version && isset($versionList[$customData->version])) $customData->app_version = $versionList[$customData->version]->app_version; if(isset($this->config->instance->keepDomainList[$customData->customDomain]) || $this->instance->domainExists($customData->customDomain)) return $this->send(array('result' => 'fail', 'message' => $customData->customDomain . $this->lang->instance->errors->domainExists)); if(!$customData->customName) { dao::$errors['customName'] = sprintf($this->lang->error->notempty, $this->lang->instance->name); return $this->send(array('result' => 'fail', 'message' => dao::getError())); } if(!$this->instance->checkAppNameUnique($customData->customName)) return $this->send(array('result' => false, 'message' => array('customName' => sprintf($this->lang->error->repeat, $this->lang->instance->name, $customData->customName)))); if(!validater::checkLength($customData->customDomain, 20, 2)) return $this->send(array('result' => 'fail', 'message' => $this->lang->instance->errors->domainLength)); if(!validater::checkREG($customData->customDomain, '/^[a-z\d]+$/')) return $this->send(array('result' => 'fail', 'message' => $this->lang->instance->errors->wrongDomainCharacter)); /* If select the version, replace the latest version of App by selected version. */ if($customData->version) { $cloudApp->version = $customData->version; $cloudApp->app_version = $customData->app_version; } $sharedDB = new stdclass; if(isset($cloudApp->dependencies->mysql) && $customData->dbType == 'sharedDB') { $sharedDB = zget($mysqlList, $customData->dbService); } elseif(isset($cloudApp->dependencies->postgresql) && $customData->dbType == 'sharedDB') { $sharedDB = zget($pgList, $customData->dbService); } $instance = $this->instance->install($cloudApp, $sharedDB, $customData); if(!$instance) return $this->send(array('result' => 'fail', 'message' => $this->lang->instance->notices['installFail'])); unset($_GET['onlybody']); return $this->send(array('result' => 'success', 'message' => $this->lang->instance->notices['installSuccess'], 'load' => $this->createLink('instance', 'view', "id=$instance->id"), 'closeModal' => true)); } $this->lang->switcherMenu = $this->instance->getInstallSwitcher($cloudApp); $this->view->position[] = $this->view->title; $this->view->title = $this->lang->instance->install . $cloudApp->alias; $this->view->cloudApp = $cloudApp; $this->view->versionList = array(); foreach($versionList as $version) $this->view->versionList[$version->version] = $version->app_version . " ({$version->version})"; $this->view->thirdDomain = $this->instance->randThirdDomain(); $this->view->mysqlList = $this->instance->dbListToOptions($mysqlList); $this->view->pgList = $this->instance->dbListToOptions($pgList); $this->display(); } /** * Uninstall app instance. * * @param int $instanceID * @access public * @return void */ public function ajaxUninstall($instanceID, $type = '') { if(!commonModel::hasPriv('instance', 'manage')) $this->loadModel('common')->deny('instance', 'manage', false); if($type !== 'store') { $instance = $this->loadModel('pipeline')->getByID($instanceID); if(!$instance) return $this->send(array('result' => 'success', 'message' => $this->lang->instance->notices['success'], 'load' => $this->createLink('space', 'browse'))); if($instance->type == 'nexus') return $this->deleteExternalApp($instance->id); return $this->fetch($instance->type, 'delete', array('id' => $instance->id)); } $instance = $this->instance->getByID($instanceID); if(!$instance) return $this->send(array('result' => 'success', 'message' => $this->lang->instance->notices['success'], 'load' => $this->createLink('space', 'browse'))); $externalApp = $this->loadModel('space')->getExternalAppByApp($instance); if($externalApp) { $actionID = $this->loadModel('pipeline')->delete($externalApp->id, strtolower($instance->appName)); if(!$actionID) return $this->send(array('result' => 'fail', 'message' => $this->lang->pipeline->delError)); } $success = $this->instance->uninstall($instance); $this->action->create('instance', $instance->id, 'uninstall', '', json_encode(array('result' => $success, 'app' => array('alias' => $instance->appName, 'app_version' => $instance->version)))); if($success) return $this->send(array('result' => 'success', 'message' => zget($this->lang->instance->notices, 'uninstallSuccess'), 'load' => $this->createLink('space', 'browse'))); return $this->send(array('result' => 'fail', 'message' => zget($this->lang->instance->notices, 'uninstallFail'))); } /** * Start app instance. * * @param int $instanceID * @access public * @return void */ public function ajaxStart($instanceID) { if(!commonModel::hasPriv('instance', 'manage')) $this->loadModel('common')->deny('instance', 'manage', false); $instance = $this->instance->getByID($instanceID); if(!$instance) return $this->send(array('result' => 'fail', 'message' => $this->lang->instance->instanceNotExists)); $result = $this->instance->start($instance); $this->action->create('instance', $instance->id, 'start', '', json_encode(array('result' => $result, 'app' => array('alias' => $instance->appName, 'app_version' => $instance->version)))); if($result->code == 200) return $this->send(array('result' => 'success', 'load' => true, 'message' => zget($this->lang->instance->notices, 'startSuccess'))); return $this->send(array('result' => 'fail', 'message' => !empty($result->message) ? $result->message : zget($this->lang->instance->notices, 'startFail'))); } /** * Stop app instance. * * @param int $instanceID * @access public * @return void */ public function ajaxStop($instanceID) { if(!commonModel::hasPriv('instance', 'manage')) $this->loadModel('common')->deny('instance', 'manage', false); $instance = $this->instance->getByID($instanceID); if(!$instance) return $this->send(array('result' => 'fail', 'message' => $this->lang->instance->instanceNotExists)); $result = $this->instance->stop($instance); $this->action->create('instance', $instance->id, 'stop', '', json_encode(array('result' => $result, 'app' => array('alias' => $instance->appName, 'app_version' => $instance->version)))); if($result->code == 200) return $this->send(array('result' => 'success', 'load' => true, 'message' => zget($this->lang->instance->notices, 'stopSuccess'))); return $this->send(array('result' => 'fail', 'message' => !empty($result->message) ? $result->message : zget($this->lang->instance->notices, 'stopFail'))); } /** * Query status of app instance. * * @access public * @return void */ public function ajaxStatus() { if(!commonModel::hasPriv('space', 'browse')) $this->loadModel('common')->deny('space', 'browse', false); $postData = fixer::input('post')->setDefault('idList', array())->get(); $instances = $this->instance->getByIdList($postData->idList); $statusList = $this->instance->batchFresh($instances); return $this->send(array('result' => 'success', 'data' => $statusList)); } /** * Backup instnacd by ajax. * * @param int $instanceID * @access public * @return void */ public function ajaxBackup($instanceID) { $instance = $this->instance->getByID($instanceID); $success = $this->instance->backup($instance, $this->app->user); if(!$success) { $this->action->create('instance', $instance->id, 'backup', '', json_encode(array('result' => array('result' => 'fail')))); return $this->send(array('result' => 'fail', 'message' => zget($this->lang->instance->notices, 'backupFail'))); } $this->action->create('instance', $instance->id, 'backup', '', json_encode(array('result' => array('result' => 'success')))); return $this->send(array('result' => 'success', 'message' => zget($this->lang->instance->notices, 'backupSuccess'))); } /** * Restore instance by ajax * * @access public * @return void */ public function ajaxRestore() { $postData = fixer::input('post') ->trim('instanceID') ->trim('backupName')->get(); if(empty($postData->instanceID) || empty($postData->backupName)) return $this->send(array('result' => 'fail', 'message' => $this->lang->instance->wrongRequestData)); $instance = $this->instance->getByID($postData->instanceID); if(empty($instance))return print(js::alert($this->lang->instance->instanceNotExists) . js::locate($this->createLink('space', 'browse'))); $success = $this->instance->restore($instance, $this->app->user, $postData->backupName); if(!$success) { $this->action->create('instance', $instance->id, 'restore', '', json_encode(array('result' => array('result' => 'fail')))); return $this->send(array('result' => 'fail', 'message' => zget($this->lang->instance->notices, 'restoreFail'))); } $this->action->create('instance', $instance->id, 'restore', '', json_encode(array('result' => array('result' => 'success')))); return $this->send(array('result' => 'success', 'message' => zget($this->lang->instance->notices, 'restoreSuccess'))); } /** * Delete backup by ajax. * * @param int $backupID * @access public * @return void */ public function ajaxDeleteBackup($backupID) { $success = $this->instance->deleteBackup($backupID, $this->app->user); if(!$success) return $this->send(array('result' => 'fail', 'message' => zget($this->lang->instance->notices, 'deleteFail'))); return $this->send(array('result' => 'success', 'message' => zget($this->lang->instance->notices, 'deleteSuccess'))); } /** * Generate database auth parameters and jump to login page. * * @access public * @return void */ public function ajaxDBAuthUrl() { if(!commonModel::hasPriv('space', 'browse')) $this->loadModel('common')->deny('space', 'browse', false); $post = fixer::input('post') ->setDefault('namespace', 'default') ->setDefault('instanceID', 0) ->setDefault('dbType', '') ->get(); if(empty($post->dbName)) return $this->send(array('result' => 'fail', 'message' => $this->lang->instance->errors->dbNameIsEmpty)); $instance = $this->instance->getByID($post->instanceID); if(empty($instance)) return $this->send(array('result' => 'fail', 'message' => $this->lang->instance->instanceNotExists)); $detail = $this->loadModel('cne')->appDBDetail($instance, $post->dbName); if(empty($detail)) return $this->send(array('result' => 'fail', 'message' => $this->lang->instance->errors->notFoundDB)); $dbAuth = array(); $dbAuth['driver'] = zget($this->config->instance->adminer->dbTypes, $post->dbType, ''); $dbAuth['server'] = $detail->host . ':' . $detail->port; $dbAuth['username'] = $detail->username; $dbAuth['db'] = $detail->database; $dbAuth['password'] = $detail->password; $url = '/adminer?' . http_build_query($dbAuth); $this->send(array('result' => 'success', 'message' => '', 'data' => array('url' => $url))); } /** * Adjust instance memory size by ajax. * * @param int $instanceID * @access public * @return void */ public function ajaxAdjustMemory($instanceID) { if(!commonModel::hasPriv('instance', 'manage')) $this->loadModel('common')->deny('instance', 'manage', false); $postData = fixer::input('post')->get(); /* Check free memory size is enough or not. */ $clusterResource = $this->cne->cneMetrics(); $freeMemory = intval($clusterResource->metrics->memory->allocatable * 0.9); // Remain 10% memory for system. if($postData->memory_kb * 1024 > $freeMemory) $this->send(array('result' => 'fail', 'message' => $this->lang->instance->errors->notEnoughResource)); /* Request CNE to adjust memory size. */ $instance = $this->instance->getByID($instanceID); if(!$this->instance->updateMemorySize($instance, $postData->memory_kb * 1024)) { $this->send(array('result' => 'fail', 'message' => dao::getError())); } $this->send(array('result' => 'success', 'message' => '')); } /** * Switch LDAP between enable and disable by ajax. * * @param int $instanceID * @access public * @return void */ public function ajaxSwitchLDAP($instanceID) { $instance = $this->instance->getByID($instanceID); $postData = fixer::input('post')->get(); if($this->instance->switchLDAP($instance, $postData->enableLDAP == 'true')) { $this->send(array('result' => 'success', 'message' => '')); } $this->send(array('result' => 'fail', 'message' => $this->lang->instance->errors->switchLDAPFailed)); } /** * Switch SMTP between enable and disable by ajax. * * @param int $instanceID * @access public * @return void */ public function ajaxSwitchSMTP($instanceID) { $instance = $this->instance->getByID($instanceID); $postData = fixer::input('post')->get(); if($this->instance->switchSMTP($instance, $postData->enableSMTP == 'true')) { $this->send(array('result' => 'success', 'message' => '')); } $this->send(array('result' => 'fail', 'message' => $this->lang->instance->errors->switchSMTPFailed)); } /** * Update custom settings by ajax. For example: env variables. * * @param int $instanceID * @access public * @return void */ public function ajaxUpdateCustom($instanceID) { $instance = $this->instance->getByID($instanceID); if(!$instance) $this->send(array('result' => 'fail', 'message' => $this->lang->instance->instanceNotExists)); $postData = fixer::input('post')->get(); $settings = new stdclass; $settings->force_restart = true; $settings->settings_map = new stdclass; $settings->settings_map->custom = $postData; if($this->cne->updateConfig($instance, $settings)) { $this->action->create('instance', $instanceID, 'updatecustom', '', json_encode($settings)); $this->send(array('result' => 'success', 'message' => '')); } $this->send(array('result' => 'fail', 'message' => $this->lang->instance->errors->setEnvFailed)); } /** * Delete expired demo instance by cron. * * @access public * @return void */ public function deleteExpiredDemoInstance() { if(empty($this->config->demoAccounts)) return $this->send(array('result' => 'fail', 'message' => 'This api is only for demo enviroment.')); $this->instance->deleteExpiredDemoInstance(); $this->send(array('result' => 'success', 'message' => '')); } /** * Get instance info for q tool in console. * * @param int $id * @access public * @return mixed */ public function apiDetail($id) { if(!$this->checkCneToken()) { helper::setStatus(401); return print(json_encode(array('code' => 401, 'message' => 'Invalid token.'))); } if(empty($id)) return print(json_encode(array('code' => 401, 'message' => 'Invalid id.'))); $instance = $this->instance->getByID($id); if(empty($instance)) return print(json_encode(array('code' => 404, 'message' => 'Not found.', 'data' => array()))); $instance->space = $instance->spaceData && isset($instance->spaceData->k8space) ? $instance->spaceData->k8space : ''; unset($instance->desc); unset($instance->spaceData); return print(json_encode(array('code' => 200, 'message' => 'success', 'data' => $instance))); } /** * Get instances list by account through api for q tool. * * @access public * @return void */ public function apiBrowse() { if(!$this->checkCneToken()) { helper::setStatus(401); return print(json_encode(array('code' => 401, 'message' => 'Invalid token.'))); } $requestBody = json_decode(file_get_contents("php://input")); $account = zget($requestBody, 'account', ''); if(empty($account)) return print(json_encode(array('code' => 700, 'message' => 'Account is required.', 'data' => new stdclass))); $recPerPage = zget($requestBody, 'perPage', 20); $pageID = zget($requestBody, 'page', 1); $this->app->loadClass('pager', true); $pager = pager::init(0, $recPerPage, $pageID); $instanceList = $this->instance->getByAccount($account, $pager); $result = new stdclass; $result->list = $instanceList; $result->page = $pageID; $result->perPage = $recPerPage; $result->pageTotal = $pager->pageTotal; $result->total = $pager->recTotal; return print(json_encode(array('code' => 200, 'message' => 'success', 'data' => $result))); } /** * Install app by api for q tool. * * @access public * @return void */ public function apiInstall() { if(!$this->checkCneToken()) { helper::setStatus(401); return print(json_encode(array('code' => 401, 'message' => 'Invalid token.'))); } $requestBody = json_decode(file_get_contents("php://input")); $chart = zget($requestBody , 'chart', ''); if(empty($chart)) return print(json_encode(array('code' => 701, 'message' => 'Param chart is required.'))); $user = null; $account = zget($requestBody, 'account', ''); if($account) $user = $this->loadModel('user')->getById($account); if(empty($user)) $user = $this->loadModel('company')->getAdmin(); if(empty($user)) return print(json_encode(array('code' => 703, 'message' => 'No user.'))); $this->app->user = $user; $name = zget($requestBody , 'name', ''); $channel = zget($requestBody , 'channel', 'stable'); $k8name = zget($requestBody , 'k8name', ''); if($k8name && $this->instance->k8nameExists($k8name)) return print(json_encode(array('code' => 706, 'message' => $k8name . ' has been used, please change it and try again.'))); $thirdDomain = zget($requestBody , 'domain', ''); if($this->instance->domainExists($thirdDomain)) return print(json_encode(array('code' => 705, 'message' => $thirdDomain . ' has been used, please change it and try again.'))); $cloudApp = $this->store->getAppInfoByChart($chart, $channel, false); if(empty($cloudApp)) return print(json_encode(array('code' => 702, 'message' => 'App not found.'))); $result = $this->instance->apiInstall($cloudApp, $thirdDomain, $name, $k8name, $channel); if($result) return print(json_encode(array('code' => 200, 'message' => 'success', 'data' => new stdclass))); return print(json_encode(array('code' => 704, 'message' => 'Fail to install app.', 'data' => new stdclass))); } /** * Check CNE token. * * @access private * @return bool */ private function checkCneToken() { $token = zget($_SERVER, 'HTTP_TOKEN'); return $token == $this->config->CNE->api->token; } }