浏览代码

U async server, add tests using sbin/se.sh

Piotr Labudda 6 年之前
父节点
当前提交
199b7fd5da

+ 2 - 0
SE/se-lib/Core/AsyncJobs.php

@@ -141,6 +141,8 @@ class Core_AsyncJobs {
 		$jobDate = $item['DATE'];
 		$execPath = Core_AsyncJobsFiles::startScript($idJob, $jobDate);
 
+		Core_AsyncJobsDB::updateStatus($idJob, $status = 'NORMAL', $item);
+
 		// Core_AsyncJobsServer::startAsyncJob(execPath, name, [ 'out.log', 'error.log', 'cwd', 'args' ])
 		$out = [];
 		$ret = Core_AsyncJobsServer::startAsyncJob(

+ 12 - 1
SE/se-lib/Core/AsyncJobsDB.php

@@ -12,7 +12,7 @@
 		`JOB_NAME`
 		`LOCK_VALUE`
 		`USER`
-		`A_STATUS`
+		`A_STATUS`: default 'WAITING' - not started, 'NORMAL' - started, 'OFF_HARD' - not running, 'DELETED' - removed
 		`A_RECORD_CREATE_DATE`
 		`A_RECORD_CREATE_AUTHOR`
 		`A_RECORD_UPDATE_DATE`
@@ -60,6 +60,17 @@ class Core_AsyncJobsDB {
 		]);
 	}
 
+	static function updateStatus($idJob, $status, $item = []) {
+		if ($item) $item = self::fetch($idJob);
+
+		if ($status != $item['A_STATUS']) {
+			DB::getPDO()->update('CRM_ASYNC_JOB_LOG', 'ID', $idJob, [
+				'A_STATUS' => $status,
+			]);
+			// TODO: _HIST
+		}
+	}
+
 	static function checkAsyncJobDatabase() {
 		// `CRM_CONFIG`.`CONF_KEY` = 'Core_AsyncJobs__version'
 		$dbVersion = (int)DB::getPDO()->fetchValue(" select CONF_VAL from CRM_CONFIG where CONF_KEY = :key ", [ ':key' => self::$CRM_CONFIG_VERSION_KEY ]);

+ 1 - 0
SE/se-lib/Core/AsyncJobsFiles.php

@@ -60,6 +60,7 @@ class Core_AsyncJobsFiles {
 			mkdir($confAsyncPath, $mode = 0777, $recursive = TRUE);
 		}
 		if (!file_exists($confAsyncPath)) throw new Exception("Folder not exists APP_PATH_ASYNC_JOB");
+		return true;
 	}
 
 }

+ 1 - 0
SE/se-lib/Core/AsyncJobsServer.php

@@ -140,6 +140,7 @@ class Core_AsyncJobsServer {
 			// [PM2] Spawning PM2 daemon with pm2_home=/Library/WebServer/.pm2
 			// [PM2] PM2 Successfully daemonized
 			// { msg: 'pong' }
+			return true;
 		}
 		if ($ret !== 0) {
 			if (!file_exists(self::path_nodeJS())) throw new Exception("pm2 not installed");

+ 48 - 2
SE/se-lib/Route/AsyncJobs.php

@@ -93,6 +93,15 @@ class Route_AsyncJobs extends RouteBase {
 					'_postTask' => "testReinstallPm2ByWWW",
 				]
 			]),
+			" ",
+			UI::hButtonPost("Test", [
+				'class' => "btn btn-warning",
+				'title' => "Test server permissions",
+				'data' => [
+					'_route' => 'AsyncJobs',
+					'_postTask' => "makeTests",
+				]
+			]),
 		]);
 
 		$postTask = V::get('_postTask', '', $_POST);
@@ -105,6 +114,7 @@ class Route_AsyncJobs extends RouteBase {
 			case "mp2Start3": UI::tryCatchView([ $this, 'mp2Start3PostTask' ]); break;
 			case "mp2DeleteStopped": UI::tryCatchView([ $this, 'mp2DeleteStoppedPostTask' ]); break;
 			case "testReinstallPm2ByWWW": UI::tryCatchView([ $this, 'testReinstallPm2ByWWWPostTask' ]); break;
+			case "makeTests": UI::tryCatchView([ $this, 'makeTestsPostTask' ]); break;
 		}
 
 	}
@@ -282,13 +292,49 @@ class Route_AsyncJobs extends RouteBase {
 		UI::alert("DONE");
 	}
 
+	function makeTestsPostTask() {
+		$seBinPath = $this->getSbinPath();
+
+		$listTest = []; // [ [ ret_code, cmd ], ... ]
+		$listTest[] = [ 0, "cd '{$seBinPath}' && bash ./se.sh test-exit-0" ];
+		$listTest[] = [ 1, "cd '{$seBinPath}' && bash ./se.sh test-exit-1" ];
+		$listTest[] = [ 1, "cd '{$seBinPath}' && bash ./se.sh test-sudo" ];
+		$listTest[] = [ 0, "cd '{$seBinPath}' && bash ./se.sh --sudo test-sudo" ];
+
+		// $cmd = "cd '{$seBinPath}' && bash se.sh install-pm2-www"; // DBG: require root, add prefix 'sudo--'
+		// $cmd = "cd '{$seBinPath}' && bash ./se.sh --sudo install-pm2-www";
+		// $cmd = "cd '{$seBinPath}' && bash se.sh install-pm2-www"; // expected Permission denied - missing sudo
+		// $cmd = "cd '{$seBinPath}' && bash se.sh sudo "; // expected Missing script name + usage
+		// $cmd = "cd '{$seBinPath}' && bash se.sh non-existing-script"; // expecte Module not exists + usage
+		// $cmd = "cd '{$seBinPath}' && bash se.sh "; // expected usage
+
+		foreach ($listTest as $idx => $test) {
+			list($expected, $cmd) = $test;
+			$out = [];
+			V::exec($cmd = "{$cmd} 2>&1", $out, $ret);
+			echo UI::h('details', [], [
+				UI::h('summary', [], "test {$idx} " . (($expected === $ret) ? "SUCCESS" : "FAILED")),
+				UI::h('div', [], [
+					UI::h('pre', [], "RET({$ret}). OUTPUT:" . "\n" . implode("\n", $out)),
+					UI::h('div', [ 'class' => "alert alert-info" ], "test ({$ret})" . "\n<br>" . implode("\n<br>", $out) ),
+					($expected === $ret)
+					?	UI::h('div', [ 'class' => 'alert alert-success' ], "OK: script return as expected!")
+					:	UI::h('div', [ 'class' => 'alert alert-danger' ], "FAIL: script return '{$ret}' but expected '{$expected}'!")
+					,
+				]),
+			]);
+		}
+
+	}
+
 	function testReinstallPm2ByWWWPostTask() {
 		$seBinPath = $this->getSbinPath();
+
 		$out = [];
-		$cmd = "cd '{$seBinPath}' && bash se.sh sudo--install-pm2-www";
+		$cmd = "cd '{$seBinPath}' && bash ./se.sh --sudo install-pm2-www";
 		V::exec($cmd = "{$cmd} 2>&1", $out, $ret);
 		echo UI::h('pre', [], "RET({$ret}). OUTPUT:" . "\n" . implode("\n", $out));
-		if (0 !== $ret) throw new Exception( (empty($out)) ? "Error: backup failed!" : implode("\n", $out) );
+		if (0 !== $ret) throw new Exception( (empty($out)) ? "Error: install pm2-www failed! ({$ret})" : implode("\n<br>", $out) );
 
 		if (!file_exists('/usr/local/bin/pm2-www')) {
 			throw new Exception("Nie udało się zainstalować pm2-www");

+ 35 - 0
SE/se-lib/Route/UrlAction/Ant.php

@@ -141,6 +141,19 @@ class Route_UrlAction_Ant extends Route_Ant {// @doc @see Route_Ant
 
 	function listLastJobsAction() { UI::layout([ get_called_class(), 'listLastJobsView' ]); }
 	static function listLastJobsView() {
+		echo UI::h('ol', [ 'class' => "breadcrumb" ], [
+			UI::h('li', [], [
+				UI::h('a', [ 'href' => self::link() ], [
+					UI::h('i', [ 'class' => "glyphicon glyphicon-home", 'style' => "margin-right:6px" ]), // TODO: mv to h('p5:icon', [ 'type' => "home" ])
+					" ",
+					"Druki",
+				]),
+			]),
+			UI::h('li', [], [
+				"Ostatnio uruchomione zadania",
+			]),
+		]);
+
 		echo UI::h('h1', [], "Ostatnio uruchomione zadania");
 
 		$postTask = V::get('postTask', '', $_POST);
@@ -275,6 +288,28 @@ class Route_UrlAction_Ant extends Route_Ant {// @doc @see Route_Ant
 
 		DBG::nicePrint($item, "Zadanie '{$idJob}'");
 
+		// TODO: files list in task folder
+		Lib::loadClass('Core_AsyncJobsFiles');
+		$basePath     = Core_AsyncJobsFiles::basePath($item['ID'], $item['DATE']);
+		$propertyFile = Core_AsyncJobsFiles::propertyFile($item['ID'], $item['DATE']);
+		$startScript  = Core_AsyncJobsFiles::startScript($item['ID'], $item['DATE']);
+		$outLog       = Core_AsyncJobsFiles::outLog($item['ID'], $item['DATE']);
+		$errorLog     = Core_AsyncJobsFiles::errorLog($item['ID'], $item['DATE']);
+
+		DBG::nicePrint([
+			'basePath' => $basePath,
+			'propertyFile' => $propertyFile,
+			'startScript' => $startScript,
+			'outLog' => $outLog,
+			'errorLog' => $errorLog,
+		], "DBG:job files");
+
+		DBG::nicePrint(shell_exec("ls -l '{$basePath}'"), 'DBG: basePath');
+		DBG::nicePrint(shell_exec("cat '{$propertyFile}'"), 'DBG: propertyFile');
+		DBG::nicePrint(shell_exec("cat '{$startScript}'"), 'DBG: startScript');
+		DBG::nicePrint(shell_exec("cat '{$outLog}'"), 'DBG: outLog');
+		DBG::nicePrint(shell_exec("cat '{$errorLog}'"), 'DBG: errorLog');
+
 		throw new Exception("TODO: asyncJobDebug");
 	}
 

+ 24 - 0
sbin/module/install-pm2-www.sh

@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+echo "DBG:install-pm2-www - START"
+
+if [ ! -f "/usr/local/bin/pm2" ]; then
+    echo "/usr/local/bin/pm2 not exist! INSTALL: npm install -g pm2"
+    exit 1
+fi
+if [ -f "/usr/local/bin/pm2-www" ]; then
+    rm "/usr/local/bin/pm2-www"
+fi
+if [ ! -f "/usr/local/bin/pm2-www" ]; then
+    echo '#!/usr/bin/env bash' > "/usr/local/bin/pm2-www"
+    echo '' >> "/usr/local/bin/pm2-www"
+    echo 'sudo -u _www HOME=/Library/WebServer /usr/local/bin/pm2 "$@"' >> "/usr/local/bin/pm2-www"
+    chmod +x "/usr/local/bin/pm2-www"
+fi
+
+if [ ! -f "/usr/local/bin/pm2-wwwX" ]; then
+	echo "pm2-www not installed!"
+	exit 1
+fi
+
+echo "DBG:install-pm2-www - END."

+ 5 - 0
sbin/module/test-exit-0.sh

@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+echo "DBG:test-exit-0"
+
+exit 0

+ 5 - 0
sbin/module/test-exit-1.sh

@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+echo "DBG:test-exit-1"
+
+exit 1

+ 7 - 0
sbin/module/test-sudo.sh

@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+set -e
+# set -e stops the execution of a script if a command or pipeline has an error
+
+sudo echo "DBG:test-sudo #1"
+sudo echo "DBG:test-sudo #2"

+ 36 - 0
sbin/se.sh

@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+# require line in /etc/sudoers:
+# _www ALL = NOPASSWD: /Library/Server/Web/Data/Sites/SE-production-git/sbin/se.sh
+# cat /etc/sudoers |grep "_www ALL = NOPASSWD: /Library/Server/Web/Data/Sites/SE-production-git/sbin/se.sh" || echo "_www ALL = NOPASSWD: /Library/Server/Web/Data/Sites/SE-production-git/sbin/se.sh" >> /etc/sudoers;
+
+set -e
+# set -e stops the execution of a script if a command or pipeline has an error
+
+function usage {
+  echo "usage se.sh [--sudo] script_name"
+  exit 1
+}
+
+[ -z "$1" ] && usage
+
+[ "$1" = "--sudo" ] && {
+    sudo ./se.sh "$2"
+    exit 0
+}
+
+module_name="$1"
+
+echo "DBG: module_name: ${module_name}"
+
+[ ! -f "module/${module_name}.sh" ] && {
+    echo "Module not exists" >&2
+    usage
+}
+
+echo "DBG: starting module: [${module_name}'"
+/bin/bash module/${module_name}.sh "${@:2}"
+module_exit=$?
+echo "DBG: module exited with code [${module_exit}] - module: [${module_name}]"
+exit $module_exit
+# exit $? exit with same exit code what script