1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553:
<?php
namespace Nethgui\System;
class NethPlatform implements PlatformInterface, \Nethgui\Authorization\PolicyEnforcementPointInterface, \Nethgui\Log\LogConsumerInterface, \Nethgui\Utility\PhpConsumerInterface, \Nethgui\Utility\SessionConsumerInterface, \Nethgui\Component\DependencyConsumer
{
private $databases;
private $policyDecisionPoint;
private $user;
private $eventQueue;
private $log;
private $phpWrapper;
private $systemTasks;
private $notifications;
private $request;
private $conditions;
public function __construct(\Nethgui\Authorization\UserInterface $user, \Nethgui\Model\SystemTasks $systemTasks)
{
$this->eventQueue = array('post-process' => array(), 'post-response' => array(), 'now' => array());
$this->user = $user;
$this->systemTasks = $systemTasks;
$this->databases = array('SESSION' => new SessionDatabase());
$this->phpWrapper = new \Nethgui\Utility\PhpWrapper(__CLASS__);
$this->request = \Nethgui\Controller\NullRequest::getInstance();
$this->conditions = array();
}
public function setSession(\Nethgui\Utility\SessionInterface $session)
{
$this->databases['SESSION']->setSession($session);
return $this;
}
public function getDatabase($database)
{
if (isset($this->databases[$database])) {
return $this->databases[$database];
}
$object = new EsmithDatabase($database, $this->user);
$object
->setLog($this->getLog())
->setPolicyDecisionPoint($this->policyDecisionPoint)
->setPhpWrapper($this->phpWrapper)
;
return $this->databases[$database] = $object;
}
public function getIdentityAdapter($database, $key, $prop = NULL, $separator = NULL)
{
$serializer = $this->getSerializer($database, $key, $prop);
if (is_null($separator)) {
$adapter = new \Nethgui\Adapter\ScalarAdapter($serializer);
} else {
$adapter = new \Nethgui\Adapter\ArrayAdapter($separator, $serializer);
}
return $adapter;
}
public function getMapAdapter($readCallback, $writeCallback, $args)
{
$serializers = array();
foreach ($args as $serializerSpec) {
$serializers[] = call_user_func_array(array($this, 'getSerializer'), $serializerSpec);
}
$adapter = new \Nethgui\Adapter\MultipleAdapter($readCallback, $writeCallback, $serializers);
return $adapter;
}
public function getTableAdapter($database, $typeOrKey, $filterOrProp = NULL, $separators = NULL)
{
if (is_null($separators)) {
return new \Nethgui\Adapter\TableAdapter($this->getDatabase($database), $typeOrKey, $filterOrProp);
}
$innerAdapter = $this->getIdentityAdapter($database, $typeOrKey, $filterOrProp, $separators[0]);
return new \Nethgui\Adapter\TabularValueAdapter($innerAdapter, $separators[1]);
}
private function getSerializer($source, $key, $prop = NULL)
{
if ($source instanceof \ArrayAccess) {
$serializer = new \Nethgui\Serializer\ArrayAccessSerializer($source, $key, $prop);
} elseif (is_string($source)) {
if (is_null($prop)) {
$serializer = new \Nethgui\Serializer\KeySerializer($this->getDatabase($source), $key);
} else {
$serializer = new \Nethgui\Serializer\PropSerializer($this->getDatabase($source), $key, $prop);
}
} else {
throw new \InvalidArgumentException(sprintf('%s: cannot create a SerializerInterface instance', __CLASS__), 1336467547);
}
return $serializer;
}
public function signalEvent($eventSpecification, $arguments = array())
{
$matches = array();
preg_match('/(?P<event>[^@ ]+)(@(?P<queue>[^ ]+))?( +(?P<detached>&))?/', $eventSpecification, $matches);
if ( ! isset($matches['event'])) {
throw new \InvalidArgumentException(sprintf("%s: invalid event specification", get_class($this)), 1325578497);
}
$detached = isset($matches['detached']) && $matches['detached'] === '&' ? TRUE : FALSE;
if ($detached) {
$queue = 'post-response';
} else {
$queue = isset($matches['queue']) && in_array($matches['queue'], array_keys($this->eventQueue)) ? $matches['queue'] : 'now';
}
$cmd = '/usr/bin/sudo -n /sbin/e-smith/signal-event ${@}';
$args = array_merge(array($matches['event']), $arguments);
if ($queue === 'post-process') {
$process = $this->createPtrackProcess($cmd, $args, FALSE);
$this->eventQueue['post-process'][] = $process;
} else {
$process = $this->createPtrackProcess($cmd, $args, $detached);
if ($detached) {
$this->eventQueue['post-response'][] = $process;
} else {
$process->run();
$this->notifyEvent($process);
}
}
return $process;
}
private function notifyEvent(\Symfony\Component\Process\Process $process)
{
if ($process->getExitCode() !== 0) {
$this->notifications->trackerError(array('failedTasks' => \Nethgui\Module\Tracker::findFailures($this->systemTasks->getTaskStatus($process->taskId))));
}
}
private function getLangForProcess()
{
$locale = $this->request->getLocale();
if($locale === 'en') {
$locale = 'en-GB';
} elseif($locale === 'it') {
$locale = 'it-IT';
}
return \str_replace('-', '_', $locale) . '.utf8';
}
private function createPtrackProcess($command, $args, $detached)
{
$taskId = md5(uniqid());
if ($detached) {
$this->systemTasks->setTaskStarting($taskId);
}
$socketPath = sprintf('/var/run/ptrack/%s.sock', $taskId);
$dumpPath = sprintf(\Nethgui\Model\SystemTasks::PTRACK_DUMP_PATH, md5($socketPath));
$cmd = strtr('/usr/libexec/nethserver/ptrack %detached -j -s %socketPath -d %dumpPath %verbose -- ', array(
'%detached' => $detached ? '-D' : '',
'%verbose' => \NETHGUI_DEBUG ? '-v' : '',
'%dumpPath' => \escapeshellarg($dumpPath),
'%socketPath' => \escapeshellarg($socketPath)
)) . $this->prepareEscapedCommand($command, $args);
$process = new \Nethgui\System\Process($cmd);
$process->setEnv(array('LANG' => $this->getLangForProcess()));
$process->setInput('{}');
$process->taskId = $taskId;
return $process;
}
private function getProcessInput()
{
$onSuccessDefault = array(
'location' => array('url' => implode('/', $this->request->getPath()) . '?taskStatus=success&taskId={taskId}',
'freeze' => TRUE));
$onFailureDefault = array(
'location' => array('url' => implode('/', $this->request->getPath()) . '?taskStatus=failure&taskId={taskId}',
'freeze' => TRUE));
$input = json_encode(array(
'starttime' => microtime(TRUE),
'conditions' => array(
'success' => isset($this->conditions['success']) ? $this->conditions['success'] : $onSuccessDefault,
'failure' => isset($this->conditions['failure']) ? $this->conditions['failure'] : $onFailureDefault
)
));
return $input;
}
public function setDetachedProcessCondition($condition, $values)
{
if (isset($this->conditions[$condition])) {
return $this;
}
$this->conditions[$condition] = $values;
return $this;
}
public function runEvents($queueName)
{
if ( ! isset($this->eventQueue[$queueName])) {
return;
}
foreach ($this->eventQueue[$queueName] as $process) {
if($queueName === 'post-response') {
$process->setInput($this->getProcessInput());
}
$process->run();
if ($process->getExitCode() !== 0) {
$this->getLog()->error(sprintf("%s: process on queue `%s` exited with code %d: %s", get_class($this), $queueName, $process->getExitCode(), $process->getCommandLine()));
}
$this->notifyEvent($process);
}
$this->eventQueue[$queueName] = array();
}
public function setPolicyDecisionPoint(\Nethgui\Authorization\PolicyDecisionPointInterface $pdp)
{
$this->policyDecisionPoint = $pdp;
return $this;
}
private function prepareEscapedCommand($command, $arguments)
{
$escapedArguments = array();
$i = 1;
foreach ($arguments as $arg) {
if (is_string($arg)) {
$argOutput = $arg;
} elseif (is_callable($arg)) {
$argOutput = call_user_func($arg);
} else {
$argOutput = strval($arg);
}
$escapedArguments[sprintf('${%d}', $i)] = escapeshellarg($argOutput);
$i ++;
}
$escapedArguments['${@}'] = implode(' ', $escapedArguments);
return strtr($command, $escapedArguments);
}
public function exec($command, $arguments = array(), $detached = FALSE)
{
if ($detached === FALSE) {
$process = new \Nethgui\System\Process($this->prepareEscapedCommand($command, $arguments));
$process->setEnv(array('LANG' => $this->getLangForProcess()));
$process->log = $this->getLog();
$process->run();
} else {
$process = $this->createPtrackProcess($command, $arguments, $detached);
$this->eventQueue['post-response'][] = $process;
}
return $process;
}
public function getLog()
{
if ( ! isset($this->log)) {
$this->log = new \Nethgui\Log\Nullog();
}
return $this->log;
}
public function setLog(\Nethgui\Log\LogInterface $log)
{
$this->log = $log;
$this->phpWrapper->setLog($log);
return $this;
}
public function getDateFormat()
{
return 'YYYY-mm-dd';
}
public function setPhpWrapper(\Nethgui\Utility\PhpWrapper $object)
{
$this->phpWrapper = $object;
return $this;
}
public function getDetachedProcesses()
{
return array();
}
public function getDetachedProcess($identifier)
{
return NULL;
}
public function createValidator()
{
$validator = new Validator($this);
foreach (func_get_args() as $ruleCode) {
switch ($ruleCode) {
case self::ANYTHING:
$validator->forceResult(TRUE);
break;
case self::ANYTHING_COLLECTION:
$validator->orValidator($this->createValidator()->isEmpty(), $this->createValidator()->collectionValidator($this->createValidator()->forceResult(TRUE)));
break;
case self::USERNAME_COLLECTION:
$validator->orValidator($this->createValidator()->isEmpty(), $this->createValidator()->collectionValidator($this->createValidator()->username()));
break;
case self::SERVICESTATUS:
$validator->memberOf('enabled', 'disabled');
break;
case self::USERNAME:
$validator->username();
break;
case self::HOSTNAME:
$validator->hostname();
break;
case self::HOSTNAME_FQDN:
$validator->hostname(1);
break;
case self::HOSTNAME_SIMPLE:
$validator->hostname(0, 0);
break;
case self::HOSTADDRESS:
$validator->orValidator($this->createValidator()->ipV4Address(), $this->createValidator()->hostname());
break;
case self::NOTEMPTY:
$validator->notEmpty();
break;
case self::DATE:
$validator->date();
break;
case self::TIME:
$validator->time();
break;
case self::IP:
case self::IPv4:
$validator->ipV4Address();
break;
case self::NETMASK:
case self::IPv4_NETMASK:
$validator->ipV4Netmask();
break;
case self::MACADDRESS:
$validator->macAddress();
break;
case self::POSITIVE_INTEGER:
$validator->integer()->positive();
break;
case self::NONNEGATIVE_INTEGER:
$validator->integer()->greatThan(-1);
break;
case self::PORTNUMBER:
$validator->integer()->greatThan(0)->lessThan(65536);
break;
case self::BOOLEAN:
$validator->memberOf('1', 'yes', '0', '');
break;
case self::IP_OR_EMPTY:
case self::IPv4_OR_EMPTY:
$validator->orValidator($this->createValidator()->ipV4Address(), $this->createValidator()->isEmpty());
break;
case self::NETMASK_OR_EMPTY:
case self::IPv4_NETMASK_OR_EMPTY:
$validator->orValidator($this->createValidator()->ipV4Netmask(), $this->createValidator()->isEmpty());
break;
case self::YES_NO:
$validator->memberOf('yes', 'no');
break;
case self::EMAIL:
$validator->email();
break;
case self::EMPTYSTRING:
$validator->maxLength(0);
break;
case self::CIDR_BLOCK:
$validator->cidrBlock();
break;
case NULL:
continue;
default:
throw new \InvalidArgumentException(sprintf('%s: Unknown validator code: %s', get_class($this), $ruleCode), 1326380984);
}
}
return $validator;
}
public function setRequest(\Nethgui\Controller\Request $request)
{
$this->request = $request;
return $this;
}
public function setUserNotifications(\Nethgui\Model\UserNotifications $notifications)
{
$this->notifications = $notifications;
return $this;
}
public function getDependencySetters()
{
return array(
'UserNotifications' => array($this, 'setUserNotifications'),
'OriginalRequest' => array($this, 'setRequest')
);
}
}