/** * @functional */ public function testUser() { $userId = \Scalr::config('scalr.phpunit.userid'); $envId = \Scalr::config('scalr.phpunit.envid'); if (empty($userId) || empty($envId)) { $this->markTestSkipped("This test requires valid database connection so it's considered to be functional."); } /* @var $user User */ $user = User::findOne([['id' => $userId]]); $this->assertInstanceOf('Scalr\\Model\\Entity\\Account\\User', $user); $email = $user->getSetting(UserSetting::NAME_GRAVATAR_EMAIL); $this->assertNotEmpty($email); $environment = Environment::findPk($envId); $this->assertInstanceOf('Scalr\\Model\\Entity\\Account\\Environment', $environment); $entityIterator = User::result(User::RESULT_ENTITY_ITERATOR)->find(null, null, null, 10); $this->assertInstanceOf('Scalr\\Model\\Collections\\EntityIterator', $entityIterator); $this->assertNotEmpty($entityIterator->count()); $this->assertNotEmpty($entityIterator->getArrayCopy()); foreach ($entityIterator->filterByType(User::TYPE_ACCOUNT_OWNER) as $item) { $this->assertEquals(User::TYPE_ACCOUNT_OWNER, $item->type); } foreach (User::result(User::RESULT_ENTITY_ITERATOR)->findByType(User::TYPE_SCALR_ADMIN) as $item) { $this->assertEquals(User::TYPE_SCALR_ADMIN, $item->type); } $arrayCollection = User::result(User::RESULT_ENTITY_COLLECTION)->find(null, null, null, 10); $this->assertInstanceOf('Scalr\\Model\\Collections\\ArrayCollection', $arrayCollection); $this->assertNotEmpty($arrayCollection->count()); $this->assertNotEmpty($arrayCollection->getArrayCopy()); $rs = User::result(User::RESULT_RAW)->find(null, null, null, 10); $this->assertInstanceOf('ADORecordSet', $rs); foreach ($rs as $item) { $this->assertNotEmpty($item); $this->assertInternalType('array', $item); } }
/** * Check whether the user has access permissions to the specified object. * * It should check only Entity level access permissions, NOT ACL * * @param AbstractEntity $entity Object that defines permissions * @param User $user The User Entity * @param Environment $environment optional The Environment Entity if request is from Environment scope * @param bool $modify optional Whether it should check MODIFY permission. By default it checks READ permission. * * @return bool Returns TRUE if the user has access to the specified object * * @see AccessPermissionsInterface::hasAccessPermissions() */ public function checkInheritedPermissions(AbstractEntity $entity, User $user, Environment $environment = null, $modify = null) { if (!$entity instanceof ScopeInterface) { throw new InvalidArgumentException("Entity must implements ScopeInterface!"); } switch ($entity->getScope()) { case static::SCOPE_ACCOUNT: return $entity->accountId == $user->accountId && (empty($environment) || !$modify); case static::SCOPE_ENVIRONMENT: return $environment ? $entity->envId == $environment->id : $user->hasAccessToEnvironment($entity->envId); case static::SCOPE_SCALR: return !$modify; default: return false; } }
public function _owner($from, $to, $action) { switch ($action) { case static::ACT_CONVERT_TO_OBJECT: /* @var $from Farm */ $to->owner = ['id' => $from->ownerId]; break; case static::ACT_CONVERT_TO_ENTITY: /* @var $to Farm */ $owner = ApiController::getBareId($from, 'owner'); if (!isset($owner)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed owner.id property"); } if (!empty($to->ownerId) && $to->ownerId != $owner) { $this->controller->checkPermissions($to, Acl::PERM_FARMS_CHANGE_OWNERSHIP); $user = User::findOne([['id' => $owner], ['accountId' => $this->controller->getUser()->getAccountId()]]); /* @var $user User */ if (!$user) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Requested User either does not exist or is not owned by current account"); } $to->createdByEmail = $user->getEmail(); FarmSetting::addOwnerHistory($to, $user, $this->controller->getUser()); } $to->ownerId = $owner; break; case static::ACT_GET_FILTER_CRITERIA: $owner = ApiController::getBareId($from, 'owner'); return [['ownerId' => $owner]]; break; } }
/** * Gets the User Entity for the current request * * @return User|null Returns the User entity for the current Request */ public function getUser() { if (empty($this->_user) && $this->user->getId()) { $this->_user = User::findPk($this->user->getId()); } return $this->_user; }
public function xRequestResultAction() { $this->request->defineParams(array('requests' => array('type' => 'json'), 'decision')); if (!in_array($this->getParam('decision'), array(FarmLease::STATUS_APPROVE, FarmLease::STATUS_DECLINE))) { throw new Scalr_Exception_Core('Wrong status'); } foreach ($this->getParam('requests') as $id) { $req = $this->db->GetRow('SELECT * FROM farm_lease_requests WHERE id = ? LIMIT 1', array($id)); if ($req) { $dbFarm = DBFarm::LoadByID($req['farm_id']); $this->user->getPermissions()->validate($dbFarm); $this->db->Execute('UPDATE farm_lease_requests SET status = ?, answer_comment = ?, answer_user_id = ? WHERE id = ?', array($this->getParam('decision'), $this->getParam('comment'), $this->user->getId(), $id)); try { $mailer = Scalr::getContainer()->mailer; if ($dbFarm->ownerId) { $user = Entity\Account\User::findPk($dbFarm->ownerId); if (\Scalr::config('scalr.auth_mode') == 'ldap') { $email = $user->getSetting(Entity\Account\User\UserSetting::NAME_LDAP_EMAIL); if (!$email) { $email = $user->email; } } else { $email = $user->email; } $mailer->addTo($email); } else { $mailer = null; } } catch (Exception $e) { $mailer = null; } if ($this->getParam('decision') == FarmLease::STATUS_APPROVE) { if ($req['request_days'] > 0) { $dt = $dbFarm->GetSetting(Entity\FarmSetting::LEASE_TERMINATE_DATE); $dt = new DateTime($dt); $dt->add(new DateInterval('P' . $req['request_days'] . 'D')); $dbFarm->SetSetting(Entity\FarmSetting::LEASE_TERMINATE_DATE, $dt->format('Y-m-d H:i:s')); $dbFarm->SetSetting(Entity\FarmSetting::LEASE_NOTIFICATION_SEND, null); if ($mailer) { $mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/farm_lease_non_standard_approve.eml', array('{{farm_name}}' => $dbFarm->Name, '{{user_name}}' => $this->user->getEmail(), '{{comment}}' => $this->getParam('comment'), '{{date}}' => $dt->format('M j, Y'), '{{envName}}' => $dbFarm->GetEnvironmentObject()->name, '{{envId}}' => $dbFarm->GetEnvironmentObject()->id)); } } else { $dbFarm->SetSetting(Entity\FarmSetting::LEASE_STATUS, ''); $dbFarm->SetSetting(Entity\FarmSetting::LEASE_TERMINATE_DATE, ''); $dbFarm->SetSetting(Entity\FarmSetting::LEASE_NOTIFICATION_SEND, ''); if ($mailer) { $mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/farm_lease_non_standard_forever.eml', array('{{farm_name}}' => $dbFarm->Name, '{{user_name}}' => $this->user->getEmail(), '{{comment}}' => $this->getParam('comment'), '{{envName}}' => $dbFarm->GetEnvironmentObject()->name, '{{envId}}' => $dbFarm->GetEnvironmentObject()->id)); } } } else { $dt = new DateTime($dbFarm->GetSetting(Entity\FarmSetting::LEASE_TERMINATE_DATE)); SettingEntity::increase(SettingEntity::LEASE_DECLINED_REQUEST); if ($mailer) { $mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/farm_lease_non_standard_decline.eml', array('{{farm_name}}' => $dbFarm->Name, '{{user_name}}' => $this->user->getEmail(), '{{date}}' => $dt->format('M j, Y'), '{{comment}}' => $this->getParam('comment'), '{{envName}}' => $dbFarm->GetEnvironmentObject()->name, '{{envId}}' => $dbFarm->GetEnvironmentObject()->id)); } } } } $this->response->success(); }
/** * Creates and save Account Team entities with data from fixtures * * @param string $name Account Team data name */ protected function prepareAccountTeam($name) { foreach ($this->sets[$name] as &$accTeamData) { $accTeamData['accountId'] = static::$user->getAccountId(); /* @var $accTeam Account\Team() */ $accTeam = ApiTest::createEntity(new Account\Team(), $accTeamData); $accTeamData['id'] = $accTeam->id; } }
/** * {@inheritdoc} * @see \Scalr\LogCollector\AuditLoggerRetrieveConfigurationInterface::getAuditLoggerConfig() */ public function getAuditLoggerConfig() { $config = new AuditLoggerConfiguration(AuditLogger::REQUEST_TYPE_API); $config->user = $this->user; $config->accountId = $this->user ? $this->user->getAccountId() : null; $config->envId = $this->env ? $this->env->id : null; $config->remoteAddr = $this->request->getIp(); return $config; }
/** * LockedException * * @param int $lockedBy Id of User that add a lock to the object * @param mixed $object optional Locked object * @param string $comment optional Lock comment * @param int $code optional The Exception code * @param Exception $previous optional The previous exception used for the exception chaining */ public function __construct($lockedBy, $object = null, $comment = '', $code = 0, Exception $previous = null) { $this->lockedBy = $lockedBy; $this->object = $object; /* @var $user User */ $user = User::findPk($lockedBy); $userName = empty($user) ? $lockedBy : $user->email; if (!empty($comment)) { $comment = " with comment: '{$comment}'"; } if (is_object($object)) { $object = array_pop(preg_split('\\', get_class($object))); } parent::__construct((empty($object) ? "Locked" : "{$object} locked") . " by {$userName}{$comment}", $code, $previous); }
/** * LockedException * * @param int $lockedBy Id of User that add a lock to the object * @param mixed $object optional Locked object * @param string $comment optional Lock comment * @param int $code optional The Exception code * @param Exception $previous optional The previous exception used for the exception chaining */ public function __construct($lockedBy, $object = null, $comment = '', $code = 0, Exception $previous = null) { if (is_array($object)) { throw new InvalidArgumentException("Second argument can not be an array"); } $this->lockedBy = $lockedBy; $this->object = $object; /* @var $user User */ $user = User::findPk($lockedBy); $userName = empty($user) ? $lockedBy : $user->email; if (!empty($comment)) { $comment = " with comment: '{$comment}'"; } if (is_object($object)) { $nameParts = explode('\\', get_class($object)); $object = array_pop($nameParts); } parent::__construct((empty($object) ? "Locked" : "{$object} locked") . " by {$userName}{$comment}", $code, $previous); }
/** * Generate data for ApiTestCaseV2 * * @param string $fixtures patch to fixtures directory * @return array * @throws \Scalr\System\Config\Exception\YamlException */ public static function dataFixtures($fixtures) { // set config static::$testUserId = \Scalr::config('scalr.phpunit.userid'); static::$user = User::findPk(static::$testUserId); static::$testEnvId = \Scalr::config('scalr.phpunit.envid'); static::$env = Environment::findPk(static::$testEnvId); $data = []; foreach (new DirectoryIterator($fixtures) as $fileInfo) { if ($fileInfo->isFile()) { $class = __NAMESPACE__ . '\\' . ucfirst($fileInfo->getBasename('.yaml')); if (class_exists($class)) { /* @var $object TestDataFixtures */ $object = new $class(Yaml::load($fileInfo->getPathname())->toArray()); $object->prepareTestData(); $data = array_merge($data, $object->preparePathInfo()); } } } return $data; }
public function _owner($from, $to, $action) { switch ($action) { case static::ACT_CONVERT_TO_OBJECT: /* @var $from Farm */ $to->owner = ['id' => $from->createdById]; break; case static::ACT_CONVERT_TO_ENTITY: /* @var $to Farm */ $owner = ApiController::getBareId($from, 'owner'); if (!isset($owner)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed owner.id property"); } if (!empty($to->createdById) && $to->createdById != $owner) { $this->controller->checkPermissions($to, Acl::PERM_FARMS_CHANGE_OWNERSHIP); $user = User::findOne([['id' => $owner], ['accountId' => $this->controller->getUser()->getAccountId()]]); /* @var $user User */ if (!$user) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Requested User either does not exist or is not owned by current account"); } $to->createdByEmail = $user->getEmail(); $history = unserialize($to->settings[FarmSetting::OWNER_HISTORY]); if (!is_array($history)) { $history = []; } $history[] = ['newId' => $owner, 'newEmail' => $to->createdByEmail, 'changedById' => $this->controller->getUser()->getId(), 'changedByEmail' => $this->controller->getUser()->getEmail(), 'dt' => date('Y-m-d H:i:s')]; // TODO: move to subclass \Farm\Setting\OwnerHistory $to->settings[FarmSetting::OWNER_HISTORY] = serialize($history); } $to->createdById = $owner; break; case static::ACT_GET_FILTER_CRITERIA: $owner = ApiController::getBareId($from, 'owner'); return [['createdById' => $owner]]; break; } }
/** * {@inheritdoc} * @see ServerImportInterface::import() */ public function import($instanceId, $tags = []) { $instances = PlatformFactory::NewPlatform($this->farmRole->platform)->getOrphanedServers($this->farmRole->getFarm()->getEnvironment(), $this->farmRole->cloudLocation, [$instanceId]); if (count($instances) != 1) { throw new ValidationErrorException("Instance was not found"); } $this->orphaned = $instances[0]; $this->tags = $tags; $this->validate(); $farm = $this->farmRole->getFarm(); $server = $this->server = new Entity\Server(); try { $server->serverId = \Scalr::GenerateUID(false); // DBServer::Create, startWithLetter $server->platform = $this->farmRole->platform; $server->cloudLocation = $this->farmRole->cloudLocation; $server->accountId = $farm->accountId; $server->envId = $farm->envId; $server->farmId = $farm->id; $server->farmRoleId = $this->farmRole->id; $server->imageId = $this->orphaned->imageId; $server->status = Entity\Server::STATUS_RUNNING; $server->type = $this->orphaned->instanceType; $server->remoteIp = $this->orphaned->publicIp; $server->localIp = $this->orphaned->privateIp; $server->added = new DateTime(); $server->initialized = new DateTime(); // initialized is used in billing, so we set current time as start point $server->scalarized = 0; $server->setFreeFarmIndex(); $server->setFreeFarmRoleIndex(); $server->properties[Entity\Server::SZR_KEY] = \Scalr::GenerateRandomKey(40); $server->properties[Entity\Server::SZR_KEY_TYPE] = SZR_KEY_TYPE::ONE_TIME; $server->properties[Entity\Server::SZR_VESION] = ''; $server->properties[Entity\Server::LAUNCHED_BY_ID] = $this->user->id; $server->properties[Entity\Server::LAUNCHED_BY_EMAIL] = $this->user->email; $server->properties[Entity\Server::LAUNCH_REASON_ID] = DBServer::LAUNCH_REASON_IMPORT; $server->properties[Entity\Server::LAUNCH_REASON] = DBServer::getLaunchReason(DBServer::LAUNCH_REASON_IMPORT); $server->properties[Entity\Server::FARM_ROLE_ID] = $this->farmRole->id; $server->properties[Entity\Server::ROLE_ID] = $this->farmRole->roleId; $server->properties[Entity\Server::FARM_CREATED_BY_ID] = $farm->ownerId ?: $farm->settings[Entity\FarmSetting::CREATED_BY_ID]; $server->properties[Entity\Server::FARM_CREATED_BY_EMAIL] = $farm->ownerId ? Entity\Account\User::findPk($farm->ownerId)->email : $farm->settings[Entity\FarmSetting::CREATED_BY_EMAIL]; // projectId, ccId $projectId = $farm->settings[Entity\FarmSetting::PROJECT_ID]; $ccId = null; if (!empty($projectId)) { try { $projectEntity = ProjectEntity::findPk($projectId); if ($projectEntity instanceof ProjectEntity) { /* @var $projectEntity ProjectEntity */ $ccId = $projectEntity->ccId; } else { $projectId = null; } } catch (Exception $e) { $projectId = null; } } $server->properties[Entity\Server::FARM_PROJECT_ID] = $projectId; if (empty($ccId)) { $ccId = Entity\Account\Environment::findPk($farm->envId)->getProperty(Entity\Account\EnvironmentProperty::SETTING_CC_ID); } $server->properties[Entity\Server::ENV_CC_ID] = $ccId; if (!empty($server->getImage())) { $server->getImage()->update(['dtLastUsed' => new DateTime()]); } if (!empty($this->farmRole->getRole())) { $this->farmRole->getRole()->update(['lastUsed' => new DateTime()]); } $this->importServer(); $server->save(); $server->setTimeLog('ts_created'); $server->setTimeLog('ts_launched', time()); $history = $server->getHistory(); $history->markAsLaunched($server->properties[Entity\Server::LAUNCH_REASON], $server->properties[Entity\Server::LAUNCH_REASON_ID]); $history->update(['cloudServerId' => $this->orphaned->cloudServerId, 'scuCollecting' => 1]); $this->applyTags(); return $server; } catch (Exception $e) { if (!empty($server->serverId)) { // cleanup $server->deleteBy([['serverId' => $server->serverId]]); Entity\ServerProperty::deleteBy([['serverId' => $server->serverId]]); Entity\Server\History::deletePk($server->serverId); $this->db->Execute("DELETE FROM `servers_launch_timelog` WHERE server_id = ?", [$server->serverId]); } throw new ServerImportException(sprintf("Server create was failed with error: %s", $e->getMessage()), $e->getCode(), $e); } }
/** * @param int $farmId optional * @param int $roleId optional * @param string $scalrPageHash optional * @param string $scalrPageUiHash optional * @throws Scalr_Exception_InsufficientPermissions */ public function xGetFarmAction($farmId = null, $roleId = null, $scalrPageHash = null, $scalrPageUiHash = null) { if ($scalrPageHash && $scalrPageHash != $this->calcFarmDesignerHash()) { $this->response->data(['scalrPageHashMismatch' => true]); return; } if ($scalrPageUiHash && $scalrPageUiHash != $this->response->pageUiHash()) { $this->response->data(['scalrPageUiHashMismatch' => true]); return; } $moduleParams = array('farmId' => $farmId, 'roleId' => $roleId, 'behaviors' => ROLE_BEHAVIORS::GetName(null, true)); unset($moduleParams['behaviors'][ROLE_BEHAVIORS::CASSANDRA]); unset($moduleParams['behaviors'][ROLE_BEHAVIORS::CUSTOM]); unset($moduleParams['behaviors'][ROLE_BEHAVIORS::HAPROXY]); //platforms list $platforms = self::loadController('Platforms')->getEnabledPlatforms(); if (empty($platforms)) { throw new Exception('Before building new farm you need to configure environment and setup cloud credentials'); } $moduleParams['categories'] = self::loadController('Roles')->listRoleCategories(true, true); $moduleParams['farmVpcEc2Enabled'] = $this->getEnvironment()->isPlatformEnabled(SERVER_PLATFORMS::EC2); if ($moduleParams['farmVpcEc2Enabled']) { $moduleParams['farmVpcEc2Locations'] = self::loadController('Platforms')->getCloudLocations(SERVER_PLATFORMS::EC2, false); } if ($farmId) { $this->request->checkPermissions(DBFarm::LoadByID($farmId)->__getNewFarmObject(), Acl::PERM_FARMS_UPDATE); $c = self::loadController('Builder', 'Scalr_UI_Controller_Farms'); $moduleParams['farm'] = $c->getFarm2($farmId); } else { $this->request->restrictAccess(Acl::RESOURCE_OWN_FARMS, Acl::PERM_FARMS_CREATE); // TODO: remove hack, do better $vars = new Scalr_Scripting_GlobalVariables($this->user->getAccountId(), $this->getEnvironmentId(), ScopeInterface::SCOPE_FARM); $moduleParams['farmVariables'] = $vars->getValues(); } $moduleParams['tabs'] = array('vpcrouter', 'dbmsr', 'mongodb', 'mysql', 'scaling', 'network', 'cloudfoundry', 'rabbitmq', 'haproxy', 'proxy', 'scripting', 'ec2', 'openstack', 'gce', 'azure', 'security', 'devel', 'storage', 'variables', 'advanced', 'chef'); //deprecated tabs if (\Scalr::config('scalr.ui.show_deprecated_features')) { $moduleParams['tabs'][] = 'ebs'; } $conf = $this->getContainer()->config->get('scalr.load_statistics.connections.plotter'); $moduleParams['tabParams'] = array('farmId' => $farmId, 'farmHash' => $moduleParams['farm'] ? $moduleParams['farm']['farm']['hash'] : '', 'accountId' => $this->environment->keychain(SERVER_PLATFORMS::EC2)->properties[Entity\CloudCredentialsProperty::AWS_ACCOUNT_ID], 'remoteAddress' => $this->request->getRemoteAddr(), 'monitoringHostUrl' => "{$conf['scheme']}://{$conf['host']}:{$conf['port']}", 'nginx' => array('server_section' => file_get_contents(APPPATH . '/templates/services/nginx/server_section.tpl'), 'server_section_ssl' => file_get_contents(APPPATH . '/templates/services/nginx/server_section_ssl.tpl'))); $moduleParams['tabParams']['scalr.instances_connection_policy'] = \Scalr::config('scalr.instances_connection_policy'); $moduleParams['tabParams']['scalr.scalarizr_update.default_repo'] = \Scalr::config('scalr.scalarizr_update.default_repo'); if (Scalr::isHostedScalr()) { $moduleParams['tabParams']['scalr.scalarizr_update.repos'] = ['latest' => Utils::getScalarizrUpdateRepoTitle('latest')]; if ($this->user->getAccount()->priority == 100) { $moduleParams['tabParams']['scalr.scalarizr_update.repos']['stable'] = Utils::getScalarizrUpdateRepoTitle('stable'); } } else { $repos = array_keys(\Scalr::config('scalr.scalarizr_update.repos')); $moduleParams['tabParams']['scalr.scalarizr_update.repos'] = array_combine($repos, $repos); } $moduleParams['tabParams']['scalr.scalarizr_update.devel_repos'] = is_array(\Scalr::config('scalr.scalarizr_update.devel_repos')) ? array_keys(\Scalr::config('scalr.scalarizr_update.devel_repos')) : []; $moduleParams['tabParams']['scalr.aws.ec2.limits.security_groups_per_instance'] = \Scalr::config('scalr.aws.ec2.limits.security_groups_per_instance'); $moduleParams['metrics'] = Entity\ScalingMetric::getList($this->getEnvironmentId()); $moduleParams['timezones_list'] = Scalr_Util_DateTime::getTimezones(); $moduleParams['timezone_default'] = $this->user->getSetting(Scalr_Account_User::SETTING_UI_TIMEZONE); if ($moduleParams['farm']['farm']['ownerEditable']) { $moduleParams['usersList'] = []; foreach (Entity\Account\User::findByAccountId($this->user->getAccountId()) as $user) { $moduleParams['usersList'][] = ['id' => $user->id, 'email' => $user->email]; } } $defaultFarmRoleSecurityGroups = array('default'); if (\Scalr::config('scalr.aws.security_group_name')) { $defaultFarmRoleSecurityGroups[] = \Scalr::config('scalr.aws.security_group_name'); } $moduleParams['roleDefaultSettings'] = array('base.keep_scripting_logs_time' => \Scalr::config('scalr.system.scripting.default_instance_log_rotation_period'), 'security_groups.list' => json_encode($defaultFarmRoleSecurityGroups), 'base.abort_init_on_script_fail' => \Scalr::config('scalr.system.scripting.default_abort_init_on_script_fail') ? 1 : 0, 'base.disable_firewall_management' => \Scalr::config('scalr.system.default_disable_firewall_management') ? 1 : 0); //cost analytics if ($this->getContainer()->analytics->enabled && $this->getEnvironment()->getPlatformConfigValue(Scalr_Environment::SETTING_CC_ID)) { $farmCostData = $this->getFarmCostData($farmId); $moduleParams['analytics'] = $farmCostData['analytics']; if ($farmId) { $moduleParams['farm']['farm']['projectId'] = $farmCostData['projectId']; $moduleParams['analytics']['farmCostMetering'] = $farmCostData['farmCostMetering']; } } $moduleParams['farmLaunchPermission'] = $farmId ? $moduleParams['farm']['farm']['launchPermission'] : $this->request->isAllowed([Acl::RESOURCE_FARMS, Acl::RESOURCE_TEAM_FARMS, Acl::RESOURCE_OWN_FARMS], Acl::PERM_FARMS_LAUNCH_TERMINATE); $this->response->data($moduleParams); }
/** * {@inheritdoc} * @see \Scalr\System\Zmq\Cron\TaskInterface::worker() */ public function worker($request) { //Warming up static DI cache \Scalr::getContainer()->warmup(); // Reconfigure observers \Scalr::ReconfigureObservers(); try { $dbFarm = DBFarm::LoadByID($request->farmId); $curDate = new DateTime(); $tdValue = $dbFarm->GetSetting(Entity\FarmSetting::LEASE_TERMINATE_DATE); if ($tdValue) { $td = new DateTime($tdValue); if ($td < $curDate) { //Terminates farm SettingEntity::increase(SettingEntity::LEASE_TERMINATE_FARM); //Ajdusts both account & environment for the audit log \Scalr::getContainer()->auditlogger->setAccountId($dbFarm->ClientID)->setAccountId($dbFarm->EnvID); \Scalr::FireEvent($request->farmId, new FarmTerminatedEvent(0, 1, false, 1, true, null)); $this->log('INFO', sprintf('Farm: %s [ID: %d] was terminated by lease manager', $dbFarm->Name, $dbFarm->ID)); } else { // only inform user $days = $td->diff($curDate)->days; $notifications = json_decode($dbFarm->GetSetting(Entity\FarmSetting::LEASE_NOTIFICATION_SEND), true); $governance = new Scalr_Governance($dbFarm->EnvID); $settings = $governance->getValue(Scalr_Governance::CATEGORY_GENERAL, Scalr_Governance::GENERAL_LEASE, 'notifications'); if (is_array($settings)) { foreach ($settings as $n) { if (!$notifications[$n['key']] && $n['period'] >= $days) { $mailer = \Scalr::getContainer()->mailer; $tdHuman = Scalr_Util_DateTime::convertDateTime($td, $dbFarm->GetSetting(Entity\FarmSetting::TIMEZONE), 'M j, Y'); /* @var $user Entity\Account\User */ if ($n['to'] == 'owner') { if ($dbFarm->ownerId) { $user = Entity\Account\User::findPk($dbFarm->ownerId); } else { $user = Entity\Account\User::findOne([['accountId' => $dbFarm->ClientID], ['type' => Entity\Account\User::TYPE_ACCOUNT_OWNER]]); } if (\Scalr::config('scalr.auth_mode') == 'ldap') { $email = $user->getSetting(Entity\Account\User\UserSetting::NAME_LDAP_EMAIL); if (!$email) { $email = $user->email; } } else { $email = $user->email; } $mailer->addTo($email); } else { foreach (explode(',', $n['emails']) as $email) { $mailer->addTo(trim($email)); } } $mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/farm_lease_terminate.eml.php', array('terminateDate' => $tdHuman, 'farm' => $dbFarm->Name, 'envName' => $dbFarm->GetEnvironmentObject()->name, 'envId' => $dbFarm->GetEnvironmentObject()->id, 'showOwnerWarning' => !$dbFarm->ownerId)); $notifications[$n['key']] = 1; $dbFarm->SetSetting(Entity\FarmSetting::LEASE_NOTIFICATION_SEND, json_encode($notifications)); $this->log('INFO', "Notification was sent by key: %s about farm: %s [ID: %d] by lease manager", $n['key'], $dbFarm->Name, $dbFarm->ID); } } } } } } catch (Exception $e) { throw $e; } return $request; }
/** * List farm roles and hosts list for each role * * Allowed args: role=(String Role Name) | behaviour=(app|www|mysql|base|memcached) * * @return DOMDocument */ protected function ListRoles() { $ResponseDOMDocument = $this->CreateResponse(); $RolesDOMNode = $ResponseDOMDocument->createElement('roles'); $ResponseDOMDocument->documentElement->appendChild($RolesDOMNode); $sql_query = "SELECT id FROM farm_roles WHERE farmid=?"; $sql_query_args = array($this->DBServer->farmId); // Filter by behaviour if ($this->GetArg("behaviour")) { $sql_query .= " AND role_id IN (SELECT role_id FROM role_behaviors WHERE behavior=?)"; array_push($sql_query_args, $this->GetArg("behaviour")); } // Filter by role if ($this->GetArg("role")) { $sql_query .= " AND role_id IN (SELECT id FROM roles WHERE name=?)"; array_push($sql_query_args, $this->GetArg("role")); } if ($this->GetArg("role-id")) { $sql_query .= " AND role_id = ?"; array_push($sql_query_args, $this->GetArg("role-id")); } if ($this->GetArg("farm-role-id")) { $sql_query .= " AND id = ?"; array_push($sql_query_args, $this->GetArg("farm-role-id")); } $farm_roles = $this->DB->GetAll($sql_query, $sql_query_args); foreach ($farm_roles as $farm_role) { $DBFarmRole = DBFarmRole::LoadByID($farm_role['id']); // Create role node $RoleDOMNode = $ResponseDOMDocument->createElement('role'); $RoleDOMNode->setAttribute('behaviour', implode(",", $DBFarmRole->GetRoleObject()->getBehaviors())); $RoleDOMNode->setAttribute('name', DBRole::loadById($DBFarmRole->RoleID)->name); $RoleDOMNode->setAttribute('alias', $DBFarmRole->Alias); $RoleDOMNode->setAttribute('id', $DBFarmRole->ID); $RoleDOMNode->setAttribute('role-id', $DBFarmRole->RoleID); $RoleDOMNode->setAttribute('scaling-min-instances', $DBFarmRole->GetSetting(Entity\FarmRoleSetting::SCALING_MIN_INSTANCES)); $RoleDOMNode->setAttribute('scaling-max-instances', $DBFarmRole->GetSetting(Entity\FarmRoleSetting::SCALING_MAX_INSTANCES)); $HostsDomNode = $ResponseDOMDocument->createElement('hosts'); $RoleDOMNode->appendChild($HostsDomNode); // List instances (hosts) $serversSql = "SELECT server_id FROM servers WHERE farm_roleid=?"; $serversArgs = array($farm_role['id'], SERVER_STATUS::RUNNING); if ($this->GetArg("showInitServers")) { $serversSql .= " AND status IN (?,?)"; $serversArgs[] = SERVER_STATUS::INIT; } else { $serversSql .= " AND status=?"; } $servers = $this->DB->GetAll($serversSql, $serversArgs); // Add hosts to response if (count($servers) > 0) { foreach ($servers as $server) { $DBServer = DBServer::LoadByID($server['server_id']); $serverProperties = $DBServer->GetAllProperties(); $HostDOMNode = $ResponseDOMDocument->createElement("host"); $HostDOMNode->setAttribute('scalr-server-id', $DBServer->serverId); $HostDOMNode->setAttribute('cloud-server-id', $DBServer->GetCloudServerID()); $HostDOMNode->setAttribute('internal-ip', $DBServer->localIp); $HostDOMNode->setAttribute('external-ip', $DBServer->remoteIp); $HostDOMNode->setAttribute('index', $DBServer->index); $HostDOMNode->setAttribute('status', $DBServer->status); $HostDOMNode->setAttribute('cloud-location', $DBServer->GetCloudLocation()); $HostDOMNode->setAttribute('cloud-location-zone', $DBServer->cloudLocationZone); $HostDOMNode->setAttribute('hostname', $serverProperties[Scalr_Role_Behavior::SERVER_BASE_HOSTNAME]); if (array_key_exists(SERVER_PROPERTIES::LAUNCHED_BY_EMAIL, $serverProperties)) { $launchedByEmail = $serverProperties[SERVER_PROPERTIES::LAUNCHED_BY_EMAIL]; } else { $launchedByEmail = Entity\Account\User::findPk($DBServer->GetFarmObject()->ownerId)->email; } $HostDOMNode->setAttribute('launched-by', $launchedByEmail); if (array_key_exists(SERVER_PROPERTIES::LAUNCH_REASON_ID, $serverProperties)) { $HostDOMNode->setAttribute('launch-reason-id', $serverProperties[SERVER_PROPERTIES::LAUNCH_REASON_ID]); } if ($DBFarmRole->GetRoleObject()->hasBehavior(ROLE_BEHAVIORS::MONGODB)) { $HostDOMNode->setAttribute('replica-set-index', (int) $serverProperties[Scalr_Role_Behavior_MongoDB::SERVER_REPLICA_SET_INDEX]); $HostDOMNode->setAttribute('shard-index', (int) $serverProperties[Scalr_Role_Behavior_MongoDB::SERVER_SHARD_INDEX]); } if ($DBFarmRole->GetRoleObject()->hasBehavior(ROLE_BEHAVIORS::MYSQL)) { if (array_key_exists(SERVER_PROPERTIES::DB_MYSQL_MASTER, $serverProperties)) { $isMySqlMaster = (int) $serverProperties[SERVER_PROPERTIES::DB_MYSQL_MASTER]; } else { $isMySqlMaster = 0; } $HostDOMNode->setAttribute('replication-master', $isMySqlMaster); } if ($DBFarmRole->GetRoleObject()->getDbMsrBehavior()) { if (array_key_exists(Scalr_Db_Msr::REPLICATION_MASTER, $serverProperties)) { $isMaster = (int) $serverProperties[Scalr_Db_Msr::REPLICATION_MASTER]; } else { $isMaster = 0; } $HostDOMNode->setAttribute('replication-master', $isMaster); } $HostsDomNode->appendChild($HostDOMNode); } } // Add role node to roles node $RolesDOMNode->appendChild($RoleDOMNode); } return $ResponseDOMDocument; }
/** * Marks server as to be terminated. * * @param int|array $reason The reason possibly with the format parameters. * @param bool $forcefully optional Method: forcefully (true) | gracefully (false) * @param User $user optional The user entity * @return bool */ public function terminate($reason, $forcefully = null, $user = null) { if (in_array($this->status, [Server::STATUS_PENDING_TERMINATE, Server::STATUS_TERMINATED])) { return false; } $forcefully = $forcefully === null ? true : (bool) $forcefully; $fnGetReason = function ($reasonId) { $args = func_get_args(); $args[0] = Server::getTerminateReason($reasonId); return [call_user_func_array('sprintf', $args), $reasonId]; }; list($reason, $reasonId) = is_array($reason) ? call_user_func_array($fnGetReason, $reason) : $fnGetReason($reason); $properties = $this->properties; if ($user instanceof User) { $properties[self::TERMINATED_BY_ID] = $user->getId(); $properties[self::TERMINATED_BY_EMAIL] = $user->getEmail(); } $properties[self::REBOOTING] = 0; $properties->save(); $this->update(['status' => Server::STATUS_PENDING_TERMINATE, 'shutdownScheduled' => new DateTime($forcefully ? 'now' : Scalr::config('scalr.system.server_terminate_timeout'))]); $this->getHistory()->markAsTerminated($reason, $reasonId); if (isset($this->farmId)) { $DBServer = $this->__getDBServer(); Scalr::FireEvent($this->farmId, new BeforeHostTerminateEvent($DBServer, false)); // If instance was terminated outside scalr, we need manually fire HostDown if ($reasonId == self::TERMINATE_REASON_CRASHED) { Scalr::FireEvent($this->farmId, new HostDownEvent($DBServer, false)); } } return true; }
/** * Check whether the user has either READ or WRITE access to the specified object * * * @param object $object * The object to check * * @param Entity\Account\User|int $user * Either the User Entity or its identifier * * @param Entity\Account\Environment|int $enviroment optional * Either the Environment Entity or its identifier * * @param bool $modify optional * Whether it should check MODIFY permission. By default it checks READ permission. * * @return bool Returns TRUE if the user has access to the specified object * @throws \InvalidArgumentException * @throws NotYetImplementedException */ public function hasAccessTo($object, $user, $enviroment = null, $modify = null) { $modify = $modify ?: false; if (is_int($user)) { $user = Entity\Account\User::findPk($user); } if ($enviroment !== null && is_int($enviroment)) { $enviroment = Entity\Account\Environment::findPk($enviroment); if (!$enviroment) { throw new \InvalidArgumentException(sprintf("Could not find the Environment by id: %d", func_get_arg(2))); } } if (!$user instanceof Entity\Account\User) { throw new \InvalidArgumentException(sprintf('Second argument should be instance of \\Scalr\\Model\\Entity\\Account\\User class.')); } if ($enviroment !== null && !$enviroment instanceof Entity\Account\Environment) { throw new \InvalidArgumentException(sprintf('Third argument should be instance of \\Scalr\\Model\\Entity\\Account\\Environment class.')); } if (!is_object($object)) { throw new \InvalidArgumentException(sprintf("The first argument must be an object.")); } if ($object instanceof AccessPermissionsInterface) { return $object->hasAccessPermissions($user, $enviroment, $modify); } throw new NotYetImplementedException(sprintf("%s nothing knows about %s class", __METHOD__, get_class($object))); }
/** * Checks whether the user is allowed to edit specified user * * @param User $user The user to edit * @return boolean Returns true if the user is allowed to edit specified user */ public function canEditUser(User $user) { return !$this->isTeamUser() && $user->accountId == $this->accountId && ($this->id == $user->id || $this->isAccountOwner() || $this->isAccountSuperAdmin() && !$user->isAccountOwner() || $this->isAccountAdmin() && !$user->isAccountOwner() && !$user->isAccountSuperAdmin()); }
/** * Add test environment, test Acl, setups test user, environment and API key */ public static function setUpBeforeClass() { if (!Scalr::getContainer()->config->defined('scalr.phpunit.apiv2')) { static::markTestIncomplete('phpunit apiv2 configurations is invalid'); } if (Scalr::getContainer()->config->defined('scalr.phpunit.apiv2.params.max_results')) { static::$maxResults = Scalr::config('scalr.phpunit.apiv2.params.max_results'); } static::$testUserId = Scalr::config('scalr.phpunit.apiv2.userid'); static::$user = User::findPk(static::$testUserId); static::$testUserType = static::$user->type; static::$testEnvId = Scalr::config('scalr.phpunit.apiv2.envid'); static::$env = Environment::findPk(static::$testEnvId); if (empty(static::$user) || empty(static::$env)) { static::markTestIncomplete('Either test environment or user is invalid.'); } $apiKeyName = static::getTestName(); $apiKeyEntity = ApiKeyEntity::findOne([['name' => $apiKeyName], ['userId' => static::$testUserId]]); if (empty($apiKeyEntity)) { $apiKeyEntity = new ApiKeyEntity(static::$testUserId); $apiKeyEntity->name = $apiKeyName; $apiKeyEntity->save(); } static::$apiKeyEntity = $apiKeyEntity; static::$defaultAcl = Scalr::getContainer()->acl; static::$data = [static::$testEnvId => []]; if (empty(static::$fullAccessAcl)) { static::$fullAccessAcl = new ApiTestAcl(); static::$fullAccessAcl->setDb(Scalr::getContainer()->adodb); static::$fullAccessAcl->createTestAccountRole(static::$user->getAccountId(), static::getTestName(ApiFixture::ACL_FULL_ACCESS), ApiTestAcl::ROLE_ID_FULL_ACCESS); static::$fullAccessAcl->aclType = ApiFixture::ACL_FULL_ACCESS; } if (empty(static::$readOnlyAccessAcl)) { static::$readOnlyAccessAcl = new ApiTestAcl(); static::$readOnlyAccessAcl->setDb(Scalr::getContainer()->adodb); static::$readOnlyAccessAcl->createTestAccountRole(static::$user->getAccountId(), static::getTestName(ApiFixture::ACL_READ_ONLY_ACCESS), ApiTestAcl::ROLE_ID_READ_ONLY_ACCESS); static::$readOnlyAccessAcl->aclType = ApiFixture::ACL_READ_ONLY_ACCESS; } }
/** * Setups test user, environment and API key * * @throws \Scalr\Exception\ModelException */ public static function setUpBeforeClass() { static::$testUserId = \Scalr::config('scalr.phpunit.userid'); static::$user = User::findPk(static::$testUserId); static::$testEnvId = \Scalr::config('scalr.phpunit.envid'); static::$env = Environment::findPk(static::$testEnvId); if (empty(static::$user) || empty(static::$env)) { static::markTestIncomplete('Either test environment or user is invalid.'); } $apiKeyName = static::getTestName(); $apiKeyEntity = ApiKeyEntity::findOne([['name' => $apiKeyName], ['userId' => static::$testUserId]]); if (empty($apiKeyEntity)) { $apiKeyEntity = new ApiKeyEntity(static::$testUserId); $apiKeyEntity->name = $apiKeyName; $apiKeyEntity->save(); } static::$apiKeyEntity = $apiKeyEntity; static::changeLoggerConfiguration(); }
/** * Transform entity of type MESSAGE for client-side (view, edit) * * @param Announcement $announcement * @return array Contains keys `id`, `accountId`, `added`, `title`, `msg`, `user`. */ private function prepareDataForList(Announcement $announcement) { $obj = ['id' => $announcement->id, 'accountId' => $announcement->accountId, 'added' => Scalr_Util_DateTime::convertTz($announcement->added, 'M d, Y G:i'), 'title' => $announcement->title, 'msg' => $announcement->msg]; /* @var $user Scalr\Model\Entity\Account\User */ $user = User::findPk($announcement->createdById); if ($user) { $obj['user'] = ['name' => $user->fullName, 'email' => $user->email]; } else { $obj['user'] = ['name' => '#' . $announcement->createdById, 'email' => $announcement->createdByEmail]; } return $obj; }
public function FarmAddRole($Alias, $FarmID, $RoleID, $Platform, $CloudLocation, array $Configuration = array()) { try { $dbFarm = DBFarm::LoadByID($FarmID); if ($dbFarm->EnvID != $this->Environment->id) { throw new Exception("N"); } } catch (Exception $e) { throw new Exception(sprintf("Farm #%s not found", $FarmID)); } $this->user->getPermissions()->validate($dbFarm); $this->restrictFarmAccess($dbFarm, Acl::PERM_FARMS_UPDATE); $dbFarm->isLocked(true); $governance = new Scalr_Governance($this->Environment->id); $dbRole = DBRole::loadById($RoleID); if (!$dbRole->__getNewRoleObject()->hasAccessPermissions(User::findPk($this->user->getId()), Environment::findPk($this->Environment->id))) { throw new Exception(sprintf("Role #%s not found", $RoleID)); } if (!empty($envs = $dbRole->__getNewRoleObject()->getAllowedEnvironments())) { if (!in_array($this->Environment->id, $envs)) { throw new Exception(sprintf("Role #%s not found", $RoleID)); } } foreach ($dbRole->getBehaviors() as $behavior) { if ($behavior != ROLE_BEHAVIORS::BASE && $behavior != ROLE_BEHAVIORS::CHEF) { throw new Exception("Only base roles supported to be added to farm via API"); } } $config = array('scaling.enabled' => 0, 'scaling.min_instances' => 1, 'scaling.max_instances' => 1, 'scaling.polling_interval' => 2, 'system.timeouts.launch' => 9600, 'system.timeouts.reboot' => 9600); if (PlatformFactory::isOpenstack($Platform)) { //TODO: } if ($Platform == SERVER_PLATFORMS::EC2) { $config['aws.security_groups.list'] = json_encode(array('default', \Scalr::config('scalr.aws.security_group_name'))); $vpcId = $dbFarm->GetSetting(Entity\FarmSetting::EC2_VPC_ID); if ($vpcId) { if (!$Configuration['aws.vpc_subnet_id']) { throw new Exception("Farm configured to run inside VPC. 'aws.vpc_subnet_id' is required"); } $vpcRegion = $dbFarm->GetSetting(Entity\FarmSetting::EC2_VPC_REGION); if ($CloudLocation != $vpcRegion) { throw new Exception(sprintf("Farm configured to run inside VPC in %s region. Only roles in this region are allowed.", $vpcRegion)); } $vpcGovernance = $governance->getValue('ec2', 'aws.vpc'); $vpcGovernanceIds = $governance->getValue('ec2', 'aws.vpc', 'ids'); $subnets = json_decode($Configuration['aws.vpc_subnet_id'], true); if (count($subnets) == 0) { throw new Exception("Subnets list is empty or json is incorrect"); } $type = false; foreach ($subnets as $subnetId) { $platform = PlatformFactory::NewPlatform(SERVER_PLATFORMS::EC2); $info = $platform->listSubnets($this->Environment, $CloudLocation, $vpcId, true, $subnetId); if (substr($info['availability_zone'], 0, -1) != $vpcRegion) { throw new Exception(sprintf("Only subnets from %s region are allowed according to VPC settings", $vpcRegion)); } if ($vpcGovernance == 1) { // Check valid subnets if ($vpcGovernanceIds[$vpcId] && is_array($vpcGovernanceIds[$vpcId]) && !in_array($subnetId, $vpcGovernanceIds[$vpcId])) { throw new Exception(sprintf("Only %s subnet(s) allowed by governance settings", implode(', ', $vpcGovernanceIds[$vpcId]))); } // Check if subnets types if ($vpcGovernanceIds[$vpcId] == "outbound-only") { if ($info['type'] != 'private') { throw new Exception("Only private subnets allowed by governance settings"); } } if ($vpcGovernanceIds[$vpcId] == "full") { if ($info['type'] != 'public') { throw new Exception("Only public subnets allowed by governance settings"); } } } if (!$type) { $type = $info['type']; } else { if ($type != $info['type']) { throw new Exception("Mix of public and private subnets are not allowed. Please specify only public or only private subnets."); } } } } } if (PlatformFactory::isCloudstack($Platform)) { $config['cloudstack.security_groups.list'] = json_encode(array('default', \Scalr::config('scalr.aws.security_group_name'))); } if ($Platform == SERVER_PLATFORMS::GCE) { $config['gce.network'] = 'default'; $config['gce.on-host-maintenance'] = 'MIGRATE'; } if ($Configuration[Scalr_Role_Behavior_Chef::ROLE_CHEF_BOOTSTRAP] == 1 && !$Configuration[Scalr_Role_Behavior_Chef::ROLE_CHEF_ENVIRONMENT]) { $config[Scalr_Role_Behavior_Chef::ROLE_CHEF_ENVIRONMENT] = '_default'; } $config = array_merge($config, $Configuration); $this->validateFarmRoleConfiguration($config); if ($Platform == SERVER_PLATFORMS::GCE) { $config['gce.cloud-location'] = $CloudLocation; $config['gce.region'] = substr($CloudLocation, 0, -1); } $Alias = $this->stripValue($Alias); if (strlen($Alias) < 4) { throw new Exception("Role Alias should be longer than 4 characters"); } if (!preg_match("/^[A-Za-z0-9]+[A-Za-z0-9-]*[A-Za-z0-9]+\$/si", $Alias)) { throw new Exception("Alias should start and end with letter or number and contain only letters, numbers and dashes."); } if (!$this->Environment->isPlatformEnabled($Platform)) { throw new Exception("'{$Platform}' cloud is not configured in your environment"); } $images = $dbRole->__getNewRoleObject()->fetchImagesArray(); $locations = isset($images[$Platform]) ? array_keys($images[$Platform]) : []; if (!in_array($CloudLocation, $locations) && $Platform != SERVER_PLATFORMS::GCE) { throw new Exception(sprintf("Role '%s' doesn't have an image configured for cloud location '%s'", $dbRole->name, $CloudLocation)); } if ($Alias) { foreach ($dbFarm->GetFarmRoles() as $farmRole) { if ($farmRole->Alias == $Alias) { throw new Exception("Selected alias is already used by another role in selected farm"); } } } $dbFarmRole = $dbFarm->AddRole($dbRole, $Platform, $CloudLocation, 1); $dbFarmRole->Alias = $Alias ? $Alias : $dbRole->name; foreach ($config as $k => $v) { $dbFarmRole->SetSetting($k, trim($v), Entity\FarmRoleSetting::TYPE_CFG); } foreach (Scalr_Role_Behavior::getListForFarmRole($dbFarmRole) as $behavior) { $behavior->onFarmSave($dbFarm, $dbFarmRole); } $dbFarmRole->Save(); $response = $this->CreateInitialResponse(); $response->FarmRoleID = $dbFarmRole->ID; return $response; }
/** * Authentication middleware */ public function authenticationMiddleware() { $bDebug = $this->request->headers('x-scalr-debug', 0) == 1; //If API is not enabled if (!$this->getContainer()->config('scalr.system.api.enabled')) { $this->halt(403, 'API is not enabled. See scalr.system.api.enabled'); } //Authentication $keyId = $this->request->headers('x-scalr-key-id'); $signature = $this->request->headers('x-scalr-signature'); //ISO-8601 formatted date $date = trim(preg_replace('/\\s+/', '', $this->request->headers('x-scalr-date'))); if (empty($keyId) || empty($signature)) { throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'Unsigned request'); } elseif (empty($date) || ($time = strtotime($date)) === false) { throw new ApiErrorException(400, ErrorMessage::ERR_BAD_REQUEST, 'Missing or invalid X-Scalr-Date header'); } $sigparts = explode(' ', $signature, 2); if (empty($sigparts) || !in_array($sigparts[0], ['V1-HMAC-SHA256'])) { throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'Invalid signature'); } $this->apiKey = ApiKeyEntity::findPk($keyId); if (!$this->apiKey instanceof ApiKeyEntity || !$this->apiKey->active) { throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'Invalid API Key'); } if (abs(time() - $time) > 300) { throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'Request is expired.' . ($bDebug ? ' Now is ' . gmdate('Y-m-d\\TH:i:s\\Z') : '')); } $now = new \DateTime('now'); if (empty($this->apiKey->lastUsed) || $now->getTimestamp() - $this->apiKey->lastUsed->getTimestamp() > 10) { $this->apiKey->lastUsed = $now; $this->apiKey->save(); } $qstr = $this->request->get(); $canonicalStr = ''; if (!empty($qstr)) { ksort($qstr); $canonicalStr = http_build_query($qstr, null, '&', PHP_QUERY_RFC3986); } $reqBody = $this->request->getBody(); $stringToSign = $this->request->getMethod() . "\n" . $date . "\n" . $this->request->getPath() . "\n" . $canonicalStr . "\n" . (empty($reqBody) ? '' : $reqBody); if ($bDebug) { $this->meta->stringToSign = $stringToSign; } switch ($sigparts[0]) { default: throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'Invalid signature method. Please use "V1-HMAC-SHA256 [SIGNATURE]"'); break; case 'V1-HMAC-SHA256': $algo = strtolower(substr($sigparts[0], 8)); } $sig = base64_encode(hash_hmac($algo, $stringToSign, $this->apiKey->secretKey, 1)); if ($sig !== $sigparts[1]) { throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'Signature does not match'); } $user = Entity\Account\User::findPk($this->apiKey->userId); /* @var $user Entity\Account\User */ if (!$user instanceof Entity\Account\User) { throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'User does not exist'); } if ($user->status != Entity\Account\User::STATUS_ACTIVE) { throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, 'Inactive user status'); } if (\Scalr::config('scalr.auth_mode') == 'ldap') { try { $ldap = \Scalr::getContainer()->ldap($user->getLdapUsername(), null); if (!$ldap->isValidUsername()) { if ($bDebug && $ldap->getConfig()->debug) { $this->meta->ldapDebug = $ldap->getLog(); } throw new ApiErrorException(401, ErrorMessage::ERR_BAD_AUTHENTICATION, 'User does not exist'); } $user->applyLdapGroups($ldap->getUserGroups()); } catch (LdapException $e) { if ($bDebug && $ldap instanceof LdapClient && $ldap->getConfig()->debug) { $this->meta->ldapDebug = $ldap->getLog(); } throw new \RuntimeException($e->getMessage()); } } $this->limiter->checkAccountRateLimit($this->apiKey->keyId); //Validates API version if ($this->settings[ApiApplication::SETTING_API_VERSION] != 1) { throw new ApiErrorException(400, ErrorMessage::ERR_BAD_REQUEST, 'Invalid API version'); } if ($this->request->getBody() !== '' && strtolower($this->request->getMediaType()) !== 'application/json') { throw new ApiErrorException(400, ErrorMessage::ERR_BAD_REQUEST, 'Invalid Content-Type'); } $this->setUser($user); $container = $this->getContainer(); //Releases auditloger to ensure it will be updated $container->release('auditlogger'); //Adjusts metadata to invoke audit loger $container->setShared('auditlogger.metadata', function ($cont) use($user) { return (object) ['user' => $user, 'envId' => null, 'remoteAddr' => $this->request->getIp(), 'ruid' => null, 'requestType' => AuditLogger::REQUEST_TYPE_API, 'systemTask' => null]; }); }
/** * @param User $user The User Entity * @param Environment $environment optional The Environment Entity * @param string|bool $modify optional ACL Permission Identifier or boolean flag whether it should check modify * permissions or not. * @return bool */ public function hasAccessPermissions($user, $environment = null, $modify = null) { $access = $environment && $this->envId == $environment->id; if (is_bool($modify)) { $modify = $modify ? Acl::PERM_FARMS_UPDATE : null; } if ($access) { $superposition = $user->getAclRolesByEnvironment($environment->id); $access = $superposition->isAllowed(Acl::RESOURCE_FARMS, $modify); if (!$access && $this->hasUserTeamOwnership($user)) { $access = $superposition->isAllowed(Acl::RESOURCE_TEAM_FARMS, $modify); } if (!$access && $this->ownerId && $user->id == $this->ownerId) { $access = $superposition->isAllowed(Acl::RESOURCE_OWN_FARMS, $modify); } } return $access; }
/** * {@inheritdoc} * @see \Scalr\System\Zmq\Cron\TaskInterface::worker() */ public function worker($request) { $db = \Scalr::getDb(); //Warming up static DI cache \Scalr::getContainer()->warmup(); // Reconfigure observers \Scalr::ReconfigureObservers(); $bundleTask = BundleTask::LoadById($request->bundleTaskId); if (!$bundleTask instanceof BundleTask) { $this->getLogger()->fatal("Could not load bundle task id: %s", $request->bundleTaskId); return false; } else { $this->bundleTask = $bundleTask; $this->getLogger()->info("Processing bundle task id: %d status: %s serverid: %s", $bundleTask->id, $bundleTask->status, $bundleTask->serverId); } try { $dbServer = DBServer::LoadByID($bundleTask->serverId); } catch (\Scalr\Exception\ServerNotFoundException $e) { if (!$bundleTask->snapshotId && $bundleTask->bundleType != \SERVER_SNAPSHOT_CREATION_TYPE::GCE_WINDOWS) { $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::FAILED; $bundleTask->setDate('finished'); $bundleTask->failureReason = sprintf(_("Server '%s' was terminated during snapshot creation process"), $bundleTask->serverId); $bundleTask->Save(); return; } $this->getLogger()->warn("Could not load server: %s. %s says: %s", $bundleTask->serverId, get_class($e), $e->getMessage()); } catch (Exception $e) { $this->getLogger()->warn("Could not load server: %s. %s says: %s", $bundleTask->serverId, get_class($e), $e->getMessage()); } switch ($bundleTask->status) { case SERVER_SNAPSHOT_CREATION_STATUS::ESTABLISHING_COMMUNICATION: $conn = @fsockopen($dbServer->getSzrHost(), $dbServer->getPort(DBServer::PORT_CTRL), $errno, $errstr, 10); if ($conn) { $dbServer->SetProperty(SERVER_PROPERTIES::SZR_IMPORTING_OUT_CONNECTION, 1); $this->bundleTaskLog("Outbound connection successfully established. Awaiting user action: prebuild automation selection"); $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::AWAITING_USER_ACTION; $this->bundleTaskLog(sprintf(_("Bundle task status: %s"), $bundleTask->status)); $bundleTask->Save(); } else { $errstr = sprintf("Unable to establish outbound (Scalr -> Scalarizr) communication (%s:%s): %s.", $dbServer->getSzrHost(), $dbServer->getPort(DBServer::PORT_CTRL), $errstr); $errMsg = $dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_OUT_CONNECTION_ERROR); if (!$errMsg || $errstr != $errMsg) { $dbServer->SetProperty(SERVER_PROPERTIES::SZR_IMPORTING_OUT_CONNECTION_ERROR, $errstr); $this->bundleTaskLog("{$errstr} Will try again in a few minutes."); } } return false; case SERVER_SNAPSHOT_CREATION_STATUS::AWAITING_USER_ACTION: //nothing to do; return false; case SERVER_SNAPSHOT_CREATION_STATUS::STARING_SERVER: $bundleTask->setDate('started'); case SERVER_SNAPSHOT_CREATION_STATUS::PREPARING_ENV: case SERVER_SNAPSHOT_CREATION_STATUS::INTALLING_SOFTWARE: if (!PlatformFactory::NewPlatform($dbServer->platform)->GetServerID($dbServer)) { $this->bundleTaskLog(sprintf(_("Waiting for temporary server"))); return false; } $status = PlatformFactory::NewPlatform($dbServer->platform)->GetServerRealStatus($dbServer); if ($status->isPending()) { //Server is in pensing state $this->bundleTaskLog(sprintf(_("Server status: %s"), $status->getName())); $this->bundleTaskLog(sprintf(_("Waiting for running state."), $status->getName())); return false; } elseif ($status->isTerminated()) { $this->bundleTaskLog(sprintf(_("Server status: %s"), $status->getName())); $dbServer->status = SERVER_STATUS::TERMINATED; $dbServer->save(); $bundleTask->SnapshotCreationFailed("Server was terminated and no longer available in cloud."); return false; } break; } $this->getLogger()->info("Continue bundle task id:%d status:%s", $bundleTask->id, $bundleTask->status); switch ($bundleTask->status) { case SERVER_SNAPSHOT_CREATION_STATUS::STARING_SERVER: $ips = PlatformFactory::NewPlatform($dbServer->platform)->GetServerIPAddresses($dbServer); $dbServer->remoteIp = $ips['remoteIp']; $dbServer->localIp = $ips['localIp']; $dbServer->save(); $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::PREPARING_ENV; $bundleTask->save(); $this->bundleTaskLog(sprintf(_("Bundle task status: %s"), $bundleTask->status)); break; case SERVER_SNAPSHOT_CREATION_STATUS::PREPARING_ENV: $this->bundleTaskLog(sprintf(_("Initializing SSH2 session to the server"))); if ($dbServer->platform == SERVER_PLATFORMS::IDCF && !$dbServer->remoteIp) { try { $this->bundleTaskLog("Creating port forwarding rules to be able to connect to the server by SSH"); $environment = $dbServer->GetEnvironmentObject(); $cloudLocation = $dbServer->GetCloudLocation(); $platform = PlatformFactory::NewPlatform($dbServer->platform); $ccProps = $environment->keychain($dbServer->platform)->properties; $sharedIpId = $ccProps[CloudCredentialsProperty::CLOUDSTACK_SHARED_IP_ID . ".{$cloudLocation}"]; $sharedIp = $ccProps[CloudCredentialsProperty::CLOUDSTACK_SHARED_IP . ".{$cloudLocation}"]; $this->bundleTaskLog("Shared IP: {$sharedIp}"); $cs = $environment->cloudstack($dbServer->platform); // Create port forwarding rules for scalarizr $port = $ccProps[CloudCredentialsProperty::CLOUDSTACK_SZR_PORT_COUNTER . ".{$cloudLocation}.{$sharedIpId}"]; if (!$port) { $port1 = 30000; $port2 = 30001; $port3 = 30002; $port4 = 30003; } else { $port1 = $port + 1; $port2 = $port1 + 1; $port3 = $port2 + 1; $port4 = $port3 + 1; } $virtualmachineid = $dbServer->GetProperty(CLOUDSTACK_SERVER_PROPERTIES::SERVER_ID); $result2 = $cs->firewall->createPortForwardingRule(array('ipaddressid' => $sharedIpId, 'privateport' => 8014, 'protocol' => "udp", 'publicport' => $port1, 'virtualmachineid' => $virtualmachineid)); $result1 = $cs->firewall->createPortForwardingRule(array('ipaddressid' => $sharedIpId, 'privateport' => 8013, 'protocol' => "tcp", 'publicport' => $port1, 'virtualmachineid' => $virtualmachineid)); $result3 = $cs->firewall->createPortForwardingRule(array('ipaddressid' => $sharedIpId, 'privateport' => 8010, 'protocol' => "tcp", 'publicport' => $port3, 'virtualmachineid' => $virtualmachineid)); $result4 = $cs->firewall->createPortForwardingRule(array('ipaddressid' => $sharedIpId, 'privateport' => 8008, 'protocol' => "tcp", 'publicport' => $port2, 'virtualmachineid' => $virtualmachineid)); $result5 = $cs->firewall->createPortForwardingRule(array('ipaddressid' => $sharedIpId, 'privateport' => 22, 'protocol' => "tcp", 'publicport' => $port4, 'virtualmachineid' => $virtualmachineid)); $dbServer->SetProperties(array(SERVER_PROPERTIES::SZR_CTRL_PORT => $port1, SERVER_PROPERTIES::SZR_SNMP_PORT => $port1, SERVER_PROPERTIES::SZR_API_PORT => $port3, SERVER_PROPERTIES::SZR_UPDC_PORT => $port2, SERVER_PROPERTIES::CUSTOM_SSH_PORT => $port4)); $dbServer->remoteIp = $sharedIp; $dbServer->Save(); $ccProps->saveSettings([CloudCredentialsProperty::CLOUDSTACK_SZR_PORT_COUNTER . ".{$cloudLocation}.{$sharedIpId}" => $port4]); } catch (Exception $e) { $this->bundleTaskLog("Unable to create port-forwarding rules: {$e->getMessage()}"); } return false; } try { $ssh2Client = $dbServer->GetSsh2Client(); $ssh2Client->connect($dbServer->remoteIp, $dbServer->getPort(DBServer::PORT_SSH)); } catch (Exception $e) { $this->bundleTaskLog(sprintf(_("Scalr unable to establish SSH connection with server on %:%. Error: %s"), $dbServer->remoteIp, $dbServer->getPort(DBServer::PORT_SSH), $e->getMessage())); //TODO: Set status of bundle log to failed return false; } $this->bundleTaskLog(sprintf(_("Created SSH session. Username: %s"), $ssh2Client->getLogin())); //Prepare script $this->bundleTaskLog(sprintf(_("Uploading builder scripts..."))); $behaviors = $dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_BEHAVIOR); try { if ($dbServer->isOpenstack()) { $platform = SERVER_PLATFORMS::OPENSTACK; } else { $platform = $dbServer->platform; } $baseUrl = rtrim(\Scalr::config('scalr.endpoint.scheme') . "://" . \Scalr::config('scalr.endpoint.host'), '/'); $options = array('server-id' => $dbServer->serverId, 'role-name' => $bundleTask->roleName, 'crypto-key' => $dbServer->GetProperty(SERVER_PROPERTIES::SZR_KEY), 'platform' => $platform, 'queryenv-url' => $baseUrl . "/query-env", 'messaging-p2p.producer-url' => $baseUrl . "/messaging", 'behaviour' => trim(trim(str_replace("base", "", $behaviors), ",")), 'env-id' => $dbServer->envId, 'region' => $dbServer->GetCloudLocation(), 'scalr-id' => SCALR_ID); $command = 'scalarizr --import -y'; foreach ($options as $k => $v) { $command .= sprintf(' -o %s=%s', $k, $v); } if ($dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_MYSQL_SERVER_TYPE) == 'percona') { $recipes = 'mysql=percona'; } else { $recipes = ''; } $scalarizrBranch = $dbServer->GetProperty(SERVER_PROPERTIES::SZR_DEV_SCALARIZR_BRANCH); $scriptContents = @file_get_contents(APPPATH . "/templates/services/role_builder/chef_import.tpl"); /* %CHEF_SERVER_URL% %CHEF_VALIDATOR_NAME% %CHEF_VALIDATOR_KEY% %CHEF_ENVIRONMENT% %CHEF_ROLE_NAME% */ $chefServerId = $dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_CHEF_SERVER_ID); if ($chefServerId) { $chefServerInfo = $db->GetRow("SELECT * FROM services_chef_servers WHERE id=?", array($chefServerId)); $chefServerInfo['v_auth_key'] = \Scalr::getContainer()->crypto->decrypt($chefServerInfo['v_auth_key']); } $scriptContents = str_replace(array("%PLATFORM%", "%BEHAVIOURS%", "%SZR_IMPORT_STRING%", "%DEV%", "%SCALARIZR_BRANCH%", "%RECIPES%", "%BUILD_ONLY%", "%CHEF_SERVER_URL%", "%CHEF_VALIDATOR_NAME%", "%CHEF_VALIDATOR_KEY%", "%CHEF_ENVIRONMENT%", "%CHEF_ROLE%", "%CHEF_ROLE_NAME%", "%CHEF_NODE_NAME%", "\r\n"), array($platform, trim(str_replace("base", "", str_replace(",", " ", $behaviors))), $command, $scalarizrBranch ? '1' : '0', $scalarizrBranch, $recipes, '0', $chefServerInfo['url'], $chefServerInfo['v_username'], $chefServerInfo['v_auth_key'], $dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_CHEF_ENVIRONMENT), $dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_CHEF_ROLE_NAME), $dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_CHEF_ROLE_NAME), '', "\n"), $scriptContents); if (!$ssh2Client->sendFile('/tmp/scalr-builder.sh', $scriptContents, "w+", false)) { throw new Exception("Cannot upload script"); } /* $this->bundleTaskLog(sprintf(_("Uploading chef recipes..."))); if (!$ssh2Client->sendFile('/tmp/recipes.tar.gz', APPPATH . '/www/storage/chef/recipes.tar.gz')) { throw new Exception("Cannot upload chef recipes"); } */ } catch (Exception $e) { $this->bundleTaskLog(sprintf(_("Scripts upload failed: %s"), $e->getMessage())); //TODO: Set status of bundle log to failed return false; } $this->bundleTaskLog("Launching role builder routines on server"); $ssh2Client->exec("chmod 0777 /tmp/scalr-builder.sh"); // For CGE we need to use sudo if ($bundleTask->platform == SERVER_PLATFORMS::GCE || $bundleTask->osFamily == 'amazon') { $shell = $ssh2Client->getShell(); @stream_set_blocking($shell, true); @stream_set_timeout($shell, 5); @fwrite($shell, "sudo touch /var/log/role-builder-output.log 2>&1" . PHP_EOL); $output = @fgets($shell, 4096); $this->bundleTaskLog("Verbose 1: {$output}"); @fwrite($shell, "sudo chmod 0666 /var/log/role-builder-output.log 2>&1" . PHP_EOL); $output2 = @fgets($shell, 4096); $this->bundleTaskLog("Verbose 2: {$output2}"); @fwrite($shell, "sudo setsid /tmp/scalr-builder.sh > /var/log/role-builder-output.log 2>&1 &" . PHP_EOL); $output3 = @fgets($shell, 4096); $this->bundleTaskLog("Verbose 3: {$output3}"); sleep(5); $meta = stream_get_meta_data($shell); $this->bundleTaskLog(sprintf("Verbose (Meta): %s", json_encode($meta))); $i = 4; if ($meta['eof'] == false && $meta['unread_bytes'] != 0) { $output4 = @fread($shell, $meta['unread_bytes']); $this->bundleTaskLog("Verbose {$i}: {$output4}"); $meta = stream_get_meta_data($shell); $this->bundleTaskLog(sprintf("Verbose (Meta): %s", json_encode($meta))); } @fclose($shell); /* $r1 = $ssh2Client->exec("sudo touch /var/log/role-builder-output.log"); $this->bundleTaskLog("1: {$r1} ({$ssh2Client->stdErr})"); $r2 = $ssh2Client->exec("sudo chmod 0666 /var/log/role-builder-output.log"); $this->bundleTaskLog("2: {$r2} ({$ssh2Client->stdErr})"); $r3 = $ssh2Client->exec("sudo setsid /tmp/scalr-builder.sh > /var/log/role-builder-output.log 2>&1 &"); $this->bundleTaskLog("3: {$r3} ({$ssh2Client->stdErr})"); */ } else { $ssh2Client->exec("setsid /tmp/scalr-builder.sh > /var/log/role-builder-output.log 2>&1 &"); } $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::INTALLING_SOFTWARE; $bundleTask->save(); break; case SERVER_SNAPSHOT_CREATION_STATUS::INTALLING_SOFTWARE: try { $ssh2Client = $dbServer->GetSsh2Client(); $ssh2Client->connect($dbServer->remoteIp, $dbServer->getPort(DBServer::PORT_SSH)); } catch (Exception $e) { $this->bundleTaskLog(sprintf(_("Scalr unable to establish SSH connection with server on %:%. Error: %s"), $dbServer->remoteIp, $dbServer->getPort(DBServer::PORT_SSH), $e->getMessage())); //TODO: Set status of bundle log to failed return false; } $log = $ssh2Client->getFile('/var/log/role-builder-output.log'); $log_lines = explode("\r\n", $log); $last_msg = $dbServer->GetProperty(SERVER_PROPERTIES::SZR_IMPORTING_LAST_LOG_MESSAGE); while ($msg = trim(array_shift($log_lines))) { if (substr($msg, -1, 1) != ']') { continue; } if ($last_msg) { if ($msg != $last_msg) { continue; } elseif ($msg == $last_msg) { $last_msg = null; continue; } } if (stristr($msg, '[ Failed ]')) { $stepLog = $ssh2Client->getFile('/var/log/role-builder-step.log'); $this->bundleTaskLog(sprintf("role-builder-step.log: %s", $stepLog)); $bundleTask->SnapshotCreationFailed($msg); } else { $this->bundleTaskLog($msg); $dbServer->SetProperty(SERVER_PROPERTIES::SZR_IMPORTING_LAST_LOG_MESSAGE, $msg); } } //Read /var/log/role-builder-output.log break; case SERVER_SNAPSHOT_CREATION_STATUS::PENDING: try { $platformModule = PlatformFactory::NewPlatform($bundleTask->platform); $platformModule->CreateServerSnapshot($bundleTask); } catch (Exception $e) { $this->getLogger()->error($e->getMessage()); $bundleTask->SnapshotCreationFailed($e->getMessage()); } break; case SERVER_SNAPSHOT_CREATION_STATUS::PREPARING: $addedTime = strtotime($bundleTask->dateAdded); if ($addedTime + 3600 < time()) { $bundleTask->SnapshotCreationFailed("Server didn't send PrepareBundleResult message in time."); } break; case SERVER_SNAPSHOT_CREATION_STATUS::IN_PROGRESS: PlatformFactory::NewPlatform($bundleTask->platform)->CheckServerSnapshotStatus($bundleTask); break; case SERVER_SNAPSHOT_CREATION_STATUS::CREATING_ROLE: try { if ($bundleTask->object == BundleTask::BUNDLETASK_OBJECT_IMAGE) { if ($bundleTask->replaceType == SERVER_REPLACEMENT_TYPE::REPLACE_ALL) { $dbRole = $dbServer->GetFarmRoleObject()->GetRoleObject(); $dbRole->__getNewRoleObject()->setImage($bundleTask->platform, $bundleTask->cloudLocation, $bundleTask->snapshotId, $bundleTask->createdById, $bundleTask->createdByEmail); $this->bundleTaskLog(sprintf(_("Image replacement completed."))); } $this->bundleTaskLog(sprintf(_("Bundle task completed."))); $bundleTask->setDate('finished'); $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::SUCCESS; $bundleTask->Save(); } elseif ($bundleTask->object == BundleTask::BUNDLETASK_OBJECT_ROLE) { if ($bundleTask->replaceType == SERVER_REPLACEMENT_TYPE::REPLACE_ALL) { $saveOldRole = false; try { $dbRole = $dbServer->GetFarmRoleObject()->GetRoleObject(); if ($dbRole->name == $bundleTask->roleName && $dbRole->envId == $bundleTask->envId) { $saveOldRole = true; } } catch (Exception $e) { //NO OLD ROLE } if ($dbRole && $saveOldRole) { if ($dbServer) { $new_role_name = BundleTask::GenerateRoleName($dbServer->GetFarmRoleObject(), $dbServer); } else { $new_role_name = $bundleTask->roleName . "-" . rand(1000, 9999); } $dbRole->name = $new_role_name; $this->bundleTaskLog(sprintf(_("Old role '%s' (ID: %s) renamed to '%s'"), $bundleTask->roleName, $dbRole->id, $new_role_name)); $dbRole->save(); } } try { $DBRole = DBRole::createFromBundleTask($bundleTask); } catch (Exception $e) { $bundleTask->SnapshotCreationFailed("Role creation failed due to internal error ({$e->getMessage()}). Please try again."); return; } if ($bundleTask->replaceType == SERVER_REPLACEMENT_TYPE::NO_REPLACE) { $bundleTask->setDate('finished'); $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::SUCCESS; $this->bundleTaskLog(sprintf(_("Replacement type: %s. Bundle task status: %s"), SERVER_REPLACEMENT_TYPE::NO_REPLACE, SERVER_SNAPSHOT_CREATION_STATUS::SUCCESS)); } else { try { $this->bundleTaskLog(sprintf(_("Replacement type: %s"), $bundleTask->replaceType)); $r_farm_roles = array(); try { $DBFarm = DBFarm::LoadByID($bundleTask->farmId); } catch (Exception $e) { if (stristr($e->getMessage(), "not found in database")) { $bundleTask->SnapshotCreationFailed("Farm was removed before task was finished"); } return; } if ($bundleTask->replaceType == SERVER_REPLACEMENT_TYPE::REPLACE_FARM) { try { $r_farm_roles[] = $DBFarm->GetFarmRoleByRoleID($bundleTask->prototypeRoleId); } catch (Exception $e) { } } elseif ($bundleTask->replaceType == SERVER_REPLACEMENT_TYPE::REPLACE_ALL) { /* @var $user Entity\Account\User */ $user = Entity\Account\User::findPk($bundleTask->createdById); /* @var $env Entity\Account\Environment */ $env = Entity\Account\Environment::findPk($bundleTask->envId); /* @var $acl Acl */ $acl = Scalr::getContainer()->acl; $sql = "SELECT fr.id FROM farm_roles fr JOIN farms f ON f.id = fr.farmid WHERE fr.role_id=? AND f.env_id = ?"; $args = [$bundleTask->prototypeRoleId, $bundleTask->envId]; if (!$acl->isUserAllowedByEnvironment($user, $env, Acl::RESOURCE_FARMS, Acl::PERM_FARMS_UPDATE)) { $q = []; if ($acl->isUserAllowedByEnvironment($user, $env, Acl::RESOURCE_TEAM_FARMS, Acl::PERM_FARMS_UPDATE)) { $q[] = Entity\Farm::getUserTeamOwnershipSql($user->id); } if ($acl->isUserAllowedByEnvironment($user, $env, Acl::RESOURCE_OWN_FARMS, Acl::PERM_FARMS_UPDATE)) { $q[] = "f.created_by_id = ?"; $args[] = $user->getId(); } if (count($q)) { $sql .= ' AND (' . join(' OR ', $q) . ')'; } else { $sql .= ' AND 0'; // no permissions } } $farm_roles = $db->GetAll($sql, $args); foreach ($farm_roles as $farm_role) { try { $r_farm_roles[] = DBFarmRole::LoadByID($farm_role['id']); } catch (Exception $e) { } } } foreach ($r_farm_roles as $DBFarmRole) { if ($DBFarmRole->CloudLocation != $bundleTask->cloudLocation) { $this->bundleTaskLog(sprintf("Role '%s' (ID: %s), farm '%s' (ID: %s) using the same role " . "but in abother cloud location. Skiping it.", $DBFarmRole->GetRoleObject()->name, $DBFarmRole->ID, $DBFarmRole->GetFarmObject()->Name, $DBFarmRole->FarmID)); } else { $DBFarmRole->RoleID = $bundleTask->roleId; $DBFarmRole->Save(); } } $this->bundleTaskLog(sprintf(_("Replacement completed. Bundle task completed."))); try { if ($dbServer->status == SERVER_STATUS::IMPORTING) { $dbServer->Remove(); } elseif ($dbServer->status == SERVER_STATUS::TEMPORARY) { $this->bundleTaskLog("Terminating temporary server"); $dbServer->terminate(DBServer::TERMINATE_REASON_TEMPORARY_SERVER_ROLE_BUILDER); $this->bundleTaskLog("Termination request has been sent"); } } catch (Exception $e) { $this->bundleTaskLog("Warning: {$e->getMessage()}"); } $bundleTask->setDate('finished'); $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::SUCCESS; $bundleTask->Save(); } catch (Exception $e) { $this->getLogger()->error($e->getMessage()); $this->bundleTaskLog(sprintf(_("Server replacement failed: %s"), $e->getMessage())); $bundleTask->setDate('finished'); $bundleTask->status = SERVER_SNAPSHOT_CREATION_STATUS::SUCCESS; } } } if ($bundleTask->status == SERVER_SNAPSHOT_CREATION_STATUS::SUCCESS) { try { if ($dbServer->status == SERVER_STATUS::IMPORTING) { $dbServer->Remove(); } elseif ($dbServer->status == SERVER_STATUS::TEMPORARY) { $this->bundleTaskLog("Terminating temporary server"); $dbServer->terminate(DBServer::TERMINATE_REASON_TEMPORARY_SERVER_ROLE_BUILDER); $this->bundleTaskLog("Termination request has been sent"); } } catch (Exception $e) { $this->bundleTaskLog("Warning: {$e->getMessage()}"); } } $bundleTask->Save(); } catch (Exception $e) { $this->getLogger()->error($e->getMessage()); } break; } return $request; }
/** * user.auth.login handler * * @param Entity\Account\User|Scalr_Account_User|array $user User object * @param int $envId Identifier of the Environment * @param string $ip Remote Addres of the User * @param int $ruid Real user identifier * @return array Returns array of the fields to log */ private function handlerUserAuthLogin($user, $envId = null, $ip = null, $ruid = null) { if ($user instanceof Scalr_Account_User || $user instanceof Entity\Account\User) { $this->user = $user; $this->envId = $envId; $this->ipAddress = $ip; $this->realUserId = $ruid; // Teams are needed for the audit log $teams = []; foreach ($user->getTeams() as $rec) { $teams[$rec['id']] = $rec['name']; } $lastVisit = $user->dtLastLogin ?: $user->dtCreated; $data = ['result' => 'success', 'teams' => $teams, 'last_login' => $lastVisit ? static::getTimestamp(strtotime($lastVisit)) : null, 'user_type' => $user->type]; } return isset($data) ? $data : $user; }
/** * Check if session is valid and is not expired. If no valid session, check cookie keepSession. * * @param bool $checkKeepSessionCookie If true check cookie keepSession * @param bool $isAutomaticRequest If true don't update sessionLastTime */ protected static function restore($checkKeepSessionCookie = true, $isAutomaticRequest = false) { $session = self::getInstance(); if (session_status() != PHP_SESSION_ACTIVE) { static::startSession(); self::sessionLog("session_start():" . __LINE__); } $refClass = self::getReflectionClass(); foreach ($refClass->getConstants() as $constname => $constvalue) { if (substr($constname, 0, 8) !== 'SESSION_') { continue; } $session->{$constvalue} = isset($_SESSION[__CLASS__][$constvalue]) ? $_SESSION[__CLASS__][$constvalue] : null; } $newhash = self::createHash($session->userId, $session->sault); if (!($newhash == $session->hash && !empty($session->hash))) { // reset session (invalid) self::sessionLog("invalid hash:" . __LINE__); $session->userId = 0; $session->hash = ''; if ($checkKeepSessionCookie && self::isCookieKeepSession()) { self::restore(false, $isAutomaticRequest); if ($session->userId) { // we've recovered session, update last login $u = new User(); Scalr::getDb()->Execute("UPDATE {$u->table()} SET {$u->columnLastLogin} = NOW() WHERE {$u->columnId} = ?", [$session->userId]); } } } else { if (strtotime(Scalr::config('scalr.security.user.session.timeout'), $session->lastTime) < time()) { self::sessionLog("session timeout was expired:" . __LINE__); if ($checkKeepSessionCookie) { $_SESSION[__CLASS__][self::SESSION_USER_ID] = 0; $_SESSION[__CLASS__][self::SESSION_HASH] = ''; self::restore($checkKeepSessionCookie, $isAutomaticRequest); } else { $session->userId = 0; $session->hash = ''; } return; } if (!$isAutomaticRequest) { $_SESSION[__CLASS__][self::SESSION_LAST_TIME] = $session->lastTime = time(); } if (strtotime(Scalr::config('scalr.security.user.session.lifetime'), $session->initTime) < time()) { self::sessionLog("session lifetime was expired:" . __LINE__); if ($checkKeepSessionCookie) { $_SESSION[__CLASS__][self::SESSION_USER_ID] = 0; $_SESSION[__CLASS__][self::SESSION_HASH] = ''; self::restore($checkKeepSessionCookie, $isAutomaticRequest); } else { $session->userId = 0; $session->hash = ''; } return; } } session_write_close(); self::sessionLog("session_write_close():" . __LINE__); }
/** * Launches server * * @param \ServerCreateInfo $ServerCreateInfo optional The server create info * @param \DBServer $DBServer optional The DBServer object * @param bool $delayed optional * @param integer|array $reason optional * @param \Scalr_Account_User|int $user optional The Scalr_Account_User object or its unique identifier * @return DBServer|null Returns the DBServer object on cussess or null otherwise */ public static function LaunchServer(ServerCreateInfo $ServerCreateInfo = null, DBServer $DBServer = null, $delayed = false, $reason = 0, $user = null) { $db = self::getDb(); $farm = null; //Ensures handling identifier of the user instead of the object if ($user !== null && !$user instanceof \Scalr_Account_User) { try { $user = Scalr_Account_User::init()->loadById(intval($user)); } catch (\Exception $e) { } } if (!$DBServer && $ServerCreateInfo) { $ServerCreateInfo->SetProperties(array(SERVER_PROPERTIES::SZR_KEY => self::GenerateRandomKey(40), SERVER_PROPERTIES::SZR_KEY_TYPE => SZR_KEY_TYPE::ONE_TIME)); $DBServer = DBServer::Create($ServerCreateInfo, false, true); } elseif (!$DBServer && !$ServerCreateInfo) { // incorrect arguments self::getContainer()->logger(LOG_CATEGORY::FARM)->error(sprintf("Cannot create server")); return null; } else { if ($DBServer && empty($DBServer->cloudLocation)) { trigger_error('Cloud location is missing in DBServer', E_USER_WARNING); } } $propsToSet = array(); if ($user instanceof \Scalr_Account_User) { $propsToSet[SERVER_PROPERTIES::LAUNCHED_BY_ID] = $user->id; $propsToSet[SERVER_PROPERTIES::LAUNCHED_BY_EMAIL] = $user->getEmail(); } //We should keep role_id and farm_role_id in server properties to use in cost analytics if (!empty($DBServer->farmRoleId)) { $propsToSet[SERVER_PROPERTIES::FARM_ROLE_ID] = $DBServer->farmRoleId; $propsToSet[SERVER_PROPERTIES::ROLE_ID] = $DBServer->farmRoleId ? $DBServer->GetFarmRoleObject()->RoleID : 0; } try { // Ensures the farm object will be fetched as correctly as possible $farm = $DBServer->farmId ? $DBServer->GetFarmObject() : null; $farmRole = $DBServer->farmRoleId ? $DBServer->GetFarmRoleObject() : null; if (!$farmRole instanceof DBFarmRole) { $farmRole = null; } else { if (!$farm instanceof DBFarm) { // Gets farm through FarmRole object in this case $farm = $farmRole->GetFarmObject(); } } if ($farm instanceof DBFarm) { $propsToSet[SERVER_PROPERTIES::FARM_CREATED_BY_ID] = $farm->ownerId ?: $farm->GetSetting(Entity\FarmSetting::CREATED_BY_ID); $propsToSet[SERVER_PROPERTIES::FARM_CREATED_BY_EMAIL] = $farm->ownerId ? Entity\Account\User::findPk($farm->ownerId)->email : $farm->GetSetting(Entity\FarmSetting::CREATED_BY_EMAIL); $projectId = $farm->GetSetting(Entity\FarmSetting::PROJECT_ID); if (!empty($projectId)) { try { $projectEntity = ProjectEntity::findPk($projectId); if ($projectEntity instanceof ProjectEntity) { /* @var $projectEntity ProjectEntity */ $ccId = $projectEntity->ccId; } else { $projectId = null; } } catch (Exception $e) { $projectId = null; } } $propsToSet[SERVER_PROPERTIES::FARM_PROJECT_ID] = $projectId; } if ($farmRole instanceof DBFarmRole) { $role = $farmRole->GetRoleObject(); $DBServer->isScalarized = $role->isScalarized; if (!$DBServer->isScalarized) { $propsToSet[SERVER_PROPERTIES::SZR_VESION] = ''; } $DBServer->Save(); } if (!empty($ccId)) { $propsToSet[SERVER_PROPERTIES::ENV_CC_ID] = $ccId; } elseif ($DBServer->envId && ($environment = $DBServer->GetEnvironmentObject()) instanceof Scalr_Environment) { $propsToSet[SERVER_PROPERTIES::ENV_CC_ID] = $environment->getPlatformConfigValue(Scalr_Environment::SETTING_CC_ID); } } catch (Exception $e) { self::getContainer()->logger(LOG_CATEGORY::FARM)->error(sprintf("Could not load related object for recently created server %s. It says: %s", $DBServer->serverId, $e->getMessage())); } if (!empty($propsToSet)) { $DBServer->SetProperties($propsToSet); } $fnGetReason = function ($reasonId) { $args = func_get_args(); $args[0] = DBServer::getLaunchReason($reasonId); return [call_user_func_array('sprintf', $args), $reasonId]; }; if ($reason) { list($reasonMsg, $reasonId) = is_array($reason) ? call_user_func_array($fnGetReason, $reason) : $fnGetReason($reason); $DBServer->SetProperties([SERVER_PROPERTIES::LAUNCH_REASON => $reasonMsg, SERVER_PROPERTIES::LAUNCH_REASON_ID => $reasonId]); } else { $reasonMsg = $DBServer->GetProperty(SERVER_PROPERTIES::LAUNCH_REASON); $reasonId = $DBServer->GetProperty(SERVER_PROPERTIES::LAUNCH_REASON_ID); } if ($delayed) { $DBServer->updateStatus(SERVER_STATUS::PENDING_LAUNCH); return $DBServer; } if ($ServerCreateInfo && $ServerCreateInfo->roleId) { $dbRole = DBRole::loadById($ServerCreateInfo->roleId); if ($dbRole->generation == 1) { $DBServer->updateStatus(SERVER_STATUS::PENDING_LAUNCH); $DBServer->SetProperties([SERVER_PROPERTIES::LAUNCH_ERROR => "ami-scripts servers no longer supported", SERVER_PROPERTIES::LAUNCH_ATTEMPT => $DBServer->GetProperty(SERVER_PROPERTIES::LAUNCH_ATTEMPT) + 1, SERVER_PROPERTIES::LAUNCH_LAST_TRY => (new DateTime())->format('Y-m-d H:i:s')]); return $DBServer; } } // Limit amount of pending servers if ($DBServer->isOpenstack()) { $config = self::getContainer()->config; if ($config->defined("scalr.{$DBServer->platform}.pending_servers_limit")) { $pendingServersLimit = $config->get("scalr.{$DBServer->platform}.pending_servers_limit"); $pendingServers = $db->GetOne("SELECT COUNT(*) FROM servers WHERE platform=? AND status=? AND server_id != ?", array($DBServer->platform, SERVER_STATUS::PENDING, $DBServer->serverId)); if ($pendingServers >= $pendingServersLimit) { self::getContainer()->logger("SERVER_LAUNCH")->warn("{$pendingServers} servers in PENDING state on {$DBServer->platform}. Limit is: {$pendingServersLimit}. Waiting."); $DBServer->updateStatus(SERVER_STATUS::PENDING_LAUNCH); $DBServer->SetProperties([SERVER_PROPERTIES::LAUNCH_ATTEMPT => $DBServer->GetProperty(SERVER_PROPERTIES::LAUNCH_ATTEMPT) + 1, SERVER_PROPERTIES::LAUNCH_LAST_TRY => (new DateTime())->format('Y-m-d H:i:s')]); return $DBServer; } else { self::getContainer()->logger("SERVER_LAUNCH")->warn("{$pendingServers} servers in PENDING state on {$DBServer->platform}. Limit is: {$pendingServersLimit}. Launching server."); } } } try { $account = Scalr_Account::init()->loadById($DBServer->clientId); $account->validateLimit(Scalr_Limits::ACCOUNT_SERVERS, 1); PlatformFactory::NewPlatform($DBServer->platform)->LaunchServer($DBServer); $DBServer->status = SERVER_STATUS::PENDING; $DBServer->Save(); try { $DBServer->getServerHistory()->markAsLaunched($reasonMsg, $reasonId); $DBServer->updateTimelog('ts_launched'); if ($DBServer->imageId) { //Update Image last used date /* @var $server Entity\Server */ $server = Entity\Server::findPk($DBServer->serverId); $image = $server->getImage(); if ($image) { $image->update(['dtLastUsed' => new DateTime()]); } if ($server->farmRoleId && empty($server->getFarmRole())) { trigger_error(sprintf("Call to a member function getRole() on null. Server: %s, FarmRole: %d", $server->serverId, $server->farmRoleId), E_USER_WARNING); } if ($server->farmRoleId && !empty($server->getFarmRole()->getRole())) { //Update Role last used date $server->getFarmRole()->getRole()->update(['lastUsed' => new DateTime()]); } } } catch (Exception $e) { self::getContainer()->logger('SERVER_HISTORY')->error(sprintf("Cannot update servers history: {$e->getMessage()}")); } } catch (Exception $e) { self::getContainer()->logger(LOG_CATEGORY::FARM)->error(new FarmLogMessage($DBServer, sprintf("Cannot launch server on '%s' platform: %s", !empty($DBServer->platform) ? $DBServer->platform : null, $e->getMessage()))); $existingLaunchError = $DBServer->GetProperty(SERVER_PROPERTIES::LAUNCH_ERROR); $DBServer->SetProperties([SERVER_PROPERTIES::LAUNCH_ERROR => $e->getMessage(), SERVER_PROPERTIES::LAUNCH_ATTEMPT => $DBServer->GetProperty(SERVER_PROPERTIES::LAUNCH_ATTEMPT) + 1, SERVER_PROPERTIES::LAUNCH_LAST_TRY => (new DateTime())->format('Y-m-d H:i:s')]); $DBServer->updateStatus(SERVER_STATUS::PENDING_LAUNCH); if ($DBServer->farmId && !$existingLaunchError) { self::FireEvent($DBServer->farmId, new InstanceLaunchFailedEvent($DBServer, $e->getMessage())); } } if ($DBServer->status == SERVER_STATUS::PENDING) { self::FireEvent($DBServer->farmId, new BeforeInstanceLaunchEvent($DBServer)); $DBServer->SetProperty(SERVER_PROPERTIES::LAUNCH_ERROR, ""); } return $DBServer; }
/** * Migrates an Image to another Cloud Location * * @param string $cloudLocation The cloud location * @param \Scalr_Account_User|\Scalr\Model\Entity\Account\User $user The user object * @return Image * @throws Exception * @throws NotEnabledPlatformException * @throws DomainException */ public function migrateEc2Location($cloudLocation, $user) { if (!$this->getEnvironment()->isPlatformEnabled(SERVER_PLATFORMS::EC2)) { throw new NotEnabledPlatformException("You can migrate image between regions only on EC2 cloud"); } if ($this->cloudLocation == $cloudLocation) { throw new DomainException('Destination region is the same as source one'); } $snap = $this->getEnvironment()->aws($this->cloudLocation)->ec2->image->describe($this->id); if ($snap->count() == 0) { throw new Exception("Image haven't been found on cloud."); } if ($snap->get(0)->toArray()['imageState'] != 'available') { throw new Exception('Image is not in "available" status on cloud and cannot be copied.'); } $this->checkImage(); // re-check properties $aws = $this->getEnvironment()->aws($cloudLocation); $newImageId = $aws->ec2->image->copy($this->cloudLocation, $this->id, $this->name, "Image was copied by Scalr from image: {$this->name}, cloudLocation: {$this->cloudLocation}, id: {$this->id}", null, $cloudLocation); $newImage = new Image(); $newImage->platform = $this->platform; $newImage->cloudLocation = $cloudLocation; $newImage->id = $newImageId; $newImage->name = $this->name; $newImage->architecture = $this->architecture; $newImage->size = $this->size; $newImage->accountId = $this->accountId; $newImage->envId = $this->envId; $newImage->osId = $this->osId; $newImage->source = Image::SOURCE_MANUAL; $newImage->type = $this->type; $newImage->agentVersion = $this->agentVersion; $newImage->createdById = $user->getId(); $newImage->createdByEmail = $user->getEmail(); $newImage->status = Image::STATUS_ACTIVE; $newImage->isScalarized = $this->isScalarized; $newImage->hasCloudInit = $this->hasCloudInit; $newImage->save(); $newImage->setSoftware($this->getSoftware()); return $newImage; }
/** * user.auth.login handler * * @param Scalr_Account_User|Entity\Account\User $user User object * @return array Returns array of the fields to log */ protected function handlerUserAuthLogin($user) { if ($user instanceof Scalr_Account_User || $user instanceof Entity\Account\User) { $this->user = $user; $teams = []; // Teams are needed for the audit log foreach ($user->getTeams() as $rec) { $teams[$rec['id']] = $rec['name']; } $lastVisit = $user->dtLastLogin ?: $user->dtCreated; $data = ['.result' => 'success', '.teams' => $teams, '.last_login' => $lastVisit ? static::getTimestamp(strtotime($lastVisit)) : null, '.user_type' => $user->type]; } return isset($data) ? $data : $user; }