zentaopms/module/zahost/model.php
2023-05-16 10:47:08 +08:00

604 lines
18 KiB
PHP

<?php
/**
* The model file of zahost module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Wang Jianhua <wangjiahua@easycorp.ltd>
* @package zahost
* @version $Id$
* @link http://www.zentao.net
*/
class zahostModel extends model
{
/**
* Set lang;
*
* @access public
* @return void
*/
public function __construct()
{
parent::__construct();
$this->app->lang->host = $this->lang->zahost;
}
/**
* Create a host.
*
* @access public
* @return int|bool
*/
public function create()
{
$hostInfo = fixer::input('post')
->setDefault('cpuNumber,cpuCores,diskSize,memory', 0)
->trim('extranet')
->get();
$this->dao->table = 'zahost';
$hostInfo->type = 'zahost';
$hostInfo->status = 'wait';
$hostInfo->createdBy = $this->app->user->account;
$hostInfo->createdDate = helper::now();
$hostInfo->zap = $this->config->zahost->defaultPort;
$hostInfo->secret = md5($hostInfo->name . time());
$this->dao->update(TABLE_ZAHOST)->data($hostInfo)
->batchCheck($this->config->zahost->create->requiredFields, 'notempty')
->batchCheck('cpuCores,diskSize', 'gt', 0)
->batchCheck('diskSize,memory', 'float')
->check('name', 'unique', "type='zahost'")
->autoCheck();
if(dao::isError()) return false;
$ping = $this->checkAddress($hostInfo->extranet);
if(!$ping)
{
return false;
}
$this->dao->insert(TABLE_ZAHOST)->data($hostInfo)->autoCheck()->exec();
$hostID = $this->dao->lastInsertID();
if(!dao::isError())
{
$this->loadModel('action')->create('zahost', $hostID, 'created');
return $hostID;
}
return false;
}
/**
* Update a host.
*
* @param int $hostID
* @access public
* @return array|bool
*/
public function update($hostID)
{
$oldHost = $this->getById($hostID);
$hostInfo = fixer::input('post')->get();
$hostInfo->editedBy = $this->app->user->account;
$hostInfo->editedDate = helper::now();
$this->dao->update(TABLE_ZAHOST)->data($hostInfo)
->batchCheck($this->config->zahost->create->requiredFields, 'notempty')
->batchCheck('diskSize,memory', 'float')
->check('name', 'unique', "id != $hostID and type in ('vhost', 'zahost')")
->autoCheck();
if(dao::isError()) return false;
$ping = $this->checkAddress($hostInfo->extranet);
if(!$ping)
{
return false;
}
$this->dao->update(TABLE_ZAHOST)->data($hostInfo)->autoCheck()
->batchCheck('cpuCores,diskSize', 'gt', 0)
->batchCheck('diskSize,memory', 'float')
->where('id')->eq($hostID)->exec();
return common::createChanges($oldHost, $hostInfo);
}
/**
* Ping ip/domain.
*
* @param string $address
* @access public
* @return bool
*/
public function ping($address)
{
if (strcasecmp(PHP_OS, 'WINNT') === 0)
{
exec("ping -n 1 {$address}", $outcome, $status);
}
elseif (strcasecmp(PHP_OS, 'Linux') === 0)
{
exec("ping -c 1 {$address}", $outcome, $status);
}
if (0 == $status)
{
$status = true;
}
else
{
$status = false;
}
return $status;
}
/**
* Telnet ip/domain.
*
* @param string $address
* @access public
* @return bool
*/
public function checkAddress($address)
{
$address = str_replace(array('https://', 'http://'), '', $address);
if ($this->ping($address)) return true;
foreach(array(80, 443, $this->config->zahost->defaultPort) as $port)
{
$fp = fsockopen($address, $port, $errno, $errstr, 3);
if ($fp) return true;
}
return false;
}
/**
* Get image by ID.
*
* @param int $imageID
* @access public
* @return object
*/
public function getImageByID($imageID)
{
return $this->dao->select('*')->from(TABLE_IMAGE)->where('id')->eq($imageID)->fetch();
}
/**
* Get image by name.
*
* @param string $imageName
* @param int $hostID
* @access public
* @return object
*/
public function getImageByNameAndHostID($imageName, $hostID)
{
return $this->dao->select('*')->from(TABLE_IMAGE)
->where('host')->eq($hostID)
->andWhere('name')->eq($imageName)->fetch();
}
/**
* 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->zahost->imageListUrl, array(), 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->id = 0;
$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');
}
foreach($downloadedImageList as $image)
{
if($image->status == 'notDownloaded')
{
$image->cancelMisc = sprintf("title='%s' class='btn image-cancel image-cancel-%d %s'", $this->lang->zahost->cancel, $image->id, "disabled");
$image->downloadMisc = sprintf("title='%s' class='btn image-download image-download-%d %s'", $this->lang->zahost->image->downloadImage, $image->id, "");
}
else
{
$image->cancelMisc = sprintf("title='%s' data-id='%s' class='btn image-cancel image-cancel-%d %s'", $this->lang->zahost->cancel, $image->id, $image->id, in_array($image->status, array("inprogress", "created")) ? "" : "disabled");
$image->downloadMisc = sprintf("title='%s' data-id='%s' class='btn image-download image-download-%d %s'", $this->lang->zahost->image->downloadImage, $image->id, $image->id, in_array($image->status, array("completed", "inprogress", "created")) || $image->from == 'user' ? "disabled" : "");
}
}
return $downloadedImageList;
}
/**
* create image.
*
* @param int $hostID
* @param string $imageName
* @access public
* @return object
*/
public function createImage($hostID, $imageName)
{
$imageList = json_decode(commonModel::http($this->config->zahost->imageListUrl, array(), array()));
$imageData = new stdclass;
foreach($imageList as $item) if($item->name == $imageName) $imageData = $item;
$imageData->host = $hostID;
$imageData->status = 'created';
$imageData->osName = $imageData->os;
unset($imageData->os);
$this->dao->insert(TABLE_IMAGE)->data($imageData, 'desc')->autoCheck()->exec();
if(dao::isError()) return false;
$imageID = $this->dao->lastInsertID();
$this->loadModel('action')->create('image', $imageID, 'Created');
return $this->getImageByID($imageID);
}
/**
* Send download image command to HOST.
*
* @param object $image
* @access public
* @return bool
*/
public function downloadImage($image)
{
$host = $this->getById($image->host);
$apiUrl = 'http://' . $host->extranet . ':' . $host->zap . '/api/v1/download/add';
$apiParams['md5'] = $image->md5;
$apiParams['url'] = $image->address;
$apiParams['task'] = intval($image->id);
$response = json_decode(commonModel::http($apiUrl, array($apiParams), array(CURLOPT_CUSTOMREQUEST => 'POST'), array("Authorization:$host->tokenSN"), 'json'));
if($response and $response->code == 'success')
{
$this->dao->update(TABLE_IMAGE)
->set('status')->eq('created')
->where('id')->eq($image->id)->exec();
return true;
}
dao::$errors[] = $this->lang->zahost->image->downloadImageFail;
return false;
}
/**
* Query image download progress.
*
* @param object $image
* @access public
* @return object Return Status code.
*/
public function queryDownloadImageStatus($image)
{
if(empty($this->imageStatusList))
{
$host = $this->getById($image->host);
$apiUrl = 'http://' . $host->extranet . ':' . $host->zap . '/api/v1/task/getStatus';
$this->imageStatusList = $result = json_decode(commonModel::http($apiUrl, array(), array(CURLOPT_CUSTOMREQUEST => 'POST'), array("Authorization:$host->tokenSN"), 'json'));
if(!$result or $result->code != 'success') return $image->status;
}else{
$result = $this->imageStatusList;
}
$currentTask = null;
$is_finish = false;
foreach($result->data as $status => $group)
{
if($is_finish) break;
foreach($group as $task)
{
if($is_finish) break;
if($task->task == $image->id)
{
$task->endDate = substr($task->endDate, 0, 19);
if(empty($currentTask) || strtotime($task->endDate) > strtotime($currentTask->endDate))
{
$currentTask = $task;
}
if($task->status == 'inprogress')
{
$currentTask = $task;
$is_finish = true;
break;
}
}
}
}
if($currentTask)
{
$image->rate = $currentTask->rate;
$image->status = $currentTask->status;
if(!empty($result->data->inprogress) && $currentTask->task != $result->data->inprogress[0]->task && $currentTask->status == 'created') $image->status = 'pending';
$this->dao->update(TABLE_IMAGE)
->set('status')->eq($image->status)
->set('path')->eq(!empty($currentTask->path) ? $currentTask->path : '')
->where('id')->eq($image->id)->exec();
$image->taskID = $currentTask->id;
}
else
{
$image->taskID = 0;
}
return $image;
}
/**
* Query download image status.
*
* @param object $image
* @access public
* @return object
*/
public function downloadImageStatus($image)
{
$host = $this->getById($image->host);
$statusApi = 'http://' . $host->extranet . ':' . $host->zap . '/api/v1/task/status';
$response = json_decode(commonModel::http($statusApi, array(), array(CURLOPT_CUSTOMREQUEST => 'GET'), array("Authorization:$host->tokenSN"), 'json'));
if($response->code == 200) return true;
dao::$errors[] = $response->msg;
return false;
}
/**
* Send cancel download image command to HOST.
*
* @param object $image
* @access public
* @return bool
*/
public function cancelDownload($image)
{
$zaInfo = $this->queryDownloadImageStatus($image);
$host = $this->getById($image->host);
$apiUrl = 'http://' . $host->extranet . ':' . $host->zap . '/api/v1/download/cancel';
$apiParams['id'] = intval($zaInfo->taskID);
$response = json_decode(commonModel::http($apiUrl, $apiParams, array(CURLOPT_CUSTOMREQUEST => 'POST'), array("Authorization:$host->tokenSN"), 'json'));
if($response and $response->code == 'success')
{
$this->dao->update(TABLE_IMAGE)
->set('status')->eq('canceled')
->where('id')->eq($image->id)->exec();
return true;
}
dao::$errors[] = $this->lang->zahost->image->cancelDownloadFail;
return false;
}
/**
* Get host by id.
*
* @param int $hostID
* @access public
* @return object
*/
public function getById($hostID)
{
$host = $this->dao->select('*,id as hostID')->from(TABLE_ZAHOST)
->where('id')->eq($hostID)
->fetch();
if(time() - strtotime($host->heartbeat) > 60 && $host->status == 'online')
{
$host->status = 'offline';
}
return $host;
}
/**
* Get pairs.
*
* @param string $idFrom
* @access public
* @return array
*/
public function getPairs()
{
return $this->dao->select("id,name")->from(TABLE_ZAHOST)
->where('deleted')->eq('0')
->andWhere('type')->eq('zahost')
->orderBy('`group`')
->fetchPairs('id', 'name');
}
/**
* Get host list.
*
* @param string $browseType
* @param int $param
* @param string $orderBy
* @param object $pager
* @access public
* @return array
*/
public function getList($browseType = 'all', $param = 0, $orderBy = 'id_desc', $pager = null)
{
$query = '';
if($browseType == 'bysearch')
{
/* Concatenate the conditions for the query. */
if($param)
{
$query = $this->loadModel('search')->getQuery($param);
if($query)
{
$this->session->set('zahostQuery', $query->sql);
$this->session->set('zahostForm', $query->form);
}
else
{
$this->session->set('zahostQuery', ' 1 = 1');
}
}
else
{
if($this->session->zahostQuery == false) $this->session->set('zahostQuery', ' 1 = 1');
}
$query = $this->session->zahostQuery;
}
$list = $this->dao->select('*,id as hostID')->from(TABLE_ZAHOST)
->where('deleted')->eq('0')
->andWhere('type')->eq('zahost')
->beginIF($query)->andWhere($query)->fi()
->orderBy($orderBy)
->page($pager)
->fetchAll();
foreach($list as $host)
{
if(time() - strtotime($host->heartbeat) > 60 && $host->status == 'online')
{
$host->status = 'offline';
}
}
return $list;
}
/**
* Get zanode group by zahost.
*
* @access public
* @return void
*/
public function getHostNodeGroup()
{
return $this->dao->select('t1.id as hostID, t2.*')->from(TABLE_ZAHOST)->alias('t1')
->leftJoin(TABLE_ZAHOST)->alias('t2')->on('t2.parent = t1.id')
->where('t2.deleted')->eq('0')
->andWhere('t1.deleted')->eq('0')
->fetchGroup('hostID', 'id');
}
/**
* Build test task menu.
*
* @param object $host
* @param string $type
* @access public
* @return string
*/
public function buildOperateMenu($host, $type = 'view')
{
$function = 'buildOperate' . ucfirst($type) . 'Menu';
return $this->$function($host);
}
/**
* Build test task view menu.
*
* @param object $host
* @access public
* @return string
*/
public function buildOperateViewMenu($host)
{
if($host->deleted) return '';
$nodeList = $this->loadModel('zanode')->getListByHost($host->id);
$disabled = '';
$title = !empty($nodeList) ? $this->lang->zahost->undeletedNotice : $this->lang->zahost->delete;
if($nodeList) $disabled = 'disabled';
$menu = '';
$params = "hostID=$host->id";
$menu .= $this->buildMenu('zahost', 'browseImage', $params, $host, 'view', 'mirror', '', 'iframe', true, '', $this->lang->zahost->image->browseImage);
$menu .= "<div class='divider'></div>";
$menu .= $this->buildMenu('zahost', 'edit', $params, $host, 'view');
$menu .= $this->buildMenu('zahost', 'delete', $params, $host, 'view', 'trash', 'hiddenwin', $disabled, true, '', $title);
return $menu;
}
/**
* Get image pairs by host.
*
* @param int $hostID
* @access public
* @return array
*/
public function getImagePairs($hostID)
{
return $this->dao->select('id,name')->from(TABLE_IMAGE)->where('host')->eq($hostID)->andWhere('status')->eq('completed')->fetchPairs();
}
/**
* Get service status from ZAgent server.
*
* @param object $host
* @access public
* @return array
*/
public function getServiceStatus($host)
{
if(in_array($host->status, array('wait', 'offline'))) return $this->lang->zahost->init->serviceStatus;
$result = json_decode(commonModel::http("http://{$host->extranet}:{$host->zap}/api/v1/service/check", json_encode(array("services" => "all")), array(), array("Authorization:$host->tokenSN")));
if(empty($result) || $result->code != 'success')
{
$result = new stdclass;
$result->data = $this->lang->zahost->init->serviceStatus;
}
return $result->data;
}
}