- [refactor] remove solution module

This commit is contained in:
liyang
2025-06-20 15:12:07 +08:00
parent e8fef71036
commit 46d753cab7
31 changed files with 8 additions and 1561 deletions
-2
View File
@@ -621,7 +621,6 @@ define('TABLE_METRICRECORDS', '`' . $config->db->prefix . 'metricrecords`');
define('TABLE_SPACE', '`' . $config->db->prefix . 'space`');
define('TABLE_INSTANCE', '`' . $config->db->prefix . 'instance`');
define('TABLE_SOLUTION', '`' . $config->db->prefix . 'solution`');
define('TABLE_ARTIFACTREPO', '`' . $config->db->prefix . 'artifactrepo`');
define('TABLE_AI_PROMPT', '`' . $config->db->prefix . 'ai_prompt`');
@@ -723,7 +722,6 @@ $config->objectTables['serverroom'] = TABLE_SERVERROOM;
$config->objectTables['host'] = TABLE_ZAHOST;
$config->objectTables['instance'] = TABLE_INSTANCE;
$config->objectTables['space'] = TABLE_SPACE;
$config->objectTables['solution'] = TABLE_SOLUTION;
$config->objectTables['artifactrepo'] = TABLE_ARTIFACTREPO;
$config->objectTables['metric'] = TABLE_METRIC;
$config->objectTables['cron'] = TABLE_CRON;
+2
View File
@@ -21,3 +21,5 @@ ALTER TABLE `zt_compile` ADD `branch` varchar(255) NOT NULL DEFAULT '' AFTER `st
ALTER TABLE `zt_doc`
ADD `templateDesc` text NULL AFTER `templateType`,
ADD `builtIn` enum('0','1') NOT NULL DEFAULT '0' AFTER `version`;
DROP TABLE IF EXISTS `zt_solution`;
-23
View File
@@ -15668,29 +15668,6 @@ CREATE TABLE IF NOT EXISTS `zt_instance` (
KEY `k8name` (`k8name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- DROP TABLE IF EXISTS `zt_solution`;
CREATE TABLE IF NOT EXISTS `zt_solution` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`name` char(50) NOT NULL DEFAULT '',
`appID` mediumint(8) unsigned NOT NULL DEFAULT 0,
`appName` char(50) NOT NULL DEFAULT '',
`appVersion` char(20) NOT NULL DEFAULT '',
`version` char(50) NOT NULL DEFAULT '',
`chart` char(50) NOT NULL DEFAULT '',
`cover` varchar(255) NOT NULL DEFAULT '',
`desc` text NULL,
`introduction` varchar(255) NOT NULL DEFAULT '',
`source` char(20) NOT NULL DEFAULT '',
`channel` char(20) NOT NULL DEFAULT '',
`components` text NULL,
`status` char(20) NOT NULL DEFAULT '',
`deleted` tinyint(1) NOT NULL DEFAULT 0,
`createdBy` char(30) NOT NULL DEFAULT '',
`createdAt` datetime NULL,
`updatedDate` datetime NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- DROP TABLE IF EXISTS `zt_demandpool`;
CREATE TABLE IF NOT EXISTS `zt_demandpool` (
`id` int(8) NOT NULL AUTO_INCREMENT,
-127
View File
@@ -455,133 +455,6 @@ class install extends control
$this->display();
}
/**
* 展示应用安装进度。
* Show installation progress of solution.
*
* @param int $id
* @param bool $startInstall
* @access public
* @return void
*/
public function progress(int $id, bool $startInstall = false)
{
$solution = $this->loadModel('solution')->getByID($id);
$this->view->title = $this->lang->solution->progress;
$this->view->solution = $solution;
$this->view->startInstall = $startInstall;
$this->app->loadConfig('message');
$this->config->message->browser->turnon = 0;
$this->display();
}
/**
* 获取安装进度。
* AJAX: Get installing progress of solution.
*
* @param int $id
* @access public
* @return void
*/
public function ajaxProgress(int $id)
{
$this->loadModel('common');
$solution = $this->loadModel('solution')->getByID($id);
$result = 'success';
$message = '';
$logs = array();
if($solution->status == 'installed') return $this->send(array('result' => $result, 'message' => $message, 'data' => json_decode($solution->components), 'logs' => $logs));
if($solution->status != 'installing')
{
$result = 'fail';
$message = zget($this->lang->solution->installationErrors, $solution->status, $this->lang->solution->errors->hasInstallationError);
return $this->send(array('result' => $result, 'message' => $message, 'data' => json_decode($solution->components), 'logs' => $logs));
}
if((time() - strtotime($solution->updatedDate)) > 60 * 20)
{
$this->solution->saveStatus($id, 'timeout');
$result = 'fail';
$message = $this->lang->solution->errors->timeout;
return $this->send(array('result' => $result, 'message' => $message, 'data' => json_decode($solution->components), 'logs' => $logs));
}
$components = json_decode($solution->components);
foreach($components as $componentApp)
{
if($componentApp->status != 'installing') continue;
$instance = $this->loadModel('instance')->instanceOfSolution($solution, $componentApp->chart);
if(!$instance) continue;
$chartLogs = $this->loadModel('cne')->getAppLogs($instance);
$logs[$componentApp->chart] = !empty($chartLogs->data) ? $chartLogs->data : array();
}
return $this->send(array('result' => $result, 'message' => $message, 'data' => json_decode($solution->components), 'logs' => $logs));
}
/**
* 安装应用。
* AJAX: Start install.
*
* @param int $solutionID
* @access public
* @return void
*/
public function ajaxInstall(int $solutionID)
{
$this->loadModel('solution')->install($solutionID);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
return $this->send(array('result' => 'success', 'message' => '', 'locate' => $this->inLink('step6')));
}
/**
* 取消安装时卸载应用。
* AJAX: Uninstall app.
*
* @param int $solutionID
* @access public
* @return void
*/
public function ajaxUninstall(int $solutionID)
{
$this->loadModel('common');
$this->loadModel('solution')->uninstall($solutionID);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
return $this->send(array('result' => 'success', 'message' => '', 'load' => $this->inLink('app')));
}
/**
* 检查内存与CPU是否满足安装所需。
* AJAX: Check memory and cpu.
*
* @access public
* @return void
*/
public function ajaxCheck()
{
$this->loadModel('common');
$apps = (array)$this->post->apps;
foreach($apps as $index => $app)
{
if($app == $this->lang->install->solution->skipInstall) unset($apps[$index]);
}
$appMap = $this->loadModel('store')->getAppMapByNames($apps);
$resources = array();
foreach($apps as $app) $resources[] = array('cpu' => $appMap->$app->cpu, 'memory' => $appMap->$app->memory);
$result = $this->loadModel('cne')->tryAllocate($resources);
return $this->send(array('result' => 'success', 'message' => '', 'code' => $result->code));
}
/**
* 安装DuckDB引擎界面。
* Install duckdb.
-30
View File
@@ -45,7 +45,6 @@ class instanceModel extends model
if(!$instance) return null;
$instance->spaceData = $this->dao->select('*')->from(TABLE_SPACE)->where('id')->eq($instance->space)->fetch();
if($instance->solution) $instance->solutionData = $this->dao->select('*')->from(TABLE_SOLUTION)->where('id')->eq($instance->solution)->fetch();
return $instance;
}
@@ -98,34 +97,9 @@ class instanceModel extends model
$spaces = $this->dao->select('*')->from(TABLE_SPACE)->where('deleted')->eq(0)->andWhere('id')->in(helper::arrayColumn($instances, 'space'))->fetchAll('id');
foreach($instances as $instance) $instance->spaceData = zget($spaces, $instance->space, new stdclass);
$solutionIDList = helper::arrayColumn($instances, 'solution');
$solutions = $this->dao->select('*')->from(TABLE_SOLUTION)->where('id')->in($solutionIDList)->fetchAll('id');
foreach($instances as $instance) $instance->solutionData = zget($solutions, $instance->solution, new stdclass);
return $instances;
}
/**
* 根据解决方案ID获取应用实例列表。
* Get instance list by solution.
*
* @param object $solution
* @param string $chart
* @access public
* @return object|null
*/
public function instanceOfSolution(object $solution, string $chart): object|null
{
$instance = $this->dao->select('id')->from(TABLE_INSTANCE)->where('deleted')->eq(0)
->andWhere('solution')->eq($solution->id)
->andWhere('chart')->eq($chart)
->fetch();
if($instance) return $this->getByID($instance->id);
return null;
}
/**
* 获取应用实例列表。
* Get instances list.
@@ -159,10 +133,6 @@ class instanceModel extends model
foreach($instances as $instance) $instance->spaceData = zget($spaces, $instance->space, new stdclass);
$solutionIDList = helper::arrayColumn($instances, 'solution');
$solutions = $this->dao->select('*')->from(TABLE_SOLUTION)->where('id')->in($solutionIDList)->fetchAll('id');
foreach($instances as $instance) $instance->solutionData = zget($solutions, $instance->solution, new stdclass);
return $instances;
}
+1 -5
View File
@@ -22,7 +22,6 @@ cid=1
- 属性name @默认空间1
- 查看获取到的第一条instance的solution
- 属性id @1
- 属性name @解决方案1
- 查看获取到的第二条instance
- 属性id @2
- 属性name @禅道开源版
@@ -32,7 +31,6 @@ cid=1
- 属性name @默认空间2
- 查看获取到的第二条instance的solution
- 属性id @2
- 属性name @解决方案2
- 查看不存在的instance @0
*/
@@ -43,12 +41,10 @@ $tester->loadModel('instance');
$instance = $tester->instance->getByID(1);
r($instance) && p('id,name,chart') && e('1,Subversion,subversion'); // 查看获取到的第一条instance
r($instance->spaceData) && p('id,name') && e('1,默认空间1'); // 查看获取到的第一条instance的space
r($instance->solutionData) && p('id,name') && e('1,解决方案1'); // 查看获取到的第一条instance的solution
$instance = $tester->instance->getByID(2);
r($instance) && p('id,name,chart') && e('2,禅道开源版,zentao'); // 查看获取到的第二条instance
r($instance->spaceData) && p('id,name') && e('2,默认空间2'); // 查看获取到的第二条instance的space
r($instance->solutionData) && p('id,name') && e('2,解决方案2'); // 查看获取到的第二条instance的solution
$instance = $tester->instance->getByID(10000);
r($instance) && p('') && e('0'); // 查看不存在的instance
r($instance) && p('') && e('0'); // 查看不存在的instance
@@ -32,15 +32,6 @@ cid=1
- 查看获取到的第三条instance的space的id和name
- 属性id @3
- 属性name @默认空间3
- 查看获取到的第一条instance的solution的id和name
- 属性id @1
- 属性name @解决方案1
- 查看获取到的第二条instance的solution的id和name
- 属性id @2
- 属性name @解决方案2
- 查看获取到的第三条instance的solution的id和name
- 属性id @3
- 属性name @解决方案3
*/
@@ -57,7 +48,3 @@ r($instance) && p('3:id,name') && e('3,adminer'); // 查看获取到的第三
r($instance[1]->spaceData) && p('id,name') && e('1,默认空间1'); // 查看获取到的第一条instance的space的id和name
r($instance[2]->spaceData) && p('id,name') && e('2,默认空间2'); // 查看获取到的第二条instance的space的id和name
r($instance[3]->spaceData) && p('id,name') && e('3,默认空间3'); // 查看获取到的第三条instance的space的id和name
r($instance[1]->solutionData) && p('id,name') && e('1,解决方案1'); // 查看获取到的第一条instance的solution的id和name
r($instance[2]->solutionData) && p('id,name') && e('2,解决方案2'); // 查看获取到的第二条instance的solution的id和name
r($instance[3]->solutionData) && p('id,name') && e('3,解决方案3'); // 查看获取到的第三条instance的solution的id和name
@@ -1,65 +0,0 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . '/test/lib/init.php';
su('admin');
zenData('instance')->gen(5);
zenData('space')->gen(5);
zenData('solution')->gen(5);
/**
title=instanceModel->instanceOfSolution();
timeout=0
cid=1
- 查看获取到的第一条instance
- 属性id @1
- 属性name @Subversion
- 属性chart @subversion
- 查看获取到的第一条instance的space
- 属性id @1
- 属性name @默认空间1
- 查看获取到的第一条instance的solution
- 属性id @1
- 属性name @解决方案1
- 查看获取到的第二条instance
- 属性id @2
- 属性name @禅道开源版
- 属性chart @zentao
- 查看获取到的第二条instance的space
- 属性id @2
- 属性name @默认空间2
- 查看获取到的第二条instance的solution
- 属性id @2
- 属性name @解决方案2
- 查看不存在的instance @0
- 查看不存在的instance @0
*/
global $tester;
$tester->loadModel('instance');
$solution = new stdclass();
$solution->id = 1;
$instance = $tester->instance->instanceOfSolution($solution, 'subversion');
r($instance) && p('id,name,chart') && e('1,Subversion,subversion'); // 查看获取到的第一条instance
r($instance->spaceData) && p('id,name') && e('1,默认空间1'); // 查看获取到的第一条instance的space
r($instance->solutionData) && p('id,name') && e('1,解决方案1'); // 查看获取到的第一条instance的solution
$solution->id = 2;
$instance = $tester->instance->instanceOfSolution($solution, 'zentao');
r($instance) && p('id,name,chart') && e('2,禅道开源版,zentao'); // 查看获取到的第二条instance
r($instance->spaceData) && p('id,name') && e('2,默认空间2'); // 查看获取到的第二条instance的space
r($instance->solutionData) && p('id,name') && e('2,解决方案2'); // 查看获取到的第二条instance的solution
$solution->id = 10000;
$instance = $tester->instance->instanceOfSolution($solution, '');
r($instance) && p() && e('0'); // 查看不存在的instance
$solution->id = 3;
$instance = $tester->instance->instanceOfSolution($solution, 'qucheng');
r($instance) && p() && e('0'); // 查看不存在的instance
-5
View File
@@ -1,5 +0,0 @@
<?php
$config->solution = new stdclass();
$config->solution->gitlab = new stdclass();
$config->solution->gitlab->minCompatibleVersion = '9.0';
-66
View File
@@ -1,66 +0,0 @@
<?php
$lang->solution->market = new stdclass;
$lang->solution->market->browse = 'Solution Market';
$lang->solution->market->view = 'Solution Detail';
$lang->solution->name = 'Name';
$lang->solution->browse = 'Installed';
$lang->solution->view = 'Solution Detail';
$lang->solution->detail = 'Detail';
$lang->solution->progress = 'Progress';
$lang->solution->install = 'Install';
$lang->solution->background = 'Background';
$lang->solution->cancelInstall = 'Cancel';
$lang->solution->uninstall = 'Uninstall';
$lang->solution->retryInstall = 'Retry';
$lang->solution->nextStep = 'Next';
$lang->solution->config = 'Config';
$lang->solution->introduction = 'Introduction';
$lang->solution->scenes = 'Scenes';
$lang->solution->diagram = 'Diagram';
$lang->solution->includedApp = 'Included App';
$lang->solution->features = 'Features';
$lang->solution->relatedLinks = 'Related Links';
$lang->solution->customers = 'Customers';
$lang->solution->apps = 'Installed Apps';
$lang->solution->externalApps = 'External Apps';
$lang->solution->resources = 'Resources';
$lang->solution->editName = 'Edit Name';
$lang->solution->chooseApp = 'Choose App';
$lang->solution->noInstalledSolution = 'No installed solution';
$lang->solution->toInstall = 'To Install';
$lang->solution->notices = new stdclass;
$lang->solution->notices->fail = 'Fail';
$lang->solution->notices->success = 'Success';
$lang->solution->notices->creatingSolution = 'Creating solution...';
$lang->solution->notices->uninstallingSolution = 'Uninstalling solution...';
$lang->solution->notices->installingApp = 'Installing: ';
$lang->solution->notices->installationSuccess = 'Installation success!';
$lang->solution->notices->cancelInstall = 'Are you sure to cancel installation?';
$lang->solution->notices->confirmToUninstall = 'Are you sure to uninstall?';
$lang->solution->notices->confirmReinstall = 'Are you sure to retry installation?';
$lang->solution->errors = new stdclass;
$lang->solution->errors->error = 'Error';
$lang->solution->errors->notFound = 'Not found';
$lang->solution->errors->failToInstallApp = 'Fail to install %s';
$lang->solution->errors->timeout = 'Timeout';
$lang->solution->errors->failToUninstallApp = 'Fail to uninstall %s';
$lang->solution->errors->hasInstallationError = 'Has installation error';
$lang->solution->errors->notFoundAppByVersion = 'Not found %s version of %s';
$lang->solution->errors->notEnoughResource = 'Not enough resource, please increase the configuration or release other resources and try again.';
$lang->solution->installationErrors = array();
$lang->solution->installationErrors['waiting'] = 'Installation not started.';
$lang->solution->installationErrors['installing'] = 'Installing.';
$lang->solution->installationErrors['installed'] = 'Installed';
$lang->solution->installationErrors['uninstalling'] = 'Installation canceled.';
$lang->solution->installationErrors['cneError'] = 'Installation failed.';
$lang->solution->installationErrors['timeout'] = 'Installation timeout.';
$lang->solution->installationErrors['notFoundApp'] = 'Not found app to be installed.';
$lang->solution->installationErrors['notEnoughResource'] = 'Not enough resource, please increase the configuration or release other resources and try again.';
-66
View File
@@ -1,66 +0,0 @@
<?php
$lang->solution->market = new stdclass;
$lang->solution->market->browse = 'Solution Market';
$lang->solution->market->view = 'Solution Detail';
$lang->solution->name = 'Name';
$lang->solution->browse = 'Installed';
$lang->solution->view = 'Solution Detail';
$lang->solution->detail = 'Detail';
$lang->solution->progress = 'Progress';
$lang->solution->install = 'Install';
$lang->solution->background = 'Background';
$lang->solution->cancelInstall = 'Cancel';
$lang->solution->uninstall = 'Uninstall';
$lang->solution->retryInstall = 'Retry';
$lang->solution->nextStep = 'Next';
$lang->solution->config = 'Config';
$lang->solution->introduction = 'Introduction';
$lang->solution->scenes = 'Scenes';
$lang->solution->diagram = 'Diagram';
$lang->solution->includedApp = 'Included App';
$lang->solution->features = 'Features';
$lang->solution->relatedLinks = 'Related Links';
$lang->solution->customers = 'Customers';
$lang->solution->apps = 'Installed Apps';
$lang->solution->externalApps = 'External Apps';
$lang->solution->resources = 'Resources';
$lang->solution->editName = 'Edit Name';
$lang->solution->chooseApp = 'Choose App';
$lang->solution->noInstalledSolution = 'No installed solution';
$lang->solution->toInstall = 'To Install';
$lang->solution->notices = new stdclass;
$lang->solution->notices->fail = 'Fail';
$lang->solution->notices->success = 'Success';
$lang->solution->notices->creatingSolution = 'Creating solution...';
$lang->solution->notices->uninstallingSolution = 'Uninstalling solution...';
$lang->solution->notices->installingApp = 'Installing: ';
$lang->solution->notices->installationSuccess = 'Installation success!';
$lang->solution->notices->cancelInstall = 'Are you sure to cancel installation?';
$lang->solution->notices->confirmToUninstall = 'Are you sure to uninstall?';
$lang->solution->notices->confirmReinstall = 'Are you sure to retry installation?';
$lang->solution->errors = new stdclass;
$lang->solution->errors->error = 'Error';
$lang->solution->errors->notFound = 'Not found';
$lang->solution->errors->failToInstallApp = 'Fail to install %s';
$lang->solution->errors->timeout = 'Timeout';
$lang->solution->errors->failToUninstallApp = 'Fail to uninstall %s';
$lang->solution->errors->hasInstallationError = 'Has installation error';
$lang->solution->errors->notFoundAppByVersion = 'Not found %s version of %s';
$lang->solution->errors->notEnoughResource = 'Not enough resource, please increase the configuration or release other resources and try again.';
$lang->solution->installationErrors = array();
$lang->solution->installationErrors['waiting'] = 'Installation not started.';
$lang->solution->installationErrors['installing'] = 'Installing.';
$lang->solution->installationErrors['installed'] = 'Installed';
$lang->solution->installationErrors['uninstalling'] = 'Installation canceled.';
$lang->solution->installationErrors['cneError'] = 'Installation failed.';
$lang->solution->installationErrors['timeout'] = 'Installation timeout.';
$lang->solution->installationErrors['notFoundApp'] = 'Not found app to be installed.';
$lang->solution->installationErrors['notEnoughResource'] = 'Not enough resource, please increase the configuration or release other resources and try again.';
-66
View File
@@ -1,66 +0,0 @@
<?php
$lang->solution->market = new stdclass;
$lang->solution->market->browse = 'Solution Market';
$lang->solution->market->view = 'Solution Detail';
$lang->solution->name = 'Name';
$lang->solution->browse = 'Installed';
$lang->solution->view = 'Solution Detail';
$lang->solution->detail = 'Detail';
$lang->solution->progress = 'Progress';
$lang->solution->install = 'Install';
$lang->solution->background = 'Background';
$lang->solution->cancelInstall = 'Cancel';
$lang->solution->uninstall = 'Uninstall';
$lang->solution->retryInstall = 'Retry';
$lang->solution->nextStep = 'Next';
$lang->solution->config = 'Config';
$lang->solution->introduction = 'Introduction';
$lang->solution->scenes = 'Scenes';
$lang->solution->diagram = 'Diagram';
$lang->solution->includedApp = 'Included App';
$lang->solution->features = 'Features';
$lang->solution->relatedLinks = 'Related Links';
$lang->solution->customers = 'Customers';
$lang->solution->apps = 'Installed Apps';
$lang->solution->externalApps = 'External Apps';
$lang->solution->resources = 'Resources';
$lang->solution->editName = 'Edit Name';
$lang->solution->chooseApp = 'Choose App';
$lang->solution->noInstalledSolution = 'No installed solution';
$lang->solution->toInstall = 'To Install';
$lang->solution->notices = new stdclass;
$lang->solution->notices->fail = 'Fail';
$lang->solution->notices->success = 'Success';
$lang->solution->notices->creatingSolution = 'Creating solution...';
$lang->solution->notices->uninstallingSolution = 'Uninstalling solution...';
$lang->solution->notices->installingApp = 'Installing: ';
$lang->solution->notices->installationSuccess = 'Installation success!';
$lang->solution->notices->cancelInstall = 'Are you sure to cancel installation?';
$lang->solution->notices->confirmToUninstall = 'Are you sure to uninstall?';
$lang->solution->notices->confirmReinstall = 'Are you sure to retry installation?';
$lang->solution->errors = new stdclass;
$lang->solution->errors->error = 'Error';
$lang->solution->errors->notFound = 'Not found';
$lang->solution->errors->failToInstallApp = 'Fail to install %s';
$lang->solution->errors->timeout = 'Timeout';
$lang->solution->errors->failToUninstallApp = 'Fail to uninstall %s';
$lang->solution->errors->hasInstallationError = 'Has installation error';
$lang->solution->errors->notFoundAppByVersion = 'Not found %s version of %s';
$lang->solution->errors->notEnoughResource = 'Not enough resource, please increase the configuration or release other resources and try again.';
$lang->solution->installationErrors = array();
$lang->solution->installationErrors['waiting'] = 'Installation not started.';
$lang->solution->installationErrors['installing'] = 'Installing.';
$lang->solution->installationErrors['installed'] = 'Installed';
$lang->solution->installationErrors['uninstalling'] = 'Installation canceled.';
$lang->solution->installationErrors['cneError'] = 'Installation failed.';
$lang->solution->installationErrors['timeout'] = 'Installation timeout.';
$lang->solution->installationErrors['notFoundApp'] = 'Not found app to be installed.';
$lang->solution->installationErrors['notEnoughResource'] = 'Not enough resource, please increase the configuration or release other resources and try again.';
-66
View File
@@ -1,66 +0,0 @@
<?php
$lang->solution->market = new stdclass;
$lang->solution->market->browse = '解决方案市场';
$lang->solution->market->view = '解决方案详情';
$lang->solution->name = '名称';
$lang->solution->browse = '已安装';
$lang->solution->view = '解决方案详情';
$lang->solution->detail = '查看';
$lang->solution->progress = '安装进度';
$lang->solution->install = '安装';
$lang->solution->background = '后台安装';
$lang->solution->cancelInstall = '取消安装';
$lang->solution->uninstall = '卸载';
$lang->solution->retryInstall = '重试';
$lang->solution->nextStep = '下一步';
$lang->solution->config = '配置';
$lang->solution->introduction = '基本介绍';
$lang->solution->scenes = '适用场景';
$lang->solution->diagram = '架构图';
$lang->solution->includedApp = '包含应用';
$lang->solution->features = '方案亮点';
$lang->solution->relatedLinks = '相关链接';
$lang->solution->customers = '典型客户';
$lang->solution->apps = '安装的应用';
$lang->solution->externalApps = '外部应用';
$lang->solution->resources = '资源占用';
$lang->solution->editName = '修改名称';
$lang->solution->chooseApp = '请选择要安装的应用';
$lang->solution->noInstalledSolution = '还没有安装解决方案';
$lang->solution->toInstall = '去安装';
$lang->solution->notices = new stdclass;
$lang->solution->notices->fail = '失败';
$lang->solution->notices->success = '成功';
$lang->solution->notices->creatingSolution = '正在创建解决方案。';
$lang->solution->notices->uninstallingSolution = '正在卸载解决方案';
$lang->solution->notices->installingApp = '正在安装:';
$lang->solution->notices->installationSuccess = '解决方案安装成功!';
$lang->solution->notices->cancelInstall = '确定要取消安装吗?';
$lang->solution->notices->confirmToUninstall = '确定要卸载吗?';
$lang->solution->notices->confirmReinstall = '确定要重试安装吗?';
$lang->solution->errors = new stdclass;
$lang->solution->errors->error = '错误';
$lang->solution->errors->notFound = '找不到相关数据';
$lang->solution->errors->failToInstallApp = '安装%s应用失败';
$lang->solution->errors->timeout = '安装超时';
$lang->solution->errors->failToUninstallApp = '卸载%s应用失败';
$lang->solution->errors->hasInstallationError = '安装过程中发生错误';
$lang->solution->errors->notFoundAppByVersion = '找不到%s版本的%s应用';
$lang->solution->errors->notEnoughResource = '资源不足, 请增加配置或释放其它资源后重试。';
$lang->solution->installationErrors = array();
$lang->solution->installationErrors['waiting'] = '安装未开始。';
$lang->solution->installationErrors['installing'] = '正在安装中。';
$lang->solution->installationErrors['installed'] = '安装已完成。';
$lang->solution->installationErrors['uninstalling'] = '安装已取消。';
$lang->solution->installationErrors['cneError'] = '安装失败。';
$lang->solution->installationErrors['timeout'] = '安装超时。';
$lang->solution->installationErrors['notFoundApp'] = '找不到待安装的应用。';
$lang->solution->installationErrors['notEnoughResource'] = '资源不足, 请增加配置或释放其它资源后重试。';
-461
View File
@@ -1,461 +0,0 @@
<?php
declare(strict_types=1);
/**
* The model file of solution module of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Jianhua Wang<wangjianhua@easycorp.ltd>
* @package solution
* @link https://www.zentao.net
*/
class solutionModel extends model
{
/**
* 根据ID获取解决方案。
* Get solution by id.
*
* @param int $solutionID
* @access public
* @return object
*/
public function getByID(int $solutionID): ?object
{
$solution = $this->dao->select('*')->from(TABLE_SOLUTION)->where('id')->eq($solutionID)->fetch();
if(!$solution) return null;
$solution->instances = array();
$instanceIDList = $this->dao->select('id')->from(TABLE_INSTANCE)->where('solution')->eq($solutionID)->fetchAll('id');
if($instanceIDList) $solution->instances = $this->loadModel('instance')->getByIDList(array_keys($instanceIDList));
return $solution;
}
/**
* 根据应用市场的解决方案创建本地解决方案。
* Create by solution of cloud market.
*
* @param object $cloudSolution
* @param object $components
* @access public
* @return object|null
*/
public function create(object $cloudSolution, object $components): object|null
{
$postedCharts = $this->session->solutionCharts ? $this->session->solutionCharts : fixer::input('post')->get();
/* Sort selected apps. */
$orderedCategories = $components->order;
$selectedApps = array();
foreach($orderedCategories as $category)
{
$chart = zget($postedCharts, $category, '');
if(empty($chart)) continue;
$selectedApps[$category] = $this->pickAppFromSchema($components, $category, $chart, $cloudSolution);
if(empty($selectedApps[$category])) unset($selectedApps[$category]);
}
if(empty($selectedApps)) return null;
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');
}
/* Create solution. */
$solution = new stdclass;
$solution->name = $cloudSolution->title;
$solution->appID = $cloudSolution->id;
$solution->appName = $cloudSolution->name;
$solution->appVersion = $cloudSolution->app_version;
$solution->version = $cloudSolution->version;
$solution->chart = $cloudSolution->chart;
$solution->cover = $cloudSolution->background_url;
$solution->introduction = $cloudSolution->introduction;
$solution->desc = $cloudSolution->description;
$solution->status = 'waiting';
$solution->source = 'cloud';
$solution->components = json_encode($selectedApps);
$solution->createdBy = $this->app->user->account;
$solution->createdAt = helper::now();
$solution->channel = $this->app->session->cloudChannel ? $this->app->session->cloudChannel : $this->config->cloud->api->channel;
$this->dao->insert(TABLE_SOLUTION)->data($solution)->exec();
if(dao::isError()) return null;
return $this->getByID($this->dao->lastInsertID());
}
/**
* 按类别和应用从配置信息中获取应用信息。
* Pick App from schema info by category and app.
*
* @param object $schema
* @param string $category
* @param string $app
* @param object $cloudSolution
* @access public
* @return object|null
*/
public function pickAppFromSchema(object $schema, string $category, string $app, object $cloudSolution): object|null
{
$categoryList = helper::arrayColumn($schema->category, null, 'name');
$appGroup = zget($categoryList, $category, array());
foreach($appGroup->choices as $appInSchema)
{
if($appInSchema->name != $app) continue;
$appInfo = zget($cloudSolution->apps, $app);
$appInfo->version = $appInSchema->version;
$appInfo->app_version = $appInSchema->app_version;
$appInfo->status = 'waiting';
return $appInfo;
}
return null;
}
/**
* 如果实例未安装,则安装实例。
* Install instance if instance not installed.
*
* @param object $solution
* @param object $componentApp
* @param object $solutionSchema
* @param array $allMappings
* @access private
* @return bool
*/
private function installInstance(object $solution, object $componentApp, object $solutionSchema, array $allMappings): bool
{
static $apps, $components, $channel;
if(empty($apps)) $apps = helper::arrayColumn(json_decode($solution->components, true), 'chart');
if(empty($channel)) $channel = $this->app->session->cloudChannel ? $this->app->session->cloudChannel : $this->config->cloud->api->channel;
if(empty($components)) $components = json_decode($solution->components);
$cloudApp = $this->loadModel('store')->getAppInfo($componentApp->id, false, '', $componentApp->version, $channel);
if(!$cloudApp)
{
$this->saveStatus($solution->id, 'notFoundApp');
dao::$errors[] = sprintf($this->lang->solution->errors->notFoundAppByVersion, $componentApp->version, $componentApp->alias);
return false;
}
/* Must install the defineded version in solution schema. */
$cloudApp->version = $componentApp->version;
$cloudApp->app_version = $componentApp->app_version;
/* Check enough memory to install app, or not.*/
if(!$this->loadModel('instance')->enoughMemory($cloudApp))
{
$this->saveStatus($solution->id, 'notEnoughResource');
dao::$errors[] = $this->lang->solution->errors->notEnoughResource;
return false;
}
if($solution->status != 'installing') return false;
$settings = $this->mountSettings($solutionSchema, $componentApp->chart, $components, $allMappings, in_array('sonarqube', $apps));
$instance = $this->installApp($cloudApp, $settings);
if(!$instance)
{
$this->saveStatus($solution->id, 'cneError');
dao::$errors[] = sprintf($this->lang->solution->errors->failToInstallApp, $cloudApp->name);
return false;
}
$this->dao->update(TABLE_INSTANCE)->set('solution')->eq($solution->id)->where('id')->eq($instance->id)->exec();
foreach($components as &$app)
{
if($app->id == $componentApp->id) $app->status = 'installing';
}
$this->dao->update(TABLE_SOLUTION)->set('components')->eq(json_encode($components))->where('id')->eq($solution->id)->exec();
return !dao::isError();
}
/**
* 检查启动结果。
* Check start result.
*
* @param object $instance
* @param int $solutionID
* @param object $solutionSchema
* @param string $category
* @access private
* @return bool
*/
private function checkSarted(object $instance, int $solutionID, object $solutionSchema, string $category): bool
{
$instance = $this->waitInstanceStart($instance, $solutionID);
if($instance)
{
$mappingKeys = zget($solutionSchema->mappings, $instance->chart, '');
if($mappingKeys)
{
/* Load settings mapping of installed app for next app. */
$tempMappings = $this->cne->getSettingsMapping($instance, $mappingKeys);
if($tempMappings) $allMappings[$category] = $tempMappings;
}
$this->instance->saveAuthInfo($instance);
return true;
}
$this->saveStatus($solutionID, 'timeout');
dao::$errors[] = $this->lang->solution->errors->timeout;
return false;
}
/**
* 安装解决方案。
* Install solution.
*
* @param int $solutionID
* @access public
* @return bool
*/
public function install(int $solutionID): bool
{
set_time_limit(0);
session_write_close();
$solution = $this->getByID($solutionID);
if(!$solution)
{
dao::$errors[] = $this->lang->solution->errors->notFound;
return false;
}
if(in_array($solution->status, array('installing', 'installed', 'uninstalled'))) return false;
$this->saveStatus($solutionID, 'installing');
$solution->status = 'installing';
$this->loadModel('cne');
$this->loadModel('instance');
$this->loadModel('common');
$allMappings = array();
$solutionSchema = $this->loadModel('store')->solutionConfig('id', $solution->appID);
$components = json_decode($solution->components);
foreach($components as $category => $componentApp)
{
$solutionStatus = $this->dao->select('status')->from(TABLE_SOLUTION)->where('id')->eq($solutionID)->fetch();
if($solutionStatus->status !='installing')
{
/* If status is not installing, should abort installation. Becaust installation was canceled or error happened. */
dao::$errors[] = $this->lang->solution->errors->hasInstallationError;
return false;
}
$instance = $this->instance->instanceOfSolution($solution, $componentApp->chart);
if(!$instance && !$this->installInstance($solution, $componentApp, $solutionSchema, $allMappings)) return false;
$instance = $this->instance->instanceOfSolution($solution, $componentApp->chart);
/* Wait instanlled app started. */
if(!$this->checkSarted($instance, $solutionID, $solutionSchema, $category)) return false;
$componentApp->status = 'installed';
$this->dao->update(TABLE_SOLUTION)->set('components')->eq(json_encode($components))->where('id')->eq($solution->id)->exec();
}
$this->saveStatus($solutionID, 'installed');
return true;
}
/**
* 更新解决方案的状态。
* Update status of solution.
*
* @param int $solutionID
* @param string $status waiting|uninstalling|cneError|timeout|notFoundApp|notEnoughResource
* @access public
* @return bool
*/
public function saveStatus(int $solutionID, string $status): bool
{
if(!isset($this->lang->solution->installationErrors[$status])) return false;
$this->dao->update(TABLE_SOLUTION)
->set('status')->eq($status)
->set('updatedDate')->eq(helper::now())
->where('id')->eq($solutionID)
->exec();
return !dao::isError();
}
/**
* 获取安装应用的配置信息。
* Mount settings for installing app.
*
* @param object $solutionSchema
* @param string $chart
* @param object $components
* @param array $mappings example: ['git' => ['env.GIT_USERNAME' => 'admin', ...], ...]
* @param boolean $isInstallSonar
* @access private
* @return array
*/
private function mountSettings(object $solutionSchema, string $chart, object $components, array $mappings, bool $isInstallSonar = true): array
{
$settings = array();
$appSettings = zget($solutionSchema->settings, $chart, array());
$apps = helper::arrayColumn((array)$components, 'chart');
foreach($appSettings as $item)
{
if(!empty($item->when) && !in_array($item->when, $apps)) continue;
switch($item->type)
{
case 'static':
if(!$isInstallSonar && $item->key === 'solution.sonarqube.enabled')
break;
$settings[] = array('key' => $item->key, 'value' => $item->value);
break;
case 'choose':
$appInfo = zget($components, $item->target, '');
if($appInfo) $settings[] = array('key' => $item->key, 'value' => $appInfo->chart);
break;
case 'mappings':
$mappingInfo = zget($mappings, $item->target, '');
if($mappingInfo) $settings[] = array('key' => $item->key, 'value' => zget($mappingInfo, $item->key, ''));
break;
case 'auto':
if($item->value === 'protocol') $settings[] = array('key' => $item->key, 'value' => strstr(getWebRoot(true), ':', true));
break;
}
}
return $settings;
}
/**
* 安装应用。
* Install app.
*
* @param object $cloudApp
* @param array $settings
* @access private
* @return object|false
*/
private function installApp(object $cloudApp, array $settings): object|false
{
/* Fake parameters for installation. */
$customData = new stdclass;
$customData->customName = $cloudApp->alias;
$customData->dbType = null;
$customData->customDomain = $this->loadModel('instance')->randThirdDomain();
$dbInfo = new stdclass;
$dbList = $this->loadModel('cne')->sharedDBList();
if(count($dbList) > 0)
{
$dbInfo = reset($dbList);
$customData->dbType = 'sharedDB';
$customData->dbService = $dbInfo->name; // Use first shared database.
}
return $this->instance->install($cloudApp, $dbInfo, $customData, null, $settings);
}
/**
* 等待应用启动完成。
* Wait instance started.
*
* @param object $instance
* @param int $solutionID
* @access private
* @return object|false
*/
private function waitInstanceStart(object $instance, int $solutionID): object|false
{
/* Query status of the installed instance. */
$times = 0;
$this->loadModel('instance');
for($times = 0; $times < 50; $times++)
{
$solution = $this->getByID($solutionID);
if(!$solution || $solution->status != 'installing') return false;
$this->dao->update(TABLE_SOLUTION)->set('updatedDate')->eq(date("Y-m-d H:i:s"))->where('id')->eq($solutionID)->exec();
sleep(12);
$instance = $this->instance->freshStatus($instance);
$this->saveLog(date('Y-m-d H:i:s').' installing ' . $instance->name . ':' . $instance->status . '#' . $instance->solution); // Code for debug.
if($instance->status == 'running') return $instance;
}
return false;
}
/**
* 移除解决方案环境。
* Uninstall solution and all included instances .
*
* @param int $solutionID
* @access public
* @return bool
*/
public function uninstall(int $solutionID): bool
{
/* Firstly change the status to 'unintalling' for abort installing process. */
$this->dao->update(TABLE_SOLUTION)->set('status')->eq('uninstalling')->where('id')->eq($solutionID)->exec();
$solution = $this->getByID($solutionID);
if(empty($solution))
{
dao::$errors[] = $this->lang->solution->notFound;
return false;
}
$this->loadModel('instance');
foreach($solution->instances as $instance)
{
$success = $this->instance->uninstall($instance);
if(!$success)
{
dao::$errors[] = sprintf($this->lang->solution->errors->failToUninstallApp, $instance->name);
return false;
}
}
$this->dao->update(TABLE_SOLUTION)->set('status')->eq('uninstalled')->set('deleted')->eq(1)->where('id')->eq($solutionID)->exec();
return !dao::isError();
}
/**
* 保存安装日志。
* Save message to error log file.
*
* @param string $message
* @access public
* @return string
*/
public function saveLog(string $message): string
{
$errorFile = $this->app->logRoot . 'php.' . date('Ymd') . '.log.php';
if(!is_file($errorFile)) @file_put_contents($errorFile, "<\x3fphp\n die();\n\x3f>\n");
@file_put_contents($errorFile, $message . "\n", FILE_APPEND);
return $errorFile;
}
/**
* 获取最后一次安装的方案。
* Get last solution.
*
* @access public
* @return object
*/
public function getLastSolution(): object|false
{
return $this->dao->select('*')->from(TABLE_SOLUTION)
->where('deleted')->eq(0)
->orderBy('id_desc')
->fetch();
}
}
File diff suppressed because one or more lines are too long
-37
View File
@@ -1,37 +0,0 @@
#!/usr/bin/env php
<?php
/**
title=测试 solutionModel->create();
timeout=0
cid=1
- 没有选择应用 @0
- 正确选择了应用属性components @{"git":{"id":58,"name":"gitlab","alias":"GitLab","chart":"gitlab","app_version":"15.3.4","version":"2023.10.901","logo":"https:\/\/img.qucheng.com\/app\/g\/gitlab-icon.svg","status":"waiting"}}
- 选择两个应用属性components @{"git":{"id":58,"name":"gitlab","alias":"GitLab","chart":"gitlab","app_version":"15.3.4","version":"2023.10.901","logo":"https:\/\/img.qucheng.com\/app\/g\/gitlab-icon.svg","status":"waiting"},"ci":{"id":59,"name":"jenkins","alias":"Jenkins","chart":"jenkins","app_version":"2.401.3","version":"2023.10.901","logo":"https:\/\/img.qucheng.com\/app\/j\/jenkins-icon.svg","status":"waiting"}}
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/solution.unittest.class.php';
zenData('user')->gen(5);
zenData('solution')->loadYaml('solution')->gen(0);
zenData('instance')->loadYaml('instance')->gen(0);
$params = array(
'git' => '',
'ci' => '',
'analysis' => '',
'artifact' => ''
);
$solutionModel = new solutionTest();
r($solutionModel->createTest($params)) && p() && e('0'); // 没有选择应用
$params['git'] = 'gitlab';
r($solutionModel->createTest($params)) && p('components', '|') && e('{"git":{"id":58,"name":"gitlab","alias":"GitLab","chart":"gitlab","app_version":"15.3.4","version":"2023.10.901","logo":"https:\/\/img.qucheng.com\/app\/g\/gitlab-icon.svg","status":"waiting"}}'); // 正确选择了应用
$params['ci'] = 'jenkins';
r($solutionModel->createTest($params)) && p('components', '|') && e('{"git":{"id":58,"name":"gitlab","alias":"GitLab","chart":"gitlab","app_version":"15.3.4","version":"2023.10.901","logo":"https:\/\/img.qucheng.com\/app\/g\/gitlab-icon.svg","status":"waiting"},"ci":{"id":59,"name":"jenkins","alias":"Jenkins","chart":"jenkins","app_version":"2.401.3","version":"2023.10.901","logo":"https:\/\/img.qucheng.com\/app\/j\/jenkins-icon.svg","status":"waiting"}}'); // 选择两个应用
-42
View File
@@ -1,42 +0,0 @@
#!/usr/bin/env php
<?php
/**
title=测试 solutionModel->getByID();
timeout=0
cid=1
- 解决方案ID为空 @0
- 解决方案ID存在
- 属性name @禅道 DevOps 解决方案1
- 属性status @notEnoughResource
- 解决方案ID存在,检查实例数量 @3
- 解决方案ID存在
- 属性name @禅道 DevOps 解决方案2
- 属性status @notEnoughResource
- 解决方案ID存在,检查实例数量 @1
- 解决方案ID不存在 @0
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/solution.unittest.class.php';
zenData('space')->loadYaml('space')->gen(2);
zenData('solution')->loadYaml('solution')->gen(2);
zenData('instance')->loadYaml('instance')->gen(4);
$solutionModel = new solutionTest();
r($solutionModel->getByIdTest(0)) && p() && e('0'); // 解决方案ID为空
$solution = $solutionModel->getByIdTest(1);
r($solution) && p('name,status') && e('禅道 DevOps 解决方案1,notEnoughResource'); // 解决方案ID存在
r(count($solution->instances)) && p() && e('3'); // 解决方案ID存在,检查实例数量
$solution = $solutionModel->getByIdTest(2);
r($solution) && p('name,status') && e('禅道 DevOps 解决方案2,notEnoughResource'); // 解决方案ID存在
r(count($solution->instances)) && p() && e('1'); // 解决方案ID存在,检查实例数量
r($solutionModel->getByIdTest(5)) && p() && e('0'); // 解决方案ID不存在
@@ -1,27 +0,0 @@
#!/usr/bin/env php
<?php
/**
title=测试 solutionModel->getLastSolution();
timeout=0
cid=1
- 获取最后一个解决方案
- 属性id @2
- 属性name @禅道 DevOps 解决方案2
- 没有数据时获取最后一个解决方案 @0
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/solution.unittest.class.php';
zenData('solution')->loadYaml('solution')->gen(2);
$solutionModel = new solutionTest();
r($solutionModel->getLastSolutionTest()) && p('id,name') && e('2,禅道 DevOps 解决方案2'); // 获取最后一个解决方案
zenData('solution')->loadYaml('solution')->gen(0);
r($solutionModel->getLastSolutionTest()) && p() && e('0'); // 没有数据时获取最后一个解决方案
@@ -1,28 +0,0 @@
#!/usr/bin/env php
<?php
/**
title=测试 solutionModel->pickAppFromSchema();
timeout=0
cid=1
- 类别和应用不对应 @0
- 类别和应用对应
- 属性id @58
- 属性alias @GitLab
- 属性status @waiting
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/solution.unittest.class.php';
zenData('user')->gen(5);
zenData('solution')->loadYaml('solution')->gen(0);
zenData('instance')->loadYaml('instance')->gen(0);
$solutionModel = new solutionTest();
r($solutionModel->pickAppFromSchemaTest('git', 'gitee')) && p() && e('0'); // 类别和应用不对应
r($solutionModel->pickAppFromSchemaTest('git', 'gitlab')) && p('id,alias,status') && e('58,GitLab,waiting'); // 类别和应用对应
-30
View File
@@ -1,30 +0,0 @@
#!/usr/bin/env php
<?php
/**
title=测试 solutionModel->saveStatus();
timeout=0
cid=1
- 错误的状态
- 属性id @1
- 属性status @notEnoughResource
- 正确的状态
- 属性id @1
- 属性status @cneError
- 不存在的解决方案 @0
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/solution.unittest.class.php';
zenData('solution')->loadYaml('solution')->gen(1);
$solutionModel = new solutionTest();
r($solutionModel->saveStatusTest(1, 'test')) && p('id,status') && e('1,notEnoughResource'); // 错误的状态
r($solutionModel->saveStatusTest(1, 'cneError')) && p('id,status') && e('1,cneError'); // 正确的状态
r($solutionModel->saveStatusTest(2, 'cneError')) && p() && e('0'); // 不存在的解决方案
-66
View File
@@ -1,66 +0,0 @@
---
title: instance
author: Yanyi Cao
version: "1.0"
fields:
- field: id
range: 1-4
- field: space
range: '1{2},2{2}'
- field: solution
range: '1{3},2'
- field: name
range: '`Jenkins`,`GitLab`,`GitLab`,`Jenkins`'
- field: appID
range: '`59`,`58`,`58`,`59`'
- field: appName
range: '`Jenkins`,`GitLab`,`GitLab`,`Jenkins`'
- field: appVersion
range: '`2.401.3`,`15.3.4`,`15.3.4`,`2.401.3`'
- field: chart
range: '`jenkins`,`gitlab`,`gitlab`,`jenkins`'
- field: logo
range: '`//img.qucheng.com/app/j/jenkins-icon.svg`,`//img.qucheng.com/app/g/gitlab-icon.svg`,`//img.qucheng.com/app/g/gitlab-icon.svg`,`//img.qucheng.com/app/j/jenkins-icon.svg`'
- field: version
range: '`2023.10.901`'
- field: desc
range: '`Jenkins是国际上流行的免费开源软件项目,是基于Java开发持续集成工具,用于监控持续重复的工作,旨在提供一个开放的易用的软件平台,使软件的持续集成自动化,大大节约人力和时效。`,`GitLab是由GitLab
Inc.开发,使用MIT许可证的基于网络的Git仓库管理工具,且具有wiki和issue跟踪功能。使用Git作为代码管理工具,并在此基础上搭建起来的web服务。`,`GitLab是由GitLab
Inc.开发,使用MIT许可证的基于网络的Git仓库管理工具,且具有wiki和issue跟踪功能。使用Git作为代码管理工具,并在此基础上搭建起来的web服务。`,`Jenkins是国际上流行的免费开源软件项目,是基于Java开发持续集成工具,用于监控持续重复的工作,旨在提供一个开放的易用的软件平台,使软件的持续集成自动化,大大节约人力和时效。`'
- field: introduction
range: '`基于Java开发的一款持续集成工具`,`GitLab 一款基于Git的一体化软件开发平台。`,`GitLab 一款基于Git的一体化软件开发平台。`,`基于Java开发的一款持续集成工具`'
- field: source
range: '`cloud`'
- field: channel
range: '`stable`'
- field: k8name
range: '`jenkins-20231019112830`,`gitlab-20231019131424`,`gitlab-20231025104407`,`jenkins-20231025104735`'
- field: status
range: '`running`,`starting`,,'
- field: pinned
range: "0"
- field: domain
range: '`jvud.devops.corp.cc`,`gmip.devops.corp.cc`,`9krd.devops.corp.cc`,`adkm.devops.corp.cc`'
- field: smtpSnippetName
range: ""
- field: ldapSnippetName
range: ""
- field: ldapSettings
range: ""
- field: dbSettings
range: '`{"ingress":{"enabled":true,"host":"jvud.devops.corp.cc"},"global":{"ingress":{"enabled":true,"host":"jvud.devops.corp.cc"}},"ci":{"enabled":true},"mysql":{"enabled":false,"auth":{"user":"user_52","password":"vmqA3pzlswbB","host":"qucheng-mysql.quickon-system.svc","port":3306,"database":"db_52","dbservice":{"name":"qucheng-mysql","namespace":"quickon-system"}}}}`,`{"ingress":{"enabled":true,"host":"gmip.devops.corp.cc"},"global":{"ingress":{"enabled":true,"host":"gmip.devops.corp.cc"}},"ci":{"enabled":true},"mysql":{"enabled":false,"auth":{"user":"user_53","password":"cjPmBztaTYvy","host":"qucheng-mysql.quickon-system.svc","port":3306,"database":"db_53","dbservice":{"name":"qucheng-mysql","namespace":"quickon-system"}}}}`,`{"ingress":{"enabled":true,"host":"9krd.devops.corp.cc"},"global":{"ingress":{"enabled":true,"host":"9krd.devops.corp.cc"}},"ci":{"enabled":true},"mysql":{"enabled":false,"auth":{"user":"user_54","password":"GTFyIESAUjsP","host":"qucheng-mysql.quickon-system.svc","port":3306,"database":"db_54","dbservice":{"name":"qucheng-mysql","namespace":"quickon-system"}}}}`,`{"ingress":{"enabled":true,"host":"adkm.devops.corp.cc"},"global":{"ingress":{"enabled":true,"host":"adkm.devops.corp.cc"}},"ci":{"enabled":true},"mysql":{"enabled":false,"auth":{"user":"user_55","password":"wvKn8a7JyxcZ","host":"qucheng-mysql.quickon-system.svc","port":3306,"database":"db_55","dbservice":{"name":"qucheng-mysql","namespace":"quickon-system"}}}}`'
- field: autoBackup
range: "0"
- field: backupKeepDays
range: '`1`'
- field: autoRestore
range: "0"
- field: env
range: ""
- field: createdBy
range: '`wwccss`'
- field: createdAt
range: '`2023-10-19 11:28:30`,`2023-10-19 13:14:24`,`2023-10-25 10:44:07`,`2023-10-25 10:47:35`'
- field: deleted
range: "0"
...
-43
View File
@@ -1,43 +0,0 @@
---
title: solution
author: Yanyi Cao
version: "1.0"
fields:
- field: id
range: 1-2
- field: name
prefix: '禅道 DevOps 解决方案'
range: 1-2
- field: appID
range: '`2`'
- field: appName
range: '`devops`'
- field: appVersion
range: '`1.1.0`'
- field: version
range: '`2023.10.901`'
- field: chart
range: '`devops`'
- field: cover
range: '`https://img.qucheng.com/app/d/devops-bg.png`'
- field: desc
range: '`禅道 DevOps 解决方案是一套软件全生命周期管理、跟踪、集成、发布解决方案。包含禅道项目管理工具、代码仓库、集成工具等。用户可以跟踪软件项目进度,管理代码的集成与发布。`'
- field: introduction
range: '`覆盖从立项到发布,端到端的软件开发全流程跟踪。全面集成 Jenkins、Gitlab 等工具。`'
- field: source
range: '`cloud`'
- field: channel
range: '`stable`'
- field: components
range: '`{"git":{"id":58,"name":"gitlab","alias":"GitLab","chart":"gitlab","app_version":"15.3.4","version":"2023.10.901","logo":"https:\/\/img.qucheng.com\/app\/g\/gitlab-icon.svg","status":"installed"},"ci":{"id":59,"name":"jenkins","alias":"Jenkins","chart":"jenkins","app_version":"2.401.3","version":"2023.10.901","logo":"https:\/\/img.qucheng.com\/app\/j\/jenkins-icon.svg","status":"installing"}}`'
- field: status
range: '`notEnoughResource`'
- field: deleted
range: "0"
- field: createdBy
range: '`wwccss`'
- field: createdAt
range: '`2023-10-16 09:25:07`'
- field: updatedDate
range: '`2023-12-08 16:10:08`'
...
-20
View File
@@ -1,20 +0,0 @@
---
title: space
author: Yanyi Cao
version: "1.0"
fields:
- field: id
range: 1-2
- field: name
range: '`默认空间`'
- field: k8space
range: '`quickon-app`'
- field: owner
range: '`wwccss`,'
- field: default
range: '`1`'
- field: createdAt
range: '`2023-08-29 11:20:29`,`2023-10-16 09:25:11`'
- field: deleted
range: "0"
...
-5
View File
@@ -47,14 +47,9 @@ class space extends control
$pager = new pager($newRecTotal, $recPerPage, $pageID);
$allInstances = array_chunk($allInstances, $pager->recPerPage);
$solutionID = 0;
$solution = $this->loadModel('solution')->getLastSolution();
if($solution && $solution->status == 'installing') $solutionID = $solution->id;
$this->view->title = $this->lang->space->common;
$this->view->pager = $pager;
$this->view->orderBy = $orderBy;
$this->view->solutionID = $solutionID;
$this->view->browseType = $browseType;
$this->view->instances = (empty($allInstances) or empty($allInstances[$pageID - 1])) ? array() : $allInstances[$pageID - 1];
$this->view->users = $this->loadModel('user')->getPairs('noclosed,noletter');
-3
View File
@@ -126,9 +126,6 @@ class spaceModel extends model
if($this->config->inQuickon) $instances = $this->loadModel('store')->batchSetLatestVersions($instances);
$solutionIDList = helper::arrayColumn($instances, 'solution');
$solutions = $this->dao->select('*')->from(TABLE_SOLUTION)->where('id')->in($solutionIDList)->fetchAll('id');
foreach($instances as $instance) $instance->solutionData = zget($solutions, $instance->solution, new stdclass);
return $instances;
}
-11
View File
@@ -31,17 +31,6 @@ featureBar
$app->loadLang('solution');
toolBar
(
$config->inQuickon && $solutionID && hasPriv('install', 'progress') ? item(set(array
(
'text' => $lang->solution->progress,
'icon' => 'spinner-indicator',
'class' => 'ghost',
'url' => createLink('install', 'progress', "solutionID=$solutionID&install=true"),
'data-size' => array('width' => '900', 'height' => '500'),
'data-class-name' => 'install-progress',
'data-id' => 'installProgress',
'data-toggle' => 'modal'
))) : null,
$canInstall ? item(set(array
(
'text' => $lang->space->install,
-47
View File
@@ -299,53 +299,6 @@ class storeModel extends model
return null;
}
/**
* 根据参数获取解决方案信息。
* Get solution info.
*
* @param string $type
* @param int|string $value
* @access public
* @return object
*/
public function getSolution(string $type, string $value): object
{
$apiParams = array();
$apiParams[$type] = $value;
$apiUrl = $this->config->cloud->api->host;
$apiUrl .= '/api/market/solution/info?channel='. $this->config->cloud->api->channel;
$result = commonModel::apiGet($apiUrl, $apiParams, $this->config->cloud->api->headers);
if(!isset($result->code) || $result->code != 200) return new stdclass();
$solution = $result->data;
$solution->apps = array_combine(helper::arrayColumn($solution->apps, 'chart'), $solution->apps);
return $solution;
}
/**
* 获取解决方案的配置信息。
* Get solution config.
*
* @param string $type
* @param int|string $value
* @access public
* @return object
*/
public function solutionConfig(string $type, int|string $value): object
{
$apiParams = array();
$apiParams[$type] = $value;
$apiUrl = $this->config->cloud->api->host;
$apiUrl .= '/api/market/solution/schema?channel='. $this->config->cloud->api->channel;
$result = commonModel::apiGet($apiUrl, $apiParams, $this->config->cloud->api->headers);
if(!isset($result->code) || $result->code != 200) return new stdclass();
return $result->data;
}
/**
* 设置应用最新版本。
* Set app latest version.
+3 -33
View File
@@ -11,9 +11,9 @@ class storeTest
$this->objectModel->config->inQuickon = true;
$this->objectModel->config->k8space = 'quickon-system';
$this->objectModel->config->CNE->api->host = 'http://10.0.7.210:32380';
$this->objectModel->config->CNE->api->token = 'JMz7HCoQ3WHoYbpNyYNpvMfHqde9ugtV';
$this->objectModel->config->CNE->app->domain = 'dops.corp.cc';
$this->objectModel->config->CNE->api->host = 'http://devops.corp.cc:32380';
$this->objectModel->config->CNE->api->token = 'R09p3H5mU1JCg60NGPX94RVbGq31JVkF';
$this->objectModel->config->CNE->app->domain = 'devops.corp.cc';
$this->objectModel->config->cloud->api->host = 'http://api.qucheng.com';
$this->objectModel->config->cloud->api->channel = 'stable';
@@ -171,36 +171,6 @@ class storeTest
return $categories;
}
/**
* 测试获取解决方案的配置信息。
* Test get solution config.
*
* @param string $type
* @param int|string $value
* @access public
* @return object
*/
public function solutionConfigTest(string $type, int|string $value): string
{
$result = $this->solutionConfig($type, $value);
return empty((array)$result) ? 'No data' : 'Success';
}
/**
* 测试根据参数获取解决方案信息。
* Test get solution info.
*
* @param string $type
* @param string $value
* @access public
* @return object|string
*/
public function getSolutionTest(string $type, string $value): object|string
{
$result = $this->getSolution($type, $value);
return empty((array)$result) ? 'No data' : $result;
}
/**
* 测试从渠成获取应用动态消息。
* Test get app dynamic news from Qucheng offical site.
-29
View File
@@ -1,29 +0,0 @@
#!/usr/bin/env php
<?php
declare(strict_types=1);
/**
title=测试 storeModel->getSolution().
timeout=0
cid=1
- 测试查询devops解决方案
- 属性name @devops
- 属性title @禅道 DevOps 解决方案
- 测试查询失败 @No data
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/store.unittest.class.php';
zenData('user')->gen(5);
su('admin');
$typeList = array('name', 'id');
$valueList = array('devops', '29');
$store = new storeTest();
r($store->getSolutionTest($typeList[0], $valueList[0])) && p('name,title') && e('devops,禅道 DevOps 解决方案'); //测试查询devops解决方案
r($store->getSolutionTest($typeList[1], $valueList[1])) && p() && e('No data'); //测试查询失败
@@ -1,27 +0,0 @@
#!/usr/bin/env php
<?php
declare(strict_types=1);
/**
title=测试 storeModel->solutionConfig().
timeout=0
cid=1
- 测试查询成功 @Success
- 测试查询无数据 @No data
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/store.unittest.class.php';
zenData('user')->gen(5);
su('admin');
$typeList = array('name', 'id');
$valueList = array('devops', 29);
$store = new storeTest();
r($store->solutionConfigTest($typeList[0], $valueList[0])) && p() && e('Success'); //测试查询成功
r($store->solutionConfigTest($typeList[1], $valueList[1])) && p() && e('No data'); //测试查询无数据
+2
View File
@@ -1485,6 +1485,8 @@ $config->delete['21_6_beta'][] = 'extension/ipd/project/ext/model/zentaoipd.php'
$config->delete['21_6_beta'][] = 'extension/max/project/ext/model/zentaoipd.php';
$config->delete['21_6_beta'][] = 'extension/biz/project/ext/model/zentaoipd.php';
$config->delete['21_7_2'][] = 'module/solution';
$config->upgrade->openModules = array('action', 'admin', 'ai', 'bi', 'aiapp', 'api', 'automation', 'backup', 'block', 'branch', 'budget', 'bug', 'build', 'cache', 'caselib', 'chart', 'ci', 'client', 'common', 'company', 'compile', 'convert', 'cron', 'custom', 'datatable', 'dataview', 'dept', 'design', 'dev', 'dimension', 'doc', 'durationestimation', 'entry', 'execution', 'extension', 'file', 'git', 'gitlab', 'group', 'holiday', 'im', 'index', 'index.html', 'install', 'issue', 'jenkins', 'job', 'kanban', 'license', 'mail', 'message', 'metric', 'misc', 'mr', 'my', 'personnel', 'pipeline', 'product', 'productplan', 'productset', 'program', 'programplan', 'project', 'projectbuild', 'projectplan', 'projectrelease', 'projectstory', 'pivot', 'qa', 'release', 'repo', 'report', 'risk', 'score', 'screen', 'search', 'setting', 'sonarqube', 'sso', 'stage', 'stakeholder', 'story', 'subject', 'svn', 'task', 'testcase', 'testreport', 'testsuite', 'testtask', 'todo', 'tree', 'tutorial', 'upgrade', 'user', 'webhook', 'weekly', 'workestimation', 'gitea', 'gogs', 'transfer', 'zahost', 'zanode', 'editor', 'charter', 'roadmap', 'account', 'cne', 'host', 'instance', 'ops', 'serverroom', 'space', 'store', 'system', 'solution', 'demand', 'gitfox', 'epic', 'requirement', 'mark');
$config->upgrade->unsetModules = array('design', 'program', 'programplan', 'projectbuild', 'projectrelease', 'stage', 'stakeholder', 'product', 'branch', 'productplan', 'release', 'build', 'qa', 'bug', 'testcase', 'testtask', 'testreport', 'testsuite', 'caselib', 'automation', 'repo', 'ci', 'compile', 'jenkins', 'job', 'svn', 'gitlab', 'sonarqube', 'mr', 'git', 'report', 'sqlbuilder', 'feedback', 'faq', 'attend', 'holiday', 'leave', 'makeup', 'overtime', 'lieu', 'ops', 'host', 'serverroom', 'account', 'domain', 'service', 'deploy', 'conference', 'traincourse', 'pssp', 'baseline', 'classify', 'cm', 'cmcl', 'auditcl', 'reviewcl', 'process', 'activity', 'zoutput', 'auditplan', 'nc', 'subject', 'weekly', 'workestimation', 'issue', 'durationestimation', 'risk', 'opportunity', 'trainplan', 'gapanalysis', 'researchplan', 'researchreport', 'meeting', 'meetingroom', 'budget', 'reviewissue', 'reviewsetting', 'review', 'milestone', 'measurement', 'measrecord', 'assetlib', 'setting', 'im', 'client', 'ldap', 'dev', 'api', 'gitea', 'gogs', 'zanode', 'zahost');