/** * @return Script|NULL */ public function getScript() { if (!$this->_script) { $this->_script = Script::findPk($this->scriptId); } return $this->_script; }
/** * Creates versions for specified script from versions definitions * * @param Script $script Script for witch created versions * @param array $versionsData Versions definitions * * @return ScriptVersion[] * * @throws Exception */ public static function generateVersions(Script $script, array $versionsData) { $versions = []; try { $latestVersion = $script->getLatestVersion()->version + 1; } catch (Exception $e) { $latestVersion = 1; } foreach ($versionsData as $versionData) { $versionData['scriptId'] = $script->id; $versionData['version'] = $latestVersion++; $versionData['changedById'] = static::$testUserId; $versionData['changedByEmail'] = static::$user->getEmail(); $versions[] = static::createEntity(new ScriptVersion(), $versionData); } return $versions; }
/** * Gets specified Script taking into account both scope and authentication token * * @param string $scriptId Numeric identifier of the Script * @param bool $modify optional Flag checking write permissions * * @return Script Returns the Script Entity on success * * @throws ApiErrorException * */ public function getScript($scriptId, $modify = false) { /* @var $script Script */ $script = Script::findPk($scriptId); if (!$script) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Requested Script either does not exist or is not owned by your environment."); } if (!$this->hasPermissions($script, $modify)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } return $script; }
/** * {@inheritdoc} * @see \Scalr\Api\DataType\ApiEntityAdapter::validateEntity() */ public function validateEntity($entity) { if (!$entity instanceof ScriptVersion) { throw new InvalidArgumentException(sprintf("First argument must be instance of Scalr\\Model\\Entity\\ScriptVersion class")); } if (!Script::findPk($entity->scriptId)) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Script {$entity->scriptId} not found"); } if (!$this->controller->hasPermissions($entity, true)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } }
/** * {@inheritdoc} * @see \Scalr\Api\DataType\ApiEntityAdapter::validateEntity() */ public function validateEntity($entity) { if (!$entity instanceof ScriptVersion) { throw new InvalidArgumentException(sprintf("First argument must be instance of Scalr\\Model\\Entity\\ScriptVersion class")); } if (!Script::findPk($entity->scriptId)) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Script {$entity->scriptId} not found"); } if (substr($entity->content, 0, 2) !== '#!') { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, 'Property body is not valid. First line must contain shebang (#!/path/to/interpreter)'); } if (!$this->controller->hasPermissions($entity, true)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } }
/** * @test * @functional */ public function testGetVersions() { $list = Script::find(null, null, null, 10); $this->assertInternalType('array', $list->getArrayCopy()); $this->assertInternalType('integer', count($list)); $this->assertInternalType('integer', $list->count()); try { /* @var $script Script */ $script = Script::findOne([]); } catch (\Exception $e) { $this->markTestSkipped($e->getMessage()); } if (!$script) { $this->markTestSkipped("There are no scripts so it can not proceed"); } $versions = $script->getVersions()->getArrayCopy(); $this->assertInternalType('array', $versions); }
/** * {@inheritdoc} * @see \Scalr\Api\DataType\ApiEntityAdapter::validateEntity() */ public function validateEntity($entity) { if (!$entity instanceof Script) { throw new InvalidArgumentException(sprintf("First argument must be instance of Scalr\\Model\\Entity\\Script class")); } if ($entity->id !== null) { if (!Script::findPk($entity->id)) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, sprintf("Could not find out the Script with ID: %d", $entity->id)); } } if ($entity->getScope() == ScopeInterface::SCOPE_SCALR) { throw new ApiErrorException(403, ErrorMessage::ERR_SCOPE_VIOLATION, sprintf("Scalr scope is not allowed")); } if (!$this->controller->hasPermissions($entity, true)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } }
/** * {@inheritdoc} * @see AccessPermissionsInterface::hasAccessPermissions() */ public function hasAccessPermissions($user, $environment = null, $modify = null) { return $this->checkInheritedPermissions(Role::findPk($this->roleId), $user, $environment, $modify) && (empty($this->scriptId) || $this->checkInheritedPermissions(Script::findPk($this->scriptId), $user, $environment)); }
public function ScriptsList() { $this->restrictAccess(Acl::RESOURCE_ADMINISTRATION_SCRIPTS); $response = $this->CreateInitialResponse(); $response->ScriptSet = new stdClass(); $response->ScriptSet->Item = array(); foreach (Script::find(array('$or' => array(array('accountId' => NULL), array('accountId' => $this->user->getAccountId())))) as $script) { /* @var $script Script */ $itm = new stdClass(); $itm->{"ID"} = $script->id; $itm->{"Name"} = $script->name; $itm->{"Description"} = $script->description; $itm->{"LatestRevision"} = $script->getLatestVersion()->version; $response->ScriptSet->Item[] = $itm; } return $response; }
public function xUpdateAgentAction() { $this->request->restrictAccess(Acl::RESOURCE_FARMS_SERVERS); $this->request->defineParams(array('serverId')); /* @var Entity\Script $scr */ $scr = Entity\Script::find(array(array('id' => 2102), array('accountId' => NULL))); if (!$scr) { throw new Exception("Automatical scalarizr update doesn't supported by this scalr version"); } $dbServer = DBServer::LoadByID($this->getParam('serverId')); $this->user->getPermissions()->validate($dbServer); $scriptSettings = array('version' => $scr->getLatestVersion()->version, 'scriptid' => 2102, 'timeout' => 300, 'issync' => 0, 'params' => serialize(array()), 'type' => Scalr_Scripting_Manager::ORCHESTRATION_SCRIPT_TYPE_SCALR); $message = new Scalr_Messaging_Msg_ExecScript("Manual"); $message->setServerMetaData($dbServer); $script = Scalr_Scripting_Manager::prepareScript($scriptSettings, $dbServer); $itm = new stdClass(); // Script $itm->asynchronous = $script['issync'] == 1 ? '0' : '1'; $itm->timeout = $script['timeout']; if ($script['body']) { $itm->name = $script['name']; $itm->body = $script['body']; } else { $itm->path = $script['path']; } $itm->executionId = $script['execution_id']; $message->scripts = array($itm); $dbServer->SendMessage($message); $this->response->success('Scalarizr update successfully initiated. Please wait a few minutes and then refresh the page'); }
/** * @param int $farmId * @param int $farmRoleId optional * @param string $serverId optional * @param int $scriptId optional * @param string $scriptPath optional * @param int $scriptIsSync * @param int $scriptTimeout * @param int $scriptVersion * @param array $scriptParams optional * @param int $shortcutId optional * @param int $editShortcut optional * @throws Exception */ public function xExecuteAction($farmId, $farmRoleId = 0, $serverId = '', $scriptId = 0, $scriptPath = '', $scriptIsSync, $scriptTimeout, $scriptVersion, array $scriptParams = [], $shortcutId = null, $editShortcut = null) { $this->request->restrictAccess(Acl::RESOURCE_SCRIPTS_ENVIRONMENT, Acl::PERM_SCRIPTS_ENVIRONMENT_EXECUTE); if ($serverId) { $dbServer = DBServer::LoadByID($serverId); $this->user->getPermissions()->validate($dbServer); $target = Script::TARGET_INSTANCE; $serverId = $dbServer->serverId; $farmRoleId = $dbServer->farmRoleId; $farmId = $dbServer->farmId; } else { if ($farmRoleId) { $dbFarmRole = DBFarmRole::LoadByID($farmRoleId); $this->user->getPermissions()->validate($dbFarmRole); $target = Script::TARGET_ROLE; $farmRoleId = $dbFarmRole->ID; $farmId = $dbFarmRole->FarmID; } else { if (!$farmId) { $target = Script::TARGET_ALL; } else { $dbFarm = DBFarm::LoadByID($farmId); $this->user->getPermissions()->validate($dbFarm); $target = Script::TARGET_FARM; $farmId = $dbFarm->ID; } } } if ($farmId) { $this->request->checkPermissions(Entity\Farm::findPk($farmId), Acl::PERM_FARMS_SERVERS); } if ($scriptId) { $script = Script::findPk($scriptId); /* @var $script Script */ if (!$script) { throw new Scalr_UI_Exception_NotFound(); } $script->checkPermission($this->user, $this->getEnvironmentId()); } elseif (!$scriptPath) { throw new Scalr_Exception_Core('scriptId or scriptPath should be set'); } if (!$scriptTimeout) { $scriptTimeout = $scriptIsSync == 1 ? Scalr::config('scalr.script.timeout.sync') : Scalr::config('scalr.script.timeout.async'); } $executeScript = true; if ($shortcutId && ($target != Script::TARGET_INSTANCE || $target != Script::TARGET_ALL)) { if ($shortcutId == -1) { $shortcut = new ScriptShortcut(); $shortcut->farmId = $farmId; } else { $shortcut = ScriptShortcut::findPk($shortcutId); /* @var $shortcut ScriptShortcut */ if (!$shortcut) { throw new Scalr_UI_Exception_NotFound(); } if ($editShortcut == 1) { $executeScript = false; } } $shortcut->farmRoleId = $farmRoleId == 0 ? NULL : $farmRoleId; if ($scriptId) { $shortcut->scriptId = $scriptId; $shortcut->scriptPath = ''; } else { $shortcut->scriptPath = $scriptPath; $shortcut->scriptId = NULL; } $shortcut->isSync = $scriptIsSync; $shortcut->version = $scriptVersion; $shortcut->timeout = $scriptTimeout; $shortcut->params = $scriptParams; $shortcut->save(); } if ($executeScript) { switch ($target) { case Script::TARGET_FARM: $servers = $this->db->GetAll("\n SELECT server_id\n FROM servers\n WHERE is_scalarized = 1 AND status IN (?,?) AND farm_id=?", [SERVER_STATUS::INIT, SERVER_STATUS::RUNNING, $farmId]); break; case Script::TARGET_ROLE: $servers = $this->db->GetAll("\n SELECT server_id\n FROM servers\n WHERE is_scalarized = 1 AND status IN (?,?) AND farm_roleid=?", [SERVER_STATUS::INIT, SERVER_STATUS::RUNNING, $farmRoleId]); break; case Script::TARGET_INSTANCE: $servers = $this->db->GetAll("\n SELECT server_id\n FROM servers\n WHERE is_scalarized = 1 AND status IN (?,?) AND server_id=?", [SERVER_STATUS::INIT, SERVER_STATUS::RUNNING, $serverId]); break; case Script::TARGET_ALL: $sql = "\n SELECT s.server_id\n FROM servers s\n JOIN farms f ON f.id = s.farm_id\n WHERE s.is_scalarized = 1\n AND s.status IN (?,?)\n AND s.env_id = ?\n AND " . $this->request->getFarmSqlQuery(Acl::PERM_FARMS_SERVERS); $args = [SERVER_STATUS::INIT, SERVER_STATUS::RUNNING, $this->getEnvironmentId()]; $servers = $this->db->GetAll($sql, $args); break; } $scriptSettings = array('version' => $scriptVersion, 'timeout' => $scriptTimeout, 'issync' => $scriptIsSync, 'params' => serialize($scriptParams)); if ($scriptId) { $scriptSettings['scriptid'] = $scriptId; $scriptSettings['type'] = Scalr_Scripting_Manager::ORCHESTRATION_SCRIPT_TYPE_SCALR; } else { $scriptSettings['script_path'] = $scriptPath; $scriptSettings['type'] = Scalr_Scripting_Manager::ORCHESTRATION_SCRIPT_TYPE_LOCAL; } $serializer = Scalr_Messaging_JsonSerializer::getInstance(); $cryptoTool = \Scalr::getContainer()->srzcrypto; // send message to start executing task (starts script) if (count($servers) > 0) { foreach ($servers as $server) { $DBServer = DBServer::LoadByID($server['server_id']); $msg = new Scalr_Messaging_Msg_ExecScript("Manual"); $msg->setServerMetaData($DBServer); $script = Scalr_Scripting_Manager::prepareScript($scriptSettings, $DBServer); if ($script) { $DBServer->executeScript($script, $msg); $this->auditLog("script.execute", $script, $DBServer); $manualLog = new OrchestrationLogManualScript($script['execution_id'], $msg->serverId); $manualLog->userId = $this->getUser()->getId(); $manualLog->userEmail = $this->getUser()->getEmail(); $manualLog->added = new DateTime('now', new DateTimeZone('UTC')); $manualLog->save(); } } } $this->response->success('Script execution has been queued and will occur on the selected instance(s) within a couple of minutes.'); } else { $this->response->success('Script shortcut successfully saved'); } }
public static function prepareScript($scriptSettings, DBServer $targetServer, AbstractServerEvent $event = null) { $template = ['type' => isset($scriptSettings['type']) ? $scriptSettings['type'] : null, 'timeout' => isset($scriptSettings['timeout']) ? $scriptSettings['timeout'] : null, 'issync' => isset($scriptSettings['issync']) ? $scriptSettings['issync'] : null, 'run_as' => isset($scriptSettings['run_as']) ? $scriptSettings['run_as'] : null, 'execution_id' => Scalr::GenerateUID()]; if ($scriptSettings['type'] == self::ORCHESTRATION_SCRIPT_TYPE_SCALR) { /* @var $script Script */ $script = Script::findPk($scriptSettings['scriptid']); if (!$script) { return false; } // TODO: validate permission to access script ? if ($script->os && $targetServer->osType && $script->os != $targetServer->osType) { return false; } if ($scriptSettings['version'] == 'latest' || (int) $scriptSettings['version'] == -1) { $version = $script->getLatestVersion(); } else { $version = $script->getVersion((int) $scriptSettings['version']); } if (empty($version)) { return false; } $template['name'] = $script->name; $template['id'] = $script->id; $template['body'] = $version->content; $template['scriptVersion'] = $version->version; // variables could be null $scriptParams = $script->allowScriptParameters ? (array) $version->variables : []; foreach ($scriptParams as &$val) { $val = ""; } $params = array_merge($scriptParams, $targetServer->GetScriptingVars(), (array) unserialize($scriptSettings['params'])); if ($event) { $eventServer = $event->DBServer; foreach ($eventServer->GetScriptingVars() as $k => $v) { $params["event_{$k}"] = $v; } foreach ($event->GetScriptingVars() as $k => $v) { $params[$k] = $event->{$v}; } if (isset($event->params) && is_array($event->params)) { foreach ($event->params as $k => $v) { $params[$k] = $v; } } $params['event_name'] = $event->GetName(); } if ($event instanceof CustomEvent && count($event->params) > 0) { $params = array_merge($params, $event->params); } // Prepare keys array and array with values for replacement in script $keys = array_keys($params); $keys = array_map(function ($item) { return '%' . $item . '%'; }, $keys); $values = array_values($params); $script_contents = str_replace($keys, $values, $template['body']); $template['body'] = str_replace('\\%', "%", $script_contents); // Generate script contents $template['name'] = preg_replace("/[^A-Za-z0-9]+/", "_", $template['name']); } elseif ($scriptSettings['type'] == self::ORCHESTRATION_SCRIPT_TYPE_LOCAL) { $template['path'] = $targetServer->applyGlobalVarsToValue($scriptSettings['script_path']); } elseif ($scriptSettings['type'] == self::ORCHESTRATION_SCRIPT_TYPE_CHEF) { $chef = new stdClass(); $chefSettings = (array) unserialize($scriptSettings['params']); if ($chefSettings['chef.cookbook_url']) { $chef->cookbookUrl = $chefSettings['chef.cookbook_url']; } if ($chefSettings['chef.cookbook_url_type']) { $chef->cookbookUrlType = $chefSettings['chef.cookbook_url_type']; } if ($chefSettings['chef.relative_path']) { $chef->relativePath = $chefSettings['chef.relative_path']; } if ($chefSettings['chef.ssh_private_key']) { $chef->sshPrivateKey = $chefSettings['chef.ssh_private_key']; } if ($chefSettings['chef.role_name']) { $chef->role = $chefSettings['chef.role_name']; } else { $chef->runList = $chefSettings['chef.runlist']; } $chef->jsonAttributes = $chefSettings['chef.attributes']; $template['chef'] = $chef; } return $template; }
/** * Gets role scripts * * @param array $criteria optional The search criteria. * @param array $order optional The results order looks like [[property1 => true|false], ...] * @param int $limit optional The records limit * @param int $offset optional The offset * @param bool $countRecords optional True to calculate total number of the records without limit * * @return Script[] */ public function getScripts(array $criteria = null, array $order = null, $limit = null, $offset = null, $countRecords = null) { return Script::find(array_merge(['roleId' => $this->id], $criteria), $order, $limit, $offset, $countRecords); }
/** * @test * * @throws \Scalr\Exception\ModelException */ public function testComplex() { $user = $this->getUser(); $environment = $this->getEnvironment(); $fictionController = new ApiController(); /* @var $script Script */ $script = static::createEntity(new Script(), ['name' => "{$this->uuid}-script", 'description' => "{$this->uuid}-description", 'envId' => $environment->id, 'createdById' => $user->getId()]); //post script version $data = ['body' => '#!cmd']; $response = $this->postVersion($script->id, $data); $this->assertEquals(201, $response->status, $this->printResponseError($response)); $versionNumber = $response->getBody()->data->version; /* @var $version ScriptVersion */ $version = ScriptVersion::findPk($script->id, $versionNumber); $this->assertNotEmpty($version); $this->assertObjectEqualsEntity($data, $version); //post script version already existing $data = ['version' => $version->version, 'body' => '#!/bin/sh']; $response = $this->postVersion($script->id, $data); $this->assertEquals(201, $response->status, $this->printResponseError($response)); $versionNumber = $response->getBody()->data->version; $this->assertNotEquals($data['version'], $versionNumber); //post script with properties that not existing $data = ['foo' => 'bar']; $response = $this->postVersion($script->id, $data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //post version to scalr-scoped script /* @var $scalrScript Script */ $scalrScript = static::createEntity(new Script(), ['name' => "{$this->uuid}-script-scalr-scoped", 'description' => "{$this->uuid}-description-scalr-scoped", 'createdById' => $user->getId()]); $data = ['body' => '#!/bin/sh']; $response = $this->postVersion($scalrScript->id, $data); $this->assertErrorMessageContains($response, 403, ErrorMessage::ERR_PERMISSION_VIOLATION); //test script fetch $response = $this->getVersion($script->id, $version->version); $this->assertEquals(200, $response->status, $this->printResponseError($response)); $this->assertObjectEqualsEntity($response->getBody()->data, $version); //test fetch script that doe not exists $response = $this->getVersion($script->id, $script->getLatestVersion()->version + 1); $this->assertErrorMessageContains($response, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND); //modify script version $data = ['body' => '#!/bin/bash']; $response = $this->modifyVersion($script->id, $version->version, $data); $this->assertEquals(200, $response->status, $this->printResponseError($response)); $this->assertObjectEqualsEntity($response->getBody()->data, ScriptVersion::findPk($script->id, $version->version)); //modify property that does not exists $data = ['foo' => 'bar']; $response = $this->modifyVersion($script->id, $version->version, $data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //modify properties that not alterable $scriptVersionAdapter = new ScriptVersionAdapter($fictionController); $adapterRules = $scriptVersionAdapter->getRules(); $publicProperties = $adapterRules[BaseAdapter::RULE_TYPE_TO_DATA]; $alterableProperties = $adapterRules[ApiEntityAdapter::RULE_TYPE_ALTERABLE]; $nonAlterableProperties = array_diff(array_values($publicProperties), $alterableProperties); foreach ($nonAlterableProperties as $property) { if (in_array($property, ['id', 'version'])) { continue; } $data = [$property => 'foo']; $response = $this->modifyVersion($script->id, $version->version, $data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); } //modify script that does not exists $data = ['body' => '#!powershell']; $response = $this->modifyVersion($script->id, $script->getLatestVersion()->version + 1, $data); $this->assertErrorMessageContains($response, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND); //modify Scalr-scoped script version /* @var $scalrVersion ScriptVersion */ $scalrVersion = static::createEntity(new ScriptVersion(), ['scriptId' => $scalrScript->id, 'version' => 2, 'content' => '#!/bin/sh']); //modify Scalr-scoped script version $data = ['body' => '#!cmd']; $response = $this->modifyVersion($scalrScript->id, $scalrVersion->version, $data); $this->assertErrorMessageContains($response, 403, ErrorMessage::ERR_PERMISSION_VIOLATION, 'Insufficient permissions'); /* @var $version ScriptVersion */ $version = static::createEntity(new ScriptVersion(), ['scriptId' => $script->id, 'version' => $script->getLatestVersion()->version + 1, 'content' => '#!foobar']); //test have access to all listed scripts versions $versions = $this->listVersions($script->id); foreach ($versions as $version) { $this->assertTrue(ScriptVersion::findPk($script->id, $version->version)->hasAccessPermissions($user)); } $listUri = static::getUserApiUrl("/scripts/{$script->id}/script-versions/"); //test list script versions filters $filterable = $scriptVersionAdapter->getRules()[ApiEntityAdapter::RULE_TYPE_FILTERABLE]; /* @var $version ScriptVersion */ foreach ($versions as $version) { foreach ($filterable as $property) { $filterValue = $version->{$property}; $listResult = $this->listVersions($script->id, [$property => $filterValue]); if (!static::isRecursivelyEmpty($filterValue)) { foreach ($listResult as $filtered) { $this->assertEquals($filterValue, $filtered->{$property}, "Property '{$property}' mismatch"); } } } $response = $this->getVersion($script->id, $version->version); $this->assertEquals(200, $response->status, $this->printResponseError($response)); $dbScriptVersions = ScriptVersion::findPk($script->id, $version->version); $this->assertObjectEqualsEntity($response->getBody()->data, $dbScriptVersions, $scriptVersionAdapter); } //test invalid filters $response = $this->request($listUri, Request::METHOD_GET, ['foo' => 'bar']); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //delete script version /* @var $version ScriptVersion */ $version = static::createEntity(new ScriptVersion(), ['scriptId' => $script->id, 'version' => $script->getLatestVersion()->version + 1, 'content' => '#!/bin/sh foobar']); $response = $this->deleteVersion($script->id, $version->version); $this->assertEquals(200, $response->status, $this->printResponseError($response)); //delete scalr-scoped script version $response = $this->deleteVersion($scalrVersion->scriptId, $scalrVersion->version); $this->assertErrorMessageContains($response, 403, ErrorMessage::ERR_PERMISSION_VIOLATION); //delete script version that does not exists $response = $this->deleteVersion($script->id, $script->getLatestVersion()->version + 1); $this->assertErrorMessageContains($response, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND); $scripts = Script::find([['$or' => [['accountId' => $user->accountId], ['accountId' => null]]], ['$or' => [['envId' => $environment->id], ['envId' => null]]]]); foreach ($scripts as $script) { //test have access to all listed scripts versions $versions = $this->listVersions($script->id); foreach ($versions as $version) { $version = ScriptVersion::findPk($script->id, $version->version); $this->assertTrue($version->hasAccessPermissions($user)); } if ($version->getScope() !== ScopeInterface::SCOPE_ENVIRONMENT) { $response = $this->postVersion($version->scriptId, ['body' => '#!/bin/sh' . $this->getTestName()]); $this->assertErrorMessageContains($response, 403, ErrorMessage::ERR_PERMISSION_VIOLATION); } } }
public function xSaveAction() { $this->request->restrictAccess(Acl::RESOURCE_GENERAL_SCHEDULERTASKS, Acl::PERM_GENERAL_SCHEDULERTASKS_MANAGE); $this->request->defineParams(array('id' => array('type' => 'integer'), 'name' => array('type' => 'string', 'validator' => array(Scalr_Validator::REQUIRED => true, Scalr_Validator::NOHTML => true)), 'type' => array('type' => 'string', 'validator' => array(Scalr_Validator::RANGE => array(Scalr_SchedulerTask::SCRIPT_EXEC, Scalr_SchedulerTask::LAUNCH_FARM, Scalr_SchedulerTask::TERMINATE_FARM, Scalr_SchedulerTask::FIRE_EVENT), Scalr_Validator::REQUIRED => true)), 'startTime', 'startTimeDate', 'restartEvery', 'timezone' => array('type' => 'string', 'validator' => array(Scalr_Validator::REQUIRED => true)), 'farmId' => array('type' => 'integer'), 'farmRoleId' => array('type' => 'integer'), 'serverId' => array('type' => 'string'), 'scriptOptions' => array('type' => 'array'), 'eventParams' => array('type' => 'array'), 'eventName' => array('type' => 'string'))); $task = Scalr_SchedulerTask::init(); if ($this->getParam('id')) { $task->loadById($this->getParam('id')); $this->user->getPermissions()->validate($task); } else { $task->accountId = $this->user->getAccountId(); $task->envId = $this->getEnvironmentId(); $task->status = Scalr_SchedulerTask::STATUS_ACTIVE; } $this->request->validate(); $params = array(); $timezone = new DateTimeZone($this->getParam('timezone')); $startTm = $this->getParam('startTime') ? new DateTime($this->getParam('startTimeDate') . " " . $this->getParam('startTime'), $timezone) : NULL; if ($startTm) { Scalr_Util_DateTime::convertTimeZone($startTm, NULL); } $curTm = new DateTime(); if ($startTm && $startTm < $curTm && !$task->id) { $this->request->addValidationErrors('startTimeDate', array('Start time must be greater then current time')); } switch ($this->getParam('type')) { case Scalr_SchedulerTask::FIRE_EVENT: case Scalr_SchedulerTask::SCRIPT_EXEC: if ($this->getParam('serverId')) { $dbServer = DBServer::LoadByID($this->getParam('serverId')); $this->user->getPermissions()->validate($dbServer); $task->targetId = $dbServer->GetFarmRoleObject()->ID; $task->targetServerIndex = $dbServer->index; $task->targetType = Scalr_SchedulerTask::TARGET_INSTANCE; } else { if ($this->getParam('farmRoleId')) { $dbFarmRole = DBFarmRole::LoadByID($this->getParam('farmRoleId')); $this->user->getPermissions()->validate($dbFarmRole); $task->targetId = $dbFarmRole->ID; $task->targetType = Scalr_SchedulerTask::TARGET_ROLE; } else { if ($this->getParam('farmId')) { $dbFarm = DBFarm::LoadByID($this->getParam('farmId')); $this->user->getPermissions()->validate($dbFarm); $task->targetId = $dbFarm->ID; $task->targetType = Scalr_SchedulerTask::TARGET_FARM; } else { $this->request->addValidationErrors('farmId', array('Farm ID is required')); } } } if ($this->getParam('type') == Scalr_SchedulerTask::SCRIPT_EXEC) { /* @var $script Script */ $script = Script::findPk($this->getParam('scriptId')); try { if ($script) { $script->checkPermission($this->user, $this->getEnvironmentId()); $task->scriptId = $this->getParam('scriptId'); $params['scriptId'] = $this->getParam('scriptId'); $params['scriptIsSync'] = $this->getParam('scriptIsSync'); $params['scriptTimeout'] = $this->getParam('scriptTimeout'); $params['scriptVersion'] = $this->getParam('scriptVersion'); $params['scriptOptions'] = $this->getParam('scriptOptions'); } else { throw new Exception(); } } catch (Exception $e) { $this->request->addValidationErrors('scriptId', array('Script ID is required')); } } elseif ($this->getParam('type') == Scalr_SchedulerTask::FIRE_EVENT) { if (!EventDefinition::findOne([['name' => $this->getParam('eventName')], ['$or' => [['accountId' => null], ['accountId' => $this->user->getAccountId()]]], ['$or' => [['envId' => null], ['envId' => $this->getEnvironmentId()]]]])) { throw new Exception("Event definition not found"); } $params['eventName'] = $this->getParam('eventName'); $params['eventParams'] = $this->getParam('eventParams'); } break; case Scalr_SchedulerTask::LAUNCH_FARM: if ($this->getParam('farmId')) { $dbFarm = DBFarm::LoadByID($this->getParam('farmId')); $this->user->getPermissions()->validate($dbFarm); $task->targetId = $dbFarm->ID; $task->targetType = Scalr_SchedulerTask::TARGET_FARM; } else { $this->request->addValidationErrors('farmId', array('Farm ID is required')); } break; case Scalr_SchedulerTask::TERMINATE_FARM: if ($this->getParam('farmId')) { $dbFarm = DBFarm::LoadByID($this->getParam('farmId')); $this->user->getPermissions()->validate($dbFarm); $task->targetId = $dbFarm->ID; $task->targetType = Scalr_SchedulerTask::TARGET_FARM; } else { $this->request->addValidationErrors('farmId', array('Farm ID is required')); } $params['deleteDNSZones'] = $this->getParam('deleteDNSZones'); $params['deleteCloudObjects'] = $this->getParam('deleteCloudObjects'); break; } if (!$this->request->isValid()) { $this->response->failure(); $this->response->data($this->request->getValidationErrors()); return; } $task->name = $this->getParam('name'); $task->type = $this->getParam('type'); $task->comments = $this->getParam('comments'); $task->timezone = $this->getParam('timezone'); $task->startTime = $startTm ? $startTm->format('Y-m-d H:i:s') : NULL; //$task->endTime = $endTm ? $endTm->format('Y-m-d H:i:s') : NULL; $task->restartEvery = $this->getParam('restartEvery'); $task->config = $params; $task->save(); $this->response->success(); }
/** * {@inheritdoc} * @see \Scalr\Api\DataType\ApiEntityAdapter::validateEntity() */ public function validateEntity($entity) { if (!$entity instanceof RoleScript) { throw new InvalidArgumentException(sprintf("First argument must be instance of Scalr\\Model\\Entity\\RoleScript class")); } if ($entity->id !== null) { if (!RoleScript::findPk($entity->id)) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, sprintf("Could not find out the rule with ID: %d", $entity->id)); } } //Getting the role initiates check permissions $role = $this->controller->getRole($entity->roleId); if (!empty($entity->scriptId)) { if ($entity->version == ScriptVersion::LATEST_SCRIPT_VERSION) { $found = ScriptVersion::findOne([['scriptId' => $entity->scriptId]], null, ['version' => false]); } else { $found = ScriptVersion::findPk($entity->scriptId, $entity->version); } if (empty($found)) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, sprintf("Could not find version %d of the script with ID: %d", $entity->version, $entity->scriptId)); } if (Script::findPk($entity->scriptId)->os == 'windows' && $role->getOs()->family != 'windows') { throw new ApiErrorException(409, ErrorMessage::ERR_OS_MISMATCH, "Script OS family does not match role OS family"); } } if (empty($entity->eventName)) { $entity->eventName = '*'; } else { if ($entity->eventName !== '*') { if (array_key_exists($entity->eventName, array_merge(EVENT_TYPE::getScriptingEventsWithScope(), EventDefinition::getList($this->controller->getUser()->id, $this->controller->getEnvironment()->id))) === false) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Could not find out the event '{$entity->eventName}'"); } if ($entity->scriptType == OrchestrationRule::ORCHESTRATION_RULE_TYPE_CHEF && in_array($entity->eventName, EVENT_TYPE::getChefRestrictedEvents())) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Chef can't be used with {$entity->eventName}"); } } } if (!$this->controller->hasPermissions($entity, true)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } }
/** * @param int $roleId * @throws Exception * @throws Scalr_Exception_Core * @throws Scalr_Exception_InsufficientPermissions * @throws Scalr_UI_Exception_NotFound */ public function editAction($roleId = 0) { $this->request->restrictAccess('ROLES', 'MANAGE'); $params = array(); $params['scriptData'] = \Scalr\Model\Entity\Script::getScriptingData($this->user->getAccountId(), $this->getEnvironmentId(true)); $params['categories'] = array_values($this->listRoleCategories()); $params['accountScripts'] = []; if (!$this->user->isScalrAdmin()) { foreach (Scalr_UI_Controller_Account2_Orchestration::controller()->getOrchestrationRules() as $script) { $script['system'] = 'account'; $params['accountScripts'][] = $script; } } $envs = []; if ($this->request->getScope() == ScopeInterface::SCOPE_ACCOUNT) { foreach (Environment::find([['accountId' => $this->user->getAccountId()]], null, ['name' => true]) as $env) { /* @var $env Environment */ $envs[] = ['id' => $env->id, 'name' => $env->name, 'enabled' => 1]; } } $variables = new Scalr_Scripting_GlobalVariables($this->user->getAccountId(), $this->getEnvironmentId(true), ScopeInterface::SCOPE_ROLE); if ($roleId) { /* @var $role Role */ $role = Role::findPk($roleId); if (!$role) { throw new Scalr_Exception_Core(sprintf(_("Role ID#%s not found in database"), $roleId)); } $this->request->checkPermissions($role, true); $images = array(); foreach (RoleImage::find([['roleId' => $role->id]]) as $image) { /* @var $image RoleImage */ $im = $image->getImage(); $a = get_object_vars($image); if ($im) { $b = get_object_vars($im); $b['scope'] = $im->getScope(); $b['dtAdded'] = Scalr_Util_DateTime::convertTz($b['dtAdded']); $b['software'] = $im->getSoftwareAsString(); $a['name'] = $im->name; $a['hash'] = $im->hash; $a['extended'] = $b; } $images[] = $a; } $properties = []; foreach (RoleProperty::find([['roleId' => $role->id], ['name' => ['$like' => 'chef.%']]]) as $prop) { /* @var $prop RoleProperty */ $properties[$prop->name] = $prop->value; } $params['role'] = array('roleId' => $role->id, 'name' => $role->name, 'catId' => $role->catId, 'os' => $role->getOs()->name, 'osId' => $role->osId, 'osFamily' => $role->getOs()->family, 'osGeneration' => $role->getOs()->generation, 'osVersion' => $role->getOs()->version, 'description' => $role->description, 'behaviors' => $role->getBehaviors(), 'images' => $images, 'scripts' => $role->getScripts(), 'dtadded' => Scalr_Util_DateTime::convertTz($role->added), 'addedByEmail' => $role->addedByEmail, 'chef' => $properties, 'isQuickStart' => $role->isQuickStart, 'isDeprecated' => $role->isDeprecated, 'isScalarized' => $role->isScalarized, 'environments' => []); if ($this->request->getScope() == ScopeInterface::SCOPE_ACCOUNT) { $allowedEnvs = $role->getAllowedEnvironments(); if (!empty($allowedEnvs)) { foreach ($envs as &$env) { $env['enabled'] = in_array($env['id'], $allowedEnvs) ? 1 : 0; } } $params['role']['environments'] = $envs; } $params['role']['variables'] = $variables->getValues($role->id); $params['roleUsage'] = ['farms' => $role->getFarmsCount($this->user->getAccountId(), $this->getEnvironmentId(true)), 'instances' => $role->getServersCount($this->user->getAccountId(), $this->getEnvironmentId(true))]; } else { $params['role'] = array('roleId' => 0, 'name' => '', 'arch' => 'x86_64', 'agent' => 2, 'description' => '', 'behaviors' => array(), 'images' => array(), 'scripts' => array(), 'tags' => array(), 'environments' => [], 'variables' => $variables->getValues(), 'isScalarized' => 1); if ($this->request->getScope() == ScopeInterface::SCOPE_ACCOUNT) { $params['role']['environments'] = $envs; } } $this->response->page('ui/roles/edit.js', $params, ['ui/roles/edit/overview.js', 'ui/roles/edit/images.js', 'ui/roles/edit/scripting.js', 'ui/roles/edit/variables.js', 'ui/roles/edit/chef.js', 'ui/roles/edit/environments.js', 'ui/scripts/scriptfield.js', 'ui/core/variablefield.js', 'ui/services/chef/chefsettings.js'], ['ui/roles/edit.css', 'ui/scripts/scriptfield.css']); }
public function xGetScriptsAction() { $dbRole = DBRole::loadById($this->getParam('roleId')); if ($dbRole->origin == ROLE_TYPE::CUSTOM) { $this->user->getPermissions()->validate($dbRole); } $data = \Scalr\Model\Entity\Script::getScriptingData($this->user->getAccountId(), $this->getEnvironmentId()); $data['roleScripts'] = $dbRole->getScripts(); $this->response->data($data); }
/** * @param int $farmId * @param int $farmRoleId optional * @param string $serverId optional * @param int $scriptId optional * @param string $scriptPath optional * @param int $scriptIsSync * @param int $scriptTimeout * @param int $scriptVersion * @param array $scriptParams optional * @param int $shortcutId optional * @param int $editShortcut optional * @throws Exception */ public function xExecuteAction($farmId, $farmRoleId = 0, $serverId = '', $scriptId = 0, $scriptPath = '', $scriptIsSync, $scriptTimeout, $scriptVersion, array $scriptParams = [], $shortcutId = null, $editShortcut = null) { $this->request->restrictAccess(Acl::RESOURCE_ADMINISTRATION_SCRIPTS, Acl::PERM_ADMINISTRATION_SCRIPTS_EXECUTE); if ($serverId) { $dbServer = DBServer::LoadByID($serverId); $this->user->getPermissions()->validate($dbServer); $target = Script::TARGET_INSTANCE; $serverId = $dbServer->serverId; $farmRoleId = $dbServer->farmRoleId; $farmId = $dbServer->farmId; } else { if ($farmRoleId) { $dbFarmRole = DBFarmRole::LoadByID($farmRoleId); $this->user->getPermissions()->validate($dbFarmRole); $target = Script::TARGET_ROLE; $farmRoleId = $dbFarmRole->ID; $farmId = $dbFarmRole->FarmID; } else { if (!$farmId) { $target = Script::TARGET_ALL; } else { $dbFarm = DBFarm::LoadByID($this->getParam('farmId')); $this->user->getPermissions()->validate($dbFarm); $target = Script::TARGET_FARM; $farmId = $dbFarm->ID; } } } if ($scriptId) { $script = Script::findPk($scriptId); /* @var Script $script */ if (!$script) { throw new Scalr_UI_Exception_NotFound(); } $script->checkPermission($this->user, $this->getEnvironmentId()); } elseif (!$scriptPath) { throw new Scalr_Exception_Core('scriptId or scriptPath should be set'); } if (!$scriptTimeout) { $scriptTimeout = $scriptIsSync == 1 ? Scalr::config('scalr.script.timeout.sync') : Scalr::config('scalr.script.timeout.async'); } $executeScript = true; if ($shortcutId && ($target != Script::TARGET_INSTANCE || $target != Script::TARGET_ALL)) { if ($shortcutId == -1) { $shortcut = new ScriptShortcut(); $shortcut->farmId = $farmId; } else { $shortcut = ScriptShortcut::findPk($shortcutId); /* @var ScriptShortcut $shortcut */ if (!$shortcut) { throw new Scalr_UI_Exception_NotFound(); } if ($editShortcut == 1) { $executeScript = false; } } $shortcut->farmRoleId = $farmRoleId == 0 ? NULL : $farmRoleId; if ($scriptId) { $shortcut->scriptId = $scriptId; $shortcut->scriptPath = ''; } else { $shortcut->scriptPath = $scriptPath; $shortcut->scriptId = NULL; } $shortcut->isSync = $scriptIsSync; $shortcut->version = $scriptVersion; $shortcut->timeout = $scriptTimeout; $shortcut->params = $scriptParams; $shortcut->save(); } if ($executeScript) { switch ($target) { case Script::TARGET_FARM: $servers = $this->db->GetAll("SELECT server_id FROM servers WHERE status IN (?,?) AND farm_id=?", array(SERVER_STATUS::INIT, SERVER_STATUS::RUNNING, $farmId)); break; case Script::TARGET_ROLE: $servers = $this->db->GetAll("SELECT server_id FROM servers WHERE status IN (?,?) AND farm_roleid=?", array(SERVER_STATUS::INIT, SERVER_STATUS::RUNNING, $farmRoleId)); break; case Script::TARGET_INSTANCE: $servers = $this->db->GetAll("SELECT server_id FROM servers WHERE status IN (?,?) AND server_id=?", array(SERVER_STATUS::INIT, SERVER_STATUS::RUNNING, $serverId)); break; case Script::TARGET_ALL: $servers = $this->db->GetAll("SELECT server_id FROM servers WHERE status IN (?,?) AND env_id = ?", array(SERVER_STATUS::INIT, SERVER_STATUS::RUNNING, $this->getEnvironmentId())); break; } $scriptSettings = array('version' => $scriptVersion, 'timeout' => $scriptTimeout, 'issync' => $scriptIsSync, 'params' => serialize($scriptParams)); if ($scriptId) { $scriptSettings['scriptid'] = $scriptId; $scriptSettings['type'] = Scalr_Scripting_Manager::ORCHESTRATION_SCRIPT_TYPE_SCALR; } else { $scriptSettings['script_path'] = $scriptPath; $scriptSettings['type'] = Scalr_Scripting_Manager::ORCHESTRATION_SCRIPT_TYPE_LOCAL; } $serializer = Scalr_Messaging_JsonSerializer::getInstance(); $cryptoTool = Scalr_Messaging_CryptoTool::getInstance(); // send message to start executing task (starts script) if (count($servers) > 0) { foreach ($servers as $server) { $DBServer = DBServer::LoadByID($server['server_id']); $msg = new Scalr_Messaging_Msg_ExecScript("Manual"); $msg->setServerMetaData($DBServer); $script = Scalr_Scripting_Manager::prepareScript($scriptSettings, $DBServer); $itm = new stdClass(); // Script $itm->asynchronous = $script['issync'] == 1 ? '0' : '1'; $itm->timeout = $script['timeout']; if ($script['body']) { $itm->name = $script['name']; $itm->body = $script['body']; } else { $itm->path = $script['path']; $itm->name = "local-" . crc32($script['path']) . mt_rand(100, 999); } $itm->executionId = $script['execution_id']; $msg->scripts = array($itm); $msg->setGlobalVariables($DBServer, true); /* if ($DBServer->IsSupported('2.5.12')) { $DBServer->scalarizr->system->executeScripts( $msg->scripts, $msg->globalVariables, $msg->eventName, $msg->roleName ); } else */ $DBServer->SendMessage($msg, false, true); } } $this->response->success('Script execution has been queued and will occur on the selected instance(s) within a couple of minutes.'); } else { $this->response->success('Script shortcut successfully saved'); } }
/** * @return bool * @throws Exception */ public function execute($manual = false) { $farmRoleNotFound = false; $logger = Logger::getLogger(__CLASS__); switch ($this->type) { case self::LAUNCH_FARM: try { $farmId = $this->targetId; $DBFarm = DBFarm::LoadByID($farmId); if ($DBFarm->Status == FARM_STATUS::TERMINATED) { // launch farm Scalr::FireEvent($farmId, new FarmLaunchedEvent(true)); $logger->info(sprintf("Farm #{$farmId} successfully launched")); } elseif ($DBFarm->Status == FARM_STATUS::RUNNING) { // farm is running $logger->info(sprintf("Farm #{$farmId} is already running")); } else { // farm can't be launched $logger->info(sprintf("Farm #{$farmId} can't be launched because of it's status: {$DBFarm->Status}")); } } catch (Exception $e) { $farmRoleNotFound = true; $logger->info(sprintf("Farm #{$farmId} was not found and can't be launched")); } break; case self::TERMINATE_FARM: try { // get config settings $farmId = $this->targetId; $deleteDNSZones = (int) $this->config['deleteDNSZones']; $deleteCloudObjects = (int) $this->config['deleteCloudObjects']; $keepCloudObjects = $deleteCloudObjects == 1 ? 0 : 1; $DBFarm = DBFarm::LoadByID($farmId); if ($DBFarm->Status == FARM_STATUS::RUNNING) { // terminate farm $event = new FarmTerminatedEvent($deleteDNSZones, $keepCloudObjects, false, $keepCloudObjects); Scalr::FireEvent($farmId, $event); $logger->info(sprintf("Farm successfully terminated")); } else { $logger->info(sprintf("Farm #{$farmId} can't be terminated because of it's status")); } } catch (Exception $e) { $farmRoleNotFound = true; $logger->info(sprintf("Farm #{$farmId} was not found and can't be terminated")); } break; case self::SCRIPT_EXEC: // generate event name $eventName = "Scheduler (TaskID: {$this->id})"; if ($manual) { $eventName .= ' (manual)'; } try { if (!\Scalr\Model\Entity\Script::findPk($this->config['scriptId'])) { throw new Exception('Script not found'); } // get executing object by target_type variable switch ($this->targetType) { case self::TARGET_FARM: $DBFarm = DBFarm::LoadByID($this->targetId); $farmId = $DBFarm->ID; $farmRoleId = null; $servers = $this->db->GetAll("SELECT server_id FROM servers WHERE `status` IN (?,?) AND farm_id = ?", array(SERVER_STATUS::INIT, SERVER_STATUS::RUNNING, $farmId)); break; case self::TARGET_ROLE: $farmRoleId = $this->targetId; $servers = $this->db->GetAll("SELECT server_id FROM servers WHERE `status` IN (?,?) AND farm_roleid = ?", array(SERVER_STATUS::INIT, SERVER_STATUS::RUNNING, $farmRoleId)); break; case self::TARGET_INSTANCE: $servers = $this->db->GetAll("SELECT server_id FROM servers WHERE `status` IN (?,?) AND farm_roleid = ? AND `index` = ? ", array(SERVER_STATUS::INIT, SERVER_STATUS::RUNNING, $this->targetId, $this->targetServerIndex)); break; } if ($servers) { $scriptSettings = array('version' => $this->config['scriptVersion'], 'scriptid' => $this->config['scriptId'], 'timeout' => $this->config['scriptTimeout'], 'issync' => $this->config['scriptIsSync'], 'params' => serialize($this->config['scriptOptions']), 'type' => Scalr_Scripting_Manager::ORCHESTRATION_SCRIPT_TYPE_SCALR); // send message to start executing task (starts script) foreach ($servers as $server) { $DBServer = DBServer::LoadByID($server['server_id']); $msg = new Scalr_Messaging_Msg_ExecScript($eventName); $msg->setServerMetaData($DBServer); $script = Scalr_Scripting_Manager::prepareScript($scriptSettings, $DBServer); $itm = new stdClass(); // Script $itm->asynchronous = $script['issync'] == 1 ? '0' : '1'; $itm->timeout = $script['timeout']; if ($script['body']) { $itm->name = $script['name']; $itm->body = $script['body']; } else { $itm->path = $script['path']; } $itm->executionId = $script['execution_id']; $msg->scripts = array($itm); $msg->setGlobalVariables($DBServer, true); /* if ($DBServer->IsSupported('2.5.12')) { $api = $DBServer->scalarizr->system; $api->timeout = 5; $api->executeScripts( $msg->scripts, $msg->globalVariables, $msg->eventName, $msg->roleName ); } else */ $DBServer->SendMessage($msg, false, true); } } else { $farmRoleNotFound = true; } } catch (Exception $e) { // farm or role not found. $farmRoleNotFound = true; $logger->warn(sprintf("Farm, role or instances were not found, script can't be executed")); } break; } return !$farmRoleNotFound; }
/** * {@inheritdoc} * @see \Scalr\DataType\AccessPermissionsInterface::hasAccessPermissions() */ public function hasAccessPermissions($user, $environment = null, $modify = null) { /* @var $script Script */ $script = Script::findPk($this->scriptId); switch ($script->getScope()) { case static::SCOPE_ACCOUNT: return $script->accountId == $user->accountId && (empty($environment) || !$modify); case static::SCOPE_ENVIRONMENT: return $environment ? $script->envId == $environment->id : $user->hasAccessToEnvironment($script->envId); case static::SCOPE_SCALR: return !$modify; default: return false; } }
public function viewAction() { $this->request->restrictAccess(Acl::RESOURCE_ORCHESTRATION_ACCOUNT); $this->response->page('ui/account2/orchestration/view.js', array('orchestrationRules' => $this->getOrchestrationRules(), 'scriptData' => \Scalr\Model\Entity\Script::getScriptingData($this->user->getAccountId(), null)), array('ui/scripts/scriptfield.js', 'ui/services/chef/chefsettings.js'), array('ui/scripts/scriptfield.css')); }
/** * @test */ public function testComplex() { /* @var Script $script */ $script = static::generateScripts([['os' => 'linux']])[0]; /* @var ScriptVersion $version */ $version = static::generateVersions($script, [['content' => '#!/bin/sh']])[0]; $adapter = $this->getAdapter('OrchestrationRules\\FarmRoleScript'); /* @var User $user */ $user = $this->getUser(); $environment = $this->getEnvironment(); /* @var $farm Farm */ $farm = static::createEntity(new Farm(), ['changedById' => $user->getId(), 'name' => "{$this->uuid}-farm", 'description' => "{$this->uuid}-description", 'envId' => $environment->id, 'accountId' => $user->getAccountId(), 'createdById' => $user->getId()]); $farmRole = $this->createTestFarmRole($farm); static::createEntity(new FarmRoleScript(), ['farmRoleId' => $farmRole->id, 'scriptId' => $script->id, 'farmId' => $farm->id]); //test get endpoint $filterable = $adapter->getRules()[ApiEntityAdapter::RULE_TYPE_FILTERABLE]; $rules = $this->listRules($farmRole->id); foreach ($rules as $rule) { foreach ($filterable as $property) { $filterValue = $rule->{$property}; $listResult = $this->listRules($farmRole->id, [$property => $filterValue]); if (!static::isRecursivelyEmpty($filterValue)) { foreach ($listResult as $filtered) { $this->assertEquals($filterValue, $filtered->{$property}, "Property '{$property}' mismatch"); } } } $response = $this->getRule($farmRole->id, $rule->id); $this->assertEquals(200, $response->status, $this->printResponseError($response)); $dbRule = FarmRoleScript::findPk($rule->id); $this->assertObjectEqualsEntity($response->getBody()->data, $dbRule, $adapter); } $scalrFRScriptData = ['trigger' => ['triggerType' => FarmRoleScriptAdapter::TRIGGER_SINGLE_EVENT, 'event' => ['id' => 'HostInit']], 'target' => ['targetType' => FarmRoleScriptAdapter::TARGET_NAME_TRIGGERING_SERVER], 'action' => ['actionType' => FarmRoleScriptAdapter::ACTION_SCRIPT, 'scriptVersion' => ['script' => ['id' => $script->id], 'version' => $version->version]]]; $localFRScriptData = ['trigger' => ['triggerType' => FarmRoleScriptAdapter::TRIGGER_ALL_EVENTS], 'target' => ['targetType' => FarmRoleScriptAdapter::TARGET_NAME_NULL], 'action' => ['actionType' => FarmRoleScriptAdapter::ACTION_URI, 'path' => 'https://example.com']]; //post scalr rule $response = $this->postRule($farmRole->id, $scalrFRScriptData); $this->assertEquals(201, $response->status, $this->printResponseError($response)); $ruleId = $response->getBody()->data->id; /* @var $rule FarmRoleScript */ $rule = FarmRoleScript::findPk($ruleId); $this->assertNotEmpty($rule); $this->ruleToDelete($ruleId); $this->assertObjectEqualsEntity($scalrFRScriptData, $rule, $adapter); //post local rule $response = $this->postRule($farmRole->id, $localFRScriptData); $this->assertEquals(201, $response->status, $this->printResponseError($response)); $ruleId = $response->getBody()->data->id; /* @var $rule FarmRoleScript */ $rule = FarmRoleScript::findPk($ruleId); $this->assertNotEmpty($rule); $this->ruleToDelete($ruleId); $this->assertObjectEqualsEntity($localFRScriptData, $rule, $adapter); //post rule already existing $data = $scalrFRScriptData; $data['id'] = $ruleId; $response = $this->postRule($farmRole->id, $data); $this->assertEquals(201, $response->status, $this->printResponseError($response)); $ruleId = $response->getBody()->data->id; $this->ruleToDelete($ruleId); $this->assertNotEquals($data['id'], $ruleId); //post rule with script that does not exists $data = $scalrFRScriptData; $data['action']['scriptVersion']['script']['id'] = Script::findOne([], null, ['id' => true])->id + 1; $response = $this->postRule($farmRole->id, $data); $this->assertErrorMessageContains($response, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND); //post rule with version that does not exists $data = $scalrFRScriptData; $data['action']['scriptVersion']['version'] = Script::findPk($data['action']['scriptVersion']['script']['id'])->getLatestVersion()->version + 1; $response = $this->postRule($farmRole->id, $data); $this->assertErrorMessageContains($response, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND); //post rule with properties that not existing $data = $scalrFRScriptData; $data['foo'] = 'bar'; $response = $this->postRule($farmRole->id, $data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //post rule without required fields $data = $localFRScriptData; unset($data['action']); $response = $this->postRule($farmRole->id, $data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //post rule with invalid field $data = $localFRScriptData; $data['action'] = ''; $response = $this->postRule($farmRole->id, $data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //modify rule //TODO::ape add modify rule //fetch rule $response = $this->getRule($farmRole->id, $rule->id); $this->assertEquals(200, $response->status, $this->printResponseError($response)); $this->assertObjectEqualsEntity($response->getBody()->data, $rule, $adapter); //fetch rule that doe not exists $response = $this->getRule($farmRole->id, FarmRoleScript::findOne([], null, ['id' => false])->id + 1); $this->assertErrorMessageContains($response, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND); //fetch rule with missmatch farm role id $response = $this->getRule(FarmRole::findOne([], null, ['id' => false])->id + 1, $rule->id); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_VALUE); //test have access to all listed rules $rules = $this->listRules($farmRole->id); foreach ($rules as $rule) { $this->assertTrue(FarmRoleScript::findPk($rule->id)->hasAccessPermissions($user)); } //test invalid filters $url = self::getUserApiUrl("/farm-roles/{$farmRole->id}/orchestration-rules/"); $response = $this->request($url, Request::METHOD_GET, ['foo' => 'bar']); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); $response = $this->request($url, Request::METHOD_GET, ['scope' => 'foobar']); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //delete script /* @var $rule FarmRoleScript */ $rule = static::createEntity(new FarmRoleScript(), ['farmRoleId' => $farmRole->id, 'scriptId' => $script->id, 'farmId' => $farm->id]); $response = $this->deleteRule($farmRole->id, $rule->id); $this->assertEquals(200, $response->status, $this->printResponseError($response)); //delete script that does not exists $response = $this->deleteRule($farmRole->id, FarmRoleScript::findOne([], null, ['id' => false])->id + 1); $this->assertErrorMessageContains($response, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND); }
public function xListScriptingLogsAction() { $this->request->restrictAccess(Acl::RESOURCE_LOGS_SCRIPTING_LOGS); $this->request->defineParams(array('farmId' => array('type' => 'int'), 'serverId', 'eventId', 'script', 'scheduler' => array('type' => 'int'), 'query' => array('type' => 'string'), 'sort' => array('type' => 'json', 'default' => array('property' => 'id', 'direction' => 'DESC')))); $sql = "SELECT * FROM scripting_log WHERE :FILTER:"; $args = array(); $farms = $this->db->GetCol("SELECT id FROM farms WHERE env_id=?", array($this->getEnvironmentId())); if ($this->getParam('farmId') && in_array($this->getParam('farmId'), $farms)) { $sql .= ' AND farmid = ?'; $args[] = $this->getParam('farmId'); } else { if (count($farms)) { $sql .= ' AND farmid IN (' . implode(',', $farms) . ')'; } else { $sql .= ' AND 0'; } } if ($this->getParam('serverId')) { $sql .= ' AND server_id = ?'; $args[] = $this->getParam('serverId'); } if ($this->getParam('eventServerId')) { $sql .= ' AND event_server_id = ?'; $args[] = $this->getParam('eventServerId'); } if ($this->getParam('eventId')) { $sql .= ' AND event_id = ?'; $args[] = $this->getParam('eventId'); } if ($this->getParam('script')) { /* @var Script $script */ $script = Script::findPk($this->getParam('script')); if ($script && (!$script->accountId || $script->accountId == $this->user->getAccountId())) { $scriptName = substr(preg_replace("/[^A-Za-z0-9]+/", "_", $script->name), 0, 50); // because of column's length $sql .= ' AND script_name = ?'; $args[] = $scriptName; } } if ($this->getParam('scheduler')) { $sql .= ' AND event = ?'; $args[] = 'Scheduler (TaskID: ' . $this->getParam('scheduler') . ')'; } else { if ($this->getParam('event')) { $sql .= ' AND event = ?'; $args[] = $this->getParam('event'); } } if ($this->getParam('byDate')) { try { $tz = $this->user->getSetting(Scalr_Account_User::SETTING_UI_TIMEZONE); if (!$tz) { $tz = 'UTC'; } $tz = new DateTimeZone($tz); $dtS = new DateTime($this->getParam('byDate'), $tz); $dtE = new DateTime($this->getParam('byDate'), $tz); if ($this->getParam('fromTime')) { $dtS = DateTime::createFromFormat('Y-m-d H:i', $this->getParam('byDate') . ' ' . $this->getParam('fromTime'), $tz); } if ($this->getParam('toTime')) { $dtE = DateTime::createFromFormat('Y-m-d H:i', $this->getParam('byDate') . ' ' . $this->getParam('toTime'), $tz); } else { $dtE = $dtE->add(new DateInterval('P1D')); } Scalr_Util_DateTime::convertTimeZone($dtS); Scalr_Util_DateTime::convertTimeZone($dtE); $sql .= ' AND dtadded > ? AND dtadded < ?'; $args[] = $dtS->format('Y-m-d H:i:s'); $args[] = $dtE->format('Y-m-d H:i:s'); } catch (Exception $e) { } } $response = $this->buildResponseFromSql2($sql, array('id', 'dtadded'), array('event', 'script_name'), $args); $cache = array(); foreach ($response["data"] as &$row) { // //target_data // if (!$cache['farm_names'][$row['farmid']]) { $cache['farm_names'][$row['farmid']] = $this->db->GetOne("SELECT name FROM farms WHERE id=? LIMIT 1", array($row['farmid'])); } $row['target_farm_name'] = $cache['farm_names'][$row['farmid']]; $row['target_farm_id'] = $row['farmid']; $sInfo = $this->db->GetRow("SELECT role_id, farm_roleid, `index` FROM servers WHERE server_id = ? LIMIT 1", array($row['server_id'])); $row['target_farm_roleid'] = $sInfo['farm_roleid']; if (!$cache['role_names'][$sInfo['farm_roleid']]) { $cache['role_names'][$sInfo['farm_roleid']] = $this->db->GetOne("SELECT alias FROM farm_roles WHERE id=?", array($sInfo['farm_roleid'])); } $row['target_role_name'] = $cache['role_names'][$sInfo['farm_roleid']]; $row['target_server_index'] = $sInfo['index']; $row['target_server_id'] = $row['server_id']; // //event_data // if ($row['event_server_id']) { $esInfo = $this->db->GetRow("SELECT role_id, farm_roleid, `index`, farm_id FROM servers WHERE server_id = ? LIMIT 1", array($row['event_server_id'])); if (!$cache['farm_names'][$esInfo['farm_id']]) { $cache['farm_names'][$esInfo['farm_id']] = $this->db->GetOne("SELECT name FROM farms WHERE id=? LIMIT 1", array($esInfo['farm_id'])); } $row['event_farm_name'] = $cache['farm_names'][$esInfo['farm_id']]; $row['event_farm_id'] = $esInfo['farm_id']; $row['event_farm_roleid'] = $esInfo['farm_roleid']; if (!$cache['role_names'][$esInfo['farm_roleid']]) { $cache['role_names'][$esInfo['farm_roleid']] = $this->db->GetOne("SELECT alias FROM farm_roles WHERE id=? LIMIT 1", array($esInfo['farm_roleid'])); } $row['event_role_name'] = $cache['role_names'][$esInfo['farm_roleid']]; $row['event_server_index'] = $esInfo['index']; } $row['dtadded'] = Scalr_Util_DateTime::convertTz($row['dtadded']); if (\Scalr::config('scalr.system.scripting.logs_storage') == 'scalr') { $row['execution_id'] = null; } if ($row['message']) { $row['message'] = nl2br(htmlspecialchars($row['message'])); } } $this->response->data($response); }
/** * @param int $farmId * @param string $serverId * @param string $eventId * @param int $scriptId * @param string $eventServerId * @param int $schedulerId * @param string $byDate * @param string $fromTime * @param string $toTime * @param string $status * @param string $event * @param JsonData $sort * @param int $start * @param int $limit * @param string $query * @throws Scalr_Exception_Core * @throws Scalr_Exception_InsufficientPermissions */ public function xListOrchestrationLogsAction($farmId = 0, $serverId = '', $eventId = '', $scriptId = 0, $eventServerId = '', $schedulerId = 0, $byDate = '', $fromTime = '', $toTime = '', $status = '', $event = '', JsonData $sort, $start = 0, $limit = 20, $query = '') { $this->request->restrictAccess(Acl::RESOURCE_LOGS_ORCHESTRATION_LOGS); $o = new Entity\OrchestrationLog(); $f = new Entity\Farm(); $criteria = [Entity\Farm::STMT_FROM => "{$o->table()} JOIN {$f->table('f')} ON {$f->columnId('f')} = {$o->columnFarmId}", Entity\Farm::STMT_WHERE => $this->request->getFarmSqlQuery() . " AND {$f->columnEnvId('f')} = " . $this->db->qstr($this->getEnvironmentId())]; if ($farmId) { $criteria[] = ['farmId' => $farmId]; } if ($serverId) { $criteria[] = ['serverId' => $serverId]; } if ($eventId) { $criteria[] = ['eventId' => $eventId]; } if ($eventServerId) { $criteria[] = ['eventServerId' => $eventServerId]; } if ($scriptId) { /* @var $script Script */ $script = Script::findPk($scriptId); if ($script && $this->request->hasPermissions($script)) { $scriptName = preg_replace("/[^A-Za-z0-9]+/", "_", $script->name); $criteria[] = ['scriptName' => $scriptName]; } } if ($query || $event) { $logEntity = new OrchestrationLog(); $eventEntity = new Event(); $criteria[AbstractEntity::STMT_FROM] = $criteria[AbstractEntity::STMT_FROM] . "\n LEFT JOIN {$eventEntity->table('e')}\n ON {$logEntity->columnEventId} = {$eventEntity->columnEventId('e')}\n "; if ($event && $query) { $query = $this->db->qstr('%' . $query . '%'); $criteria[AbstractEntity::STMT_WHERE] = $criteria[AbstractEntity::STMT_WHERE] . " AND (\n {$eventEntity->columnType('e')} = {$this->db->qstr($event)}\n OR ({$logEntity->columnType} LIKE {$query}\n AND {$logEntity->columnScriptName} LIKE {$query})\n )"; } else { if ($event) { $criteria[AbstractEntity::STMT_WHERE] = $criteria[AbstractEntity::STMT_WHERE] . " AND (\n {$eventEntity->columnType('e')} = {$this->db->qstr($event)}\n )"; } else { $query = $this->db->qstr('%' . $query . '%'); $criteria[AbstractEntity::STMT_WHERE] = $criteria[AbstractEntity::STMT_WHERE] . " AND (\n ({$eventEntity->columnType('e')} LIKE {$query}\n OR {$logEntity->columnType} LIKE {$query}\n OR {$logEntity->columnScriptName} LIKE {$query})\n )"; } } } if ($schedulerId) { $criteria[] = ['taskId' => $schedulerId]; } if ($byDate) { try { $tz = $this->user->getSetting(Scalr_Account_User::SETTING_UI_TIMEZONE) ?: 'UTC'; $tz = new DateTimeZone($tz); $dtS = new DateTime($byDate, $tz); $dtE = new DateTime($byDate, $tz); if ($fromTime) { $dtS = DateTime::createFromFormat('Y-m-d H:i', "{$byDate} {$fromTime}", $tz); } if ($toTime) { $dtE = DateTime::createFromFormat('Y-m-d H:i', "{$byDate} {$toTime}", $tz); } else { $dtE = $dtE->add(new DateInterval('P1D')); } if ($dtS && $dtE) { Scalr_Util_DateTime::convertTimeZone($dtS); Scalr_Util_DateTime::convertTimeZone($dtE); $criteria[] = ['added' => ['$gt' => $dtS]]; $criteria[] = ['added' => ['$lt' => $dtE]]; } } catch (Exception $e) { } } if ($status === 'success') { $criteria[] = ['execExitCode' => 0]; } else { if ($status === 'failure') { $criteria[] = ['execExitCode' => ['$ne' => 0]]; } } $logs = OrchestrationLog::find($criteria, null, Scalr\UI\Utils::convertOrder($sort, ['id' => false], ['id', 'added']), $limit, $start, true); $data = $this->prepareOrchestrationLogData($logs); $this->response->data(['data' => $data, 'total' => $logs->totalNumber]); }
/** * @test */ public function testComplex() { $user = $this->getUser(); $environment = $this->getEnvironment(); $fictionController = new ApiController(); //foreach iterates through values in order of ads //we need to remove rules first, then - scripts //we initialize data set for removal with non-existing rule $this->ruleToDelete(-1); /* @var $roles Role[] */ $roles = $this->getTestRoles(); /* @var $role Role */ $role = array_shift($roles); /* @var $scalrRole Role */ $scalrRole = Role::findOne([['envId' => null, 'accountId' => null]]); /* @var $script Script */ $script = static::createEntity(new Script(), ['name' => 'test-role-scripts', 'description' => 'test-role-scripts', '']); $isWindows = $role->getOs()->family == 'windows'; /* @var $version ScriptVersion */ $version = static::createEntity(new ScriptVersion(), ['scriptId' => $script->id, 'version' => $script->getLatestVersion()->version + 1, 'content' => $isWindows ? '#!cmd' : '#!/bin/sh']); $script->os = $isWindows ? 'windows' : 'linux'; $script->save(); $scalrRoleScriptData = ['trigger' => ['type' => RoleScriptAdapter::TRIGGER_SINGLE_EVENT, 'event' => ['id' => 'HostInit']], 'target' => ['type' => RoleScriptAdapter::TARGET_TRIGGERING_FARM_ROLE], 'action' => ['actionType' => RoleScriptAdapter::ACTION_SCRIPT, 'scriptVersion' => ['script' => ['id' => $script->id], 'version' => $version->version]]]; $localRoleScriptData = ['trigger' => ['type' => RoleScriptAdapter::TRIGGER_ALL_EVENTS], 'target' => ['type' => RoleScriptAdapter::TARGET_NULL], 'action' => ['actionType' => RoleScriptAdapter::ACTION_URI, 'uri' => 'https://example.com']]; //post scalr rule $response = $this->postRule($role->id, $scalrRoleScriptData); $this->assertEquals(201, $response->status, $this->printResponseError($response)); $ruleId = $response->getBody()->data->id; /* @var $rule RoleScript */ $rule = RoleScript::findPk($ruleId); $this->assertNotEmpty($rule); $this->ruleToDelete($ruleId); $this->assertObjectEqualsEntity($scalrRoleScriptData, $rule); //post local rule $response = $this->postRule($role->id, $localRoleScriptData); $this->assertEquals(201, $response->status, $this->printResponseError($response)); $ruleId = $response->getBody()->data->id; /* @var $rule RoleScript */ $rule = RoleScript::findPk($ruleId); $this->assertNotEmpty($rule); $this->ruleToDelete($ruleId); $this->assertObjectEqualsEntity($localRoleScriptData, $rule); //post rule to environment-scoped role $response = $this->postRule($scalrRole->id, $scalrRoleScriptData); $this->assertErrorMessageContains($response, 403, ErrorMessage::ERR_PERMISSION_VIOLATION); //post rule already existing $data = $scalrRoleScriptData; $data['id'] = $ruleId; $response = $this->postRule($role->id, $data); $this->assertEquals(201, $response->status, $this->printResponseError($response)); $ruleId = $response->getBody()->data->id; $this->ruleToDelete($ruleId); $this->assertNotEquals($data['id'], $ruleId); //post rule with script that does not exists $data = $scalrRoleScriptData; $data['action']['scriptVersion']['script']['id'] = Script::findOne([], ['id' => true])->id + 1; $response = $this->postRule($role->id, $data); $this->assertErrorMessageContains($response, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND); //post rule with version that does not exists $data = $scalrRoleScriptData; $data['action']['scriptVersion']['version'] = Script::findPk($data['action']['scriptVersion']['script']['id'])->getLatestVersion()->version + 1; $response = $this->postRule($role->id, $data); $this->assertErrorMessageContains($response, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND); //post rule with properties that not existing $data = $scalrRoleScriptData; $data['foo'] = 'bar'; $response = $this->postRule($role->id, $data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //post rule without required fields $data = $localRoleScriptData; unset($data['action']); $response = $this->postRule($role->id, $data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //post rule with invalid field $data = $localRoleScriptData; $data['action'] = ''; $response = $this->postRule($role->id, $data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //fetch rule $response = $this->getRule($role->id, $rule->id); $this->assertEquals(200, $response->status, $this->printResponseError($response)); $this->assertObjectEqualsEntity($response->getBody()->data, $rule); //fetch rule that doe not exists $response = $this->getRule($role->id, RoleScript::findOne([], ['id' => ''])->id + 1); $this->assertErrorMessageContains($response, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND); //fetch rule with missmatch role id $response = $this->getRule(Role::findOne([], ['id' => ''])->id + 1, $rule->id); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_VALUE); //test have access to all listed rules $rules = $this->listRules($role->id); foreach ($rules as $rule) { $this->assertTrue(RoleScript::findPk($rule->id)->hasAccessPermissions($user)); } $listUri = static::getUserApiUrl("/scripts"); //test invalid filters $response = $this->request($listUri, Request::METHOD_GET, ['foo' => 'bar']); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //test invalid filters values $response = $this->request($listUri, Request::METHOD_GET, ['scope' => 'foobar']); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_VALUE); //delete script /* @var $rule RoleScript */ $rule = static::createEntity(new RoleScript(), ['roleId' => $role->id, 'scriptId' => $script->id]); $response = $this->deleteRule($role->id, $rule->id); $this->assertEquals(200, $response->status, $this->printResponseError($response)); //delete scalr-scoped script /* @var $rule RoleScript */ $rule = static::createEntity(new RoleScript(), ['roleId' => $scalrRole->id, 'scriptId' => $script->id, 'version' => -1]); $response = $this->deleteRule($scalrRole->id, $rule->id); $this->assertErrorMessageContains($response, 403, ErrorMessage::ERR_PERMISSION_VIOLATION); //delete script that does not exists $response = $this->deleteRule($role->id, RoleScript::findOne([], ['id' => ''])->id + 1); $this->assertErrorMessageContains($response, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND); }
/** * @test * * @throws \Scalr\Exception\ModelException */ public function testComplex() { $user = $this->getUser(); $environment = $this->getEnvironment(); $fictionController = new ApiController(); //test script post $data = ['name' => 'test-post', 'description' => 'test-post', 'timeoutDefault' => 1000, 'blockingDefault' => true, 'osType' => 'linux']; $response = $this->postScript($data); $this->assertEquals(201, $response->status, $this->printResponseError($response)); $scriptId = $response->getBody()->data->id; /* @var $script Script */ $script = Script::findPk($scriptId); $this->assertNotEmpty($script); $this->scriptToDelete($scriptId); $this->assertObjectEqualsEntity($data, $script); //post environment-scoped script $data['scope'] = ScopeInterface::SCOPE_ENVIRONMENT; $response = $this->postScript($data); $this->assertEquals(201, $response->status, $this->printResponseError($response)); $scriptId = $response->getBody()->data->id; $script = Script::findPk($scriptId); $this->assertNotEmpty($script); $this->scriptToDelete($scriptId); $this->assertObjectEqualsEntity($data, $script); //post script already existing $data = ['id' => $script->id, 'name' => 'test-post-existing', 'description' => 'test-post-existing', 'osType' => 'linux', 'scope' => ScopeInterface::SCOPE_ENVIRONMENT]; $response = $this->postScript($data); $this->assertEquals(201, $response->status, $this->printResponseError($response)); $scriptId = $response->getBody()->data->id; $this->scriptToDelete($scriptId); $this->assertNotEquals($data['id'], $scriptId); unset($data['id']); $scriptData = $data; $scriptData['accountId'] = $user->getAccountId(); $scriptData['envId'] = $environment->id; $scriptData['os'] = $data['osType']; unset($scriptData['osType'], $scriptData['scope']); $envScript = $this->createEntity(new Script(), $scriptData); //post script with name already exists in current (environment) scope $data['name'] = 'test-post-existing'; $response = $this->postScript($data); $this->assertErrorMessageContains($response, 409, ErrorMessage::ERR_UNICITY_VIOLATION); $envScript->delete(); //post script with properties that not existing $data = ['name' => 'test-post-not-existing-field', 'description' => 'test-post-not-existing-field', 'foo' => 'bar', 'osType' => 'linux']; $response = $this->postScript($data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //post script without required fields $data = ['name' => 'foobar', 'description' => 'test-post-no-scope']; $response = $this->postScript($data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //test script fetch $response = $this->getScript($script->id); $this->assertEquals(200, $response->status, $this->printResponseError($response)); $this->assertObjectEqualsEntity($response->getBody()->data, $script); //test fetch script that doe not exists $response = $this->getScript(Script::findOne([], null, ['id' => false])->id + 1); $this->assertErrorMessageContains($response, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND); //test script modify $data = ['name' => 'test-modify', 'description' => 'test-modify', 'timeoutDefault' => 0, 'blockingDefault' => false]; $response = $this->modifyScript($script->id, $data); $this->assertEquals(200, $response->status, $this->printResponseError($response)); $this->assertObjectEqualsEntity($response->getBody()->data, Script::findPk($script->id)); //modify property that does not exists $data = ['foo' => 'bar']; $response = $this->modifyScript($script->id, $data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //modify properties that not alterable $scriptAdapter = new ScriptAdapter($fictionController); $adapterRules = $scriptAdapter->getRules(); $publicProperties = $adapterRules[BaseAdapter::RULE_TYPE_TO_DATA]; $alterableProperties = $adapterRules[ApiEntityAdapter::RULE_TYPE_ALTERABLE]; $nonAlterableProperties = array_diff(array_values($publicProperties), $alterableProperties); foreach ($nonAlterableProperties as $property) { $data = [$property => 'foo']; $response = $this->modifyScript($script->id, $data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); } //modify script that does not exists $data = ['name' => 'test-modify-not-found']; $response = $this->modifyScript(Script::findOne([], null, ['id' => false])->id + 1, $data); $this->assertErrorMessageContains($response, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND); //modify Scalr-scoped script /* @var $script Script */ $script = static::createEntity(new Script(), ['name' => "{$this->uuid}-script", 'description' => "{$this->uuid}-description", 'createdById' => $user->getId()]); //modify Scalr-scoped script $data = ['name' => 'test-modify-scalr-scoped']; $response = $this->modifyScript($script->id, $data); $this->assertErrorMessageContains($response, 403, ErrorMessage::ERR_PERMISSION_VIOLATION, 'Insufficient permissions'); /* @var $script Script */ $script = static::createEntity(new Script(), ['name' => "{$this->uuid}-script", 'description' => "{$this->uuid}-description", 'accountId' => $user->getAccountId(), 'createdById' => $user->getId()]); //test have access to all listed scripts $scripts = $this->listScripts(); foreach ($scripts as $script) { $this->assertTrue(Script::findPk($script->id)->hasAccessPermissions($user), "Script id: {$script->id}"); } //test convertible data filters $mergedLists = array_merge($this->listScripts(['scope' => ScopeInterface::SCOPE_SCALR]), $this->listScripts(['scope' => ScopeInterface::SCOPE_ENVIRONMENT]), $this->listScripts(['scope' => ScopeInterface::SCOPE_ACCOUNT])); foreach ($mergedLists as $script) { $this->assertTrue(Script::findPk($script->id)->hasAccessPermissions($user), "Script id: {$script->id}"); } //test list scripts filters $filterable = $scriptAdapter->getRules()[ApiEntityAdapter::RULE_TYPE_FILTERABLE]; /* @var $script Script */ foreach ($scripts as $script) { foreach ($filterable as $property) { $filterValue = $script->{$property}; $listResult = $this->listScripts([$property => $filterValue]); if (!static::isRecursivelyEmpty($filterValue)) { foreach ($listResult as $filtered) { $this->assertEquals($filterValue, $filtered->{$property}, "Property '{$property}' mismatch"); } } } $response = $this->getScript($script->id); $this->assertEquals(200, $response->status, $this->printResponseError($response)); $dbScript = Script::findPk($script->id); $this->assertObjectEqualsEntity($response->getBody()->data, $dbScript, $scriptAdapter); } //test have write access to environments and account scoped scripts foreach (array_merge($this->listScripts(['scope' => ScopeInterface::SCOPE_ENVIRONMENT]), $this->listScripts(['scope' => ScopeInterface::SCOPE_ACCOUNT])) as $script) { $this->assertTrue(Script::findPk($script->id)->hasAccessPermissions($user, null, true)); } $listUri = static::getUserApiUrl("/scripts"); //test invalid filters $response = $this->request($listUri, Request::METHOD_GET, ['foo' => 'bar']); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //test invalid filters values $response = $this->request($listUri, Request::METHOD_GET, ['scope' => 'foobar']); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_VALUE); //delete script /* @var $script Script */ $script = static::createEntity(new Script(), ['name' => "{$this->uuid}-script", 'description' => "{$this->uuid}-description", 'envId' => $environment->id, 'createdById' => $user->getId()]); $response = $this->deleteScript($script->id); $this->assertEquals(200, $response->status, $this->printResponseError($response)); //delete scalr-scoped script $scripts = $this->listScripts(['scope' => ScopeInterface::SCOPE_SCALR]); $script = array_shift($scripts); $response = $this->deleteScript($script->id); $this->assertErrorMessageContains($response, 403, ErrorMessage::ERR_PERMISSION_VIOLATION); //delete script that does not exists $response = $this->deleteScript(Script::findOne([], null, ['id' => false])->id + 1); $this->assertErrorMessageContains($response, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND); }
public function ScriptsList() { $this->restrictAccess(Acl::RESOURCE_SCRIPTS_ENVIRONMENT); $response = $this->CreateInitialResponse(); $response->ScriptSet = new stdClass(); $response->ScriptSet->Item = array(); foreach (Script::find(['$or' => [['accountId' => null], ['accountId' => $this->user->getAccountId()]]]) as $script) { /* @var $script Script */ $itm = new stdClass(); $itm->ID = $script->id; $itm->Name = $script->name; $itm->Description = $script->description; $itm->LatestRevision = $script->getLatestVersion()->version; $response->ScriptSet->Item[] = $itm; } return $response; }
/** * @param int $farmId * @param string $serverId * @param string $event * @param string $eventId * @param string $eventServerId * @param int $scriptId * @param int $schedulerId * @param string $byDate * @param string $fromTime * @param string $toTime * @param string $status * @throws Scalr_Exception_Core * @throws Scalr_Exception_InsufficientPermissions */ public function xListScriptingLogsAction($farmId = 0, $serverId = '', $event = '', $eventId = '', $eventServerId = '', $scriptId = 0, $schedulerId = 0, $byDate = '', $fromTime = '', $toTime = '', $status = '') { $this->request->restrictAccess(Acl::RESOURCE_LOGS_SCRIPTING_LOGS); $sql = "SELECT * FROM scripting_log WHERE :FILTER:"; $args = []; $farmSql = "SELECT id FROM farms WHERE env_id = ?"; $farmArgs = [$this->getEnvironmentId()]; list($farmSql, $farmArgs) = $this->request->prepareFarmSqlQuery($farmSql, $farmArgs); $farms = $this->db->GetCol($farmSql, $farmArgs); if ($farmId && in_array($farmId, $farms)) { $sql .= ' AND farmid = ?'; $args[] = $farmId; } else { if (count($farms)) { $sql .= ' AND farmid IN (' . implode(',', $farms) . ')'; } else { $sql .= ' AND 0'; } } if ($serverId) { $sql .= ' AND server_id = ?'; $args[] = $serverId; } if ($eventServerId) { $sql .= ' AND event_server_id = ?'; $args[] = $eventServerId; } if ($eventId) { $sql .= ' AND event_id = ?'; $args[] = $eventId; } if ($scriptId) { /* @var $script Script */ $script = Script::findPk($scriptId); if ($script && (!$script->accountId || $script->accountId == $this->user->getAccountId())) { $scriptName = substr(preg_replace("/[^A-Za-z0-9]+/", "_", $script->name), 0, 50); // because of column's length $sql .= ' AND script_name = ?'; $args[] = $scriptName; } } if ($schedulerId) { $sql .= ' AND event = ?'; $args[] = 'Scheduler (TaskID: ' . $schedulerId . ')'; } else { if ($event) { $sql .= ' AND event = ?'; $args[] = $event; } } if ($byDate) { try { $tz = $this->user->getSetting(Scalr_Account_User::SETTING_UI_TIMEZONE); if (!$tz) { $tz = 'UTC'; } $tz = new DateTimeZone($tz); $dtS = new DateTime($byDate, $tz); $dtE = new DateTime($byDate, $tz); if ($fromTime) { $dtS = DateTime::createFromFormat('Y-m-d H:i', "{$byDate} {$fromTime}", $tz); } if ($toTime) { $dtE = DateTime::createFromFormat('Y-m-d H:i', "{$byDate} {$toTime}", $tz); } else { $dtE = $dtE->add(new DateInterval('P1D')); } if ($dtS && $dtE) { Scalr_Util_DateTime::convertTimeZone($dtS); Scalr_Util_DateTime::convertTimeZone($dtE); $sql .= ' AND dtadded > ? AND dtadded < ?'; $args[] = $dtS->format('Y-m-d H:i:s'); $args[] = $dtE->format('Y-m-d H:i:s'); } } catch (Exception $e) { } } if ($status === 'success') { $sql .= ' AND exec_exitcode = ?'; $args[] = 0; } else { if ($status === 'failure') { $sql .= ' AND exec_exitcode <> ?'; $args[] = 0; } } $response = $this->buildResponseFromSql2($sql, ['id', 'dtadded'], ['event', 'script_name'], $args); $cache = []; foreach ($response["data"] as &$row) { // //target_data // if (!$cache['farm_names'][$row['farmid']]) { $cache['farm_names'][$row['farmid']] = $this->db->GetOne("SELECT name FROM farms WHERE id=? LIMIT 1", [$row['farmid']]); } $row['target_farm_name'] = $cache['farm_names'][$row['farmid']]; $row['target_farm_id'] = $row['farmid']; $sInfo = $this->db->GetRow("SELECT farm_roleid, `index` FROM servers WHERE server_id = ? LIMIT 1", [$row['server_id']]); $row['target_farm_roleid'] = $sInfo['farm_roleid']; if (!$cache['role_names'][$sInfo['farm_roleid']]) { $cache['role_names'][$sInfo['farm_roleid']] = $this->db->GetOne("SELECT alias FROM farm_roles WHERE id=?", [$sInfo['farm_roleid']]); } $row['target_role_name'] = $cache['role_names'][$sInfo['farm_roleid']]; $row['target_server_index'] = $sInfo['index']; $row['target_server_id'] = $row['server_id']; // //event_data // if ($row['event_server_id']) { $esInfo = $this->db->GetRow("SELECT farm_roleid, `index`, farm_id FROM servers WHERE server_id = ? LIMIT 1", [$row['event_server_id']]); if (!$cache['farm_names'][$esInfo['farm_id']]) { $cache['farm_names'][$esInfo['farm_id']] = $this->db->GetOne("SELECT name FROM farms WHERE id=? LIMIT 1", [$esInfo['farm_id']]); } $row['event_farm_name'] = $cache['farm_names'][$esInfo['farm_id']]; $row['event_farm_id'] = $esInfo['farm_id']; $row['event_farm_roleid'] = $esInfo['farm_roleid']; if (!$cache['role_names'][$esInfo['farm_roleid']]) { $cache['role_names'][$esInfo['farm_roleid']] = $this->db->GetOne("SELECT alias FROM farm_roles WHERE id=? LIMIT 1", [$esInfo['farm_roleid']]); } $row['event_role_name'] = $cache['role_names'][$esInfo['farm_roleid']]; $row['event_server_index'] = $esInfo['index']; } $row['dtadded'] = Scalr_Util_DateTime::convertTz($row['dtadded']); if (\Scalr::config('scalr.system.scripting.logs_storage') == 'scalr') { $row['execution_id'] = null; } if ($row['message']) { $row['message'] = nl2br(htmlspecialchars($row['message'])); } } $this->response->data($response); }
/** * {@inheritdoc} * @see \Scalr\Api\DataType\ApiEntityAdapter::validateEntity() */ public function validateEntity($entity) { if (!$entity instanceof Script) { throw new InvalidArgumentException(sprintf("First argument must be instance of Scalr\\Model\\Entity\\Script class")); } if ($entity->id !== null) { if (!Script::findPk($entity->id)) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, sprintf("Could not find out the Script with ID: %d", $entity->id)); } } if (empty($entity->name)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Property name cannot be empty"); } else { switch ($entity->getScope()) { case ScopeInterface::SCOPE_ACCOUNT: $existed = Script::findOne([['name' => $entity->name], ['accountId' => $this->controller->getUser()->accountId], ['envId' => null]]); break; case ScopeInterface::SCOPE_ENVIRONMENT: $existed = Script::findOne([['name' => $entity->name], ['accountId' => $this->controller->getUser()->accountId], ['envId' => $this->controller->getEnvironment()->id]]); break; case ScopeInterface::SCOPE_SCALR: $existed = Script::findOne([['name' => $entity->name], ['accountId' => null], ['envId' => null]]); break; } /* @var $existed Script */ if (!empty($existed) && $entity->id !== $existed->id) { throw new ApiErrorException(409, ErrorMessage::ERR_UNICITY_VIOLATION, "Script '{$entity->name}' already exists on scope {$existed->getScope()}"); } } if (empty($entity->os)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property osType"); } else { if (!in_array($entity->os, [Script::OS_LINUX, Script::OS_WINDOWS])) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Invalid osType"); } } //NOTE: scalr-scope currently restricted in APIv2 switch ($entity->getScope()) { case ScopeInterface::SCOPE_ENVIRONMENT: if (!$this->controller->getEnvironment()) { throw new ApiErrorException(403, ErrorMessage::ERR_SCOPE_VIOLATION, "Invalid scope"); } break; case ScopeInterface::SCOPE_ACCOUNT: if ($this->controller->getEnvironment()) { throw new ApiErrorException(403, ErrorMessage::ERR_SCOPE_VIOLATION, "Invalid scope"); } break; case ScopeInterface::SCOPE_SCALR: case ScopeInterface::SCOPE_FARM: case ScopeInterface::SCOPE_FARMROLE: case ScopeInterface::SCOPE_ROLE: case ScopeInterface::SCOPE_SERVER: throw new ApiErrorException(403, ErrorMessage::ERR_SCOPE_VIOLATION, "Invalid scope"); default: throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Invalid scope"); } if (!$this->controller->hasPermissions($entity, true)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } }