<?php date_default_timezone_set('GMT'); ini_set('memory_limit', -1); if (PHP_SAPI !== 'cli') { header('Status: 400'); exit('Invalid access'); } function println($msg, $color = null, $eol = true) { $colorMap = [ 'white' => "\e[0;97m", 'red' => "\e[0;31m", 'green' => "\e[0;32m", 'blue' => "\e[0;34m", 'yellow' => "\e[0;33m", 'magenta' => "\e[0;35m", 'cyan' => "\e[0;36m", 'black' => "\e[0;30m", ]; $colorEnd = ""; if (!empty($colorMap[$color])) { echo $colorMap[$color]; $colorEnd = "\e[0m"; } echo $msg, $colorEnd; if ($eol) { echo PHP_EOL; } } define('CACHE_DIR', '/var/tmp/cache/'); !is_dir(CACHE_DIR) && @mkdir(CACHE_DIR); if (is_dir('/ebs1')) { define('LOGGING_DIR', '/ebs1/rackspace/'); } else { define('LOGGING_DIR', '/var/log/rackspace/'); } !is_dir(LOGGING_DIR) && @mkdir(LOGGING_DIR); class Task{ const LOCKED_FLAG = 1; const UNLOCKED_FLAG = 0; private $name; private $command; private $lockfile; private $proccessfile; public function __construct($name, $command){ if (empty($name) || empty($command)) { throw new \Exception('Parameters for counstruct required, but not given.'); } $this->name = $name; $this->command = escapeshellcmd($command); $this->lockfile = CACHE_DIR . $name . '.lock'; $this->proccessfile = CACHE_DIR . $name . '_last_item'; } public function __get($prop){ if (in_array($prop, ['name', 'command'])) { return $this->$prop; } } public function __toString(){ return $this->name; } public function __invoke($param){ switch ($param) { case 'r': return $this->start(); case 's': return $this->stop(); case 'l': return $this->lock(); case 'u': return $this->unlock(); case 'i': return $this->reset(); case 'w': return $this->watch(); case 'v': return $this->view(); case 'k': $v = `cat '{$this->lockfile}'`; println($v); return $v; } } public function reset(){ $this->unlock(); file_put_contents($this->proccessfile, '0'); $rmlog = 'rm -f ' . LOGGING_DIR . $this->name . '*.log'; exec($rmlog); } public function isLocked(){ return @file_get_contents($this->lockfile) == static::LOCKED_FLAG; } public function unlock(){ @file_put_contents($this->lockfile, static::UNLOCKED_FLAG); return $this; } public function lock(){ @file_put_contents($this->lockfile, static::LOCKED_FLAG); return $this; } public function start($force = false){ if ($this->isLocked()) { println(sprintf("Task [%s] start failed as locked.", $this->name), 'red'); return false; } if ($force) { $this->stop(); } else { if ($this->lookupCmd(true)) { println(sprintf('Task [%s] start failed as on running.', $this->name), "red"); return false; } } $pid = $this->execAsync($this->command); if ($pid) { println(sprintf('Task [%s](pid=%s) start successfully.', $this->name, $pid), "green"); } return $pid; } public function execAsync($cmd, $workDir = null){ $shell = (is_dir($workDir) ? "cd $workDir;" : "") . "nohup $cmd >>" .LOGGING_DIR . "{$this->name}.log 2>&1 & echo $!"; exec($shell, $output); return @$output[0];// return Pid } public function restart(){ return $this->start(true); } public function stop($pid = null){ $pids = $this->lookupCmd(true); foreach ($pids as $pid) { println('Stopped following command:', "magenta"); $output = $this->killCmdByPID($pid); println(implode(PHP_EOL, $output)); } return $this; } private function killCmdByPID($pid){ $pid = (int)$pid; if (!$pid) return []; exec('ps -fp ' . $pid, $output); exec('kill -9 ' . $pid, $none); return $output; } public function view() { $output = $this->lookupCmd(); println(implode(PHP_EOL, $output)); return $this; } public function lookupCmd($onlyPid = false){ $shell = 'ps -ef|grep \'' . $this->command .'\'|grep -v grep'; if ($onlyPid) { $shell .= '|awk \'{print $2}\''; } exec($shell, $output); return $output; } public function watch(){ println(@file_get_contents($this->proccessfile)); return $this; } public function monitor(){ $pid = $this->lookupCmd(true); if (empty($pid)) { $this->onLost(); } return $this; } private function onLost(){ $this->start(); } } class TaskManager{ private $tasks = []; public function addTask($name, $command = null){ if (is_array($name)) { $this->tasks = array_merge($this->tasks, $name); } else if (is_string($name) || is_int($name)) { $this->tasks[$name] = is_callable($command) ? $command($name) : $command; } return $this; } public function __call($method, $arguments){ if (substr($method, -3) == 'All') { return $this->callMethodForEveryTask(substr($method, 0, -3), $arguments); } else if (in_array($method, get_class_methods('Task')) && !empty($arguments)) { return $this->callMethodOfTask($arguments[0], $method, array_splice($arguments, 1)); } } private function callMethodOfTask($taskName, $method, $arguments) { if (!$this->valid($taskName)) { println('Task is not existed'); return false; } $taskInst = $this->getTask($taskName); return call_user_func_array([$taskInst, $method], $arguments); } private function callMethodForEveryTask($method, $arguments) { foreach ($this->tasks as $task => $cmd) { $this->callMethodOfTask($task, $method, $arguments); } } private function valid($taskName){ if (is_numeric($taskName)) { return isset(array_keys($this->tasks)[$taskName]); } else { return isset($this->tasks[$taskName]); } } public function dispatchMethod($taskName, $method, $arguments = null){ if ($taskName) { return call_user_func_array([$this, $method], array_merge([$taskName], (array)$arguments)); } else { return call_user_func_array([$this, $method . 'All'], array_merge([$taskName], (array)$arguments)); } } public function __toString(){ return var_export($this->tasks, true); } public function getTask($taskName){ if (is_numeric($taskName)) { $taskName = array_keys($this->tasks)[$taskName]; } return new Task($taskName, $this->tasks[$taskName]); } } $options = getopt('c::n::v::V::'); function initTaskManager(){ $taskManager = new TaskManager(); $dir = realpath(__DIR__); $nameFmt = 'rackspace_transfer_%d'; $cmdFmt = 'php ' . $dir . '/rackspace_transfer.php -n%s -p%d,%d'; $autoCreateTasks = function() use ($nameFmt, $cmdFmt){ $pow = 10 ** 5; $step = $pow - 1; $tasks = []; for ($i = 0; $i < 9 ; $i++) { $name = sprintf($nameFmt, $i * $pow); $cmd = sprintf($cmdFmt, $name, $i * $pow, $i * $pow + $step); $tasks[$name] = $cmd; } return $tasks; }; $tasks = $autoCreateTasks(); $taskManager->addTask($tasks); return $taskManager; } $taskManager = initTaskManager(); $taskName = !isset($options['n']) ? '' : $options['n']; if ($taskName && isset($options['v'])) { println($taskManager->getTask($taskName)); exit; } if ($taskName && isset($options['V'])) { $task = $taskManager->getTask($taskName); $task($options['V']); exit; } switch ($options['c']) { case 'start': case 'stop': case 'monitor': case 'view': case 'watch': case 'restart': case 'reset': case 'lock': case 'unlock': $taskManager->dispatchMethod($taskName, $options['c']); break; default: echo $taskManager, "\n"; break; }