protected function run1($stage) { $table = 'event_definitions'; $sql = []; if (!$this->hasTableColumn($table, 'created')) { $bCreated = true; $this->console->out("Adding scalr.event_definitions.created column..."); $sql[] = "ADD COLUMN `created` DATETIME NOT NULL COMMENT 'Created at timestamp' AFTER `description`"; } if (!$this->hasTableIndex($table, 'idx_created')) { $this->console->out('Adding index by `created` to `event_definitions`'); $sql[] = 'ADD INDEX `idx_created` (created ASC)'; } if (!empty($sql)) { $this->applyChanges($table, $sql); } if (!empty($bCreated)) { $date = new DateTime(); $date->modify('-1 hour'); $list = EventDefinition::find([['$or' => [['created' => null], ['created' => new \DateTime('0000-00-00 00:00:00')]]]]); foreach ($list as $event) { /* @var $event EventDefinition */ $event->created = $date; $event->save(); $date->modify('+1 second'); } } }
public function xGetAction() { $this->request->defineParams(array('schedulerTaskId' => array('type' => 'int'))); $events = array_map(function ($item) { if ($item->envId) { $scope = 'environment'; } else { if ($item->accountId) { $scope = 'account'; } else { $scope = 'scalr'; } } return ['name' => $item->name, 'description' => $item->description, 'scope' => $scope]; }, EventDefinition::find([['$or' => [['accountId' => null], ['accountId' => $this->user->getAccountId()]]], ['$or' => [['envId' => null], ['envId' => $this->getEnvironmentId()]]]], null, ['name' => true])->getArrayCopy()); //$DBFarmRole->FarmID; $task = Scalr_SchedulerTask::init(); $task->loadById($this->getParam(self::CALL_PARAM_NAME)); $this->user->getPermissions()->validate($task); $taskValues = array('targetId' => $task->targetId, 'targetType' => $task->targetType, 'id' => $task->id, 'name' => $task->name, 'type' => $task->type, 'comments' => $task->comments, 'config' => $task->config, 'startTime' => $task->startTime ? Scalr_Util_DateTime::convertTimeZone(new DateTime($task->startTime), $task->timezone)->format('H:i') : '', 'startTimeDate' => $task->startTime ? Scalr_Util_DateTime::convertTimeZone(new DateTime($task->startTime), $task->timezone)->format('Y-m-d') : '', 'restartEvery' => $task->restartEvery, 'timezone' => $task->timezone); $taskValues['config']['scriptId'] = (int) $taskValues['config']['scriptId']; $taskValues['config']['scriptIsSync'] = (int) $taskValues['config']['scriptIsSync']; $farmWidget = array(); switch ($task->targetType) { case Scalr_SchedulerTask::TARGET_FARM: $farmWidget = self::loadController('Farms')->getFarmWidget(array('farmId' => $task->targetId), 'addAll'); break; case Scalr_SchedulerTask::TARGET_ROLE: $farmWidget = self::loadController('Farms')->getFarmWidget(array('farmRoleId' => $task->targetId), 'addAll'); break; case Scalr_SchedulerTask::TARGET_INSTANCE: try { $DBServer = DBServer::LoadByFarmRoleIDAndIndex($task->targetId, $task->targetServerIndex); $farmWidget = self::loadController('Farms')->getFarmWidget(array('serverId' => $DBServer->serverId), 'addAll'); } catch (Exception $e) { $farmWidget = self::loadController('Farms')->getFarmWidget(array('farmRoleId' => $task->targetId), 'addAll'); } break; default: break; } if ($task->type == Scalr_SchedulerTask::LAUNCH_FARM || $task->type == Scalr_SchedulerTask::TERMINATE_FARM) { $farmWidget['options'][] = 'disabledFarmRole'; } $this->response->data(['farmWidget' => $farmWidget, 'task' => $taskValues, 'scripts' => Script::getList($this->user->getAccountId(), $this->getEnvironmentId())]); }
/** * Creates new event in current scope * * @return \Scalr\Api\DataType\ResultEnvelope * @throws ApiErrorException * @throws \Scalr\Exception\ModelException */ public function createAction() { $this->checkPermissions(Acl::RESOURCE_GENERAL_CUSTOM_EVENTS, Acl::PERM_GENERAL_CUSTOM_EVENTS_MANAGE); $object = $this->request->getJsonBody(); $eventAdapter = $this->adapter('event'); //Pre validates the request object $eventAdapter->validateObject($object, Request::METHOD_POST); if (empty($object->id)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Required field 'id' is missing."); } $object->scope = $this->getScope(); $criteria = [['name' => $object->id]]; switch ($this->getScope()) { case ScopeInterface::SCOPE_ACCOUNT: $criteria[] = ['$or' => [['$and' => [['envId' => null], ['accountId' => null]]], ['accountId' => $this->getUser()->getAccountId()]]]; break; case ScopeInterface::SCOPE_ENVIRONMENT: $criteria[] = ['$and' => [['envId' => $this->getEnvironment()->id], ['accountId' => $this->getUser()->getAccountId()]]]; break; default: throw new ApiErrorException(500, ErrorMessage::ERR_NOT_IMPLEMENTED, sprintf("The Scope '%s' has not been implemented yet", $this->getScope())); } /* @var $oldEvent Entity\EventDefinition */ $oldEvent = Entity\EventDefinition::findOne($criteria); if (!empty($oldEvent)) { if ($this->getScope() == ScopeInterface::SCOPE_ACCOUNT && $this->request->get('replace', false)) { $replacements = Entity\EventDefinition::find([['name' => $object->id], ['accountId' => $this->getUser()->getAccountId()], ['envId' => ['$ne' => null]]]); if ($replacements->count()) { foreach ($replacements as $lowerEvent) { $lowerEvent->delete(); } } else { throw new ApiErrorException(409, ErrorMessage::ERR_UNICITY_VIOLATION, sprintf('Event with id %s already exists', $object->id)); } } else { throw new ApiErrorException(409, ErrorMessage::ERR_UNICITY_VIOLATION, sprintf('Event with id %s already exists', $object->id)); } } /* @var $event Entity\EventDefinition */ //Converts object into EventDefinition entity $event = $eventAdapter->toEntity($object); $event->id = null; $eventAdapter->validateEntity($event); //Saves entity $event->save(); //Responds with 201 Created status $this->response->setStatus(201); return $this->result($eventAdapter->toData($event)); }
/** * @param string $eventName * @param int $farmId * @param int $farmRoleId * @param string $serverId * @throws Exception * @throws Scalr_Exception_InsufficientPermissions */ public function fireAction($eventName = '', $farmId = 0, $farmRoleId = 0, $serverId = '') { $this->request->restrictAccess(Acl::RESOURCE_GENERAL_CUSTOM_EVENTS, Acl::PERM_GENERAL_CUSTOM_EVENTS_FIRE); $data['farmWidget'] = self::loadController('Farms', 'Scalr_UI_Controller')->getFarmWidget(array('farmId' => $farmId == 0 ? '' : (string) $farmId, 'farmRoleId' => (string) $farmRoleId, 'serverId' => $serverId), array('addAll', 'requiredFarm')); $data['eventName'] = $eventName; $data['events'] = array_map(function ($item) { if ($item->envId) { $scope = 'environment'; } else { if ($item->accountId) { $scope = 'account'; } else { $scope = 'scalr'; } } return ['name' => $item->name, 'description' => $item->description, 'scope' => $scope]; }, EventDefinition::find([['$or' => [['accountId' => NULL], ['accountId' => $this->user->getAccountId()]]], ['$or' => [['envId' => NULL], ['envId' => $this->getEnvironmentId()]]]], null, ['name' => 'asc'])->getArrayCopy()); $this->response->page('ui/scripts/events/fire.js', $data); }
/** * @test */ public function testEventsFunctional() { $db = \Scalr::getDb(); $testName = str_replace('-', '', static::getTestName()); $events = null; $uri = self::getAccountApiUrl('/events'); static::createEntity(new EventDefinition(), ['name' => 'testAccount', 'description' => 'testAccount', 'accountId' => $this->getUser()->getAccountId()]); // test describe pagination do { $query = []; if (isset($events->pagination->next)) { $parts = parse_url($events->pagination->next); parse_str($parts['query'], $query); } $describe = $this->request($uri, Request::METHOD_GET, $query); $this->assertDescribeResponseNotEmpty($describe); $this->assertNotEmpty($describe->getBody()); $events = $describe->getBody(); foreach ($events->data as $event) { $this->assertEventObjectNotEmpty($event); if ($event->id == $testName) { $delete = $this->request($uri . '/' . $event->id, Request::METHOD_DELETE); $this->assertEquals(200, $delete->status); } } } while (!empty($events->pagination->next)); // test create action $create = $this->postEvent([]); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Invalid body'); $create = $this->postEvent(['id' => $testName, 'invalid' => 'value']); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'You are trying to set'); $create = $this->postEvent(['scope' => ScopeInterface::SCOPE_ACCOUNT]); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Required field'); $create = $this->postEvent(['id' => 'invalid*^']); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid id of the Event'); $create = $this->postEvent(['id' => $testName, 'description' => '<br>tags']); $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid description'); $create = $this->postEvent(['id' => $testName, 'description' => $testName, 'scope' => ScopeInterface::SCOPE_ACCOUNT]); $body = $create->getBody(); $this->assertEquals(201, $create->response->getStatus()); $this->assertFetchResponseNotEmpty($create); $this->assertEventObjectNotEmpty($body->data); $this->assertNotEmpty($body->data->id); $this->assertEquals($testName, $body->data->id); $this->assertEquals($testName, $body->data->description); $this->assertEquals(ScopeInterface::SCOPE_ACCOUNT, $body->data->scope); $createSame = $this->postEvent(['id' => $testName, 'description' => $testName, 'scope' => ScopeInterface::SCOPE_ACCOUNT]); $this->assertErrorMessageContains($createSame, 409, ErrorMessage::ERR_UNICITY_VIOLATION); //test event with same id already exists in other scope static::createEntity(new EventDefinition(), ['name' => 'testEnvAccount', 'description' => 'testEnvAccount', 'envId' => $this->getEnvironment()->id, 'accountId' => $this->getUser()->getAccountId()]); $scopeConflict = $this->postEvent(['id' => 'testEnvAccount', 'description' => 'testEnvAccount-scope-conflict', 'scope' => ScopeInterface::SCOPE_ACCOUNT]); $this->assertErrorMessageContains($scopeConflict, 409, ErrorMessage::ERR_UNICITY_VIOLATION); //test lower-scope replacement $replace = $this->postEvent(['id' => 'testEnvAccount', 'description' => 'testEnvAccount-scope-replace', 'scope' => ScopeInterface::SCOPE_ACCOUNT], false, ['replace' => true]); $this->assertEquals(201, $replace->response->getStatus()); $dbEvents = EventDefinition::find([['name' => 'testEnvAccount'], ['accountId' => $this->getUser()->getAccountId()]]); $this->assertEquals(1, count($dbEvents)); /* @var $dbEvent EventDefinition */ foreach ($dbEvents as $dbEvent) { $this->assertEquals(null, $dbEvent->envId); } // test filtering $describe = $this->request($uri, Request::METHOD_GET, ['description' => $testName]); $this->assertErrorMessageContains($describe, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Unsupported filter'); $describe = $this->request($uri, Request::METHOD_GET, ['scope' => 'wrong<br>']); $this->assertErrorMessageContains($describe, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid scope value'); $describe = $this->request($uri, Request::METHOD_GET, ['scope' => ScopeInterface::SCOPE_ACCOUNT]); $this->assertDescribeResponseNotEmpty($describe); foreach ($describe->getBody()->data as $data) { $this->assertEventObjectNotEmpty($data); $this->assertEquals(ScopeInterface::SCOPE_ACCOUNT, $data->scope); } $describe = $this->request($uri, Request::METHOD_GET, ['id' => $testName]); $this->assertDescribeResponseNotEmpty($describe); foreach ($describe->getBody()->data as $data) { $this->assertEventObjectNotEmpty($data); $this->assertEquals($testName, $data->id); } // test fetch action $eventId = $body->data->id; $fetch = $this->request($uri . '/' . $eventId . 'invalid', Request::METHOD_GET); $this->assertErrorMessageContains($fetch, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND, 'The Event either does not exist'); $fetch = $this->request($uri . '/' . $eventId, Request::METHOD_GET); $fetchBody = $fetch->getBody(); $this->assertEquals(200, $fetch->response->getStatus()); $this->assertFetchResponseNotEmpty($fetch); $this->assertEventObjectNotEmpty($fetchBody->data); $this->assertEquals($testName, $fetchBody->data->id); $this->assertEquals($testName, $fetchBody->data->description); $this->assertEquals(ScopeInterface::SCOPE_ACCOUNT, $fetchBody->data->scope); // test modify action $modify = $this->request($uri . '/' . $eventId, Request::METHOD_PATCH); $this->assertErrorMessageContains($modify, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Invalid body'); $scalrEventId = $db->GetOne("SELECT e.name FROM event_definitions e WHERE e.env_id IS NULL AND e.account_id IS NULL"); if (!empty($scalrEventId)) { $fetch = $this->request($uri . '/' . $scalrEventId, Request::METHOD_PATCH, [], ['description' => '']); $this->assertErrorMessageContains($fetch, 403, ErrorMessage::ERR_SCOPE_VIOLATION); } $modify = $this->request($uri . '/' . $eventId, Request::METHOD_PATCH, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT]); $this->assertErrorMessageContains($modify, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'You are trying to set the property'); $modify = $this->request($uri . '/' . $eventId, Request::METHOD_PATCH, [], ['description' => '']); $modifyBody = $modify->getBody(); $this->assertEquals(200, $modify->response->getStatus()); $this->assertFetchResponseNotEmpty($modify); $this->assertEventObjectNotEmpty($modifyBody->data); $this->assertEquals($testName, $modifyBody->data->id); $this->assertEquals('', $modifyBody->data->description); $this->assertEquals(ScopeInterface::SCOPE_ACCOUNT, $modifyBody->data->scope); // test delete action if (!empty($scalrEventId)) { $delete = $this->request($uri . '/' . $scalrEventId, Request::METHOD_DELETE); $this->assertErrorMessageContains($delete, 403, ErrorMessage::ERR_SCOPE_VIOLATION); } $delete = $this->request($uri . '/' . $eventId, Request::METHOD_DELETE); $this->assertEquals(200, $delete->status); }