%PDF- %PDF-
| Direktori : /var/www/projetos/suporte.iigd.com.br/plugins/glpiinventory/inc/ |
| Current File : /var/www/projetos/suporte.iigd.com.br/plugins/glpiinventory/inc/taskjobstate.class.php |
<?php
/**
* ---------------------------------------------------------------------
* GLPI Inventory Plugin
* Copyright (C) 2021 Teclib' and contributors.
*
* http://glpi-project.org
*
* based on FusionInventory for GLPI
* Copyright (C) 2010-2021 by the FusionInventory Development Team.
*
* ---------------------------------------------------------------------
*
* LICENSE
*
* This file is part of GLPI Inventory Plugin.
*
* GLPI Inventory Plugin is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GLPI Inventory Plugin is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with GLPI Inventory Plugin. If not, see <https://www.gnu.org/licenses/>.
* ---------------------------------------------------------------------
*/
if (!defined('GLPI_ROOT')) {
die("Sorry. You can't access this file directly");
}
/**
* Manage the state of task jobs.
*/
class PluginGlpiinventoryTaskjobstate extends CommonDBTM
{
/**
* Define constant state prepared.
* The job is just prepared and waiting for agent request
*
* @var integer
*/
const PREPARED = 0;
/**
* Define constant state has sent data to agent and not have the answer.
* The job is running and the server sent the job config
*
* @var integer
*/
const SERVER_HAS_SENT_DATA = 1;
/**
* Define constant state agent has sent data.
* The job is running and the agent sent reply to the server
*
* @var integer
*/
const AGENT_HAS_SENT_DATA = 2;
/**
* Define constant state finished.
* The agent completed successfully the job
*
* @var integer
*/
const FINISHED = 3;
/**
* Define constant state in error.
* The agent failed to complete the job
*
* @var integer
*/
const IN_ERROR = 4;
/**
* Define constant state cancelled
* The job has been cancelled either by a user or the agent himself (eg. if
* it has been forbidden to run this taskjob)
*
* @var integer
*/
const CANCELLED = 5;
/**
* Define constant state in error.
* The agent failed to complete the job
*
* @var integer
*/
const POSTPONED = 6;
/**
* Initialize the public method
*
* @var string
*/
public $method = '';
public static $rightname = 'plugin_glpiinventory_task';
/**
* Get the tab name used for item
*
* @param CommonGLPI $item the item object
* @param integer $withtemplate 1 if is a template form
* @return string name of the tab
*/
public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0)
{
switch ($item->getType()) {
case 'Computer':
return __("Tasks / Groups", "glpiinventory");
case 'PluginGlpiinventoryTask':
return __("Job executions", "glpiinventory");
}
return '';
}
/**
* Get all states name
*
* @return array
*/
public static function getStateNames()
{
return [
self::PREPARED => __('Prepared', 'glpiinventory'),
self::SERVER_HAS_SENT_DATA => __('Server has sent data to the agent', 'glpiinventory'),
self::AGENT_HAS_SENT_DATA => __('Agent replied with data to the server', 'glpiinventory'),
self::FINISHED => __('Finished', 'glpiinventory'),
self::IN_ERROR => __('Error', 'glpiinventory'),
self::CANCELLED => __('Cancelled', 'glpiinventory'),
self::POSTPONED => __('Postponed', 'glpiinventory')
];
}
/**
* Display the content of the tab
*
* @param CommonGLPI $item
* @param integer $tabnum number of the tab to display
* @param integer $withtemplate 1 if is a template form
* @return boolean
*/
public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0)
{
if ($item instanceof PluginGlpiinventoryTask) {
$item->showJobLogs();
return true;
} elseif ($item instanceof Computer) {
$pfTaskJobState = new PluginGlpiinventoryTaskjobstate();
$pfTaskJobState->showStatesForComputer($item->fields['id']);
echo "<br>";
$pfDeployGroup = new PluginGlpiinventoryDeployGroup();
$pfDeployGroup->showForComputer($item->fields['id']);
}
return false;
}
/**
* Display state of taskjob
*
* @param integer $taskjobs_id id of the taskjob
* @param integer $width how large in pixel display array
* @param string $return display or return in var (html or htmlvar or other value
* to have state number in %)
* @param string $style '' = normal or 'simple' for very simple display
*
* @return string
*
**/
public function stateTaskjob($taskjobs_id, $width = 930, $return = 'html', $style = '')
{
global $DB;
$state = [0 => 0, 1 => 0, 2 => 0, 3 => 0];
$total = 0;
$iterator = $DB->request(['FROM' => 'glpi_plugin_glpiinventory_taskjobstates',
'WHERE' => ['plugin_glpiinventory_taskjobs_id' => $taskjobs_id,
'state' => ['NOT', self::FINISHED]]
]);
if ($iterator->numrows() > 0) {
foreach ($iterator as $data) {
$total++;
$state[$data['state']]++;
}
if ($total == '0') {
$globalState = 0;
} else {
$first = 25;
$second = ((($state[1] + $state[2] + $state[3]) * 100) / $total) / 4;
$third = ((($state[2] + $state[3]) * 100) / $total) / 4;
$fourth = (($state[3] * 100) / $total) / 4;
$globalState = $first + $second + $third + $fourth;
}
if ($return == 'html') {
if ($style == 'simple') {
Html::displayProgressBar($width, ceil($globalState), ['simple' => 1]);
} else {
Html::displayProgressBar($width, ceil($globalState));
}
} elseif ($return == 'htmlvar') {
if ($style == 'simple') {
return PluginGlpiinventoryDisplay::getProgressBar(
$width,
ceil($globalState),
['simple' => 1]
);
} else {
return PluginGlpiinventoryDisplay::getProgressBar(
$width,
ceil($globalState)
);
}
} else {
return ceil($globalState);
}
}
return '';
}
/**
* Change the state
*
* @todo There is no need to pass $id since we should use this method with
* an instantiated object
*
* @param integer $id id of the taskjobstate
* @param integer $state state to set
*/
public function changeStatus($id, $state)
{
$this->update(['id' => $id, 'state' => $state]);
}
/**
* Get taskjobs of an agent
*
* @param integer $agent_id id of the agent
*/
public function getTaskjobsAgent($agent_id)
{
global $DB;
$pfTaskjob = new PluginGlpiinventoryTaskjob();
$moduleRun = [];
$params = ['FROM' => 'glpi_plugin_glpiinventory_taskjobstates',
'FIELDS' => 'plugin_glpiinventory_taskjobs_id',
'WHERE' => ['agents_id' => $agent_id,
'state' => self::PREPARED],
'ORDER' => 'id'
];
foreach ($DB->request($params) as $data) {
// Get job and data to send to agent
if ($pfTaskjob->getFromDB($data['plugin_glpiinventory_taskjobs_id'])) {
$moduleName = PluginGlpiinventoryModule::getModuleName($pfTaskjob->fields['plugins_id']);
if ($moduleName) {
$className = "Plugin" . ucfirst($moduleName) . ucfirst($pfTaskjob->fields['method']);
$moduleRun[$className][] = $data;
}
}
}
return $moduleRun;
}
/**
* Process ajax parameters for getLogs() methods
* Displays in json format, encoded list of logs grouped by jobstates
*
* since 0.85+1.0
* @param array $params list of ajax expected 'id' and 'last_date' parameters
* @return void
*/
public function ajaxGetLogs($params)
{
$id = null;
$last_date = null;
if (isset($params['id']) and $params['id'] > 0) {
$id = $params['id'];
}
if (isset($params['last_date'])) {
$last_date = $params['last_date'];
}
if (!preg_match("/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/", $last_date)) {
$last_date = null;
}
if (!is_null($id) && !is_null($last_date)) {
echo json_encode($this->getLogs($id, $last_date));
}
}
/**
* Get logs associated to a jobstate.
*
* @global object $DB
* @param integer $id
* @param string $last_date
* @return array
*/
public function getLogs($id, $last_date)
{
global $DB;
$iterator = $DB->request([
'SELECT' => [
'log.id',
'log.date',
'log.comment',
'log.state',
'run.uniqid AS runid'
],
'FROM' => 'glpi_plugin_glpiinventory_taskjoblogs AS log',
'LEFT JOIN' => [
'glpi_plugin_glpiinventory_taskjobstates AS run' => [
'ON' => [
'run' => 'id',
'log' => 'plugin_glpiinventory_taskjobstates_id'
]
]
],
'WHERE' => [
'run.id' => $id,
'log.date' => ['<=', $last_date]
],
'ORDER' => 'log.id DESC'
]);
$logs = [];
foreach ($iterator as $result) {
$run_id = $result['runid'];
$logs['run'] = $run_id;
$logs['logs'][] = [
'log.id' => $result['id'],
'log.comment' => PluginGlpiinventoryTaskjoblog::convertComment($result['comment']),
'log.date' => $result['date'],
'log.f_date' => Html::convDateTime($result['date']),
'log.state' => $result['state']
];
}
return $logs;
}
/**
* Change the status to finish
*
* @param integer $taskjobstates_id id of the taskjobstates
* @param integer $items_id id of the item
* @param string $itemtype type of the item
* @param integer $error error
* @param string $message message for the status
*/
public function changeStatusFinish($taskjobstates_id, $items_id, $itemtype, $error = 0, $message = '')
{
$pfTaskjoblog = new PluginGlpiinventoryTaskjoblog();
$pfTaskjob = new PluginGlpiinventoryTaskjob();
$this->getFromDB($taskjobstates_id);
$input = [];
$input['id'] = $this->fields['id'];
$input['state'] = self::FINISHED;
$log_input = [];
if ($error == "1") {
$log_input['state'] = PluginGlpiinventoryTaskjoblog::TASK_ERROR;
$input['state'] = self::IN_ERROR;
} else {
$log_input['state'] = PluginGlpiinventoryTaskjoblog::TASK_OK;
$input['state'] = self::FINISHED;
}
$this->update($input);
$log_input['plugin_glpiinventory_taskjobstates_id'] = $taskjobstates_id;
$log_input['items_id'] = $items_id;
$log_input['itemtype'] = $itemtype;
$log_input['date'] = $_SESSION['glpi_currenttime'];
$log_input['comment'] = $message;
$log_input = Toolbox::addslashes_deep($log_input);
$pfTaskjoblog->add($log_input);
$pfTaskjob->getFromDB($this->fields['plugin_glpiinventory_taskjobs_id']);
}
/**
* Update taskjob(log) in error
*
* @param string $reason
*/
public function fail($reason = '')
{
$this->updateState(
PluginGlpiinventoryTaskjoblog::TASK_ERROR,
self::IN_ERROR,
$reason
);
}
/*
* Postpone a job
* @param string $type the type of interaction (before download, etc)
* @param string $reason the text to be displayed
*/
public function postpone($type, $reason = '')
{
$this->updateState(
PluginGlpiinventoryTaskjoblog::TASK_INFO,
self::POSTPONED,
$reason
);
$this->processPostonedJob($type);
}
/**
* Cancel a taskjob
*
* @param string $reason
*/
public function cancel($reason = '')
{
$this->updateState(
PluginGlpiinventoryTaskjoblog::TASK_INFO,
self::CANCELLED,
$reason
);
}
/**
* Update the state of a jobstate
* @since 9.2
*
* @param string $joblog_state the state of the joblog to set
* @param string $jobstate_state the state of the jobstate to set
* @param string $reason
*/
public function updateState($joblog_state, $jobstate_state, $reason = '')
{
$log = new PluginGlpiinventoryTaskjoblog();
$log_input = [
'plugin_glpiinventory_taskjobstates_id' => $this->fields['id'],
'items_id' => $this->fields['items_id'],
'itemtype' => $this->fields['itemtype'],
'date' => $_SESSION['glpi_currenttime'],
'state' => $joblog_state,
'comment' => Toolbox::addslashes_deep($reason)
];
$log->add($log_input);
$this->update([
'id' => $this->fields['id'],
'state' => $jobstate_state
]);
}
private function processPostonedJob($type)
{
$pfDeployUserInteraction = new PluginGlpiinventoryDeployUserinteraction();
//Let's browse all user interactions
foreach ($pfDeployUserInteraction->getItemValues($this->fields['items_id']) as $interaction) {
//Look for the user interaction that matches our event
if ($interaction['type'] == $type && $interaction['template']) {
$params = $this->fields;
//Found, let's load the template
$template = new PluginGlpiinventoryDeployUserinteractionTemplate();
if ($template->getFromDB($interaction['template'])) {
//Get the template values
$template_values = $template->getValues();
//Compute the next run date for the job. Retry_after value is in seconds
$date = new \DateTime('+' . $template_values['retry_after'] . ' seconds');
$params['date_start'] = $date->format('Y-m-d H:i');
//Set the max number or retry
//(we set it each time a job is postponed because the value
//can change in the template)
$params['max_retry'] = $template_values['nb_max_retry'];
$params['nb_retry'] = $params['nb_retry'] + 1;
$params['state'] = self::PREPARED;
$states_id = $params['id'];
$this->update($params);
$reason = '-----------------------------------------------------';
$log = new PluginGlpiinventoryTaskjoblog();
$log_input = [
'plugin_glpiinventory_taskjobstates_id' => $states_id,
'items_id' => $this->fields['items_id'],
'itemtype' => $this->fields['itemtype'],
'date' => $_SESSION['glpi_currenttime'],
'state' => PluginGlpiinventoryTaskjoblog::TASK_INFO,
'comment' => Toolbox::addslashes_deep($reason)
];
$log->add($log_input);
$reason = sprintf(
__('Job available for next execution at %s', 'glpiinventory'),
Html::convDateTime($params['date_start'], 'glpiinventory')
);
$log_input = [
'plugin_glpiinventory_taskjobstates_id' => $states_id,
'items_id' => $this->fields['items_id'],
'itemtype' => $this->fields['itemtype'],
'date' => $_SESSION['glpi_currenttime'],
'state' => PluginGlpiinventoryTaskjoblog::TASK_STARTED,
'comment' => Toolbox::addslashes_deep($reason)
];
$log->add($log_input);
if ($params['nb_retry'] <= $params['max_retry']) {
$reason = ' ' . sprintf(__('Retry #%d', 'glpiinventory'), $params['nb_retry']);
} else {
$reason = ' ' . sprintf(__('Maximum number of retry reached: force deployment', 'glpiinventory'));
}
$log_input = [
'plugin_glpiinventory_taskjobstates_id' => $states_id,
'items_id' => $this->fields['items_id'],
'itemtype' => $this->fields['itemtype'],
'date' => $_SESSION['glpi_currenttime'],
'state' => PluginGlpiinventoryTaskjoblog::TASK_INFO,
'comment' => Toolbox::addslashes_deep($reason)
];
$log->add($log_input);
}
}
}
}
/**
* Cron task: clean taskjob (retention time)
*
* @global object $DB
*/
public static function cronCleantaskjob()
{
global $DB;
$config = new PluginGlpiinventoryConfig();
$retentiontime = $config->getValue('delete_task');
$pfTaskjobstate = new PluginGlpiinventoryTaskjobstate();
$iterator = $DB->request([
'FROM' => 'glpi_plugin_glpiinventory_taskjoblogs',
'WHERE' => [
'date' => ['<', new \QueryExpression('DATE_ADD(NOW(), INTERVAL -' . $retentiontime . ' DAY)')]
],
'GROUPBY' => 'plugin_glpiinventory_taskjobstates_id'
]);
if (count($iterator)) {
$delete = $DB->buildDelete(
'glpi_plugin_glpiinventory_taskjoblogs',
[
'plugin_glpiinventory_taskjobstates_id' => new \QueryParam()
]
);
$stmt = $DB->prepare($delete);
foreach ($iterator as $data) {
$pfTaskjobstate->getFromDB($data['plugin_glpiinventory_taskjobstates_id']);
$pfTaskjobstate->delete($pfTaskjobstate->fields, 1);
$stmt->bind_param('s', $data['plugin_glpiinventory_taskjobstates_id']);
$DB->executeStatement($stmt);
}
mysqli_stmt_close($stmt);
}
}
/**
* Fill a taskjobstate by it's uuid
* @since 9.2
* @param string $uniqid taskjobstate's uniqid
*/
public function getFromDBByUniqID($uniqid)
{
$result = $this->find(['uniqid' => $uniqid], [], 1);
if (!empty($result)) {
$this->fields = array_pop($result);
}
}
/**
* Display the tasks where the computer is associated
*
* @param integer $computers_id
*/
public function showStatesForComputer($computers_id)
{
global $DB;
$agent = new Agent();
$pfTask = new PluginGlpiinventoryTask();
$pfTaskjob = new PluginGlpiinventoryTaskjob();
$pfTaskjoblog = new PluginGlpiinventoryTaskjoblog();
// Get the agent of the computer
$agent->getFromDBByCrit(['itemtype' => 'Computer', 'items_id' => $computers_id]);
$agents_id = $agent->fields['id'];
$tasks_id = [];
// Get tasks ids
$iterator = $DB->request([
'FROM' => $this->getTable(),
'WHERE' => [
'agents_id' => $agents_id,
],
'ORDER' => 'id DESC',
]);
foreach ($iterator as $data) {
$pfTaskjob->getFromDB($data['plugin_glpiinventory_taskjobs_id']);
$pfTask->getFromDB($pfTaskjob->fields['plugin_glpiinventory_tasks_id']);
if (!isset($tasks_id[$pfTask->fields['id']])) {
$tasks_id[$pfTask->fields['id']] = [
'is_active' => $pfTask->fields['is_active'],
'jobstates' => [],
'method' => $pfTaskjob->fields['method'],
'name' => $pfTask->fields['name'],
];
}
// Limit to 5 last runs
if (count($tasks_id[$pfTask->fields['id']]['jobstates']) < 5) {
$tasks_id[$pfTask->fields['id']]['jobstates'][] = $data['id'];
}
}
echo "<table width='950' class='tab_cadre_fixe'>";
echo "<tr>";
echo "<th>";
echo __('Task');
echo "</th>";
echo "<th>";
echo __('Active');
echo "</th>";
echo "<th>";
echo __('Module method');
echo "</th>";
echo "<th>";
echo _n('Date', 'Dates', 1);
echo "</th>";
echo "<th>";
echo __('Status');
echo "</th>";
echo "</tr>";
$modules_methods = PluginGlpiinventoryStaticmisc::getModulesMethods();
$link = Toolbox::getItemTypeFormURL("PluginGlpiinventoryTask");
$stateColors = [
PluginGlpiinventoryTaskjoblog::TASK_PREPARED => '#efefef',
PluginGlpiinventoryTaskjoblog::TASK_RUNNING => '#aaaaff',
PluginGlpiinventoryTaskjoblog::TASK_STARTED => '#aaaaff',
PluginGlpiinventoryTaskjoblog::TASK_OK => '#aaffaa',
PluginGlpiinventoryTaskjoblog::TASK_ERROR => '#ff0000',
];
foreach ($tasks_id as $id => $data) {
echo "<tr class='tab_bg_1'>";
echo "<td>";
echo "<a href='" . $link . "?id=" . $id . "'>" . $data['name'] . "</a>";
echo "</td>";
echo "<td>";
echo Dropdown::getYesNo($data['is_active']);
echo "</td>";
echo "<td>";
echo $modules_methods[$data['method']];
echo "</td>";
echo "<td colspan='2'>";
echo "</td>";
echo "</tr>";
// Each taskjobstate
foreach ($data['jobstates'] as $jobstates_id) {
$logs = $pfTaskjoblog->find(['plugin_glpiinventory_taskjobstates_id' => $jobstates_id], ['id DESC'], 1);
if (count($logs) > 0) {
$log = current($logs);
echo "<tr class='tab_bg_1'>";
echo "<td colspan='3'>";
echo "</td>";
echo "</td>";
echo "<td style='background-color: " . ($stateColors[$log['state']] ?? '#ffffff') . "'>";
echo Html::convDateTime($log['date']);
echo "</td>";
echo "<td style='background-color: " . ($stateColors[$log['state']] ?? '#ffffff') . "'>";
echo $pfTaskjoblog->getStateName($log['state']);
// status
echo "</td>";
echo "</tr>";
}
}
}
echo "</table>";
}
}