vendor/elements/process-manager-bundle/src/Controller/MonitoringItemController.php line 47

Open in your IDE?
  1. <?php
  2. /**
  3.  * Elements.at
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Enterprise License (PEL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) elements.at New Media Solutions GmbH (https://www.elements.at)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PEL
  13.  */
  14. namespace Elements\Bundle\ProcessManagerBundle\Controller;
  15. use Elements\Bundle\ProcessManagerBundle\Executor\Action\AbstractAction;
  16. use Elements\Bundle\ProcessManagerBundle\Executor\Logger\AbstractLogger;
  17. use Elements\Bundle\ProcessManagerBundle\Executor\Logger\Application;
  18. use Elements\Bundle\ProcessManagerBundle\Executor\Logger\File;
  19. use Elements\Bundle\ProcessManagerBundle\Message\ExecuteCommandMessage;
  20. use Elements\Bundle\ProcessManagerBundle\Model\Configuration;
  21. use Elements\Bundle\ProcessManagerBundle\Model\MonitoringItem;
  22. use Pimcore\Bundle\AdminBundle\Controller\AdminController;
  23. use Pimcore\Bundle\AdminBundle\Helper\QueryParams;
  24. use Pimcore\Templating\Model\ViewModel;
  25. use Symfony\Component\HttpFoundation\JsonResponse;
  26. use Symfony\Component\HttpFoundation\Request;
  27. use Symfony\Component\HttpKernel\Profiler\Profiler;
  28. use Symfony\Component\Messenger\MessageBusInterface;
  29. use Symfony\Component\Routing\Annotation\Route;
  30. use Elements\Bundle\ProcessManagerBundle\ElementsProcessManagerBundle;
  31. use Elements\Bundle\ProcessManagerBundle\Enums;
  32. /**
  33.  * @Route("/admin/elementsprocessmanager/monitoring-item")
  34.  */
  35. class MonitoringItemController extends AdminController
  36. {
  37.     /**
  38.      * @Route("/list")
  39.      *
  40.      * @param Request $request
  41.      *
  42.      * @return JsonResponse
  43.      */
  44.     public function listAction(Request $request)
  45.     {
  46.         $this->checkPermission(Enums\Permissions::VIEW);
  47.         $data = [];
  48.         $list = new MonitoringItem\Listing();
  49.         $list->setOrder('DESC');
  50.         $list->setOrderKey('id');
  51.         $list->setLimit($request->get('limit'25));
  52.         $list->setUser($this->getAdminUser());
  53.         $list->setOffset($request->get('start'));
  54.         $allParams array_merge($request->request->all(), $request->query->all());
  55.         $sortingSettings QueryParams::extractSortingSettings($allParams);
  56.         if ($sortingSettings['orderKey'] && $sortingSettings['order']) {
  57.             $list->setOrderKey($sortingSettings['orderKey']);
  58.             $list->setOrder($sortingSettings['order']);
  59.         }
  60.         $callbacks = [
  61.             'executedByUser' => function ($f) {
  62.                 $db \Pimcore\Db::get();
  63.                 $ids $db->fetchCol('SELECT id FROM users where name LIKE '.$db->quote('%'.$f->value.'%')) ?: [0];
  64.                 return ' executedByUser IN( '.implode(','$ids).') ';
  65.             }
  66.         ];
  67.         if ($filterCondition QueryParams::getFilterCondition(
  68.             $request->get('filter'),
  69.             ['id''o_id''pid'],
  70.             true,
  71.             $callbacks
  72.         )
  73.         ) {
  74.             $list->setCondition($filterCondition);
  75.         }
  76.         $condition $list->getCondition();
  77.         if($filters $request->get('filter')){
  78.             foreach(json_decode($filters,true) as $e){
  79.                 if($e['property'] == 'id'){
  80.                     $condition .= ' OR `parentId` = ' . (int)$e['value'].' ';
  81.                 }
  82.             }
  83.         }
  84.         if (!$request->get('showHidden') || $request->get('showHidden') == 'false') {
  85.             $filterConditionArray =  QueryParams::getFilterCondition($request->get('filter'), ['id''o_id''pid'], false$callbacks);
  86.             if ($filterConditionArray && isset($filterConditionArray['id'])) {
  87.             } else {
  88.                 if ($condition) {
  89.                     $condition .= ' AND published=1';
  90.                 } else {
  91.                     $condition .= ' published=1';
  92.                 }
  93.             }
  94.         }
  95.         $list->setCondition($condition);
  96.         $total $list->getTotalCount();
  97.         foreach ($list->load() as $item) {
  98.             $data[] = $this->getItemData($item);
  99.         }
  100.         return $this->adminJson(['success' => true'total' => $total'data' => $data]);
  101.     }
  102.     /**
  103.      * @Route("/update")
  104.      *
  105.      * @param Request $request
  106.      *
  107.      * @return JsonResponse
  108.      */
  109.     public function update(Request $request){
  110.         $monitoringItem MonitoringItem::getById($request->get('id'));
  111.         $data = [];
  112.         if($monitoringItem){
  113.             if($monitoringItem->getExecutedByUser() == $this->getUser()->getId()){
  114.                 foreach($request->request->all() as $key => $value){
  115.                     $setter "set" ucfirst($key);
  116.                     if(method_exists($monitoringItem,$setter)){
  117.                         $monitoringItem->$setter($value);
  118.                     }
  119.                 }
  120.                 $monitoringItem->save();
  121.             }
  122.             $data $this->getItemData($monitoringItem);
  123.         }
  124.         return $this->json(['success' => true,'data' => $data]);
  125.     }
  126.     /**
  127.      * @return MonitoringItem\Listing
  128.      */
  129.     protected function getProcessesForCurrentUser(){
  130.         $list = new MonitoringItem\Listing();
  131.         $list->setOrder('DESC');
  132.         $list->setOrderKey('id');
  133.         #$list->setLimit(10);
  134.         $list->setCondition('executedByUser = ? and parentId IS NULL AND published = 1 ',[$this->getUser()->getId()]);
  135.         return $list;
  136.     }
  137.     /**
  138.      * @Route("/update-all-user-monitoring-items")
  139.      *
  140.      * @param Request $request
  141.      *
  142.      * @return JsonResponse
  143.      */
  144.     public function updateAllUserMonitoringItems(Request $request){
  145.         $list $this->getProcessesForCurrentUser();
  146.         $params $request->request->all();
  147.         /**
  148.          * @var MonitoringItem $item
  149.          */
  150.         foreach($list->load() as $item){
  151.             $item->setValues($params)->save();
  152.         }
  153.         return $this->adminJson(['success' => true]);
  154.     }
  155.     /**
  156.      * @Route("/list-processes-for-user")
  157.      *
  158.      * @param Request $request
  159.      *
  160.      * @return JsonResponse
  161.      */
  162.     public function listProcessesForUser(Request $request){
  163.         $data = [
  164.             'total' => 0,
  165.             'active' => 0,
  166.             'items' => []
  167.         ];
  168.         try {
  169.             $this->checkPermission(Enums\Permissions::VIEW);
  170.         }catch (\Exception $e){
  171.             return $this->adminJson($data);
  172.         }
  173.         $list $this->getProcessesForCurrentUser();
  174.         $data['total'] = $list->getTotalCount();
  175.         foreach($list->load() as $item){
  176.             $tmp $this->getItemData($item);
  177.             if($tmp['isAlive']){
  178.                 $data['active']++;
  179.             }
  180.             $data['items'][] = $tmp;
  181.         }
  182.         return $this->adminJson($data);
  183.     }
  184.     protected function getItemData(MonitoringItem $item){
  185.         $tmp $item->getObjectVars();
  186.         $tmp['messageShort'] = \Pimcore\Tool\Text::cutStringRespectingWhitespace($tmp['message'],30);
  187.         $tmp['steps'] = '-';
  188.         if ($item->getTotalSteps() > || $item->getCurrentStep()) {
  189.             $tmp['steps'] = $item->getCurrentStep().'/'.$item->getTotalSteps();
  190.         }
  191.         $tmp['duration'] = $item->getDuration() ?: '-';
  192.         $tmp['progress'] = 0;
  193.         if ($tmp['executedByUser']) {
  194.             $user \Pimcore\Model\User::getById($tmp['executedByUser']);
  195.             if ($user) {
  196.                 $tmp['executedByUser'] = $user->getName();
  197.             } else {
  198.                 $tmp['executedByUser'] = 'User id: '.$tmp['executedByUser'];
  199.             }
  200.         } else {
  201.             $tmp['executedByUser'] = 'System';
  202.         }
  203.         $logFile 0;
  204.         $tmp['action'] = '';
  205.         if ($actions $item->getActions()) {
  206.             foreach ($actions as $action) {
  207.                 /**
  208.                  * @var $class AbstractAction
  209.                  */
  210.                 $class = new $action['class'];
  211.                 if ($s $class->getGridActionHtml($item$action)) {
  212.                     $tmp['action'] .= $s;
  213.                 }
  214.             }
  215.         }
  216.         $tmp['actionItems'] = [];
  217.         if($tmp['actions']){
  218.             $actionItems json_decode($tmp['actions'],true);
  219.             foreach($actionItems as $i => $v){
  220.                 if($class $v['class']){
  221.                     if(\Pimcore\Tool::classExists($class)){
  222.                         $o = new $class();
  223.                         $v['dynamicData'] = $o->toJson($item,$v);
  224.                     }
  225.                     $actionItems[$i] = $v;
  226.                 }
  227.             }
  228.             $tmp['actionItems'] = $actionItems;
  229.         }
  230.         $tmp['logger'] = '';
  231.         if ($loggers $item->getLoggers()) {
  232.             foreach ((array)$loggers as $i => $logger) {
  233.                 /**
  234.                  * @var $class AbstractLogger
  235.                  */
  236.                 $class = new $logger['class'];
  237.                 if (\Pimcore\Tool::classExists(get_class($class))) {
  238.                     $logger['index'] = $i;
  239.                     if ($s $class->getGridLoggerHtml($item$logger)) {
  240.                         $tmp['logger'] .= $s;
  241.                     }
  242.                 }
  243.             }
  244.         }
  245.         $tmp['retry'] = 1;
  246.         if ($item->isAlive()) {
  247.             $tmp['retry'] = 0;
  248.         }
  249.         if ($tmp['retry'] == 1) {
  250.             $config Configuration::getById($item->getConfigurationId());
  251.             if ($config) {
  252.                 if ($config->getActive() == 0) {
  253.                     $tmp['retry'] = 0;
  254.                 } else {
  255.                         $uniqueExecution $config->getExecutorClassObject()->getValues()['uniqueExecution'] ?? false;
  256.                         if ($uniqueExecution) {
  257.                         $runningProcesses $config->getRunningProcesses();
  258.                         if (!empty($runningProcesses)) {
  259.                             $tmp['retry'] = 0;
  260.                         }
  261.                     }
  262.                 }
  263.             }
  264.         }
  265.         $tmp['isAlive'] = $item->isAlive();
  266.         $tmp['progress'] = '-';
  267.         if ($item->getCurrentWorkload() && $item->getTotalWorkload()) {
  268.             $progress $item->getProgressPercentage();
  269.             $tmp['progress'] = '<div class="x-progress x-progress-default x-border-box" style="width:100%;"><div class="x-progress-text x-progress-text-back" ></div><div class="x-progress-bar x-progress-bar-default" style="width:'.$progress.'%;min-width: 35px; "><div class="x-progress-text" style="text-align:left;margin-left: 5px;"><div>'.$progress.'%</div></div></div></div>';
  270.         }
  271.         $tmp['progressPercentage'] = (float)$item->getProgressPercentage();
  272.         $tmp['callbackSettingsString'] = json_encode($item->getCallbackSettings());
  273.         $tmp['callbackSettings'] = $item->getCallbackSettingsForGrid();
  274.         return $tmp;
  275.     }
  276.     /**
  277.      * @Route("/log-application-logger")
  278.      *
  279.      * @param Request $request
  280.      *
  281.      * @return JsonResponse
  282.      */
  283.     public function logApplicationLoggerAction(Request $request)
  284.     {
  285.         try {
  286.             $monitoringItem MonitoringItem::getById($request->get('id'));
  287.             if (!$monitoringItem) {
  288.                 throw new \Exception('Monitoring Item with id'.$request->get('id').' not found');
  289.             }
  290.             $loggerIndex $request->get('loggerIndex');
  291.             if ($loggers $monitoringItem->getLoggers()) {
  292.                 foreach ((array)$loggers as $i => $config) {
  293.                     /**
  294.                      * @var $class AbstractLogger
  295.                      * @var $logger Application
  296.                      */
  297.                     $class = new $config['class'];
  298.                     if (\Pimcore\Tool::classExists(get_class($class))) {
  299.                         if ($i == $loggerIndex) {
  300.                             $logger $class;
  301.                             if (!$config['logLevel']) {
  302.                                 $config['logLevel'] = 'DEBUG';
  303.                             }
  304.                             break;
  305.                         }
  306.                     }
  307.                 }
  308.             }
  309.             $result $monitoringItem->getObjectVars();
  310.             $result['logLevel'] = strtolower($config['logLevel']);
  311.             return $this->adminJson(['success' => true'data' => $result]);
  312.         } catch (\Exception $e) {
  313.             return $this->adminJson(['success' => false'message' => $e->getMessage()]);
  314.         }
  315.     }
  316.     /**
  317.      * @Route("/log-file-logger")
  318.      *
  319.      * @param Request $request
  320.      *
  321.      * @return \Symfony\Component\HttpFoundation\Response
  322.      */
  323.     public function logFileLoggerAction(Request $request, ?Profiler $profiler)
  324.     {
  325.         if(null !== $profiler) {
  326.             $profiler->disable();
  327.         }
  328.         $viewData = [];
  329.         $monitoringItem MonitoringItem::getById($request->get('id'));
  330.         $loggerIndex $request->get('loggerIndex');
  331.         if ($loggers $monitoringItem->getLoggers()) {
  332.             foreach ((array)$loggers as $i => $config) {
  333.                 /**
  334.                  * @var $class AbstractLogger
  335.                  * @var $logger File
  336.                  */
  337.                 $class = new $config['class'];
  338.                 if (\Pimcore\Tool::classExists(get_class($class))) {
  339.                     if ($i == $loggerIndex) {
  340.                         $logger $class;
  341.                         $logFile $logger->getLogFile($config$monitoringItem);
  342.                         if (!$config['logLevel']) {
  343.                             $config['logLevel'] = 'DEBUG';
  344.                         }
  345.                         break;
  346.                     }
  347.                 }
  348.             }
  349.         }
  350.         $viewData['logLevel'] = $config['logLevel'];
  351.         $viewData['logFile'] = $logFile;
  352.         if (is_readable($logFile)) {
  353.             $data file_get_contents($logFile);
  354.             if(array_key_exists("disableFileProcessing",$config) && $config['disableFileProcessing']){
  355.                 return new \Symfony\Component\HttpFoundation\Response($data);
  356.             }
  357.             $fileSizeMb round(filesize($logFile) / 1024 1024);
  358.             if ($fileSizeMb 100) {
  359.                 $data file_get_contents($logFile);
  360.                 $data explode("\n"$data);
  361.             } else {
  362.                 $data explode("\n"shell_exec('tail -n 1000 ' $logFile));
  363.                 $warning '<span style="color:#ff131c">The log file is to large to view all contents (' $fileSizeMb.'MB). The last 1000 lines are displayed. File: ' $logFile '</span>';
  364.                 array_unshift($data$warning);
  365.                 array_push($data$warning);
  366.             }
  367.             foreach ($data as $i => $row) {
  368.                 if ($row) {
  369.                     if (strpos($row'.WARNING')) {
  370.                         $data[$i] = '<span style="color:#ffb13b">'.$row.'</span>';
  371.                     }
  372.                     if (strpos($row'.ERROR') || strpos($row'.CRITICAL')) {
  373.                         $data[$i] = '<span style="color:#ff131c">'.$row.'</span>';
  374.                     }
  375.                     if (strpos($row'dev-server > ') === || strpos($row'production-server > ') === 0) {
  376.                         $data[$i] = '<span style="color:#35ad33">'.$row.'</span>';
  377.                     }
  378.                     foreach (['[echo]''[mkdir]''[delete]''[copy]'] as $k) {
  379.                         if (strpos($row$k)) {
  380.                             $data[$i] = '<span style="color:#49b7d4">'.$row.'</span>';
  381.                         }
  382.                     }
  383.                 }
  384.             }
  385.         } else {
  386.             $data = ["Log file doesn't exist. ".$logFile];
  387.         }
  388.         $data implode("\n"$data);
  389.         $viewData['data'] = $data;
  390.         $viewData['monitoringItem'] = $monitoringItem;
  391.         return $this->render('@ElementsProcessManager/MonitoringItem/logFileLogger.html.twig'$viewData);
  392.     }
  393.     /**
  394.      * @Route("/delete")
  395.      *
  396.      * @param Request $request
  397.      *
  398.      * @return JsonResponse
  399.      */
  400.     public function deleteAction(Request $request)
  401.     {
  402.         $this->checkPermission('plugin_pm_permission_delete_monitoring_item');
  403.         $entry MonitoringItem::getById($request->get('id'));
  404.         if ($entry) {
  405.             if($entry->isAlive()){
  406.                 $entry->stopProcess();
  407.             }
  408.             $entry->delete();
  409.             return $this->adminJson(['success' => true]);
  410.         }
  411.         return $this->adminJson(['success' => false'message' => "Couldn't delete entry"]);
  412.     }
  413.     /**
  414.      * @Route("/delete-batch")
  415.      *
  416.      * @param Request $request
  417.      *
  418.      * @return JsonResponse
  419.      */
  420.     public function deleteBatchAction(Request $request)
  421.     {
  422.         $this->checkPermission('plugin_pm_permission_delete_monitoring_item');
  423.         $logLevels array_filter(explode(','$request->get('logLevels')));
  424.         if (!empty($logLevels)) {
  425.             $list = new MonitoringItem\Listing();
  426.             $conditions = [];
  427.             foreach ($logLevels as $loglevel) {
  428.                 $conditions[] = ' status ="'.$loglevel.'" ';
  429.             }
  430.             $condition implode(' OR '$conditions);
  431.             $list->setCondition($condition);
  432.             $items $list->load();
  433.             foreach ($items as $item) {
  434.                 $item->delete();
  435.             }
  436.             return $this->adminJson(['success' => true]);
  437.         } else {
  438.             return $this->adminJson(
  439.                 [
  440.                     'success' => false,
  441.                     'message' => 'No statuses -> didn\'t deleted logs. Please select at least one status',
  442.                 ]
  443.             );
  444.         }
  445.     }
  446.     /**
  447.      * @Route("/cancel")
  448.      *
  449.      * @param Request $request
  450.      *
  451.      * @return JsonResponse
  452.      */
  453.     public function cancelAction(Request $request)
  454.     {
  455.         $monitoringItem MonitoringItem::getById($request->get('id'));
  456.         try {
  457.             $pid $monitoringItem->getPid();
  458.             if ($pid) {
  459.                 $status $monitoringItem->stopProcess();
  460.                 $message 'Process with PID "'.$pid.'" killed by Backend User: '.$this->getUser()->getUser()->getName();
  461.                 $monitoringItem->getLogger()->warning($message);
  462.                 foreach($monitoringItem->getChildProcesses() as $child) {
  463.                     $child->stopProcess();
  464.                 }
  465.                 return $this->adminJson(['success' => $status]);
  466.             }
  467.             return $this->adminJson(['success' => true]);
  468.         } catch (\Exception $e) {
  469.             return $this->adminJson(['success' => false'message' => $e->getMessage()]);
  470.         }
  471.     }
  472.     /**
  473.      * @Route("/restart")
  474.      *
  475.      * @param Request $request
  476.      *
  477.      * @return JsonResponse
  478.      */
  479.     public function restartAction(Request $requestMessageBusInterface $messageBus)
  480.     {
  481.         try {
  482.             $monitoringItem MonitoringItem::getById($request->get('id'));
  483.             $monitoringItem->setMessengerPending(true);
  484.             $monitoringItem->deleteLogFile()->resetState()->save();
  485.             putenv(ElementsProcessManagerBundle::MONITORING_ITEM_ENV_VAR '=' $monitoringItem->getId());
  486.             $message = new ExecuteCommandMessage($monitoringItem->getCommand(), $monitoringItem->getId(), $monitoringItem->getLogFile());
  487.             $messageBus->dispatch($message);
  488. ;
  489.             return $this->adminJson(['success' => true]);
  490.         } catch (\Exception $e) {
  491.             return $this->adminJson(['success' => false'message' => $e->getMessage()]);
  492.         }
  493.     }
  494.     /**
  495.      * @Route("/get-by-id")
  496.      *
  497.      * @param Request $request
  498.      *
  499.      * @return JsonResponse
  500.      */
  501.     public function getByIdAction(Request $request){
  502.         $data = [];
  503.         $item MonitoringItem::getById($request->get('id'));
  504.         $data $item->getObjectVars();
  505.         $data['callbackSettings'] = json_decode($data['callbackSettings']);
  506.         $data['executorSettings']['values'] = [];
  507.         return $this->adminJson($data);
  508.     }
  509. }