Blame view

src/Request/ProcessRequestImpl/Process/ProcessManagerClass.php 13.7 KB
22521f1c   Benjamin Renard   First commit
1
<?php
0a5bb843   Menouard AZIB   Refactoring Reque...
2

22521f1c   Benjamin Renard   First commit
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * @class ProcessManagerClass
 * @brief Process manager
 * @details
 */
class ProcessManagerClass
{
	private $processManagerFilePath;

	/*
	 * @brief Constructor
	*/
	function __construct($processManagerFilePath)
	{
		$this->processManagerFilePath = $processManagerFilePath;
	}

	/*
	 * @brief Run a process
	*/
a5413d3a   Benjamin Renard   Add user name in ...
23
	public function runProcess($cmd, $runningPath, $envArray, $postProcessCmd, $getErrorMsgCmd, $batchEnabled, $user, $fromWS = FALSE)
22521f1c   Benjamin Renard   First commit
24
	{
a5413d3a   Benjamin Renard   Add user name in ...
25
		$process = new ProcessClass($cmd, $postProcessCmd, $getErrorMsgCmd, $user, $fromWS);
22521f1c   Benjamin Renard   First commit
26
27

		if (!$process->run($runningPath, $envArray))
0b6b2080   Elena.Budnik   TT download
28
			return array("success" => false, "message" => "Cannot run the process");
22521f1c   Benjamin Renard   First commit
29

0a5bb843   Menouard AZIB   Refactoring Reque...
30
		$res = $this->concurrentAccessProcessManagerFile(array($this, 'addProcessInProcessManagerFile'), $process);
22521f1c   Benjamin Renard   First commit
31

0a5bb843   Menouard AZIB   Refactoring Reque...
32
		if (!$res['success']) {
22521f1c   Benjamin Renard   First commit
33
34
35
			$process->stop();
			return $res;
		}
0a5bb843   Menouard AZIB   Refactoring Reque...
36

bda99a72   Benjamin Renard   Add kill plot req...
37
38
		//Save process id in running path
		chdir($runningPath);
0a5bb843   Menouard AZIB   Refactoring Reque...
39
		file_put_contents("process_id", $res['result']['id'] . PHP_EOL);
22521f1c   Benjamin Renard   First commit
40

0a5bb843   Menouard AZIB   Refactoring Reque...
41
		$process->waitEndOfProcess(array($this, 'waitEndOfProcess'), $batchEnabled);
22521f1c   Benjamin Renard   First commit
42

0a5bb843   Menouard AZIB   Refactoring Reque...
43
		return $this->getProcessInfo($res['result']['id'], true);
22521f1c   Benjamin Renard   First commit
44
	}
0a5bb843   Menouard AZIB   Refactoring Reque...
45

bda99a72   Benjamin Renard   Add kill plot req...
46
47
48
49
50
	/*
	 * @brief Kill a process
	 */
	public function killProcess($id)
	{
0a5bb843   Menouard AZIB   Refactoring Reque...
51
		$res = $this->concurrentAccessProcessManagerFile(array($this, 'killProcessFromId'), $id);
bda99a72   Benjamin Renard   Add kill plot req...
52
53
		return $res;
	}
0a5bb843   Menouard AZIB   Refactoring Reque...
54

22521f1c   Benjamin Renard   First commit
55
56
57
	/*
	 * @brief Get info about a process
	*/
0a5bb843   Menouard AZIB   Refactoring Reque...
58
	public function getProcessInfo($id, $update)
22521f1c   Benjamin Renard   First commit
59
	{
0a5bb843   Menouard AZIB   Refactoring Reque...
60
		$res = $this->concurrentAccessProcessManagerFile(array($this, 'getProcessInfoFromId'), array('id' => $id, 'update' => $update));
22521f1c   Benjamin Renard   First commit
61
62
63
64
65
66
67
68
69
70
71
72

		if (!$res['success'])
			return $res;

		return $res['result'];
	}

	/*
	 * @brief Delete a process
	*/
	public function deleteProcess($id)
	{
0a5bb843   Menouard AZIB   Refactoring Reque...
73
		$res = $this->concurrentAccessProcessManagerFile(array($this, 'deleteProcessFromId'), $id);
22521f1c   Benjamin Renard   First commit
74
75
76
77
78
79
80
81
82
		return $res;
	}

	/*
	 * @brief Wait the end of the execution (or the timeout) of a process.
	*/
	public function waitEndOfProcess($process, $batchEnabled)
	{
		if ($batchEnabled)
0a5bb843   Menouard AZIB   Refactoring Reque...
83
84
			if (time() - $process->getRunningStart() > KernelConfigClass::getTimeToBatchMode())
				return false;
22521f1c   Benjamin Renard   First commit
85
86
87
		return true;
	}

0a5bb843   Menouard AZIB   Refactoring Reque...
88
	/*
1d67748e   Benjamin Renard   Limit number of p...
89
90
         * @brief Get nb of running processes. Is $name is not empty, get only the nb for the specifier user.
         */
0a5bb843   Menouard AZIB   Refactoring Reque...
91
92
93
	public function getNbRunningProcesses($user = "")
	{
		$res = $this->concurrentAccessProcessManagerFile(array($this, 'getRunningProcessesNb'), $user);
1d67748e   Benjamin Renard   Limit number of p...
94
95
96
		return $res;
	}

22521f1c   Benjamin Renard   First commit
97
98
99
	/*
	 * @brief Add a process in the manager file
	*/
0a5bb843   Menouard AZIB   Refactoring Reque...
100
101
102
	private function addProcessInProcessManagerFile($dom, $process)
	{
		$processId = "process_" . CommonClass::generateRandomString(6) . '_' . time() . '_' . $process->getPID();
22521f1c   Benjamin Renard   First commit
103
104
105
106
107
108
109
110
111
112
113
114
115
		$processNode = $dom->createElement("process");
		$processNode->setAttribute('xml:id', $processId);
		$dom->documentElement->appendChild($processNode);
		$this->updateProcessInProcessNode($dom, $processNode, $process);
		$dom->save($this->processManagerFilePath);
		return $this->getProcessInfoFromNode($processNode);
	}

	/*
	 * @brief Protection for concurrent access to the manager file
	*/
	private function concurrentAccessProcessManagerFile($callback, $additionalParams)
	{
0a5bb843   Menouard AZIB   Refactoring Reque...
116
		$lockFile = $this->processManagerFilePath . ".lockfile";
22521f1c   Benjamin Renard   First commit
117
118
119
120
121
122
123
124

		$fp = fopen($lockFile, "w+");

		if ($fp === false)
			return array('success' => false, 'message' => 'Cannot open process manager lock file');

		$res = true;

0a5bb843   Menouard AZIB   Refactoring Reque...
125
		if (flock($fp, LOCK_EX)) {
22521f1c   Benjamin Renard   First commit
126
127
128
			if (!file_exists($this->processManagerFilePath))
				$res = $this->createProcessManagerFile();

0a5bb843   Menouard AZIB   Refactoring Reque...
129
130
			if ($res) {
				$dom = new DOMDocument("1.0", "UTF-8");
22521f1c   Benjamin Renard   First commit
131
132
133
				$dom->preserveWhiteSpace = false;
				$dom->formatOutput = true;
				$res = $dom->load($this->processManagerFilePath);
a5413d3a   Benjamin Renard   Add user name in ...
134
135
				if ($res) {
					$this->cleanupProcessManagerFile($dom);
0a5bb843   Menouard AZIB   Refactoring Reque...
136
					$func_res = call_user_func($callback, $dom, $additionalParams);
a5413d3a   Benjamin Renard   Add user name in ...
137
				}
22521f1c   Benjamin Renard   First commit
138
			}
0a5bb843   Menouard AZIB   Refactoring Reque...
139
		} else
22521f1c   Benjamin Renard   First commit
140
141
142
143
144
145
146
147
148
149
150
151
152
			$res = false;

		fclose($fp);

		if ($res)
			return array('success' => true, 'result' => $func_res);

		return array('success' => false, 'message' => 'Error during the concurrent access of the process manager file');
	}

	/*
	 * @brief Create a new manager file
	*/
0a5bb843   Menouard AZIB   Refactoring Reque...
153
154
155
	private function createProcessManagerFile()
	{
		$dom = new DOMDocument("1.0", "UTF-8");
22521f1c   Benjamin Renard   First commit
156
157
158
159
160
161
162
163
		$dom->preserveWhiteSpace = false;
		$dom->formatOutput = true;
		$rootNode = $dom->createElement("processlist");
		$dom->appendChild($rootNode);
		return $dom->save($this->processManagerFilePath);
	}

	/*
a5413d3a   Benjamin Renard   Add user name in ...
164
165
	 * @brief Method used to be sure that the process file is always clean
	 */
0a5bb843   Menouard AZIB   Refactoring Reque...
166
167
	private function cleanupProcessManagerFile($dom)
	{
a5413d3a   Benjamin Renard   Add user name in ...
168
169
170
		$processNodes = $dom->documentElement->getElementsByTagName("process");
		$processNode = $processNodes->item(0);
		$to_remove = array();
0a5bb843   Menouard AZIB   Refactoring Reque...
171
		while ($processNode) {
a5413d3a   Benjamin Renard   Add user name in ...
172
173
			$pathNodes = $processNode->getElementsByTagName("runningpath");
			if (($pathNodes->length == 0) || empty($pathNodes->item(0)->nodeValue) ||
0a5bb843   Menouard AZIB   Refactoring Reque...
174
175
				(!is_dir($pathNodes->item(0)->nodeValue))
			) {
a5413d3a   Benjamin Renard   Add user name in ...
176
177
178
179
180
181
182
183
184
185
186
				$to_remove[] = $processNode;
			}
			$processNode = $this->fNextEltSibling($processNode);
		}
		foreach ($to_remove as $processNode) {
			$dom->documentElement->removeChild($processNode);
		}
		$dom->save($this->processManagerFilePath);
	}

	/*
22521f1c   Benjamin Renard   First commit
187
188
	 * @brief Update process info if a node of the manager file
	*/
0a5bb843   Menouard AZIB   Refactoring Reque...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
	private function updateProcessInProcessNode($dom, $processNode, $process)
	{
		$this->updateProcessStatusToNode($dom, $processNode, "cmd", $process->getCommand());
		$this->updateProcessStatusToNode($dom, $processNode, "outputfile", $process->getOutputFile());
		$this->updateProcessStatusToNode($dom, $processNode, "exitcodefile", $process->getExitCodeFile());
		$this->updateProcessStatusToNode($dom, $processNode, "processfile", $process->getProcessFile());
		$this->updateProcessStatusToNode($dom, $processNode, "exectimefile", $process->getExecTimeFile());
		$this->updateProcessStatusToNode($dom, $processNode, "errormsgfile", $process->getErrorMsgFile());
		$this->updateProcessStatusToNode($dom, $processNode, "exitcode", $process->getExitCode());
		$this->updateProcessStatusToNode($dom, $processNode, "exectime", $process->getExecTime());
		$this->updateProcessStatusToNode($dom, $processNode, "errormsg", $process->getErrorMsg());
		$this->updateProcessStatusToNode($dom, $processNode, "PID", $process->getPID());
		$this->updateProcessStatusToNode($dom, $processNode, "runningpath", $process->getRunningPath());
		$this->updateProcessStatusToNode($dom, $processNode, "runningstart", $process->getRunningStart());
		$this->updateProcessStatusToNode($dom, $processNode, "isrunning", $process->isRunning() ? "true" : "false");
		$this->updateProcessStatusToNode($dom, $processNode, "lastupdate", time());
		$this->updateProcessStatusToNode($dom, $processNode, "user", $process->getUser());
		$this->updateProcessStatusToNode($dom, $processNode, "fromws", $process->getFromWS() ? "true" : "false");
22521f1c   Benjamin Renard   First commit
207
208
209
210
211
212
213
214
	}

	/*
	 * @brief Extract process info from a node
	*/
	private function getProcessInfoFromNode($processNode)
	{
		return array(
0a5bb843   Menouard AZIB   Refactoring Reque...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
			"id"           => $processNode->getAttribute("xml:id"),
			"cmd"          => $this->getNodeValueFromNode($processNode, "cmd"),
			"outputfile"   => $this->getNodeValueFromNode($processNode, "outputfile"),
			"exitcodefile" => $this->getNodeValueFromNode($processNode, "exitcodefile"),
			"processfile"  => $this->getNodeValueFromNode($processNode, "processfile"),
			"exectimefile" => $this->getNodeValueFromNode($processNode, "exectimefile"),
			"errormsgfile" => $this->getNodeValueFromNode($processNode, "errormsgfile"),
			"exitcode"     => $this->getNodeValueFromNode($processNode, "exitcode"),
			"exectime"     => $this->getNodeValueFromNode($processNode, "exectime"),
			"errormsg"     => $this->getNodeValueFromNode($processNode, "errormsg"),
			"PID"          => $this->getNodeValueFromNode($processNode, "PID"),
			"runningpath"  => $this->getNodeValueFromNode($processNode, "runningpath"),
			"runningstart" => $this->getNodeValueFromNode($processNode, "runningstart"),
			"isrunning"    => ($this->getNodeValueFromNode($processNode, "isrunning") == "true"),
			"iskilled"     => ($this->getNodeValueFromNode($processNode, "iskilled") == "true"),
			"lastupdate"   => $this->getNodeValueFromNode($processNode, "lastupdate"),
			"user"         => $this->getNodeValueFromNode($processNode, "user"),
			"fromws"       => ($this->getNodeValueFromNode($processNode, "fromws") == "true"),
22521f1c   Benjamin Renard   First commit
233
234
235
236
237
238
		);
	}

	/*
	 * @brief Get a node by tag name and by a given parent node
	*/
0a5bb843   Menouard AZIB   Refactoring Reque...
239
240
	private function getNodeFromNode($parentNode, $name)
	{
22521f1c   Benjamin Renard   First commit
241
242
243
244
245
246
247
248
249
		$nodes = $parentNode->getElementsByTagName($name);
		if ($nodes->length > 0)
			return $nodes->item(0);
		return NULL;
	}

	/*
	 * @brief Get the value of a node by tag name and by a given parent node
	*/
0a5bb843   Menouard AZIB   Refactoring Reque...
250
251
	private function getNodeValueFromNode($parentNode, $name)
	{
22521f1c   Benjamin Renard   First commit
252
253
254
255
256
257
258
259
260
		$node = $this->getNodeFromNode($parentNode, $name);
		if ($node == NULL)
			return NULL;
		return $node->nodeValue;
	}

	/*
	 * @brief Update a process info in a process node
	*/
0a5bb843   Menouard AZIB   Refactoring Reque...
261
262
	private function updateProcessStatusToNode($dom, $parentNode, $name, $value)
	{
22521f1c   Benjamin Renard   First commit
263
264
265
266
267
		$node = $this->getNodeFromNode($parentNode, $name);
		if ($node == NULL) {
			$node = $dom->createElement($name);
			$parentNode->appendChild($node);
		}
8c57155b   Benjamin Renard   Integration for t...
268
		$node->nodeValue = htmlspecialchars($value);
22521f1c   Benjamin Renard   First commit
269
270
271
272
273
274
		return $node;
	}

	/*
	 * @brief Create a Process from node
	*/
0a5bb843   Menouard AZIB   Refactoring Reque...
275
276
	private function getProcessFromNode($processNode)
	{
22521f1c   Benjamin Renard   First commit
277
278
279
280
281
282
283
284
285
286
		$cmd = $this->getNodeValueFromNode($processNode, "cmd");
		if ($cmd == NULL)
			return NULL;
		$process = new ProcessClass($cmd);
		if ($process === false)
			return NULL;
		$processInfo = $this->getProcessInfoFromNode($processNode);
		$outputFile   = $processInfo["outputfile"];
		$processFile  = $processInfo["processfile"];
		$exitCodeFile = $processInfo["exitcodefile"];
ba82a624   Benjamin Renard   Get kernel execut...
287
		$execTimeFile = $processInfo["exectimefile"];
e4eba677   Benjamin Renard   Get error message...
288
		$errorMsgFile = isset($processInfo["errormsgfile"]) ? $processInfo["errormsgfile"] : "";
22521f1c   Benjamin Renard   First commit
289
290
291
		$pid          = $processInfo["PID"];
		$runningPath  = $processInfo["runningpath"];
		$runningStart = $processInfo["runningstart"];
e4eba677   Benjamin Renard   Get error message...
292
		$process->init($outputFile, $exitCodeFile, $processFile, $execTimeFile, $errorMsgFile, $pid, $runningPath, $runningStart);
22521f1c   Benjamin Renard   First commit
293
294
295
		return $process;
	}

8814aa3a   Benjamin Renard   Improve iteration...
296
	// Next element sibling for DOMElement
0a5bb843   Menouard AZIB   Refactoring Reque...
297
298
	function fNextEltSibling($node)
	{
8814aa3a   Benjamin Renard   Improve iteration...
299
300
301
302
303
304
305
306
307
		while ($node && ($node = $node->nextSibling)) {
			if ($node instanceof DOMElement) {
				break;
			}
		}
		return $node;
	}


22521f1c   Benjamin Renard   First commit
308
309
310
311
312
313
314
	/*
	 * @brief Get information about a process
	*/
	private function getProcessInfoFromId($dom, $args)
	{
		$id = $args['id'];
		$update = $args['update'];
0a5bb843   Menouard AZIB   Refactoring Reque...
315

22521f1c   Benjamin Renard   First commit
316
		$processNodes = $dom->documentElement->getElementsByTagName("process");
8814aa3a   Benjamin Renard   Improve iteration...
317
		$processNode = $processNodes->item(0);
0a5bb843   Menouard AZIB   Refactoring Reque...
318
319
320
		while ($processNode) {
			if ($processNode->getAttribute('xml:id') == $id) {
				if ($update) {
22521f1c   Benjamin Renard   First commit
321
322
323
324
325
					$process = $this->getProcessFromNode($processNode);
					if (!isset($process))
						return array('success' => false, 'message' => 'Error to retrieve process info');

					$this->updateProcessInProcessNode($dom, $processNode, $process);
0a5bb843   Menouard AZIB   Refactoring Reque...
326

8b8f98e3   Elena.Budnik   getStatus fixed
327
					$dom->save($this->processManagerFilePath);
22521f1c   Benjamin Renard   First commit
328
				}
0a5bb843   Menouard AZIB   Refactoring Reque...
329

22521f1c   Benjamin Renard   First commit
330
				$processInfo = $this->getProcessInfoFromNode($processNode);
0a5bb843   Menouard AZIB   Refactoring Reque...
331

22521f1c   Benjamin Renard   First commit
332
333
				return array('success' => true, 'result' => $processInfo);
			}
8814aa3a   Benjamin Renard   Improve iteration...
334
			$processNode = $this->fNextEltSibling($processNode);
22521f1c   Benjamin Renard   First commit
335
336
337
338
339
340
341
342
343
344
345
		}

		return array('success' => false, 'message' => 'Cannot get process from id');
	}

	/*
	 * @brief Delete a process
	*/
	private function deleteProcessFromId($dom, $id)
	{
		$processNodes = $dom->documentElement->getElementsByTagName("process");
8814aa3a   Benjamin Renard   Improve iteration...
346
		$processNode = $processNodes->item(0);
0a5bb843   Menouard AZIB   Refactoring Reque...
347
348
		while ($processNode) {
			if ($processNode->getAttribute('xml:id') == $id) {
22521f1c   Benjamin Renard   First commit
349
350
351
352
				$process = $this->getProcessFromNode($processNode);
				if (!isset($process))
					return array('success' => false, 'message' => 'Error to retrieve process info');

2c0e1b9a   Benjamin Renard   Remove process in...
353
				$process->delete($process->getExitCode() != 0);
0a5bb843   Menouard AZIB   Refactoring Reque...
354

22521f1c   Benjamin Renard   First commit
355
				$dom->documentElement->removeChild($processNode);
0a5bb843   Menouard AZIB   Refactoring Reque...
356

22521f1c   Benjamin Renard   First commit
357
358
359
360
				$dom->save($this->processManagerFilePath);

				return array('success' => true);
			}
8814aa3a   Benjamin Renard   Improve iteration...
361
			$processNode = $this->fNextEltSibling($processNode);
22521f1c   Benjamin Renard   First commit
362
363
		}

2c0e1b9a   Benjamin Renard   Remove process in...
364
365
		//Process not exists - Do not send any error
		return array('success' => true);
22521f1c   Benjamin Renard   First commit
366
	}
0a5bb843   Menouard AZIB   Refactoring Reque...
367

bda99a72   Benjamin Renard   Add kill plot req...
368
369
370
371
372
373
	/*
	 * @brief Kill a process
	*/
	private function killProcessFromId($dom, $id)
	{
		$processNodes = $dom->documentElement->getElementsByTagName("process");
8814aa3a   Benjamin Renard   Improve iteration...
374
		$processNode = $processNodes->item(0);
0a5bb843   Menouard AZIB   Refactoring Reque...
375
376
		while ($processNode) {
			if ($processNode->getAttribute('xml:id') == $id) {
bda99a72   Benjamin Renard   Add kill plot req...
377
378
379
				$process = $this->getProcessFromNode($processNode);
				if (!isset($process))
					return array('success' => false, 'message' => 'Error to retrieve process info');
0a5bb843   Menouard AZIB   Refactoring Reque...
380
381
382
383
384

				$this->updateProcessStatusToNode($dom, $processNode, "isrunning", "false");
				$this->updateProcessStatusToNode($dom, $processNode, "iskilled", "true");

				if ($process->stop()) {
bda99a72   Benjamin Renard   Add kill plot req...
385
					$dom->save($this->processManagerFilePath);
0a5bb843   Menouard AZIB   Refactoring Reque...
386

bda99a72   Benjamin Renard   Add kill plot req...
387
388
389
390
					return array('success' => true);
				}
				return array('success' => false, 'message' => 'Cannot process from id');
			}
8814aa3a   Benjamin Renard   Improve iteration...
391
			$processNode = $this->fNextEltSibling($processNode);
bda99a72   Benjamin Renard   Add kill plot req...
392
		}
0a5bb843   Menouard AZIB   Refactoring Reque...
393
394

		return array('success' => false, 'message' => 'Cannot kill process from id ' . $id);
bda99a72   Benjamin Renard   Add kill plot req...
395
	}
1d67748e   Benjamin Renard   Limit number of p...
396
397
398
399
400
401
402
403
404

	/*
	 * @brief Get nb of running processes. Is $name is not empty, get only the nb for the specifier user.
	 */
	private function getRunningProcessesNb($dom, $user)
	{
		$processNodes = $dom->documentElement->getElementsByTagName("process");
		$processNode = $processNodes->item(0);
		$nb = 0;
0a5bb843   Menouard AZIB   Refactoring Reque...
405
		while ($processNode) {
1d67748e   Benjamin Renard   Limit number of p...
406
407
			$isRunningNodes = $processNode->getElementsByTagName("isrunning");
			if (($isRunningNodes->length == 0) || empty($isRunningNodes->item(0)->nodeValue) ||
0a5bb843   Menouard AZIB   Refactoring Reque...
408
409
				($isRunningNodes->item(0)->nodeValue != "true")
			) {
1d67748e   Benjamin Renard   Limit number of p...
410
411
412
413
414
415
				$processNode = $this->fNextEltSibling($processNode);
				continue;
			}
			if (!empty($user)) {
				$userNodes = $processNode->getElementsByTagName("user");
				if (($userNodes->length == 0) || empty($userNodes->item(0)->nodeValue) ||
0a5bb843   Menouard AZIB   Refactoring Reque...
416
417
					($userNodes->item(0)->nodeValue != $user)
				) {
1d67748e   Benjamin Renard   Limit number of p...
418
419
420
421
422
423
424
425
426
427
					$processNode = $this->fNextEltSibling($processNode);
					continue;
				}
			}
			++$nb;
			$processNode = $this->fNextEltSibling($processNode);
		}

		return array('success' => true, 'nb' => $nb);
	}
22521f1c   Benjamin Renard   First commit
428
}