|
diff --git a/module/repo/control.php b/module/repo/control.php
index 32ea458c9f..2ccba4bfd8 100644
--- a/module/repo/control.php
+++ b/module/repo/control.php
@@ -139,7 +139,7 @@ class repo extends control
$this->app->loadLang('action');
- if($this->app->tab == 'project')
+ if($this->app->tab == 'project' or $this->app->tab == 'execution')
{
$products = $this->loadModel('product')->getProductPairsByProject($objectID);
}
@@ -154,7 +154,7 @@ class repo extends control
$this->view->users = $this->loadModel('user')->getPairs('noletter|noempty|nodeleted|noclosed');
$this->view->products = $products;
$this->view->projects = $this->loadModel('product')->getProjectPairsByProductIDList(array_keys($products));
- $this->view->relatedProjects = $this->app->tab == 'project' ? array($objectID) : array();
+ $this->view->relatedProjects = ($this->app->tab == 'project' or $this->app->tab == 'execution') ? array($objectID) : array();
$this->view->serviceHosts = $this->loadModel('gitlab')->getPairs();
$this->view->objectID = $objectID;
@@ -1382,6 +1382,50 @@ class repo extends control
return $this->send(array('result' => 'success', 'revision' => $revision));
}
+ /**
+ * Import repos.
+ *
+ * @param int $server
+ * @access public
+ * @return void
+ */
+ public function import($server = 0)
+ {
+ if($_POST)
+ {
+ $this->repo->batchCreate();
+
+ if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
+ return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->repo->createLink('maintain')));
+ }
+
+ $gitlabList = $this->loadModel('gitlab')->getList();
+ $gitlab = empty($server) ? array_shift($gitlabList) : $this->gitlab->getById($server);
+
+ $repoList = array();
+ if(!empty($gitlab))
+ {
+ $repoList = $this->gitlab->apiGetProjects($gitlab->id);
+ $existRepoList = $this->dao->select('serviceProject,name')->from(TABLE_REPO)
+ ->where('SCM')->eq(ucfirst($gitlab->type))
+ ->andWhere('serviceHost')->eq($gitlab->id)
+ ->fetchPairs();
+ foreach($repoList as $key => $repo)
+ {
+ if(isset($existRepoList[$repo->id])) unset($repoList[$key]);
+ }
+ }
+
+ $products = $this->loadModel('product')->getPairs('', 0, '', 'all');
+
+ $this->view->gitlabPairs = $this->gitlab->getPairs();
+ $this->view->products = $products;
+ $this->view->projects = $this->product->getProjectPairsByProductIDList(array_keys($products));
+ $this->view->gitlab = $gitlab;
+ $this->view->repoList = array_values($repoList);
+ $this->display();
+ }
+
/**
* Ajax sync comment.
*
@@ -1705,12 +1749,19 @@ class repo extends control
->setDefault('projects', array())
->get();
+ $productIds = $postData->products;
+ if(empty($productIds))
+ {
+ $products = $this->loadModel('product')->getPairs('', 0, '', 'all');
+ $productIds = array_keys($products);
+ }
/* Get all projects that can be accessed. */
- $accessProjects = $this->loadModel('product')->getProjectPairsByProductIDList($postData->products);
+ $accessProjects = $this->loadModel('product')->getProjectPairsByProductIDList($productIds);
$selectedProjects = array_intersect(array_keys($accessProjects), $postData->projects);
- return print (html::select('projects[]', $accessProjects, $selectedProjects, "class='form-control chosen' multiple"));
+ $name = isset($postData->number) ? "projects[{$postData->number}][]" : 'projects[]';
+ return print (html::select($name, $accessProjects, $selectedProjects, "class='form-control chosen' multiple"));
}
/**
diff --git a/module/repo/css/browse.css b/module/repo/css/browse.css
index 9a157205eb..6cdbbf2e4d 100644
--- a/module/repo/css/browse.css
+++ b/module/repo/css/browse.css
@@ -13,6 +13,7 @@
#dropMenuRepo > div.table-row > div > div > ul > li > div {padding-left: 20px;}
#dropMenuRepo > div.table-row > div > div > ul > li > ul {padding-left: 10px;}
#repoList .hide-in-search .hidden {display: block !important; visibility: inherit !important;}
+#mainMenu .btn-limit {max-width: unset !important;}
#branchList {line-height: 25px;}
#branchList .hide-in-search, #branchList .tree ul {padding-left: 20px;}
diff --git a/module/repo/css/import.css b/module/repo/css/import.css
new file mode 100644
index 0000000000..3b68af13d0
--- /dev/null
+++ b/module/repo/css/import.css
@@ -0,0 +1,8 @@
+#repoList td.form-actions {padding: 7px;}
+#repoList td.form-actions a {line-height: 18px;}
+
+.main-table .table {cursor: default;}
+.main-table thead>tr {border-bottom: none; height: 45px;}
+.main-table tbody>tr {border-bottom: none; height: 42px;}
+.icon-close {cursor: pointer;}
+a.btn-active-text {line-height: 19px;}
diff --git a/module/repo/js/import.js b/module/repo/js/import.js
new file mode 100644
index 0000000000..cb3fa9e895
--- /dev/null
+++ b/module/repo/js/import.js
@@ -0,0 +1,53 @@
+/**
+ * Delete the project.
+ *
+ * @param object $icon
+ * @access public
+ * @return void
+ */
+function delItem(icon)
+{
+ $(icon).closest('tr').remove();
+ checkItem();
+}
+
+/**
+ * Check the project.
+ *
+ * @access public
+ * @return void
+ */
+function checkItem()
+{
+ if(!$("#repoList tbody tr").length) $("#submit").prop('disabled', true);
+}
+
+$(function()
+{
+ checkItem();
+
+ $(document).on('change', '[id^=product]', function()
+ {
+ var i = $(this).attr('id').replace(/[^0-9]/ig, '');
+ var projects = $('#projects' + i).val();
+ var products = $(this).val();
+ $.post(createLink('repo', 'ajaxProjectsOfProducts'), {products, projects, 'number':i}, function(response)
+ {
+ $('#projectContainer' + i).html('').append(response);
+ $('#projects' + i).chosen().trigger("chosen:updated");
+ });
+ });
+
+});
+
+/**
+ * Change server.
+ *
+ * @access public
+ * @return void
+ */
+function selectServer()
+{
+ var server = $('#servers').val();
+ window.location.href = createLink('repo', 'import', 'server=' + server);
+}
diff --git a/module/repo/lang/de.php b/module/repo/lang/de.php
index 73f4cc4a63..90d9276f33 100644
--- a/module/repo/lang/de.php
+++ b/module/repo/lang/de.php
@@ -46,6 +46,11 @@ $lang->repo->httpClone = 'Clone with HTTP';
$lang->repo->cloneUrl = 'Clone URL';
$lang->repo->linkTask = 'Link Task';
$lang->repo->unlinkedTasks = 'Unlinked Tasks';
+$lang->repo->importAction = 'Import Repo';
+$lang->repo->import = 'Import';
+$lang->repo->importName = 'Name after import';
+$lang->repo->importServer = 'Please select a server';
+$lang->repo->gitlabList = 'Gitlab Repo';
$lang->repo->submit = 'Submit';
$lang->repo->cancel = 'Cancel';
diff --git a/module/repo/lang/en.php b/module/repo/lang/en.php
index 2c2c3b9d26..7d3a299d1b 100644
--- a/module/repo/lang/en.php
+++ b/module/repo/lang/en.php
@@ -46,6 +46,11 @@ $lang->repo->httpClone = 'Clone with HTTP';
$lang->repo->cloneUrl = 'Clone URL';
$lang->repo->linkTask = 'Link Task';
$lang->repo->unlinkedTasks = 'Unlinked Tasks';
+$lang->repo->importAction = 'Import Repo';
+$lang->repo->import = 'Import';
+$lang->repo->importName = 'Name after import';
+$lang->repo->importServer = 'Please select a server';
+$lang->repo->gitlabList = 'Gitlab Repo';
$lang->repo->submit = 'Submit';
$lang->repo->cancel = 'Cancel';
diff --git a/module/repo/lang/fr.php b/module/repo/lang/fr.php
index 3fe607091f..4a1f2a0c11 100644
--- a/module/repo/lang/fr.php
+++ b/module/repo/lang/fr.php
@@ -46,6 +46,11 @@ $lang->repo->httpClone = 'Clone with HTTP';
$lang->repo->cloneUrl = 'Clone URL';
$lang->repo->linkTask = 'Link Task';
$lang->repo->unlinkedTasks = 'Unlinked Tasks';
+$lang->repo->importAction = 'Import Repo';
+$lang->repo->import = 'Import';
+$lang->repo->importName = 'Name after import';
+$lang->repo->importServer = 'Please select a server';
+$lang->repo->gitlabList = 'Gitlab Repo';
$lang->repo->submit = 'Soumettre';
$lang->repo->cancel = 'Annuler';
diff --git a/module/repo/lang/zh-cn.php b/module/repo/lang/zh-cn.php
index 42654aa451..3f5db6da02 100644
--- a/module/repo/lang/zh-cn.php
+++ b/module/repo/lang/zh-cn.php
@@ -32,7 +32,7 @@ $lang->repo->blameTmpl = '第 %line 行代码相关信息
$lang->repo->notRelated = '暂时没有关联禅道对象';
$lang->repo->browseAction = '浏览代码库';
-$lang->repo->createAction = '创建代码库';
+$lang->repo->createAction = '添加代码库';
$lang->repo->editAction = '编辑代码库';
$lang->repo->diffAction = '版本对比';
$lang->repo->downloadAction = '下载代码库文件';
@@ -46,6 +46,11 @@ $lang->repo->httpClone = '使用HTTP克隆';
$lang->repo->cloneUrl = '克隆地址';
$lang->repo->linkTask = '关联任务';
$lang->repo->unlinkedTasks = '未关联任务';
+$lang->repo->importAction = '导入代码库';
+$lang->repo->import = '导入';
+$lang->repo->importName = '导入后的名称';
+$lang->repo->importServer = '请选择服务器';
+$lang->repo->gitlabList = 'Gitlab代码库';
$lang->repo->submit = '提交';
$lang->repo->cancel = '取消';
diff --git a/module/repo/model.php b/module/repo/model.php
index 1495a87fd5..dc05448961 100644
--- a/module/repo/model.php
+++ b/module/repo/model.php
@@ -120,6 +120,16 @@ class repoModel extends model
->page($pager)
->fetchAll('id');
+ if($getCodePath)
+ {
+ $gitlabRepos = array();
+ foreach($repos as $repo)
+ {
+ if($repo->SCM == 'Gitlab') $gitlabRepos[$repo->id] = $repo;
+ }
+ $this->loadModel('gitlab')->apiMultiGetProjects($gitlabRepos);
+ }
+
/* Get products. */
$productIdList = $this->loadModel('product')->getProductIDByProject($projectID, false);
foreach($repos as $i => $repo)
@@ -244,6 +254,67 @@ class repoModel extends model
return $repoID;
}
+ /**
+ * Batch create repos.
+ *
+ * @access public
+ * @return bool
+ */
+ public function batchCreate()
+ {
+ $repos = fixer::input('post')->get();
+
+ $dataAry = array();
+ foreach($repos as $key => $val)
+ {
+ if(strpos($key, 'serviceProject') === 0)
+ {
+ $i = substr($key, 14);
+ if(empty($repos->{'product' . $i})) dao::$errors['product' . $i][] = sprintf($this->lang->error->notempty, $this->lang->repo->product);
+ if(empty($repos->{'name' . $i})) dao::$errors['name' . $i][] = sprintf($this->lang->error->notempty, $this->lang->repo->name);
+
+ if(!empty($repos->{'product' . $i}) and !empty($repos->{'name' . $i})) $dataAry[] = array('serviceProject' => $repos->{'serviceProject' . $i}, 'product' => implode(',', $repos->{'product' . $i}), 'name' => $repos->{'name' . $i}, 'projects' => empty($repos->projects[$i]) ? '' : implode(',', $repos->projects[$i]));
+ }
+ }
+ if(dao::isError()) return false;
+
+ foreach($dataAry as $data)
+ {
+ $repo = new stdclass();
+ $repo->serviceHost = $repos->serviceHost;
+ $repo->serviceProject = $data['serviceProject'];
+ $repo->product = $data['product'];
+ $repo->name = $data['name'];
+ $repo->projects = $data['projects'];
+ $repo->SCM = 'Gitlab';
+ $repo->encoding = 'utf-8';
+ $repo->encrypt = 'base64';
+
+ $this->dao->insert(TABLE_REPO)->data($repo)
+ ->batchCheck($this->config->repo->create->requiredFields, 'notempty')
+ ->check('serviceHost,serviceProject', 'notempty')
+ ->check('name', 'unique', "`SCM` = '{$repo->SCM}'")
+ ->check('serviceProject', 'unique', "`SCM` = '{$repo->SCM}' and `serviceHost` = '{$repo->serviceHost}'")
+ ->autoCheck()
+ ->exec();
+
+ if(dao::isError()) return false;
+
+ $repoID = $this->dao->lastInsertID();
+
+ if($repo->SCM == 'Gitlab')
+ {
+ /* Add webhook. */
+ $repo = $this->getRepoByID($repoID);
+ $this->loadModel('gitlab')->addPushWebhook($repo);
+ }
+
+ $actionID = $this->loadModel('action')->create('repo', $repoID, 'created');
+ }
+
+ return true;
+ }
+
/**
* Update a repo.
*
diff --git a/module/repo/view/import.html.php b/module/repo/view/import.html.php
new file mode 100644
index 0000000000..cc1fe06a60
--- /dev/null
+++ b/module/repo/view/import.html.php
@@ -0,0 +1,65 @@
+
+ * @package repo
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
+
diff --git a/module/repo/view/maintain.html.php b/module/repo/view/maintain.html.php
index 0351fe1171..c22c59515e 100644
--- a/module/repo/view/maintain.html.php
+++ b/module/repo/view/maintain.html.php
@@ -16,7 +16,8 @@
createLink('repo', 'maintain'), "{$lang->repo->maintain}", '', "class='btn btn-link btn-active-text'");?>
- " . $this->lang->repo->create, '', "class='btn btn-primary'");?>
+ " . $this->lang->repo->importAction, '', "class='btn btn-link'");?>
+ " . $this->lang->repo->createAction, '', "class='btn btn-primary'");?>
diff --git a/module/sonarqube/css/create.css b/module/sonarqube/css/create.css
index 22cf991723..bf9498be54 100644
--- a/module/sonarqube/css/create.css
+++ b/module/sonarqube/css/create.css
@@ -1,2 +1,4 @@
.table-form .c-name {width: 130px;}
.table-form .c-input {width: 650px;}
+.main-content>.center-block {max-width: 900px;}
+#sonarqubeForm table {width: 700px;}
diff --git a/module/sonarqube/view/create.html.php b/module/sonarqube/view/create.html.php
index 2aa74e49d2..35988a653b 100644
--- a/module/sonarqube/view/create.html.php
+++ b/module/sonarqube/view/create.html.php
@@ -22,7 +22,6 @@
| sonarqube->name;?> |
sonarqube->placeholder->name}'");?> |
- |
| sonarqube->url;?> |
diff --git a/module/testcase/control.php b/module/testcase/control.php
index 71c7fa21d8..5708b96f92 100644
--- a/module/testcase/control.php
+++ b/module/testcase/control.php
@@ -2495,6 +2495,9 @@ class testcase extends control
if(dao::isError()) return print(js::error(dao::getError()));
+ if(!empty($_POST['syncToZentao']))
+ $this->zanode->syncCasesToZentao($_POST['scriptPath']);
+
$nodeID = $_POST['node'];
$node = $this->zanode->getNodeByID($_POST['node']);
diff --git a/module/testcase/css/automation.css b/module/testcase/css/automation.css
new file mode 100644
index 0000000000..dc2b387672
--- /dev/null
+++ b/module/testcase/css/automation.css
@@ -0,0 +1 @@
+table a.refresh {border-color: white;}
diff --git a/module/testcase/js/automation.js b/module/testcase/js/automation.js
new file mode 100644
index 0000000000..29a66f56fc
--- /dev/null
+++ b/module/testcase/js/automation.js
@@ -0,0 +1,8 @@
+function loadNodes()
+{
+ var nodeLink = createLink('zanode', 'ajaxGetNodes');
+ $('#nodeIdBox').load(nodeLink, function()
+ {
+ $('#nodeIdBox').find('#node').picker();
+ });
+}
diff --git a/module/testcase/view/automation.html.php b/module/testcase/view/automation.html.php
index 20a2d96b99..18ed3759e6 100644
--- a/module/testcase/view/automation.html.php
+++ b/module/testcase/view/automation.html.php
@@ -33,26 +33,31 @@
| zanode->common;?> |
- node) ? $automation->node : '', "class='form-control picker-select'");?> |
- |
+ node) ? $automation->node : '', "class='form-control picker-select'");?> |
+
+ createLink('zanode', 'create'), $lang->zanode->create, '', "class='text-primary' target='_blank'");?>
+ ", '', "class='btn btn-icon refresh' data-toggle='tooltip' title='{$lang->refresh}' onclick='loadNodes()'");?>
+ |
|
|
zanode->scriptPath;?>
|
- scriptPath) ? $automation->scriptPath : '', "class='form-control'");?> |
+ scriptPath) ? $automation->scriptPath : '', "class='form-control' placeholder='{$lang->zanode->scriptTips}'");?> |
-
|
+
+ |
+ $lang->zanode->syncToZentao), '');?> |
+
|
zanode->shell;?>
|
- shell) ? $automation->shell : '', "rows='6' class='form-control'");?> |
+ shell) ? $automation->shell : '', "rows='6' class='form-control' placeholder='{$lang->zanode->shellTips}'");?> |
-
|
diff --git a/module/testtask/model.php b/module/testtask/model.php
index ca2d2ad3b4..7d84ac6ba8 100755
--- a/module/testtask/model.php
+++ b/module/testtask/model.php
@@ -1888,11 +1888,13 @@ class testtaskModel extends model
$caseID = $case->id;
$oldCase = $this->dao->select('*')->from(TABLE_CASE)->where('id')->eq($caseID)->fetch();
- $this->dao->update(TABLE_CASE)->data($case)->where('id')->eq($caseID)->exec();
-
+ $case->version = $oldCase->version;
+ $case->openedDate = $oldCase->openedDate;
+
$changes = common::createChanges($oldCase, $case);
if($changes)
{
+ $this->dao->update(TABLE_CASE)->data($case)->where('id')->eq($caseID)->exec();
$actionID = $this->action->create('case', $caseID, 'Edited');
$this->action->logHistory($actionID, $changes);
}
@@ -2329,7 +2331,7 @@ class testtaskModel extends model
$caseStep = new stdclass();
$caseStep->type = 'step';
- $caseStep->desc = '';
+ $caseStep->desc = $step->name;
$caseStep->expect = $step->checkPoints[0]->expect;
$case->steps[] = $caseStep;
diff --git a/module/zahost/control.php b/module/zahost/control.php
index 0e25e3911e..1af478abed 100644
--- a/module/zahost/control.php
+++ b/module/zahost/control.php
@@ -44,7 +44,7 @@ class zahost extends control
$showFeature = false;
$accounts = !empty($this->config->global->skipAutomation) ? $this->config->global->skipAutomation : '';
- if(strpos(",$accounts,", $this->app->user->account) === false)
+ if(strpos(",$accounts,", $this->app->user->account) === false)
{
$showFeature = true;
$accounts .= ',' . $this->app->user->account;
@@ -109,6 +109,7 @@ class zahost extends control
}
$viewLink = $this->createLink('zahost', 'view', "hostID=$hostID");
+ if(isonlybody()) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true, 'callback' => 'parent.loadHosts()'));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $viewLink));
}
@@ -368,4 +369,16 @@ class zahost extends control
return $this->send(array('result' => 'success', 'message' => '', 'data' => $serviceStatus));
}
+
+ /**
+ * Ajax:get hosts.
+ *
+ * @access public
+ * @return void
+ */
+ public function ajaxGetHosts()
+ {
+ $hostList = $this->zahost->getPairs();
+ return print(html::select("parent", $hostList, '', "class='form-control chosen'"));
+ }
}
diff --git a/module/zahost/model.php b/module/zahost/model.php
index 3aa0029f42..e147b70e06 100644
--- a/module/zahost/model.php
+++ b/module/zahost/model.php
@@ -193,7 +193,8 @@ class zahostModel extends model
*/
public function getImageList($hostID, $browseType = 'all', $param = 0, $orderBy = 'id', $pager = null)
{
- $imageList = json_decode(commonModel::http($this->config->zahost->imageListUrl, array(), array()));
+ $imageList = json_decode(commonModel::http($this->config->zahost->imageListUrl, array(), array()));
+ if(empty($imageList)) return array();
$downloadedImageList = $this->dao->select('*')->from(TABLE_IMAGE)
->where('host')->eq($hostID)
diff --git a/module/zanode/config.php b/module/zanode/config.php
index c8a81099d6..447e580967 100644
--- a/module/zanode/config.php
+++ b/module/zanode/config.php
@@ -3,7 +3,7 @@ $config->zanode->create = new stdClass();
$config->zanode->edit = new stdClass();
$config->zanode->createimage = new stdClass();
$config->zanode->create->requiredFields = 'name,host,image,cpu,memory,disk,osName';
-$config->zanode->create->physicsRequiredFields = 'name,extranet,cpu,memory,osName';
+$config->zanode->create->physicsRequiredFields = 'name,extranet,cpu,memory,osNamePhysics';
$config->zanode->edit->requiredFields = '';
$config->zanode->createimage->requiredFields = 'name';
@@ -12,7 +12,8 @@ $config->zanode->defaultAccount = 'z';
$config->zanode->defaultWinAccount = 'admin';
$config->zanode->defaultPwd = 'CQdliYQn6tKkoFhP';
-$config->zanode->initBash = 'curl -sSL https://pkg.qucheng.com/zenagent/zagent.sh | bash /dev/stdin -szvm -z%s';
+$config->zanode->initBash = 'curl -sSL https://pkg.qucheng.com/zenagent/zagent.sh | bash /dev/stdin -s zvm -k %s -z %s';
+$config->zanode->initPosh = 'Invoke-WebRequest -UseBasicParsing -Uri "https://pkg.qucheng.com/zenagent/zagent-vm.ps1" -OutFile "./install-zanget-vm.ps1"; &"./install-zanget-vm.ps1" -s %s -z %s';
$config->zanode->os = new stdClass();
@@ -51,3 +52,33 @@ $config->zanode->editor->create = array('id' => 'desc', 'tools' => 'simpleT
$config->zanode->editor->edit = array('id' => 'desc', 'tools' => 'simpleTools');
$config->zanode->editor->createimage = array('id' => 'desc', 'tools' => 'simpleTools');
$config->zanode->editor->view = array('id' => 'comment,lastComment', 'tools' => 'simpleTools');
+
+$config->zanode->osType = array('linux' => 'Linux', 'windows' => 'Microsoft Windows');
+
+$config->zanode->linuxList[''] = '';
+$config->zanode->linuxList['centOS65'] = 'CentOS 6.5';
+$config->zanode->linuxList['centOS66'] = 'CentOS 6.6';
+$config->zanode->linuxList['centOS67'] = 'CentOS 6.7';
+$config->zanode->linuxList['centOS70'] = 'CentOS 7.0';
+$config->zanode->linuxList['centOS71'] = 'CentOS 7.1';
+$config->zanode->linuxList['centOS79'] = 'CentOS 7.9';
+
+$config->zanode->linuxList['ubuntu1404'] = 'Ubuntu 14.04';
+$config->zanode->linuxList['ubuntu1604'] = 'Ubuntu 16.04';
+$config->zanode->linuxList['ubuntu1804'] = 'Ubuntu 18.04';
+$config->zanode->linuxList['ubuntu2004'] = 'Ubuntu 20.04';
+
+$config->zanode->linuxList['debianBullseye'] = 'Debian Bullseye';
+$config->zanode->linuxList['debianBuster'] = 'Debian Buster';
+
+$config->zanode->windowsList[''] = '';
+$config->zanode->windowsList['win10'] = 'Windows 10';
+$config->zanode->windowsList['winserver08x64'] = 'Windows Server2008 x64';
+$config->zanode->windowsList['winserver12'] = 'Windows Server2012';
+$config->zanode->windowsList['winserver16'] = 'Windows Server2016';
+
+$config->zanode->versionToOs[''] = '';
+$config->zanode->versionToOs['win10'] = 'windows';
+$config->zanode->versionToOs['winserver08x64'] = 'windows';
+$config->zanode->versionToOs['winserver12'] = 'windows';
+$config->zanode->versionToOs['winserver16'] = 'windows';
\ No newline at end of file
diff --git a/module/zanode/control.php b/module/zanode/control.php
index 7360defed1..b403c4e337 100644
--- a/module/zanode/control.php
+++ b/module/zanode/control.php
@@ -161,17 +161,16 @@ class zanode extends control
$node = $this->zanode->getNodeByID($id);
$vnc = $this->zanode->getVncUrl($node);
- /* Add action log. */
- // if(!empty($vnc->token)) $this->loadModel('action')->create('zanode', $id, 'getVNC');
-
- $this->view->url = $node->ip . ":" . $node->hzap;
- $this->view->host = !empty($vnc->hostIP) ? $vnc->hostIP:'';
- $this->view->token = !empty($vnc->token) ? $vnc->token:'';
- $this->view->title = $this->lang->zanode->view;
- $this->view->zanode = $node;
+ $this->view->url = $node->ip . ":" . $node->hzap;
+ $this->view->host = !empty($vnc->hostIP) ? $vnc->hostIP:'';
+ $this->view->token = !empty($vnc->token) ? $vnc->token:'';
+ $this->view->title = $this->lang->zanode->view;
+ $this->view->zanode = $node;
$this->view->snapshotList = $this->zanode->getSnapshotList($id);
- $this->view->actions = $this->loadModel('action')->getList('zanode', $id);
- $this->view->users = $this->loadModel('user')->getPairs('noletter');
+ $this->view->initBash = sprintf(zget($this->config->zanode->versionToOs, $node->osName, '') != '' ? $this->config->zanode->initPosh : $this->config->zanode->initBash, $node->secret, getWebRoot(true));
+ $this->view->actions = $this->loadModel('action')->getList('zanode', $id);
+ $this->view->users = $this->loadModel('user')->getPairs('noletter');
+
$this->display();
}
@@ -564,8 +563,9 @@ class zanode extends control
if ($node->status != 'running')
{
$serviceStatus['ZenAgent'] = "unknown";
- $serviceStatus['ZTF'] = "unknown";
+ $serviceStatus['ZTF'] = "unknown";
}
+ $node->status = $node->status == 'online' ? 'ready' : $node->status;
$serviceStatus['node'] = $node->status;
return $this->send(array('result' => 'success', 'message' => '', 'data' => $serviceStatus));
@@ -626,4 +626,16 @@ class zanode extends control
return $this->send(array('result' => 'success', 'message' => 'success'));
}
}
+
+ /**
+ * Ajax:get nodes.
+ *
+ * @access public
+ * @return void
+ */
+ public function ajaxGetNodes()
+ {
+ $nodeList = $this->zanode->getPairs();
+ return print(html::select("node", $nodeList, '', "class='form-control picker-select'"));
+ }
}
diff --git a/module/zanode/css/browse.css b/module/zanode/css/browse.css
index 648be7123d..64b697e35c 100644
--- a/module/zanode/css/browse.css
+++ b/module/zanode/css/browse.css
@@ -1,9 +1,12 @@
.c-id {width: 70px;}
.c-memory{width: 100px;}
-.c-status {width: 70px;}
+.c-status {width: 90px;}
.c-cpu, .c-host {width: 100px;}
.c-ip{width: 150px;}
.c-os, .c-type {width: 120px;}
.desktop, .createImage{margin-right: 4px;}
#helpTab .icon-help {line-height: unset;}
#bysearchTab {margin-right: 0px;}
+
+.c-actions a img{position: relative; left: -80px; filter: drop-shadow(#18a6fd 80px 0); width: 18px;}
+.c-actions a.disabled img {filter: drop-shadow(#313c52 80px 0);}
diff --git a/module/zanode/css/browsesnapshot.css b/module/zanode/css/browsesnapshot.css
index d5033bef8f..583507c6a8 100644
--- a/module/zanode/css/browsesnapshot.css
+++ b/module/zanode/css/browsesnapshot.css
@@ -1,4 +1,5 @@
#main{min-width: 0!important;padding:0!important;}
+#main .container{padding:0!important;}
body{background-color: #fff!important;}
.c-createdBy {width: 100px;}
diff --git a/module/zanode/css/common.css b/module/zanode/css/common.css
index 1ef909a85b..8190cc895c 100644
--- a/module/zanode/css/common.css
+++ b/module/zanode/css/common.css
@@ -1 +1,3 @@
.icon-help{line-height: 34px;}
+#osNamePhysicsContainer{display: flex;}
+#osNamePhysicsContainer select{margin-right: 5px;}
\ No newline at end of file
diff --git a/module/zanode/css/view.css b/module/zanode/css/view.css
index 66481a016a..14980da02f 100644
--- a/module/zanode/css/view.css
+++ b/module/zanode/css/view.css
@@ -7,14 +7,16 @@
.zanode-mt-8{margin-top: 8px;}
.zanode-status-text{margin-left: 10px;font:small-caption;color:#838a9d;}
.zanode-status-text i{color:#18a6fd}
-.status-notice{margin-top: 8px;margin-left: 18px;line-height: 28px;}
+.status-notice{margin-top: 16px;line-height: 28px;}
.status-notice a{color: #2463c7;}
.service-status a{color: #2463c7;}
-.service-status{margin-top: 10px;}
+.service-status{margin-top: 5px;}
.vnc-detail{height: 60vh;min-height: 550px;}
.vnc-mask{width: 100%;height:100%;background-color: rgba(0,0,0,0);position: absolute;z-index: 1;}
.checkStatus{color: #313c52;}
.node-not-wrap{white-space: nowrap;}
.btn-info {background-color: unset;}
.btn.disabled i {color: #fff;}
-#serviceContent{min-height: 120px;}
+.btn-toolbar a img{margin-bottom: 2px;}
+.zanode-init{padding:15px;background: #f4f5f7;margin:10px 0;}
+.btn-snap-create{height: 30px;}
diff --git a/module/zanode/js/create.js b/module/zanode/js/create.js
index bd96c2ca22..efad795dbe 100644
--- a/module/zanode/js/create.js
+++ b/module/zanode/js/create.js
@@ -1,12 +1,18 @@
-function zahostType()
+/**
+ * Change zanode type.
+ *
+ * @access public
+ * @return void
+ */
+function zanodeType()
{
- if($('#type').val() == 'physics')
+ if($('#hostType').val() == 'physics')
{
$('#parent').closest('tr').hide();
$('#image').closest('tr').hide();
$('#extranet').closest('tr').removeClass('hidden');
$('#osName').addClass('hidden');
- $('#osNamePhysics').removeClass('hidden');
+ $('#osNamePhysicsContainer').removeClass('hidden');
}
else
{
@@ -14,6 +20,48 @@ function zahostType()
$('#image').closest('tr').show();
$('#extranet').closest('tr').addClass('hidden');
$('#osName').removeClass('hidden');
- $('#osNamePhysics').addClass('hidden');
+ $('#osNamePhysicsContainer').addClass('hidden');
}
}
+
+/**
+ * Load hosts.
+ *
+ * @access public
+ * @return void
+ */
+function loadHosts()
+{
+ var hostLink = createLink('zahost', 'ajaxGetHosts');
+ $('#hostIdBox').load(hostLink, function()
+ {
+ $('#hostIdBox').find('#parent').chosen();
+ });
+}
+
+$(function()
+{
+ $('#osNamePhysicsPre').on('change', function()
+ {
+ console.log($(this).val())
+ if($(this).val() == 'linux')
+ {
+ $('#osNamePhysics').empty();
+ for(var i in linuxList)
+ {
+ console.log(linuxList[i])
+ $('#osNamePhysics').append('')
+ }
+ }
+ else
+ {
+ $('#osNamePhysics').empty();
+ for(var i in windowsList)
+ {
+ console.log(windowsList[i])
+ $('#osNamePhysics').append('')
+ }
+ }
+ $('#osNamePhysics').trigger('chosen:updated');
+ })
+})
\ No newline at end of file
diff --git a/module/zanode/js/view.js b/module/zanode/js/view.js
index d46022f99f..59059bd739 100644
--- a/module/zanode/js/view.js
+++ b/module/zanode/js/view.js
@@ -36,7 +36,14 @@ function checkServiceStatus(){
{
if(resultData.data[key] == 'unknown')
{
- $('.ztf-status').text(zanodeLang.init.unknown)
+ if(hostType == 'physics')
+ {
+ $('.ztf-status').text(zanodeLang.init.not_install)
+ }
+ else
+ {
+ $('.ztf-status').text(zanodeLang.init.unknown)
+ }
}
else
{
@@ -47,7 +54,7 @@ function checkServiceStatus(){
}
else if(key == "node")
{
- if(nodeStatus != resultData.data[key] && resultData.data[key])
+ if(resultData.data[key] && zanodeLang.statusList[nodeStatus] != zanodeLang.statusList[resultData.data[key]])
{
window.location.reload();
}
@@ -88,14 +95,14 @@ function checkServiceStatus(){
if(!isSuccess)
{
- // $('.init-fail').show();
+ $('.init-fail').show();
$('.init-success').hide();
}
else
{
clearInterval(checkInterval)
$('.init-success').show();
- // $('.init-fail').hide();
+ $('.init-fail').hide();
}
setTimeout(function() {
$('#serviceContent').removeClass('loading');
@@ -161,6 +168,28 @@ $('.btn-pwd-copy').live('click', function()
}, 2000)
})
+$('.btn-init-copy').live('click', function()
+{
+ var copyText = $('#initBash');
+ copyText.show();
+ copyText .select();
+ document.execCommand("Copy");
+ copyText.hide();
+ $('.btn-init-copy').tooltip({
+ trigger: 'click',
+ placement: 'top',
+ title: zanodeLang.copied,
+ tipClass: 'tooltip-success'
+ });
+
+ $(this).tooltip('show');
+ var that = this;
+ setTimeout(function()
+ {
+ $(that).tooltip('hide')
+ }, 2000)
+})
+
$('.btn-pwd-show').live('click', function()
{
var pwd = $('#pwd-copy').text();
@@ -188,6 +217,9 @@ $('#jumpManual').click(function()
$(function(){
$('#checkServiceStatus').trigger("click")
+ if(hostType == 'physics'){
+ return;
+ }
checkInterval = setInterval(() => {
intervalTimes++;
if(intervalTimes > 300)
diff --git a/module/zanode/lang/de.php b/module/zanode/lang/de.php
index a3f4e4e192..6ccea2777f 100644
--- a/module/zanode/lang/de.php
+++ b/module/zanode/lang/de.php
@@ -22,6 +22,7 @@ $lang->zanode->getVNC = 'Remote management';
$lang->zanode->all = 'All';
$lang->zanode->byQuery = 'Search';
$lang->zanode->osName = 'System';
+$lang->zanode->osNamePhysics = 'System';
$lang->zanode->image = 'VM Image';
$lang->zanode->imageName = 'Image Name';
$lang->zanode->name = 'Name';
@@ -29,7 +30,8 @@ $lang->zanode->start = 'Start After Created';
$lang->zanode->hostName = 'Host Name';
$lang->zanode->host = $lang->zanode->hostName;
$lang->zanode->extranet = 'IP/Domain';
-$lang->zanode->sshAddress = 'SSH Command';
+$lang->zanode->sshCommand = 'SSH Command';
+$lang->zanode->sshAddress = 'SSH Address';
$lang->zanode->osArch = 'Arch';
$lang->zanode->cpuCores = 'CPU';
$lang->zanode->defaultUser = 'Default Account Name';
@@ -53,6 +55,7 @@ $lang->zanode->confirmRestore = "The ZenAgent Node will be restored to this sna
$lang->zanode->actionSuccess = 'Success';
$lang->zanode->deleted = "Deleted";
$lang->zanode->scriptPath = "Script path";
+$lang->zanode->syncToZentao = "Sync cases in the directory to Zentao";
$lang->zanode->shell = "Shell";
$lang->zanode->automation = "Automation";
$lang->zanode->install = "Install";
@@ -63,6 +66,9 @@ $lang->zanode->manual = 'Manual';
$lang->zanode->initializing = 'Initializing';
$lang->zanode->showPwd = 'Show Password';
$lang->zanode->hidePwd = 'Hide Password';
+$lang->zanode->baseInfo = 'Basic information';
+$lang->zanode->cpuUnit = 'CORE';
+$lang->zanode->IP = 'Extranet Address';
$lang->zanode->typeList['node'] = 'Virtual machine';
$lang->zanode->typeList['physics'] = 'Physical machine';
@@ -72,6 +78,7 @@ $lang->automation->scriptPath = $lang->zanode->scriptPath;
$lang->automation->node = $lang->zanode->common;
$lang->zanode->notFoundAgent = 'No Agent service is found';
+$lang->zanode->busy = 'This Node is %s, please wait for the operation to complete.';
$lang->zanode->createVmFail = 'Failed to create a ZenAgent Node';
$lang->zanode->noVncPort = 'Failed to get vnc port';
$lang->zanode->nameValid = "The name can only be letters, numbers, '-', '_', '.', and cannot start with a symbol";
@@ -134,6 +141,8 @@ $lang->zanode->statusList['destroy_fail'] = 'Destroy Fail';
$lang->zanode->statusList['wait'] = 'Initializing';
$lang->zanode->statusList['online'] = 'Online';
$lang->zanode->statusList['restoring'] = 'Restoring';
+$lang->zanode->statusList['creating_snap'] = 'Creating Snapshot';
+$lang->zanode->statusList['creating_img'] = 'Creating Image';
$lang->zanode->initNotice = "Succeeded. Please initialize the execution node or return to the list.";
$lang->zanode->initButton = "Initialize";
@@ -148,9 +157,9 @@ $lang->zanode->init->ready = "Ready";
$lang->zanode->init->next = "Next";
$lang->zanode->init->button = "Go To Settings";
-$lang->zanode->init->initSuccessNoticeTitle = "The service is ready, and it takes two steps to execute the automated test on the execution node: 1. Configure the automated test running environment according to the %s 2. Go to %s";
-$lang->zanode->init->initFailNoticeTitle = "Initialization failed, check the init script execution log and try the following two solutions:";
-$lang->zanode->init->initFailNoticeDesc = "1. Re-execute the script 2. Review the initialization FAQ";
+$lang->zanode->init->initSuccessNoticeTitle = "The service is ready, and it takes two steps to execute the automated test on the execution node: 1. Configure the automated test running environment according to the %s 2. Go to %s";
+$lang->zanode->init->initFailNotice = "Fail,Execute the installation service command on the node or See Help.";
+$lang->zanode->init->initFailNoticeOnPhysics = "The service has not been installed yet, please check the service status after executing the following command on the execution node。See Help";
$lang->zanode->init->serviceStatus = array(
"ZenAgent" => 'not_install',
diff --git a/module/zanode/lang/en.php b/module/zanode/lang/en.php
index 6ea6e5acbd..a4d1e9b20e 100644
--- a/module/zanode/lang/en.php
+++ b/module/zanode/lang/en.php
@@ -22,6 +22,7 @@ $lang->zanode->getVNC = 'Remote management';
$lang->zanode->all = 'All';
$lang->zanode->byQuery = 'Search';
$lang->zanode->osName = 'System';
+$lang->zanode->osNamePhysics = 'System';
$lang->zanode->image = 'VM Image';
$lang->zanode->imageName = 'Image Name';
$lang->zanode->name = 'Name';
@@ -29,7 +30,8 @@ $lang->zanode->start = 'Start After Created';
$lang->zanode->hostName = 'Host Name';
$lang->zanode->host = $lang->zanode->hostName;
$lang->zanode->extranet = 'IP/Domain';
-$lang->zanode->sshAddress = 'SSH Command';
+$lang->zanode->sshCommand = 'SSH Command';
+$lang->zanode->sshAddress = 'SSH Address';
$lang->zanode->osArch = 'Arch';
$lang->zanode->cpuCores = 'CPU';
$lang->zanode->defaultUser = 'Default Account Name';
@@ -53,6 +55,7 @@ $lang->zanode->confirmRestore = "The ZenAgent Node will be restored to this sna
$lang->zanode->actionSuccess = 'Success';
$lang->zanode->deleted = "Deleted";
$lang->zanode->scriptPath = "Script path";
+$lang->zanode->syncToZentao = "Sync cases in the directory to Zentao";
$lang->zanode->shell = "Shell";
$lang->zanode->automation = "Automation";
$lang->zanode->install = "Install";
@@ -63,6 +66,9 @@ $lang->zanode->manual = 'Manual';
$lang->zanode->initializing = 'Initializing';
$lang->zanode->showPwd = 'Show Password';
$lang->zanode->hidePwd = 'Hide Password';
+$lang->zanode->baseInfo = 'Basic information';
+$lang->zanode->cpuUnit = 'CORE';
+$lang->zanode->IP = 'Extranet Address';
$lang->zanode->typeList['node'] = 'Virtual machine';
$lang->zanode->typeList['physics'] = 'Physical machine';
@@ -72,6 +78,7 @@ $lang->automation->scriptPath = $lang->zanode->scriptPath;
$lang->automation->node = $lang->zanode->common;
$lang->zanode->notFoundAgent = 'No Agent service is found';
+$lang->zanode->busy = 'This Node is %s, please wait for the operation to complete.';
$lang->zanode->createVmFail = 'Failed to create a ZenAgent Node';
$lang->zanode->noVncPort = 'Failed to get vnc port';
$lang->zanode->nameValid = "The name can only be letters, numbers, '-', '_', '.', and cannot start with a symbol";
@@ -134,6 +141,8 @@ $lang->zanode->statusList['destroy_fail'] = 'Destroy Fail';
$lang->zanode->statusList['wait'] = 'Initializing';
$lang->zanode->statusList['online'] = 'Online';
$lang->zanode->statusList['restoring'] = 'Restoring';
+$lang->zanode->statusList['creating_snap'] = 'Creating Snapshot';
+$lang->zanode->statusList['creating_img'] = 'Creating Image';
$lang->zanode->initNotice = "Succeeded. Please initialize the execution node or return to the list.";
$lang->zanode->initButton = "Initialize";
@@ -148,9 +157,9 @@ $lang->zanode->init->ready = "Ready";
$lang->zanode->init->next = "Next";
$lang->zanode->init->button = "Go To Settings";
-$lang->zanode->init->initSuccessNoticeTitle = "The service is ready, and it takes two steps to execute the automated test on the execution node: 1. Configure the automated test running environment according to the %s 2. Go to %s";
-$lang->zanode->init->initFailNoticeTitle = "Initialization failed, check the init script execution log and try the following two solutions:";
-$lang->zanode->init->initFailNoticeDesc = "1. Re-execute the script 2. Review the initialization FAQ";
+$lang->zanode->init->initSuccessNoticeTitle = "The service is ready, and it takes two steps to execute the automated test on the execution node: 1. Configure the automated test running environment according to the %s 2. Go to %s";
+$lang->zanode->init->initFailNotice = "Fail,Execute the installation service command on the node or See Help.";
+$lang->zanode->init->initFailNoticeOnPhysics = "The service has not been installed yet, please check the service status after executing the following command on the execution node。See Help";
$lang->zanode->init->serviceStatus = array(
"ZenAgent" => 'not_install',
diff --git a/module/zanode/lang/fr.php b/module/zanode/lang/fr.php
index a3f4e4e192..6ccea2777f 100644
--- a/module/zanode/lang/fr.php
+++ b/module/zanode/lang/fr.php
@@ -22,6 +22,7 @@ $lang->zanode->getVNC = 'Remote management';
$lang->zanode->all = 'All';
$lang->zanode->byQuery = 'Search';
$lang->zanode->osName = 'System';
+$lang->zanode->osNamePhysics = 'System';
$lang->zanode->image = 'VM Image';
$lang->zanode->imageName = 'Image Name';
$lang->zanode->name = 'Name';
@@ -29,7 +30,8 @@ $lang->zanode->start = 'Start After Created';
$lang->zanode->hostName = 'Host Name';
$lang->zanode->host = $lang->zanode->hostName;
$lang->zanode->extranet = 'IP/Domain';
-$lang->zanode->sshAddress = 'SSH Command';
+$lang->zanode->sshCommand = 'SSH Command';
+$lang->zanode->sshAddress = 'SSH Address';
$lang->zanode->osArch = 'Arch';
$lang->zanode->cpuCores = 'CPU';
$lang->zanode->defaultUser = 'Default Account Name';
@@ -53,6 +55,7 @@ $lang->zanode->confirmRestore = "The ZenAgent Node will be restored to this sna
$lang->zanode->actionSuccess = 'Success';
$lang->zanode->deleted = "Deleted";
$lang->zanode->scriptPath = "Script path";
+$lang->zanode->syncToZentao = "Sync cases in the directory to Zentao";
$lang->zanode->shell = "Shell";
$lang->zanode->automation = "Automation";
$lang->zanode->install = "Install";
@@ -63,6 +66,9 @@ $lang->zanode->manual = 'Manual';
$lang->zanode->initializing = 'Initializing';
$lang->zanode->showPwd = 'Show Password';
$lang->zanode->hidePwd = 'Hide Password';
+$lang->zanode->baseInfo = 'Basic information';
+$lang->zanode->cpuUnit = 'CORE';
+$lang->zanode->IP = 'Extranet Address';
$lang->zanode->typeList['node'] = 'Virtual machine';
$lang->zanode->typeList['physics'] = 'Physical machine';
@@ -72,6 +78,7 @@ $lang->automation->scriptPath = $lang->zanode->scriptPath;
$lang->automation->node = $lang->zanode->common;
$lang->zanode->notFoundAgent = 'No Agent service is found';
+$lang->zanode->busy = 'This Node is %s, please wait for the operation to complete.';
$lang->zanode->createVmFail = 'Failed to create a ZenAgent Node';
$lang->zanode->noVncPort = 'Failed to get vnc port';
$lang->zanode->nameValid = "The name can only be letters, numbers, '-', '_', '.', and cannot start with a symbol";
@@ -134,6 +141,8 @@ $lang->zanode->statusList['destroy_fail'] = 'Destroy Fail';
$lang->zanode->statusList['wait'] = 'Initializing';
$lang->zanode->statusList['online'] = 'Online';
$lang->zanode->statusList['restoring'] = 'Restoring';
+$lang->zanode->statusList['creating_snap'] = 'Creating Snapshot';
+$lang->zanode->statusList['creating_img'] = 'Creating Image';
$lang->zanode->initNotice = "Succeeded. Please initialize the execution node or return to the list.";
$lang->zanode->initButton = "Initialize";
@@ -148,9 +157,9 @@ $lang->zanode->init->ready = "Ready";
$lang->zanode->init->next = "Next";
$lang->zanode->init->button = "Go To Settings";
-$lang->zanode->init->initSuccessNoticeTitle = "The service is ready, and it takes two steps to execute the automated test on the execution node: 1. Configure the automated test running environment according to the %s 2. Go to %s";
-$lang->zanode->init->initFailNoticeTitle = "Initialization failed, check the init script execution log and try the following two solutions:";
-$lang->zanode->init->initFailNoticeDesc = "1. Re-execute the script 2. Review the initialization FAQ";
+$lang->zanode->init->initSuccessNoticeTitle = "The service is ready, and it takes two steps to execute the automated test on the execution node: 1. Configure the automated test running environment according to the %s 2. Go to %s";
+$lang->zanode->init->initFailNotice = "Fail,Execute the installation service command on the node or See Help.";
+$lang->zanode->init->initFailNoticeOnPhysics = "The service has not been installed yet, please check the service status after executing the following command on the execution node。See Help";
$lang->zanode->init->serviceStatus = array(
"ZenAgent" => 'not_install',
diff --git a/module/zanode/lang/zh-cn.php b/module/zanode/lang/zh-cn.php
index 8e0215ced4..5a89b72e9a 100644
--- a/module/zanode/lang/zh-cn.php
+++ b/module/zanode/lang/zh-cn.php
@@ -22,6 +22,7 @@ $lang->zanode->getVNC = '远程';
$lang->zanode->all = '全部';
$lang->zanode->byQuery = '搜索';
$lang->zanode->osName = '操作系统';
+$lang->zanode->osNamePhysics = '操作系统';
$lang->zanode->image = '镜像';
$lang->zanode->imageName = '镜像名称';
$lang->zanode->name = '名称';
@@ -29,7 +30,8 @@ $lang->zanode->start = '创建后自动开启';
$lang->zanode->hostName = '所属宿主机';
$lang->zanode->host = $lang->zanode->hostName;
$lang->zanode->extranet = 'IP/域名';
-$lang->zanode->sshAddress = 'SSH命令';
+$lang->zanode->sshCommand = 'SSH命令';
+$lang->zanode->sshAddress = 'SSH地址';
$lang->zanode->osArch = '架构';
$lang->zanode->cpuCores = 'CPU';
$lang->zanode->defaultUser = '默认用户';
@@ -53,6 +55,7 @@ $lang->zanode->confirmRestore = "执行节点将会还原至此快照状态,
$lang->zanode->actionSuccess = '操作成功';
$lang->zanode->deleted = "已删除";
$lang->zanode->scriptPath = "脚本目录";
+$lang->zanode->syncToZentao = "同步脚本信息到禅道";
$lang->zanode->shell = "shell命令";
$lang->zanode->automation = "自动化设置";
$lang->zanode->install = "安装";
@@ -63,6 +66,9 @@ $lang->zanode->manual = '手册';
$lang->zanode->initializing = '初始化中';
$lang->zanode->showPwd = '显示密码';
$lang->zanode->hidePwd = '隐藏密码';
+$lang->zanode->baseInfo = '基础信息';
+$lang->zanode->cpuUnit = '核';
+$lang->zanode->IP = 'IP/域名';
$lang->zanode->typeList['node'] = '虚拟机';
$lang->zanode->typeList['physics'] = '物理机';
@@ -72,6 +78,7 @@ $lang->automation->scriptPath = $lang->zanode->scriptPath;
$lang->automation->node = $lang->zanode->common;
$lang->zanode->notFoundAgent = '没有发现Agent服务';
+$lang->zanode->busy = '节点正在%s, 请等待操作完成';
$lang->zanode->createVmFail = '创建执行节点失败';
$lang->zanode->noVncPort = '无法获取执行节点端口';
$lang->zanode->nameValid = "名称只能是字母、数字,'-','_','.',且不能以符号开头";
@@ -121,19 +128,21 @@ $lang->zanode->apiError['notRunning'] = '请检查执行节点状态';
$lang->zanode->publicList[0] = '不共享';
$lang->zanode->publicList[1] = '共享';
-$lang->zanode->statusList['created'] = '已创建';
-$lang->zanode->statusList['launch'] = '运行中';
-$lang->zanode->statusList['ready'] = '运行中';
-$lang->zanode->statusList['running'] = '运行中';
-$lang->zanode->statusList['suspend'] = '休眠';
-$lang->zanode->statusList['offline'] = '下线';
-$lang->zanode->statusList['destroy'] = '已销毁';
-$lang->zanode->statusList['shutoff'] = '已关机';
-$lang->zanode->statusList['shutodown'] = '已关机';
-$lang->zanode->statusList['destroy_fail'] = '销毁失败';
-$lang->zanode->statusList['wait'] = '初始化中';
-$lang->zanode->statusList['online'] = '已上架';
-$lang->zanode->statusList['restoring'] = '还原中';
+$lang->zanode->statusList['created'] = '已创建';
+$lang->zanode->statusList['launch'] = '运行中';
+$lang->zanode->statusList['ready'] = '运行中';
+$lang->zanode->statusList['running'] = '运行中';
+$lang->zanode->statusList['suspend'] = '休眠';
+$lang->zanode->statusList['offline'] = '下线';
+$lang->zanode->statusList['destroy'] = '已销毁';
+$lang->zanode->statusList['shutoff'] = '已关机';
+$lang->zanode->statusList['shutodown'] = '已关机';
+$lang->zanode->statusList['destroy_fail'] = '销毁失败';
+$lang->zanode->statusList['wait'] = '初始化中';
+$lang->zanode->statusList['online'] = '运行中';
+$lang->zanode->statusList['restoring'] = '还原中';
+$lang->zanode->statusList['creating_snap'] = '创建快照中';
+$lang->zanode->statusList['creating_img'] = '导出镜像中';
$lang->zanode->initNotice = "保存成功,请初始化执行节点或返回列表。";
$lang->zanode->initButton = "去初始化";
@@ -148,9 +157,9 @@ $lang->zanode->init->ready = "已就绪";
$lang->zanode->init->next = "下一步";
$lang->zanode->init->button = "去设置";
-$lang->zanode->init->initSuccessNoticeTitle = "服务已就绪,还需两步即可在执行节点上执行自动化测试: 1、根据%s配置自动化测试运行环境。 2、进行%s";
-$lang->zanode->init->initFailNoticeTitle = "初始化失败,请查看初始化脚本执行日志并尝试以下两种解决方案:";
-$lang->zanode->init->initFailNoticeDesc = "1、 重新执行脚本 2、 查看初始化常见问题";
+$lang->zanode->init->initSuccessNoticeTitle = "服务已就绪,还需两步即可在执行节点上执行自动化测试: 1、根据%s配置自动化测试运行环境。 2、进行%s";
+$lang->zanode->init->initFailNotice = "服务未就绪,在执行节点上执行安装服务命令或查看帮助.";
+$lang->zanode->init->initFailNoticeOnPhysics = "服务还没有安装,请在执行节点执行以下命令后检测服务状态。查看帮助";
$lang->zanode->init->serviceStatus = array(
"ZenAgent" => 'not_install',
diff --git a/module/zanode/model.php b/module/zanode/model.php
index 313eb4d24b..592c7b1ea8 100644
--- a/module/zanode/model.php
+++ b/module/zanode/model.php
@@ -12,16 +12,19 @@
class zanodemodel extends model
{
- const STATUS_CREATED = 'created';
- const STATUS_LAUNCH = 'launch';
- const STATUS_FAIL_CREATE = 'vm_fail_create';
- const STATUS_RUNNING = 'running';
- const STATUS_SHUTOFF = 'shutoff';
- const STATUS_BUSY = 'busy';
- const STATUS_READY = 'ready';
- const STATUS_UNKNOWN = 'unknown';
- const STATUS_DESTROY = 'destroy';
- const STATUS_DESTROY_FAIL = 'vim_destroy_fail';
+ const STATUS_CREATED = 'created';
+ const STATUS_LAUNCH = 'launch';
+ const STATUS_FAIL_CREATE = 'vm_fail_create';
+ const STATUS_RUNNING = 'running';
+ const STATUS_SHUTOFF = 'shutoff';
+ const STATUS_BUSY = 'busy';
+ const STATUS_READY = 'ready';
+ const STATUS_UNKNOWN = 'unknown';
+ const STATUS_DESTROY = 'destroy';
+ const STATUS_RESTORING = 'restoring';
+ const STATUS_CREATING_SNAP = 'creating_snap';
+ const STATUS_CREATING_IMG = 'creating_img';
+ const STATUS_DESTROY_FAIL = 'vim_destroy_fail';
const KVM_CREATE_PATH = '/api/v1/kvm/create';
const KVM_TOKEN_PATH = '/api/v1/virtual/getVncToken';
@@ -54,17 +57,29 @@ class zanodemodel extends model
public function create()
{
$data = fixer::input('post')
- ->setIF($this->post->type == 'physics', 'parent', 0)
- ->setIF($this->post->type == 'physics', 'osName', $this->post->osNamePhysics)
- ->remove('osNamePhysics')
+ ->setIF($this->post->hostType == 'physics', 'parent', 0)
+ ->setIF($this->post->hostType == 'physics', 'osName', $this->post->osNamePhysics)
->get();
+ $data->type = "node";
+
+ if($data->hostType == 'physics')
+ {
+ $data->secret = md5($data->name . time());
+ $data->status = "offline";
+ }
+ else
+ {
+ $data->hostType = '';
+ }
+
/* Batch check fields. */
$this->dao->update(TABLE_ZAHOST)->data($data)
- ->batchCheck($data->type == 'node' ? $this->config->zanode->create->requiredFields : $this->config->zanode->create->physicsRequiredFields, 'notempty');
+ ->batchCheck($data->hostType != 'physics' ? $this->config->zanode->create->requiredFields : $this->config->zanode->create->physicsRequiredFields, 'notempty');
if(dao::isError()) return false;
+ unset($data->osNamePhysics);
if(!preg_match("/^(?!_)(?!-)(?!\.)[a-zA-Z0-9\_\.\-]+$/", $data->name))
{
dao::$errors[] = $this->lang->zanode->nameValid;
@@ -72,10 +87,10 @@ class zanodemodel extends model
}
/* If name already exists return error. */
- $node = $this->dao->select('*')->from(TABLE_ZAHOST)->where('name')->eq($data->name)->andWhere('type')->in('node,physics')->fetch();
+ $node = $this->dao->select('*')->from(TABLE_ZAHOST)->where('name')->eq($data->name)->andWhere('type')->eq('node')->fetch();
if($node) return dao::$errors[] = $this->lang->zanode->nameUnique;
- if($data->type == 'physics')
+ if($data->hostType == 'physics')
{
$ping = $this->loadModel('zahost')->checkAddress($data->extranet);
if(!$ping)
@@ -181,7 +196,12 @@ class zanodemodel extends model
$result = json_decode(commonModel::http($agnetUrl . static::KVM_EXPORT_PATH, json_encode($param,JSON_NUMERIC_CHECK), null, array("Authorization:$node->tokenSN")));
- if(!empty($result) and $result->code == 'success') return $newID;
+
+ if(!empty($result) and $result->code == 'success')
+ {
+ $this->dao->update(TABLE_HOST)->set('status')->eq(static::STATUS_CREATING_IMG)->where('id')->eq($node->id)->exec();
+ return $newID;
+ }
$this->dao->delete()->from(TABLE_IMAGE)->where('id')->eq($newID)->exec();
return false;
@@ -239,11 +259,14 @@ class zanodemodel extends model
if(!empty($result) and $result->code == 'success')
{
$this->loadModel('action')->create('zanode', $zanodeID, 'createdSnapshot', '', $data->name);
+ $this->dao->update(TABLE_HOST)->set('status')->eq(static::STATUS_CREATING_SNAP)->where('id')->eq($node->id)->exec();
+
return $newID;
}
$this->dao->delete()->from(TABLE_IMAGE)->where('id')->eq($newID)->exec();
dao::$errors[] = (!empty($result) and !empty($result->msg)) ? $result->msg : $this->app->lang->fail;
+
return false;
}
@@ -286,11 +309,14 @@ class zanodemodel extends model
if(!empty($result) and $result->code == 'success')
{
+ $this->dao->update(TABLE_HOST)->set('status')->eq(static::STATUS_CREATING_SNAP)->where('id')->eq($node->id)->exec();
+
return $newID;
}
$this->dao->delete()->from(TABLE_IMAGE)->where('id')->eq($newID)->exec();
dao::$errors[] = (!empty($result) and !empty($result->msg)) ? $result->msg : $this->app->lang->fail;
+
return false;
}
@@ -415,6 +441,11 @@ class zanodemodel extends model
{
$node = $this->getNodeByID($id);
+ if(in_array($node->status, array('restoring', 'creating_img', 'creating_snap')))
+ {
+ return sprintf($this->lang->zanode->busy, $this->lang->zanode->statusList[$node->status]);
+ }
+
/* Prepare create params. */
$agnetUrl = 'http://' . $node->ip . ':' . $node->hzap;
$path = '/api/v1/kvm/' . $node->name . '/' . $type;
@@ -450,7 +481,7 @@ class zanodemodel extends model
{
$node = $this->getNodeByID($id);
- if($node)
+ if($node && $node->hostType != 'physics')
{
$req = array( 'name' => $node->name );
$agnetUrl = 'http://' . $node->ip . ':' . $node->hzap;
@@ -570,11 +601,11 @@ class zanodemodel extends model
$query = str_replace('`hostID`', 't2.`id`', $query);
}
- $list = $this->dao->select("t1.*, t2.name as hostName, if(t1.type='node', t2.extranet, t1.extranet) extranet,if(t1.type='node', t3.osName, t1.osName) osName")->from(TABLE_ZAHOST)->alias('t1')
+ $list = $this->dao->select("t1.*, t2.name as hostName, if(t1.hostType='', t2.extranet, t1.extranet) extranet,if(t1.hostType='', t3.osName, t1.osName) osName")->from(TABLE_ZAHOST)->alias('t1')
->leftJoin(TABLE_ZAHOST)->alias('t2')->on('t1.parent = t2.id')
->leftJoin(TABLE_IMAGE)->alias('t3')->on('t3.id = t1.image')
->where('t1.deleted')->eq(0)
- ->andWhere("((t1.type = 'node' and t2.type = 'zahost') or t1.type = 'physics')")
+ ->andWhere("t1.type = 'node'")
->beginIF($query)->andWhere($query)->fi()
->orderBy($orderBy)
->page($pager)
@@ -587,7 +618,9 @@ class zanodemodel extends model
foreach($list as $l)
{
- $host = zget($hosts, $l->parent);
+ $host = $l->hostType == '' ? zget($hosts, $l->parent) : clone $l;
+ $host->status = in_array($host->status, array('running', 'ready')) ? "online" : $host->status;
+
if($l->status == 'running' || $l->status == 'ready')
{
if(empty($host))
@@ -598,13 +631,13 @@ class zanodemodel extends model
if($host->status != 'online' || time() - strtotime($host->heartbeat) > 60)
{
- $l->status = self::STATUS_SHUTOFF;
+ $l->status = $l->hostType == '' ? 'wait' : 'offline';
continue;
}
if(time() - strtotime($l->heartbeat) > 60)
{
- $l->status = 'wait';
+ $l->status = $l->hostType == '' ? 'wait' : 'offline';
}
}
}
@@ -622,7 +655,7 @@ class zanodemodel extends model
{
return $this->dao->select('*')->from(TABLE_ZAHOST)
->where('deleted')->eq(0)
- ->andWhere("type")->eq('node')
+ ->andWhere("type")->in('node,physics')
->orderBy($orderBy)
->fetchAll('id');
}
@@ -638,7 +671,7 @@ class zanodemodel extends model
{
return $this->dao->select('*')->from(TABLE_ZAHOST)
->where('deleted')->eq(0)
- ->andWhere("type")->eq('node')
+ ->andWhere("type")->in('node,physics')
->orderBy($orderBy)
->fetchPairs('id', 'name');
}
@@ -654,6 +687,8 @@ class zanodemodel extends model
*/
public function getListByHost($hostID, $orderBy = 'id_desc')
{
+ if(!$hostID) return array();
+
$list = $this->dao->select('id, name, vnc, cpuCores, memory, diskSize, osName, status, heartbeat')->from(TABLE_ZAHOST)
->where('deleted')->eq(0)
->andWhere("parent")->eq($hostID)
@@ -786,15 +821,17 @@ class zanodemodel extends model
*/
public function getNodeByID($id)
{
- $node = $this->dao->select("t1.*, t2.name as hostName, t2.extranet as ip,t2.zap as hzap,if(t1.type='node', t3.osName, t1.osName) osName, t2.tokenSN as tokenSN, t2.secret as secret")->from(TABLE_ZAHOST)
+ $node = $this->dao->select("t1.*, t2.name as hostName, if(t1.hostType='', t2.extranet, t1.extranet) ip,t2.zap as hzap,if(t1.hostType='', t3.osName, t1.osName) osName, if(t1.hostType='', t2.tokenSN, t1.tokenSN) tokenSN, if(t1.hostType='', t2.secret, t1.secret) secret")->from(TABLE_ZAHOST)
->alias('t1')
->leftJoin(TABLE_ZAHOST)->alias('t2')->on('t1.parent = t2.id')
->leftJoin(TABLE_IMAGE)->alias('t3')->on('t3.id = t1.image')
->where('t1.id')->eq($id)
->fetch();
- $host = $this->loadModel("zahost")->getByID($node->type == 'node' ? $node->parent : $node->id);
- if($node->status == 'running' || $node->status == 'ready')
+ $host = $node->hostType == '' ? $this->loadModel("zahost")->getByID($node->parent) : clone $node;
+ $host->status = in_array($host->status, array('running', 'ready')) ? "online" : $host->status;
+
+ if($node->status == 'running' || $node->status == 'ready' || $node->status == 'online')
{
if(empty($host) || $host->status != 'online')
{
@@ -802,7 +839,7 @@ class zanodemodel extends model
}
elseif(time() - strtotime($node->heartbeat) > 60)
{
- $node->status = 'wait';
+ $node->status = $node->hostType == '' ? 'wait' : 'offline';
}
}
@@ -820,8 +857,11 @@ class zanodemodel extends model
$node = $this->dao->select('*')->from(TABLE_ZAHOST)
->where('mac')->eq($mac)
->fetch();
+ if(empty($node)) return $node;
+
+ $host = $node->hostType == '' ? $this->loadModel("zahost")->getByID($node->parent) : $node;
+ $host->status = in_array($host->status, array('running', 'ready')) ? "online" : $host->status;
- $host = $this->loadModel("zahost")->getByID($node->parent);
if($node->status == 'running' || $node->status == 'ready')
{
if(empty($host) || $host->status != 'online')
@@ -1048,6 +1088,7 @@ class zanodemodel extends model
{
$now = helper::now();
$data = fixer::input('post')
+ ->remove('syncToZentao')
->setDefault('createdBy', $this->app->user->account)
->setDefault('createdDate', $now)
->setDefault('node', 0)
@@ -1098,4 +1139,14 @@ class zanodemodel extends model
return dao::$errors = $this->lang->zanode->runTimeout;
}
}
+
+ /**
+ * Sync cases in dir to zentao.
+ *
+ * @access public
+ * @return void
+ */
+ public function syncCasesToZentao($path)
+ {
+ }
}
diff --git a/module/zanode/view/browse.html.php b/module/zanode/view/browse.html.php
index e586757bfa..fdae12124b 100644
--- a/module/zanode/view/browse.html.php
+++ b/module/zanode/view/browse.html.php
@@ -53,7 +53,7 @@
| idAB); ?> |
zanode->name); ?> |
- zahost->type); ?> |
+ zahost->type); ?> |
zanode->extranet); ?> |
zanode->cpuCores); ?> |
zanode->memory); ?> |
@@ -69,7 +69,7 @@
| id; ?> |
inlink('view', "id=$node->id"), $node->name, '', ""); ?> |
- lang->zanode->typeList, $node->type); ?> |
+ hostType == 'physics' ? $this->lang->zanode->typeList['physics'] : $this->lang->zanode->typeList['node']; ?> |
extranet; ?> |
zanode->os->cpuCores, $node->cpuCores); ?> |
memory . $this->lang->zahost->unitList['GB']; ?> |
@@ -80,26 +80,26 @@
zanode->suspend}' target='hiddenwin'";
- $suspendAttr .= $node->type == 'physics' || $node->status != 'running' ? ' class="btn disabled"' : "class='btn' target='hiddenwin' onclick='if(confirm(\"{$lang->zanode->confirmSuspend}\")==false) return false;'";
+ $suspendAttr .= $node->hostType == 'physics' || $node->status != 'running' ? ' class="btn disabled"' : "class='btn' target='hiddenwin' onclick='if(confirm(\"{$lang->zanode->confirmSuspend}\")==false) return false;'";
$resumeAttr = "title='{$lang->zanode->resume}' target='hiddenwin'";
- $resumeAttr .= $node->type == 'physics' || $node->status == 'running' || $node->status == 'wait' ? ' class="btn disabled"' : "class='btn' target='hiddenwin' onclick='if(confirm(\"{$lang->zanode->confirmResume}\")==false) return false;'";
+ $resumeAttr .= $node->hostType == 'physics' || $node->status == 'running' || $node->status == 'wait' ? ' class="btn disabled"' : "class='btn' target='hiddenwin' onclick='if(confirm(\"{$lang->zanode->confirmResume}\")==false) return false;'";
$rebootAttr = "title='{$lang->zanode->reboot}' target='hiddenwin'";
- $rebootAttr .= $node->type == 'physics' || $node->status == 'shutoff' || $node->status == 'wait' ? ' class="btn disabled"' : "class='btn' target='hiddenwin' onclick='if(confirm(\"{$lang->zanode->confirmReboot}\")==false) return false;'";
+ $rebootAttr .= $node->hostType == 'physics' || in_array($node->status, array('wait', 'creating_img', 'creating_snap', 'restoring', 'shutoff')) ? ' class="btn disabled"' : "class='btn' target='hiddenwin' onclick='if(confirm(\"{$lang->zanode->confirmReboot}\")==false) return false;'";
$closeAttr = "title='{$lang->zanode->shutdown}'";
- $closeAttr .= $node->type == 'physics' || $node->status == 'wait' ? ' class="btn disabled"' : ' class="btn iframe"';
+ $closeAttr .= $node->hostType == 'physics' || in_array($node->status, array('wait', 'creating_img', 'creating_snap', 'restoring')) ? ' class="btn disabled"' : ' class="btn iframe"';
$startAttr = "title='{$lang->zanode->boot}'";
- $startAttr .= $node->type == 'physics' || $node->status == 'wait' ? ' class="btn disabled"' : ' class="btn iframe"';
+ $startAttr .= $node->hostType == 'physics' || in_array($node->status, array('wait', 'creating_img', 'creating_snap', 'restoring')) ? ' class="btn disabled"' : ' class="btn iframe"';
$snapshotAttr = "title='{$lang->zanode->createSnapshot}'";
- $snapshotAttr .= $node->type == 'physics' || $node->status != 'running' ? ' class="btn disabled"' : ' class="btn iframe"';
+ $snapshotAttr .= $node->hostType == 'physics' || $node->status != 'running' ? ' class="btn disabled"' : ' class="btn iframe"';
- $imageAttr = $node->status != 'running' ? ' class="btn btn-action iframe createImage disabled"' : ' class="btn btn-action iframe createImage"';
+ $imageAttr = $node->hostType == 'physics' || $node->status != 'running' && $node->status != 'creating_img' ? ' class="btn btn-action iframe createImage disabled"' : ' class="btn btn-action iframe createImage"';
- common::printLink('zanode', 'getVNC', "id={$node->id}", " ", (in_array($node->status ,array('running', 'launch', 'wait')) ? '_blank' : ''), "title='{$lang->zanode->getVNC}' class='btn desktop " . (in_array($node->status ,array('running', 'launch', 'wait')) ? '':'disabled') . "'", '');
+ common::printLink('zanode', 'getVNC', "id={$node->id}", " ", (in_array($node->status ,array('running', 'launch', 'wait')) ? '_blank' : ''), "title='{$lang->zanode->getVNC}' class='btn desktop " . ($node->hostType == '' && in_array($node->status ,array('running', 'launch', 'wait')) ? '':'disabled') . "'", '');
if($node->status == "suspend")
{
common::printLink('zanode', 'resume', "zanodeID={$node->id}", " ", '', $resumeAttr);
@@ -119,7 +119,7 @@
}
common::printLink('zanode', 'reboot', "zanodeID={$node->id}", " ", '', $rebootAttr);
- common::printLink('zanode', 'createSnapshot', "zanodeID={$node->id}", " ", '', $snapshotAttr, true, true);
+ common::printLink('zanode', 'createSnapshot', "zanodeID={$node->id}", " ", '', $snapshotAttr, true, true);
if(common::hasPriv('zanode', 'createImage') or common::hasPriv('zanode', 'destroy'))
{
diff --git a/module/zanode/view/create.html.php b/module/zanode/view/create.html.php
index 19f1a570df..67829d80d7 100644
--- a/module/zanode/view/create.html.php
+++ b/module/zanode/view/create.html.php
@@ -13,6 +13,8 @@
getModuleRoot() . 'common/view/kindeditor.html.php';?>
+zanode->linuxList);?>
+zanode->windowsList);?>
| |