diff --git a/module/common/lang/en.php b/module/common/lang/en.php index 1cb2f6e3e7..2d416e5b66 100644 --- a/module/common/lang/en.php +++ b/module/common/lang/en.php @@ -376,6 +376,8 @@ $lang->devops->oss = 'Oss'; $lang->devops->host = 'Host'; $lang->devops->account = 'Account'; $lang->devops->serverroom = 'IDC'; +$lang->devops->deploy = 'Deploy'; +$lang->devops->service = 'Service'; $lang->devops->provider = 'IDC Provider'; $lang->devops->cpuBrand = 'CPU Brand'; $lang->devops->city = 'IDC Location'; diff --git a/module/host/config.php b/module/host/config.php index f04d4e8fb4..14f14f744f 100644 --- a/module/host/config.php +++ b/module/host/config.php @@ -31,4 +31,32 @@ $config->host->featureBar = array( $config->host->actions = new stdclass(); $config->host->actions->view = array(); -$config->host->actions->view['suffixActions'] = array('edit', 'delete'); \ No newline at end of file +$config->host->actions->view['suffixActions'] = array('edit', 'delete'); + +$config->host->create = new stdclass(); +$config->host->create->requiredFields = 'name,hostType,extranet,cpuCores,memory,diskSize,vsoft'; +$config->host->create->ipFields = 'extranet'; + +$config->host->defaultPort = '55001'; + +$config->host->edit = new stdclass(); +$config->host->edit->requiredFields = 'name,hostType,cpuCores,memory,diskSize,vsoft'; + +$config->host->imageListUrl = 'https://pkg.qucheng.com/zenagent/list.json'; + +$config->host->cpuCoreList = array(1 => 1, 2 => 2, 4 => 4, 6 => 6, 8 => 8, 10 => 10, 12 => 12, 16 => 16, 24 => 24, 32 => 32, 64 => 64); + +$config->host->initBash = 'curl -sSL https://pkg.qucheng.com/zenagent/zagent.sh | bash /dev/stdin -k %s -z %s'; + +$config->host->editor = new stdclass(); +$config->host->editor->create = array('id' => 'desc', 'tools' => 'simpleTools'); +$config->host->editor->edit = array('id' => 'desc', 'tools' => 'simpleTools'); +$config->host->editor->view = array('id' => 'comment,lastComment', 'tools' => 'simpleTools'); + +$config->host->automation = new stdclass(); +$config->host->automation->zenAgentURL = 'https://github.com/easysoft/zenagent/blob/main/guide/deploy/index.md'; +$config->host->automation->ztfURL = 'https://ztf.im/'; +$config->host->automation->kvmURL = 'https://www.linux-kvm.org/page/Documents'; +$config->host->automation->nginxURL = 'http://nginx.org/en/docs/'; +$config->host->automation->novncURL = 'https://novnc.com/info.html'; +$config->host->automation->websockifyURL = 'https://github.com/novnc/websockify'; \ No newline at end of file diff --git a/module/host/config/dtable.php b/module/host/config/dtable.php index 7bf1a18392..7d4aa6e815 100644 --- a/module/host/config/dtable.php +++ b/module/host/config/dtable.php @@ -1,6 +1,7 @@ loadLang('serverroom'); +$app->loadLang('zahost'); $config->host->dtable = new stdclass(); @@ -101,3 +102,58 @@ $config->host->dtable->fieldList['actions']['sortType'] = false; $config->host->dtable->fieldList['actions']['fixed'] = 'right'; $config->host->dtable->fieldList['actions']['menu'] = array('online|offline', 'edit', 'delete'); $config->host->dtable->fieldList['actions']['list'] = $config->host->actionList; + +$config->host->imageDtable = new stdclass(); + +$config->host->imageDtable->fieldList['name']['title'] = $lang->zahost->image->name; +$config->host->imageDtable->fieldList['name']['name'] = 'name'; +$config->host->imageDtable->fieldList['name']['sortType'] = true; +$config->host->imageDtable->fieldList['name']['width'] = 120; +$config->host->imageDtable->fieldList['name']['hint'] = true; + +$config->host->imageDtable->fieldList['osName']['title'] = $lang->zahost->image->os; +$config->host->imageDtable->fieldList['osName']['name'] = 'osName'; +$config->host->imageDtable->fieldList['osName']['sortType'] = true; +$config->host->imageDtable->fieldList['osName']['width'] = 120; +$config->host->imageDtable->fieldList['osName']['hint'] = true; + +$config->host->imageDtable->fieldList['status']['title'] = $lang->zahost->status; +$config->host->imageDtable->fieldList['status']['name'] = 'status'; +$config->host->imageDtable->fieldList['status']['sortType'] = false; +$config->host->imageDtable->fieldList['status']['width'] = 100; +$config->host->imageDtable->fieldList['status']['map'] = $lang->zahost->image->statusList; + +$config->host->imageDtable->fieldList['path']['title'] = $lang->zahost->image->path; +$config->host->imageDtable->fieldList['path']['name'] = 'path'; +$config->host->imageDtable->fieldList['path']['type'] = 'desc'; +$config->host->imageDtable->fieldList['path']['sortType'] = false; +$config->host->imageDtable->fieldList['path']['hint'] = true; + +$config->host->imageDtable->fieldList['progress']['title'] = $lang->zahost->image->progress; +$config->host->imageDtable->fieldList['progress']['name'] = 'progress'; +$config->host->imageDtable->fieldList['progress']['sortType'] = false; +$config->host->imageDtable->fieldList['progress']['width'] = 120; +$config->host->imageDtable->fieldList['progress']['hint'] = true; + +$config->host->imageActionList = array(); +$config->host->imageActionList['download']['icon'] = 'download'; +$config->host->imageActionList['download']['text'] = $lang->zahost->image->downloadImage; +$config->host->imageActionList['download']['hint'] = $lang->zahost->image->downloadImage; +$config->host->imageActionList['download']['url'] = helper::createLink('host', 'downloadImage', 'imageID={id}'); +$config->host->imageActionList['download']['ajaxSubmit'] = true; +$config->host->imageActionList['download']['data-confirm'] = false; + +$config->host->imageActionList['cancel']['icon'] = 'ban-circle'; +$config->host->imageActionList['cancel']['text'] = $lang->cancel; +$config->host->imageActionList['cancel']['hint'] = $lang->cancel; +$config->host->imageActionList['cancel']['url'] = helper::createLink('host', 'cancelDownload', 'id={id}'); +$config->host->imageActionList['cancel']['ajaxSubmit'] = true; +$config->host->imageActionList['cancel']['data-confirm'] = $lang->zahost->cancelDelete; + +$config->host->imageDtable->fieldList['actions']['name'] = 'actions'; +$config->host->imageDtable->fieldList['actions']['title'] = $lang->actions; +$config->host->imageDtable->fieldList['actions']['type'] = 'actions'; +$config->host->imageDtable->fieldList['actions']['sortType'] = false; +$config->host->imageDtable->fieldList['actions']['fixed'] = 'right'; +$config->host->imageDtable->fieldList['actions']['menu'] = array('download', 'cancel'); +$config->host->imageDtable->fieldList['actions']['list'] = $config->host->imageActionList; diff --git a/module/host/control.php b/module/host/control.php index 799774a2ff..b3273c3e9b 100644 --- a/module/host/control.php +++ b/module/host/control.php @@ -66,6 +66,76 @@ class host extends control $this->display(); } + /** + * Show image list page. + * + * @param int $hostID + * @param string $browseType + * @param int $param + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function browseImage($hostID, $browseType = 'all', $param = 0, $orderBy = 'id', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + $this->app->session->set('imageList', $this->app->getURI(true)); + $this->app->loadClass('pager', $static = true); + $pager = pager::init($recTotal, $recPerPage, $pageID); + + $imageList = $this->host->getImageList($hostID, $browseType, $param, $orderBy, $pager); + + $this->app->loadLang('zahost'); + $this->view->title = $this->lang->zahost->image->browseImage; + $this->view->hostID = $hostID; + $this->view->imageList = $imageList; + $this->view->pager = $pager; + $this->view->param = $param; + $this->view->orderBy = $orderBy; + $this->view->browseType = $browseType; + + $this->display(); + } + + /** + * Sent download image request to Host. + * + * @param int $hostID + * @param int $imageID + * @access public + * @return object + */ + public function downloadImage($imageID) + { + $this->loadModel('zahost'); + $image = $this->zahost->getImageByID($imageID); + $this->zahost->downloadImage($image); + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => $this->lang->zahost->image->downloadImageFail)); + + return $this->send(array('result' => 'success', 'load' => true)); + } + + /** + * Sent cancel download image request to Host. + * + * @param int $hostID + * @param string $imageName + * @access public + * @return object + */ + public function cancelDownload($imageID) + { + $this->loadModel('zahost'); + $image = $this->zahost->getImageByID($imageID); + + $this->zahost->cancelDownload($image); + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => $this->lang->zahost->image->downloadImageFail)); + + $this->send(array('result' => 'success', 'load' => true)); + } + /** * Create host. * diff --git a/module/host/css/browseimage.css b/module/host/css/browseimage.css new file mode 100644 index 0000000000..ef7500cb63 --- /dev/null +++ b/module/host/css/browseimage.css @@ -0,0 +1,4 @@ +.c-name,.c-status,.c-progress,.c-osName{width: 130px;} +.main-header-image{border:none;margin-left: 0!important;padding-left:0;} +.body-modal #mainContent{padding-top: 85px; padding-bottom: 50px;} +.dropdown-menu>li>a {margin: 1px 0;} diff --git a/module/host/js/browseimage.js b/module/host/js/browseimage.js new file mode 100644 index 0000000000..aa7117f964 --- /dev/null +++ b/module/host/js/browseimage.js @@ -0,0 +1,60 @@ +var interval; + +$(function () { + updateProgressInterval(); +}); + +function updateProgressInterval() { + updateProgress(); + interval = setInterval(function () + { + updateProgress(); + }, 3000); +} + +function updateProgress() { + $.get(createLink('zahost', 'ajaxImageDownloadProgress', 'hostID=' + hostID)).done(function (response) + { + var result = JSON.parse(response); + var statusList = result.data; + + var hasInprogress = false; + for (var imageID in statusList) { + if (statusList[imageID].statusCode) { + if (statusList[imageID].statusCode == 'inprogress' || statusList[imageID].statusCode == 'created' || statusList[imageID].statusCode == 'pending') + { + hasInprogress = true; + $('.image-download-' + imageID).addClass('disabled'); + $('.image-cancel-' + imageID).removeClass('disabled'); + } + else if (statusList[imageID].statusCode == 'completed') + { + $('.image-path-' + imageID).text(statusList[imageID].path); + $('.image-path-' + imageID).attr('title', statusList[imageID].path); + $('.image-download-' + imageID).addClass('disabled'); + $('.image-cancel-' + imageID).addClass('disabled'); + $('.image-cancel-' + imageID).attr('href', '#'); + $('.image-progress-' + imageID).text("100%"); + } + else + { + var link = createLink('zahost', 'downloadImage', "hostID="+hostID+"&imageID="+imageID); + $('.image-download-' + imageID).removeClass('disabled'); + $('.image-download-' + imageID).attr('href', link); + $('.image-cancel-' + imageID).addClass('disabled'); + $('.image-cancel-' + imageID).attr('href', '#'); + $('.image-progress-' + imageID).text(''); + } + $('.image-status-' + imageID).text(statusList[imageID].status); + if(statusList[imageID].progress != '' && statusList[imageID].statusCode != 'completed') + { + $('.image-progress-' + imageID).text(statusList[imageID].progress); + } + } + } + if (!hasInprogress) + { + clearInterval(interval) + } + }); +} diff --git a/module/host/js/browseimage.ui.js b/module/host/js/browseimage.ui.js new file mode 100644 index 0000000000..553021097e --- /dev/null +++ b/module/host/js/browseimage.ui.js @@ -0,0 +1,81 @@ +var interval; + +window.createSortLink = function(col) +{ + var sort = col.name + '_asc'; + if(sort == orderBy) sort = col.name + '_desc'; + + return sortLink.replace('{orderBy}', sort); +} + +window.renderCell = function(result, {col, row}) +{ + if(col.name === 'progress') + { + result[0] = {html: ""}; + } + + if(col.name === 'path') + { + result[0] = {html: ""}; + } + + if(col.name === 'status') + { + result[0] = {html: "" + result[0] + ""}; + } + + return result; +}; + +$(function () { + updateProgressInterval(); +}); + +function updateProgressInterval() { + updateProgress(); + interval = setInterval(function () + { + updateProgress(); + }, 3000); +} + +function updateProgress() { + $.get($.createLink('zahost', 'ajaxImageDownloadProgress', 'hostID=' + hostID)).done(function (response) + { + var result = JSON.parse(response); + var statusList = result.data; + + var hasInprogress = false; + for (var imageID in statusList) { + if (statusList[imageID].statusCode) { + if (statusList[imageID].statusCode == 'inprogress' || statusList[imageID].statusCode == 'created' || statusList[imageID].statusCode == 'pending') + { + hasInprogress = true; + } + else if (statusList[imageID].statusCode == 'completed') + { + $('.image-path-' + imageID).text(statusList[imageID].path); + $('.image-path-' + imageID).attr('title', statusList[imageID].path); + $('.image-progress-' + imageID).text("100%"); + } + else + { + $('.image-progress-' + imageID).text(''); + } + + if(statusList[imageID].status != $('.image-status-' + imageID).text()) loadPage(); + + $('.image-status-' + imageID).text(statusList[imageID].status); + if(statusList[imageID].progress != '' && statusList[imageID].statusCode != 'completed') + { + $('.image-progress-' + imageID).text(statusList[imageID].progress); + } + } + } + if (!hasInprogress) + { + clearInterval(interval) + } + }); +} diff --git a/module/host/model.php b/module/host/model.php index e6b6125abd..295d8aec2c 100644 --- a/module/host/model.php +++ b/module/host/model.php @@ -481,6 +481,64 @@ class hostModel extends model if($host->status == 'online' && $action == 'online') return false; if($host->status == 'offline' && $action == 'offline') return false; + if($action === 'download') + { + if(in_array($host->status, array("completed", "inprogress", "created")) || $host->from == 'user') return false; + } + + if($action === 'cancel') + { + if(!in_array($host->status, array("inprogress", "created"))) return false; + } + return true; } + + /** + * Get image files from ZAgent server. + * + * @param object $hostID + * @access public + * @return array + */ + public function getImageList($hostID, $browseType = 'all', $param = 0, $orderBy = 'id', $pager = null) + { + $imageList = json_decode(commonModel::http($this->config->host->imageListUrl, array(), array())); + if(empty($imageList)) return array(); + + $downloadedImageList = $this->dao->select('*')->from(TABLE_IMAGE) + ->where('host')->eq($hostID) + ->orderBy($orderBy) + ->page($pager) + ->fetchAll('name'); + + $refreshPageData = false; + foreach($imageList as $remoteImage) + { + $downloadedImage = zget($downloadedImageList, $remoteImage->name, ''); + if(empty($downloadedImage)) + { + $refreshPageData = true; + $remoteImage->status = 'notDownloaded'; + $remoteImage->from = 'zentao'; + $remoteImage->osName = $remoteImage->os; + $remoteImage->host = $hostID; + $remoteImage->status = 'notDownloaded'; + + unset($remoteImage->os); + $this->dao->insert(TABLE_IMAGE)->data($remoteImage, 'desc')->autoCheck()->exec(); + } + } + + if($refreshPageData) + { + $downloadedImageList = $this->dao->select('*')->from(TABLE_IMAGE) + ->where('host')->eq($hostID) + ->orderBy($orderBy) + ->page($pager) + ->fetchAll('name'); + } + + return $downloadedImageList; + } } diff --git a/module/host/ui/browseimage.html.php b/module/host/ui/browseimage.html.php new file mode 100644 index 0000000000..6a2c8ed322 --- /dev/null +++ b/module/host/ui/browseimage.html.php @@ -0,0 +1,30 @@ + + * @package host + * @link http://www.zentao.net + */ + +namespace zin; + +jsVar('hostID', $hostID); +jsVar('orderBy', $orderBy); +jsVar('sortLink', helper::createLink('host', 'browseImage', "hostID={$hostID}&browseType=$browseType¶m=$param&orderBy={orderBy}&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}")); + +$tableData = initTableData($imageList, $config->host->imageDtable->fieldList); + +dtable +( + set::cols(array_values($config->host->imageDtable->fieldList)), + set::data($tableData), + set::sortLink(jsRaw('createSortLink')), + set::onRenderCell(jsRaw('window.renderCell')), + set::footPager(usePager()), +); + +render(); diff --git a/module/host/view/browseimage.html.php b/module/host/view/browseimage.html.php new file mode 100644 index 0000000000..9cea536bf9 --- /dev/null +++ b/module/host/view/browseimage.html.php @@ -0,0 +1,63 @@ + + * @package zahost + * @version $Id$ + * @link http://www.zentao.net + */ +?> +getModuleRoot() . 'common/view/header.html.php';?> + + +
' data-module='vmTemplate'>
+
+ recTotal}&recPerPage={$pager->recPerPage}";?> + +
+

+ zahost->image->imageEmpty;?> +

+
+ + + + + + + + + + + + + + + + status == 'completed' ? zget($image, 'path', '') : '';?> + + + + + + + + + +
zahost->image->name);?>zahost->image->os);?>zahost->status;?>zahost->image->path;?>zahost->image->progress;?>actions;?>
name;?>osName;?>'>zahost->image->statusList, $image->status, '');?>'> + createLink('zahost', 'downloadImage', "hostID={$hostID}&imageID={$image->id}"), '', 'hiddenwin', zget($image, 'downloadMisc', ''));?> + createLink('zahost', 'cancelDownload', "id={$image->id}"), '', 'hiddenwin', zget($image, 'cancelMisc', ''));?> +
+ + +
+getModuleRoot() . 'common/view/footer.html.php';?>