/** * @param string $url * @param string $endpointId * @throws Exception */ public function xSaveAction($url, $endpointId = null) { if (!$endpointId) { $endpoint = new WebhookEndpoint(); $endpoint->setScope($this->request->getScope(), $this->user->getAccountId(), $this->getEnvironmentId(true)); $endpoint->securityKey = Scalr::GenerateRandomKey(64); } else { $endpoint = WebhookEndpoint::findPk($endpointId); if (!$this->canEditEndpoint($endpoint)) { throw new Scalr_Exception_Core('Insufficient permissions to edit endpoint at this scope'); } } $validator = new Validator(); $validator->validate($url, 'url', Validator::URL); //check url unique within current level $criteria = []; $criteria[] = ['url' => $url]; if ($endpoint->endpointId) { $criteria[] = ['endpointId' => ['$ne' => $endpoint->endpointId]]; } switch ($this->request->getScope()) { case WebhookEndpoint::SCOPE_ENVIRONMENT: $criteria[] = ['level' => WebhookEndpoint::LEVEL_ENVIRONMENT]; $criteria[] = ['envId' => $endpoint->envId]; $criteria[] = ['accountId' => $endpoint->accountId]; break; case WebhookEndpoint::SCOPE_ACCOUNT: $criteria[] = ['level' => WebhookEndpoint::LEVEL_ACCOUNT]; $criteria[] = ['envId' => null]; $criteria[] = ['accountId' => $endpoint->accountId]; break; case WebhookEndpoint::SCOPE_SCALR: $criteria[] = ['level' => WebhookEndpoint::LEVEL_SCALR]; $criteria[] = ['envId' => null]; $criteria[] = ['accountId' => null]; break; } if (WebhookEndpoint::findOne($criteria)) { $validator->addError('url', 'Endpoint url must be unique within current scope'); } if (!$validator->isValid($this->response)) { return; } if ($endpoint->url != $url) { $endpoint->isValid = false; $endpoint->url = $url; } ////temporarily disable url validation per Igor`s request(see also webhooks/endpoints/view.js) $endpoint->isValid = true; $endpoint->save(); $this->response->success('Endpoint successfully saved'); $this->response->data(array('endpoint' => array('endpointId' => $endpoint->endpointId, 'url' => $endpoint->url, 'isValid' => $endpoint->isValid, 'validationToken' => $endpoint->validationToken, 'securityKey' => $endpoint->securityKey, 'scope' => $endpoint->getScope()))); }
/** * Save metric. * * @param string $name * @param string $retrieveMethod * @param string $calcFunction * @param int $metricId optional * @param string $filePath optional * @param bool $isInvert optional * @throws Exception * @throws Scalr_Exception_Core * @throws Scalr_Exception_InsufficientPermissions * @throws \Scalr\Exception\ModelException */ public function xSaveAction($name, $retrieveMethod, $calcFunction, $metricId = null, $filePath = null, $isInvert = false) { $this->request->restrictAccess(Acl::RESOURCE_GENERAL_CUSTOM_SCALING_METRICS, Acl::PERM_GENERAL_CUSTOM_SCALING_METRICS_MANAGE); $validator = new Validator(); if ($metricId) { /* @var \Scalr\Model\Entity\ScalingMetric $metric */ $metric = Entity\ScalingMetric::findPk($metricId); if (!$metric) { throw new Scalr_UI_Exception_NotFound(); } $this->user->getPermissions()->validate($metric); } else { $metric = new Entity\ScalingMetric(); $metric->accountId = $this->user->getAccountId(); $metric->envId = $this->getEnvironmentId(); $metric->alias = 'custom'; $metric->algorithm = Entity\ScalingMetric::ALGORITHM_SENSOR; } if (!preg_match('/^[A-Za-z0-9]{5,}$/', $name)) { $validator->addError('name', 'Metric name should be both alphanumeric and greater than 5 chars'); } $criteria = []; $criteria[] = ['name' => $name]; if ($metricId) { $criteria[] = ['id' => ['$ne' => $metricId]]; } if (Entity\ScalingMetric::findOne($criteria)) { $validator->addError('name', 'Metric with the same name already exists'); } if ($validator->isValid($this->response)) { $metric->name = $name; $metric->filePath = $filePath; $metric->retrieveMethod = $retrieveMethod; $metric->calcFunction = $calcFunction; $metric->isInvert = $isInvert; $metric->save(); $this->response->success('Scaling metric has been successfully saved.'); $this->response->data(['metric' => get_object_vars($metric)]); } }
/** * Saves ACL * * @param string $id * @param string $name * @param int $baseRoleId * @param string $color * @param JsonData $resources * @throws InvalidArgumentException */ public function xSaveAction($id, $name, $baseRoleId, $color, JsonData $resources) { $validator = new Validator(); $validator->validate($name, 'name', Validator::NOEMPTY); if (!$validator->isValid($this->response)) { return; } $acl = \Scalr::getContainer()->acl; $r = []; foreach ($resources as $v) { $r[$v['id']] = $v; } try { $id = $acl->setAccountRole($this->request->getUser()->getAccountId(), $baseRoleId, $name, hexdec($color), $r, $id); } catch (\Exception $e) { if ($e instanceof \Scalr\Acl\Exception\AclException) { return $this->response->failure($e->getMessage()); } else { throw $e; } } $this->response->data(['role' => $acl->getAccountRoleComputed($id)]); $this->response->success('ACL successfully saved'); }
/** * @param string $id * @param string $status * @param string $name * @param string $family * @param string $generation * @param string $version * @throws Exception */ public function xSaveAction($id, $status, $name, $family, $generation, $version = '') { $os = Os::findPk($id); if (!$os) { $os = new Os(); $os->isSystem = 0; $os->id = $id; } $validator = new Validator(); $validator->validate($id, 'id', Validator::NOEMPTY); $validator->validate($name, 'name', Validator::NOEMPTY); $validator->validate($family, 'family', Validator::NOEMPTY); $validator->validate($generation, 'generation', Validator::NOEMPTY); //check by name, family, generation,version $criteria = []; $criteria[] = ['name' => $name]; $criteria[] = ['family' => $family]; $criteria[] = ['generation' => $generation]; $criteria[] = ['version' => $version]; if ($os->id) { $criteria[] = ['id' => ['$ne' => $os->id]]; } if (Os::findOne($criteria)) { $validator->addError('name', 'Operating system with such name, family, generation and version already exists'); } if (!$validator->isValid($this->response)) { return; } $os->status = $status; if ($os->isSystem != 1) { $os->name = $name; $os->family = $family; $os->generation = $generation; $os->version = $version; } $os->save(); $result = get_object_vars($os); $result['used'] = $os->getUsed(); $this->response->data(['os' => $os]); $this->response->success('Operating system successfully saved'); }
/** * @param int $accountId * @param RawData $password * @param RawData $currentPassword * @throws Exception */ public function xSaveOwnerPasswordAction($accountId, RawData $password, RawData $currentPassword) { $account = new Scalr_Account(); $account->loadById($accountId); $password = (string) $password; $validator = new Validator(); $validator->addErrorIf(!$this->user->checkPassword($currentPassword), "currentPassword", "Invalid password"); $validator->validate($password, "password", Validator::PASSWORD, ['admin']); if ($validator->isValid($this->response)) { $user = $account->getOwner(); $user->updatePassword($password); $user->save(); // Send notification E-mail $this->getContainer()->mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/password_change_admin_notification.eml', array('{{fullname}}' => $user->fullname ? $user->fullname : $user->getEmail(), '{{administratorFullName}}' => $this->user->fullname ? $this->user->fullname : $this->user->getEmail()), $user->getEmail(), $user->fullname); $this->response->success('Password successfully updated'); } }
/** * @param int $id * @param string $name * @param string $description * @param int $isSync * @param bool $allowScriptParameters * @param int $envId optional * @param int $timeout optional * @param int $version * @param RawData $content * @param string $tags * @param string $uploadType optional * @param string $uploadUrl optional * @param FileUploadData $uploadFile optional * @param bool $checkScriptParameters optional * @throws Scalr_UI_Exception_NotFound * @throws Scalr_Exception_InsufficientPermissions * @throws Exception */ public function xSaveAction($id, $name, $description, $isSync = 0, $allowScriptParameters = false, $envId = NULL, $timeout = NULL, $version, RawData $content, $tags, $uploadType = NULL, $uploadUrl = NULL, FileUploadData $uploadFile = NULL, $checkScriptParameters = false) { $this->request->restrictAccess('SCRIPTS', 'MANAGE'); $validator = new Validator(); $validator->validate($name, 'name', Validator::NOEMPTY); if ($uploadType && $uploadType == 'URL') { $validator->validate($uploadUrl, 'uploadUrl', Validator::URL); if (!$validator->isValid($this->response)) { return; } } if ($uploadType) { $content = false; if ($uploadType == 'URL') { $content = @file_get_contents($uploadUrl); $validator->validate($content, 'uploadUrl', Validator::NOEMPTY, [], 'Invalid source'); } else { if ($uploadType == 'File') { $content = $uploadFile; $validator->validate($content, 'uploadFile', Validator::NOEMPTY, [], 'Invalid source'); } else { $validator->addError('uploadType', 'Invalid source for script'); } } } $envId = $this->getEnvironmentId(true); $content = str_replace("\r\n", "\n", $content); $tagsResult = []; foreach (explode(',', $tags) as $t) { $t = trim($t); if ($t) { if (!preg_match('/^[a-zA-Z0-9-]{3,10}$/', $t)) { $validator->addError('tags', sprintf('Invalid name for tag: %s', $t)); } $tagsResult[] = $t; } } $tags = $tagsResult; $criteria = []; $criteria[] = ['name' => $name]; if ($id) { $criteria[] = ['id' => ['$ne' => $id]]; } switch ($this->request->getScope()) { case Script::SCOPE_ENVIRONMENT: $criteria[] = ['envId' => $envId]; $criteria[] = ['accountId' => $this->user->getAccountId()]; break; case Script::SCOPE_ACCOUNT: $criteria[] = ['envId' => null]; $criteria[] = ['accountId' => $this->user->getAccountId()]; break; case Script::SCOPE_SCALR: $criteria[] = ['envId' => null]; $criteria[] = ['accountId' => null]; break; } if (Script::findOne($criteria)) { $validator->addError('name', 'Script name must be unique within current scope'); } if (!$validator->isValid($this->response)) { return; } /* @var $script Script */ if ($id) { $script = Script::findPk($id); if (!$script) { throw new Scalr_UI_Exception_NotFound(); } $script->checkPermission($this->user, $envId); if (!$script->accountId && $this->user->getType() != Scalr_Account_User::TYPE_SCALR_ADMIN) { throw new Scalr_Exception_InsufficientPermissions(); } if (!$script->envId && $this->request->getScope() == ScopeInterface::SCOPE_ENVIRONMENT) { throw new Scalr_Exception_InsufficientPermissions(); } } else { $script = new Script(); $script->accountId = $this->user->getAccountId() ?: NULL; $script->createdById = $this->user->getId(); $script->createdByEmail = $this->user->getEmail(); $script->envId = $envId; $version = 1; } //check variables in script content if (!$id && $checkScriptParameters && !$allowScriptParameters) { $scriptHasParameters = Script::hasVariables($content); if (!$scriptHasParameters) { /* @var $scriptVersion ScriptVersion */ foreach ($script->getVersions() as $scriptVersion) { if ($scriptVersion->version != $version) { $scriptHasParameters = Script::hasVariables($scriptVersion->content); if ($scriptHasParameters) { break; } } } } if ($scriptHasParameters) { $this->response->data(['showScriptParametersConfirmation' => true]); $this->response->failure(); return; } } $script->name = $name; $script->description = $description; $script->timeout = $timeout ? $timeout : NULL; $script->isSync = $isSync == 1 ? 1 : 0; $script->allowScriptParameters = $allowScriptParameters ? 1 : 0; $script->os = !strncmp($content, '#!cmd', strlen('#!cmd')) || !strncmp($content, '#!powershell', strlen('#!powershell')) ? Script::OS_WINDOWS : Script::OS_LINUX; $script->save(); $scriptVersion = NULL; if ($version) { $scriptVersion = $script->getVersion($version); } if (!$scriptVersion && $script->getLatestVersion()->content !== $content) { $scriptVersion = new ScriptVersion(); $scriptVersion->scriptId = $script->id; $scriptVersion->version = $script->getLatestVersion()->version + 1; } if ($scriptVersion) { $scriptVersion->changedById = $this->user->getId(); $scriptVersion->changedByEmail = $this->user->getEmail(); $scriptVersion->content = $content; $scriptVersion->save(); } if ($this->user->getAccountId()) { Tag::setTags($tags, $this->user->getAccountId(), Tag::RESOURCE_SCRIPT, $script->id); } $this->response->success('Script successfully saved'); $this->response->data(['script' => array_merge($this->getScript($script), $this->getScriptInfo($script))]); }
public function xSaveAction() { $this->request->defineParams(array('password' => array('type' => 'string', 'rawValue' => true))); $sendResetLink = $newUser = false; $user = Scalr_Account_User::init(); $validator = new Validator(); $email = $this->getParam('email'); if (($isEmailValid = $validator->validateEmail($email)) !== true) { throw new Scalr_Exception_Core($isEmailValid); } if ($this->user->canManageAcl() || $this->user->isTeamOwner()) { $password = $this->getParam('password'); if (empty($password)) { $password = CryptoTool::sault(10); $sendResetLink = true; } if (($isPasswordValid = $validator->validatePassword($password)) !== true) { throw new Scalr_Exception_Core($isPasswordValid); } if ($this->getParam('id')) { $user->loadById((int) $this->getParam('id')); if (!$this->user->canEditUser($user)) { throw new Scalr_Exception_InsufficientPermissions(); } $user->updateEmail($email); } else { $this->user->getAccount()->validateLimit(Scalr_Limits::ACCOUNT_USERS, 1); $user->create($email, $this->user->getAccountId()); $user->type = Scalr_Account_User::TYPE_TEAM_USER; $newUser = true; } if ($password != '******') { $user->updatePassword($password); } if (in_array($this->getParam('status'), array(Scalr_Account_User::STATUS_ACTIVE, Scalr_Account_User::STATUS_INACTIVE)) && !$user->isAccountOwner()) { $user->status = $this->getParam('status'); } $user->fullname = $this->getParam('fullname'); $user->comments = $this->getParam('comments'); $user->save(); if ($this->getParam('enableApi')) { $keys = Scalr::GenerateAPIKeys(); $user->setSetting(Scalr_Account_User::SETTING_API_ENABLED, true); $user->setSetting(Scalr_Account_User::SETTING_API_ACCESS_KEY, $keys['id']); $user->setSetting(Scalr_Account_User::SETTING_API_SECRET_KEY, $keys['key']); } if ($newUser) { if ($sendResetLink) { try { $hash = $this->getCrypto()->sault(10); $user->setSetting(Scalr_Account::SETTING_OWNER_PWD_RESET_HASH, $hash); $clientinfo = array('email' => $user->getEmail(), 'fullname' => $user->fullname); // Send reset password E-mail $res = $this->getContainer()->mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/user_account_confirm.eml', array("{{fullname}}" => $clientinfo['fullname'], "{{pwd_link}}" => "https://{$_SERVER['HTTP_HOST']}/#/guest/updatePassword/?hash={$hash}"), $clientinfo['email'], $clientinfo['fullname']); } catch (Exception $e) { } } } $this->response->data(array('user' => array('id' => $user->getId(), 'email' => $user->getEmail(), 'fullname' => $user->fullname))); $this->response->success('User successfully saved'); } else { throw new Scalr_Exception_InsufficientPermissions(); } }
/** * xSaveAction * * @param string $projectId * @param string $name * @param string $description * @param string $billingCode * @param string $leadEmail * @param string $ccId optional * @throws \InvalidArgumentException * @throws Scalr_Exception_InsufficientPermissions * @throws Scalr_UI_Exception_NotFound */ public function xSaveAction($projectId, $name, $description, $billingCode, $leadEmail, $ccId = null) { $this->request->restrictAccess(Acl::RESOURCE_ANALYTICS_ACCOUNT, Acl::PERM_ANALYTICS_ACCOUNT_MANAGE_PROJECTS); $validator = new Validator(); $validator->validate($name, 'name', Validator::NOEMPTY); if (!$validator->isValid($this->response)) { return; } if ($projectId) { $project = $this->getContainer()->analytics->projects->get($projectId); if (!$project) { throw new Scalr_UI_Exception_NotFound(); } elseif ($project->shared != ProjectEntity::SHARED_WITHIN_ACCOUNT || $project->accountId != $this->user->getAccountId()) { throw new Scalr_Exception_InsufficientPermissions(); } } else { $project = new ProjectEntity(); if ($this->request->getScope() == 'environment') { $project->ccId = $this->getEnvironment()->getPlatformConfigValue(\Scalr_Environment::SETTING_CC_ID); } else { $project->ccId = $ccId; } $cc = $this->getContainer()->analytics->ccs->get($project->ccId); if (!empty($cc)) { if ($cc->getProperty(CostCentrePropertyEntity::NAME_LOCKED) == 1) { throw new Scalr_Exception_InsufficientPermissions(); } $email = $cc->getProperty(CostCentrePropertyEntity::NAME_LEAD_EMAIL); $emailData = ['projectName' => $name, 'ccName' => $cc->name]; } else { throw new Scalr_UI_Exception_NotFound(); } $project->shared = ProjectEntity::SHARED_WITHIN_ACCOUNT; $project->accountId = $this->user->getAccountId(); $project->createdById = $this->user->id; $project->createdByEmail = $this->user->getEmail(); } $project->name = $name; $this->db->BeginTrans(); try { $project->save(); //NOTE please take into account the presence of the usage->createHostedScalrAccountCostCenter() method $project->saveProperty(ProjectPropertyEntity::NAME_BILLING_CODE, $billingCode); $project->saveProperty(ProjectPropertyEntity::NAME_DESCRIPTION, $description); $project->saveProperty(ProjectPropertyEntity::NAME_LEAD_EMAIL, $leadEmail); $this->db->CommitTrans(); } catch (Exception $e) { $this->db->RollbackTrans(); throw $e; } if (!$projectId && !empty($email)) { \Scalr::getContainer()->mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/analytics_on_project_add.eml.php', $emailData, $email); } $this->response->data(['project' => $this->getProjectData($project)]); $this->response->success('Project has been successfully saved'); }
/** * @param int $accountId * @param RawData $password * @param RawData $cpassword * @param RawData $currentPassword * @throws Exception */ public function xSaveOwnerPasswordAction($accountId, $password, $cpassword, $currentPassword) { $account = new Scalr_Account(); $account->loadById($accountId); $validator = new Validator(); $validator->addErrorIf(!$this->user->checkPassword($currentPassword), ['currentPassword'], 'Invalid password'); $validator->validate($password, 'password', Validator::NOEMPTY); $validator->validate($cpassword, 'cpassword', Validator::NOEMPTY); $validator->addErrorIf($password && $cpassword && $password != $cpassword, ['password', 'cpassword'], 'Two passwords are not equal'); if ($validator->isValid($this->response)) { $user = $account->getOwner(); $user->updatePassword($password); $user->save(); // Send notification E-mail $this->getContainer()->mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/password_change_admin_notification.eml', array('{{fullname}}' => $user->fullname ? $user->fullname : $user->getEmail(), '{{administratorFullName}}' => $this->user->fullname ? $this->user->fullname : $this->user->getEmail()), $user->getEmail(), $user->fullname); $this->response->success('Password successfully updated'); } }
/** * @param int $id * @param string $url * @param string $username * @param string $authKey * @param string $vUsername * @param string $vAuthKey * @throws Exception */ public function xSaveAction($id, $url, $username, $authKey, $vUsername, $vAuthKey) { if (!$this->canManageServers()) { throw new Scalr_Exception_InsufficientPermissions(); } if (!$id) { $server = new ChefServer(); $server->setScope($this->request->getScope(), $this->user->getAccountId(), $this->getEnvironmentId(true)); } else { $server = ChefServer::findPk($id); if (!$this->canEditServer($server)) { throw new Scalr_Exception_Core('Insufficient permissions to edit chef server at this scope'); } } $validator = new Validator(); $validator->validate($url, 'url', Validator::NOEMPTY); //check url unique within current scope $criteria = []; $criteria[] = ['url' => $url]; if ($server->id) { $criteria[] = ['id' => ['$ne' => $server->id]]; } switch ($this->request->getScope()) { case ChefServer::SCOPE_ENVIRONMENT: $criteria[] = ['level' => ChefServer::LEVEL_ENVIRONMENT]; $criteria[] = ['envId' => $server->envId]; $criteria[] = ['accountId' => $server->accountId]; break; case ChefServer::SCOPE_ACCOUNT: $criteria[] = ['level' => ChefServer::LEVEL_ACCOUNT]; $criteria[] = ['envId' => null]; $criteria[] = ['accountId' => $server->accountId]; break; case ChefServer::SCOPE_SCALR: $criteria[] = ['level' => ChefServer::LEVEL_SCALR]; $criteria[] = ['envId' => null]; $criteria[] = ['accountId' => null]; break; } if (ChefServer::findOne($criteria)) { $validator->addError('url', 'Url must be unique within current scope'); } if (!$validator->isValid($this->response)) { return; } $authKey = str_replace("\r\n", "\n", $authKey); $vAuthKey = str_replace("\r\n", "\n", $vAuthKey); $server->url = $url; $server->username = $username; $server->vUsername = $vUsername; $server->authKey = $this->getCrypto()->encrypt($authKey); $server->vAuthKey = $this->getCrypto()->encrypt($vAuthKey); $chef = Scalr_Service_Chef_Client::getChef($server->url, $server->username, $authKey); $response = $chef->listCookbooks(); $chef2 = Scalr_Service_Chef_Client::getChef($server->url, $server->vUsername, $vAuthKey); $clientName = 'scalr-temp-client-' . rand(10000, 99999); $response = $chef2->createClient($clientName); $response2 = $chef->removeClient($clientName); $server->save(); $this->response->data(array('server' => $this->getServerData($server))); $this->response->success('Chef server successfully saved'); }
/** * @param string $serverId * @param string $name * @param string $description * @param bool $createRole * @param string $scope * @param string $replaceRole * @param bool $replaceImage * @param int $rootVolumeSize * @param string $rootVolumeType * @param int $rootVolumeIops * @throws Exception */ public function xServerCreateSnapshotAction($serverId, $name = '', $description = '', $createRole = false, $scope = '', $replaceRole = '', $replaceImage = false, $rootVolumeSize = 0, $rootVolumeType = '', $rootVolumeIops = 0) { $this->request->restrictAccess(Acl::RESOURCE_IMAGES_ENVIRONMENT, Acl::PERM_IMAGES_ENVIRONMENT_MANAGE); $server = $this->getServerEntity($serverId); $this->request->checkPermissions($server, true); $farm = $server->getFarm(); $role = $server->getFarmRole()->getRole(); //Check for already running bundle on selected instance if ($this->db->GetOne("SELECT id FROM bundle_tasks WHERE server_id=? AND status NOT IN ('success', 'failed') LIMIT 1", array($server->serverId))) { throw new Exception(sprintf(_("Server '%s' is already synchonizing."), $server->serverId)); } $validator = new Validator(); $validator->addErrorIf(!Entity\Role::isValidName($name), 'name', "Role name is incorrect"); $validator->addErrorIf(!in_array($replaceRole, ['farm', 'all', '']), 'replaceRole', 'Invalid value'); $object = $createRole ? BundleTask::BUNDLETASK_OBJECT_ROLE : BundleTask::BUNDLETASK_OBJECT_IMAGE; $replaceType = SERVER_REPLACEMENT_TYPE::NO_REPLACE; $createScope = ScopeInterface::SCOPE_ENVIRONMENT; if ($createRole) { $this->request->restrictAccess(Acl::RESOURCE_ROLES_ENVIRONMENT, Acl::PERM_ROLES_ENVIRONMENT_MANAGE); if ($replaceRole == 'farm') { if ($farm->hasAccessPermissions($this->getUser(), $this->getEnvironment(), Acl::PERM_FARMS_UPDATE)) { $replaceType = SERVER_REPLACEMENT_TYPE::REPLACE_FARM; } else { $validator->addError('replaceRole', "You don't have permissions to update farm"); } } else { if ($replaceRole == 'all') { if ($this->request->isAllowed([Acl::RESOURCE_FARMS, Acl::RESOURCE_TEAM_FARMS, Acl::RESOURCE_OWN_FARMS], Acl::PERM_FARMS_UPDATE)) { $replaceType = SERVER_REPLACEMENT_TYPE::REPLACE_ALL; } else { $validator->addError('replaceRole', "You don't have permissions to update farms"); } } } /* @var $existRole Entity\Role */ $existRole = Entity\Role::findOne([['name' => $name], ['$or' => [['accountId' => null], ['$and' => [['accountId' => $this->getUser()->accountId], ['$or' => [['envId' => null], ['envId' => $this->getEnvironment()->id]]]]]]]]); if ($existRole) { if (empty($existRole->accountId)) { $validator->addError('name', _("Selected role name is reserved and cannot be used for custom role")); } else { if ($replaceType != SERVER_REPLACEMENT_TYPE::REPLACE_ALL) { $validator->addError('name', _("Specified role name is already used by another role. You can use this role name only if you will replace old one on ALL your farms.")); } else { if ($replaceType == SERVER_REPLACEMENT_TYPE::REPLACE_ALL && $existRole->id != $role->id) { $validator->addError('name', _("Specified role name is already in use. You cannot replace a Role different from the one you are currently snapshotting.")); } } } } if ($btId = BundleTask::getActiveTaskIdByName($name, $this->getUser()->accountId, $this->getEnvironment()->id)) { $validator->addError('name', sprintf("Specified role name is already reserved for BundleTask with ID: %d.", $btId)); } if ($replaceType != SERVER_REPLACEMENT_TYPE::NO_REPLACE) { $chk = BundleTask::getActiveTaskIdByRoleId($role->id, $this->getEnvironment()->id, BundleTask::BUNDLETASK_OBJECT_ROLE); $validator->addErrorIf($chk, 'replaceRole', sprintf("Role is already synchronizing in BundleTask: %d.", $chk)); } } else { $sc = $role->getScope(); if ($replaceImage) { if ($sc == ScopeInterface::SCOPE_ENVIRONMENT && $this->request->isAllowed(Acl::RESOURCE_ROLES_ENVIRONMENT, Acl::PERM_ROLES_ENVIRONMENT_MANAGE) || $sc == ScopeInterface::SCOPE_ACCOUNT && $this->request->isAllowed(Acl::RESOURCE_ROLES_ACCOUNT, Acl::PERM_ROLES_ACCOUNT_MANAGE)) { $replaceType = SERVER_REPLACEMENT_TYPE::REPLACE_ALL; $chk = BundleTask::getActiveTaskIdByRoleId($role->id, $this->getEnvironment()->id, BundleTask::BUNDLETASK_OBJECT_IMAGE); $validator->addErrorIf($chk, 'replaceImage', sprintf("Role is already synchronizing in BundleTask: %d.", $chk)); } else { $validator->addError('replaceImage', "You don't have permissions to replace image in role"); } } } if ($scope && ($createRole || $scope != $createScope)) { if ($createRole) { $c = $scope == ScopeInterface::SCOPE_ENVIRONMENT && $this->request->isAllowed(Acl::RESOURCE_ROLES_ENVIRONMENT, Acl::PERM_ROLES_ENVIRONMENT_MANAGE) || $scope == ScopeInterface::SCOPE_ACCOUNT && $this->request->isAllowed(Acl::RESOURCE_ROLES_ACCOUNT, Acl::PERM_ROLES_ACCOUNT_MANAGE); $validator->addErrorIf(!$c, 'scope', sprintf("You don't have permissions to create role in scope %s", $scope)); } $c = $scope == ScopeInterface::SCOPE_ENVIRONMENT && $this->request->isAllowed(Acl::RESOURCE_IMAGES_ENVIRONMENT, Acl::PERM_IMAGES_ENVIRONMENT_MANAGE) || $scope == ScopeInterface::SCOPE_ACCOUNT && $this->request->isAllowed(Acl::RESOURCE_IMAGES_ACCOUNT, Acl::PERM_IMAGES_ACCOUNT_MANAGE); $validator->addErrorIf(!$c, 'scope', sprintf("You don't have permissions to create image in scope %s", $scope)); $createScope = $scope; } $image = $role->getImage($server->platform, $server->cloudLocation)->getImage(); $rootBlockDevice = []; if ($server->platform == SERVER_PLATFORMS::EC2 && ($server->isVersionSupported('0.7') && $server->os == 'linux' || $image->isEc2HvmImage())) { if ($rootVolumeSize > 0) { $rootBlockDevice['size'] = $rootVolumeSize; } if (in_array($rootVolumeType, [CreateVolumeRequestData::VOLUME_TYPE_STANDARD, CreateVolumeRequestData::VOLUME_TYPE_GP2, CreateVolumeRequestData::VOLUME_TYPE_IO1, CreateVolumeRequestData::VOLUME_TYPE_SC1, CreateVolumeRequestData::VOLUME_TYPE_ST1])) { $rootBlockDevice['volume_type'] = $rootVolumeType; if ($rootVolumeType == CreateVolumeRequestData::VOLUME_TYPE_IO1 && $rootVolumeIops > 0) { $rootBlockDevice['iops'] = $rootVolumeIops; } } } if (!$validator->isValid($this->response)) { return; } $ServerSnapshotCreateInfo = new ServerSnapshotCreateInfo(DBServer::LoadByID($server->serverId), $name, $replaceType, $object, $description, $rootBlockDevice); $BundleTask = BundleTask::Create($ServerSnapshotCreateInfo); $BundleTask->createdById = $this->user->id; $BundleTask->createdByEmail = $this->user->getEmail(); $BundleTask->osId = $role->osId; $BundleTask->objectScope = $createScope; if ($role->getOs()->family == 'windows') { $BundleTask->osFamily = $role->getOs()->family; $BundleTask->osVersion = $role->getOs()->generation; $BundleTask->osName = ''; } else { $BundleTask->osFamily = $role->getOs()->family; $BundleTask->osVersion = $role->getOs()->version; $BundleTask->osName = $role->getOs()->name; } if (in_array($role->getOs()->family, array('redhat', 'oel', 'scientific')) && $server->platform == SERVER_PLATFORMS::EC2) { $BundleTask->bundleType = SERVER_SNAPSHOT_CREATION_TYPE::EC2_EBS_HVM; } $BundleTask->save(); $this->response->data(['bundleTaskId' => $BundleTask->id]); $this->response->success("Bundle task successfully created."); }
/** * @param string $hash * @param RawData $password */ public function xUpdatePasswordAction($hash, RawData $password) { if ($hash && ($user = Scalr_Account_User::init()->loadBySetting(Scalr_Account::SETTING_OWNER_PWD_RESET_HASH, $hash)) && $password) { $validator = new Validator(); $validator->validate($password, "password", Validator::PASSWORD, $user->isAccountAdmin() || $user->isAccountOwner() ? ['admin'] : []); if ($validator->isValid($this->response)) { $user->updatePassword($password); $user->loginattempts = 0; $user->save(); $user->setSetting(Scalr_Account::SETTING_OWNER_PWD_RESET_HASH, ""); $this->response->data(['email' => $user->getEmail(), 'message' => 'Password has been reset. Please log in.']); } } else { $this->response->failure("Incorrect confirmation link"); } }
/** * @param int $id * @param string $name * @param string $description * @param int $isSync * @param int $envId optional * @param int $timeout optional * @param int $version * @param RawData $content * @param string $tags * @param string $uploadType optional * @param string $uploadUrl optional * @param FileUploadData $uploadFile optional * @throws Scalr_UI_Exception_NotFound * @throws Scalr_Exception_InsufficientPermissions * @throws Exception */ public function xSaveAction($id, $name, $description, $isSync = 0, $envId = 2, $timeout = NULL, $version, RawData $content, $tags, $uploadType = NULL, $uploadUrl = NULL, FileUploadData $uploadFile = NULL) { $this->request->restrictAccess(Acl::RESOURCE_ADMINISTRATION_SCRIPTS, Acl::PERM_ADMINISTRATION_SCRIPTS_MANAGE); $validator = new Validator(); $validator->validate($name, 'name', Validator::NOEMPTY); if ($uploadType) { $content = false; if ($uploadType == 'URL') { $content = @file_get_contents($uploadUrl); $validator->validate($content, 'uploadUrl', Validator::NOEMPTY, [], 'Invalid source'); } else { if ($uploadType == 'File') { $content = $uploadFile; $validator->validate($content, 'uploadFile', Validator::NOEMPTY, [], 'Invalid source'); } else { $validator->addError('uploadType', 'Invalid source for script'); } } } $content = str_replace("\r\n", "\n", $content); $tagsResult = []; foreach (explode(',', $tags) as $t) { $t = trim($t); if ($t) { if (!preg_match('/^[a-zA-Z0-9-]{3,10}$/', $t)) { $validator->addError('tags', sprintf('Invalid name for tag: %s', $t)); } $tagsResult[] = $t; } } $tags = $tagsResult; if (!$validator->isValid($this->response)) { return; } /* @var Script $script */ if ($id) { $script = Script::findPk($id); if (!$script) { throw new Scalr_UI_Exception_NotFound(); } $script->checkPermission($this->user, $this->getEnvironmentId(true)); if (!$script->accountId && $this->user->getType() != Scalr_Account_User::TYPE_SCALR_ADMIN) { throw new Scalr_Exception_InsufficientPermissions(); } } else { $script = new Script(); $script->accountId = $this->user->getAccountId() ? $this->user->getAccountId() : NULL; $script->createdById = $this->user->getId(); $script->createdByEmail = $this->user->getEmail(); $version = 1; } if ($this->user->isScalrAdmin()) { $envId = NULL; } else { if (!in_array($envId, array_map(function ($e) { return $e['id']; }, $this->user->getEnvironments()))) { $envId = NULL; } } $script->name = $name; $script->description = $description; $script->timeout = $timeout ? $timeout : NULL; $script->isSync = $isSync == 1 ? 1 : 0; $script->envId = $envId; $script->os = !strncmp($content, '#!cmd', strlen('#!cmd')) || !strncmp($content, '#!powershell', strlen('#!powershell')) ? Script::OS_WINDOWS : Script::OS_LINUX; $script->save(); $scriptVersion = NULL; if ($version) { $scriptVersion = $script->getVersion($version); } if (!$scriptVersion && $script->getLatestVersion()->content !== $content) { $scriptVersion = new ScriptVersion(); $scriptVersion->scriptId = $script->id; $scriptVersion->version = $script->getLatestVersion()->version + 1; } if ($scriptVersion) { $scriptVersion->changedById = $this->user->getId(); $scriptVersion->changedByEmail = $this->user->getEmail(); $scriptVersion->content = $content; $scriptVersion->save(); } if ($this->user->getAccountId()) { Tag::setTags($tags, $this->user->getAccountId(), Tag::RESOURCE_SCRIPT, $script->id); } $this->response->success('Script successfully saved'); }
public function xSaveAction() { $this->request->defineParams(array('teams' => array('type' => 'json'), 'action', 'password' => array('type' => 'string', 'rawValue' => true), 'currentPassword' => array('type' => 'string', 'rawValue' => true))); $newUser = $existingPasswordChanged = $sendResetLink = false; $user = Scalr_Account_User::init(); $validator = new Validator(); $id = (int) $this->getParam('id'); if ($id) { $user->loadById($id); } else { if ($this->getContainer()->config->get('scalr.auth_mode') == 'ldap') { throw new Exception("Adding new users is not supported with LDAP user management"); } $newUser = true; } if ($this->getContainer()->config->get('scalr.auth_mode') != 'ldap') { $email = $this->getParam('email'); if (($isEmailValid = $validator->validateEmail($email)) !== true) { throw new Scalr_Exception_Core($isEmailValid); } $password = $this->getParam('password'); if (empty($password) && ($this->request->hasParam('password') || $newUser)) { if ($user->id == $this->user->id) { $this->response->data(['errors' => ['password' => 'You cannot reset password for yourself']]); $this->response->failure(); return; } $password = Scalr::GenerateSecurePassword($user->isAccountAdmin() || $user->isAccountOwner() ? User::PASSWORD_ADMIN_LENGTH : User::PASSWORD_USER_LENGTH); $sendResetLink = true; } else { if ($this->request->hasParam('password') && ($isPasswordValid = $validator->validatePassword($password, $user->isAccountAdmin() || $user->isAccountOwner() ? ['admin'] : [])) !== true) { $this->response->data(['errors' => ['password' => $isPasswordValid]]); $this->response->failure(); return; } if (!empty($password)) { $existingPasswordChanged = true; } } if (!$newUser && ($sendResetLink || $existingPasswordChanged) && $this->request->hasParam('password') && !$this->user->checkPassword($this->getParam('currentPassword'), false)) { $this->response->data(['errors' => ['currentPassword' => 'Invalid password']]); $this->response->failure(); return; } if ($id) { if (!$this->user->canEditUser($user)) { throw new Scalr_Exception_InsufficientPermissions(); } $user->updateEmail($email); } else { $this->user->getAccount()->validateLimit(Scalr_Limits::ACCOUNT_USERS, 1); $user->type = Scalr_Account_User::TYPE_TEAM_USER; $user->create($email, $this->user->getAccountId()); } if (!empty($password)) { $user->updatePassword($password); } } if ($user->getId() != $this->user->getId() && in_array($this->getParam('status'), array(Scalr_Account_User::STATUS_ACTIVE, Scalr_Account_User::STATUS_INACTIVE))) { $user->status = $this->getParam('status'); } if (!$user->isAccountOwner()) { if ($this->getParam('isAccountAdmin')) { if ($this->user->isAccountOwner()) { $user->type = $this->getParam('isAccountSuperAdmin') ? Scalr_Account_User::TYPE_ACCOUNT_SUPER_ADMIN : Scalr_Account_User::TYPE_ACCOUNT_ADMIN; } else { if ($this->user->isAccountAdmin() && $user->type != Scalr_Account_User::TYPE_ACCOUNT_SUPER_ADMIN) { $user->type = Scalr_Account_User::TYPE_ACCOUNT_ADMIN; } } } else { $user->type = Scalr_Account_User::TYPE_TEAM_USER; } } $user->fullname = $this->getParam('fullname'); $user->comments = $this->getParam('comments'); $user->save(); if (!empty($password)) { $user->setSetting(Scalr_Account::SETTING_OWNER_PWD_RESET_HASH, ""); } $user->setAclRoles($this->getParam('teams')); if ($this->getParam('enableApi')) { $keys = Scalr::GenerateAPIKeys(); $user->setSetting(Scalr_Account_User::SETTING_API_ENABLED, true); $user->setSetting(Scalr_Account_User::SETTING_API_ACCESS_KEY, $keys['id']); $user->setSetting(Scalr_Account_User::SETTING_API_SECRET_KEY, $keys['key']); } $creatorName = $this->user->fullname; if (empty($creatorName)) { $creatorName = $this->user->isAccountOwner() ? 'Account owner' : ($this->user->isAccountAdmin() ? 'Account admin' : 'Team user'); } if ($newUser) { try { $clientinfo = array('fullname' => $user->fullname, 'firstname' => $user->fullname, 'email' => $user->getEmail(), 'password' => $password); $url = Scalr::config('scalr.endpoint.scheme') . "://" . Scalr::config('scalr.endpoint.host'); $res = $this->getContainer()->mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/referral.eml.php', array("creatorName" => $creatorName, "clientFirstname" => $clientinfo['firstname'], "email" => $clientinfo['email'], "password" => $clientinfo['password'], "siteUrl" => $url, "wikiUrl" => \Scalr::config('scalr.ui.wiki_url'), "supportUrl" => \Scalr::config('scalr.ui.support_url'), "isUrl" => preg_match('/^http(s?):\\/\\//i', \Scalr::config('scalr.ui.support_url'))), $user->getEmail()); } catch (Exception $e) { } } elseif ($sendResetLink) { try { $hash = $this->getCrypto()->sault(10); $url = Scalr::config('scalr.endpoint.scheme') . "://" . Scalr::config('scalr.endpoint.host'); $user->setSetting(Scalr_Account::SETTING_OWNER_PWD_RESET_HASH, $hash); $clientinfo = array('email' => $user->getEmail(), 'fullname' => $user->fullname); $res = $this->getContainer()->mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/user_account_confirm.eml', array("{{fullname}}" => $clientinfo['fullname'], "{{pwd_link}}" => "{$url}/?resetPasswordHash={$hash}"), $clientinfo['email'], $clientinfo['fullname']); } catch (Exception $e) { } } else { if ($existingPasswordChanged) { // Send notification E-mail $this->getContainer()->mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/password_change_notification.eml', array('{{fullname}}' => $user->fullname ? $user->fullname : $user->getEmail()), $user->getEmail(), $user->fullname); } } $userTeams = array(); $troles = $this->getContainer()->acl->getUserRoleIdsByTeam($user->id, array_map(create_function('$v', 'return $v["id"];'), $user->getTeams()), $user->getAccountId()); foreach ($troles as $teamId => $roles) { $userTeams[$teamId] = array('roles' => $roles); } $data = ['user' => $user->getUserInfo(), 'teams' => $userTeams]; if ($existingPasswordChanged && $user->getId() == $this->user->getId()) { Scalr_Session::create($this->user->getId()); $data['specialToken'] = Scalr_Session::getInstance()->getToken(); } $this->response->data($data); $this->response->success('User successfully saved'); }
/** * @param int $id * @param string $email * @param string $type * @param RawData $password * @param string $status * @param string $fullname * @param string $comments * @param RawData $currentPassword optional * @throws Scalr_Exception_Core * @throws Scalr_Exception_InsufficientPermissions */ public function xSaveAction($id = 0, $email, $type, RawData $password, $status, $fullname, $comments, RawData $currentPassword = null) { $user = Scalr_Account_User::init(); $validator = new Validator(); $isNewUser = empty($id); $isExistingPasswordChanged = false; $password = (string) $password; if (!$isNewUser && $password && !$this->user->checkPassword($currentPassword, false)) { $this->response->data(['errors' => ['currentPassword' => 'Invalid password']]); $this->response->failure(); return; } if ($password || $isNewUser) { $validator->validate($password, 'password', Validator::PASSWORD, ['admin']); } $validator->validate($email, 'email', Validator::NOEMPTY); if ($type == User::TYPE_FIN_ADMIN) { $validator->validate($email, 'email', Validator::EMAIL); } if ($isNewUser) { $validator->addErrorIf($this->db->GetOne("SELECT EXISTS(SELECT 1 FROM `account_users` WHERE email = ?)", [$email]), 'email', 'This email is already in use.'); } $validator->addErrorIf(!in_array($type, [User::TYPE_SCALR_ADMIN, User::TYPE_FIN_ADMIN]), 'type', 'Type is not valid'); $validator->addErrorIf(!in_array($status, [User::STATUS_ACTIVE, User::STATUS_INACTIVE]), 'type', 'Status is not valid'); if (!$validator->isValid($this->response)) { return; } if (!$isNewUser) { $user->loadById($id); if ($user->getEmail() == 'admin' && $user->getId() != $this->user->getId()) { throw new Scalr_Exception_InsufficientPermissions(); } if ($user->getEmail() != 'admin') { $user->updateEmail($email); } } else { $user->create($email, $this->user->getAccountId()); $user->type = $type; } if ($password) { $user->updatePassword($password); if (!$isNewUser) { $isExistingPasswordChanged = true; } } if ($user->getEmail() != 'admin') { $user->status = $status; $user->type = $type; $user->fullname = $fullname; $user->comments = $comments; } $user->save(); // Send notification E-mail if ($isExistingPasswordChanged) { $this->getContainer()->mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/password_change_admin_notification.eml', array('{{fullname}}' => $user->fullname ? $user->fullname : $user->getEmail(), '{{administratorFullName}}' => $this->user->fullname ? $this->user->fullname : $this->user->getEmail()), $user->getEmail(), $user->fullname); } else { if ($isNewUser) { $this->getContainer()->mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/user_new_admin_notification.eml', array('{{fullname}}' => $user->fullname ? $user->fullname : $user->getEmail(), '{{subject}}' => $user->type == Scalr_Account_User::TYPE_FIN_ADMIN ? 'Financial Admin for Scalr Cost Analytics' : 'Admin for Scalr', '{{user_type}}' => $user->type == Scalr_Account_User::TYPE_FIN_ADMIN ? 'a Financial Admin' : 'an Admin', '{{link}}' => Scalr::config('scalr.endpoint.scheme') . "://" . Scalr::config('scalr.endpoint.host')), $user->getEmail(), $user->fullname); } } $this->response->success('User successfully saved'); }
/** * @param string $cloudLocation * @param string $availabilityZone * @param int $size * @param string $snapshotId * @param bool $encrypted * @param string $kmsKeyId * @param string $type * @param int $iops * @param string $serverId * @param bool $mount * @param string $mountPoint */ public function xCreateAction($cloudLocation, $availabilityZone, $size, $snapshotId = null, $encrypted = false, $kmsKeyId = null, $type = 'standard', $iops = null, $serverId = null, $mount = false, $mountPoint = null) { $this->request->restrictAccess(Acl::RESOURCE_AWS_VOLUMES, Acl::PERM_AWS_VOLUMES_MANAGE); $aws = $this->getEnvironment()->aws($cloudLocation); $decision = $this->getFilteringDecision(); $validator = new Validator(); if (empty($serverId) && $decision->mode == CloudResourceScopeMode::MODE_MANAGED_FARMS) { $validator->addError('serverId', 'Your permissions do not allow you to create EBS volume without attaching it to the Server.'); } if ($encrypted && $kmsKeyId) { $kmsKey = $aws->kms->key->describe($kmsKeyId); if (!$kmsKey->enabled) { $validator->addError('kmsKeyId', 'This KMS Key is disabled, please choose another one.'); } } if (!$validator->isValid($this->response)) { return; } $req = new CreateVolumeRequestData($availabilityZone, $size); if ($snapshotId) { $req->snapshotId = $snapshotId; } if ($encrypted) { $req->encrypted = true; if ($kmsKeyId) { $req->kmsKeyId = $kmsKeyId; } } if (in_array($type, [CreateVolumeRequestData::VOLUME_TYPE_STANDARD, CreateVolumeRequestData::VOLUME_TYPE_GP2, CreateVolumeRequestData::VOLUME_TYPE_IO1, CreateVolumeRequestData::VOLUME_TYPE_ST1, CreateVolumeRequestData::VOLUME_TYPE_SC1])) { $req->volumeType = $type; if ($type == CreateVolumeRequestData::VOLUME_TYPE_IO1) { $req->iops = $iops ? $iops : 100; } } $info = $aws->ec2->volume->create($req); if ($serverId) { //TODO You can attach only volume in available state $attempts = 6; while ($info->status != 'available' && $attempts--) { sleep(2); $info = $aws->ec2->volume->describe($info->volumeId)->get(0); } $this->attachVolumeToServer($info); } else { //Creates tags for the AWS resource $aws->ec2->tag->create($info->volumeId, $this->getEnvironment()->getAwsTags()); } $this->response->success('EBS volume has been successfully created'); $this->response->data(array('data' => array('volumeId' => $info->volumeId))); }
/** * xSaveAction * * @param string $ccId * @param string $projectId * @param string $name * @param string $description * @param string $billingCode * @param string $leadEmail * @param int $shared * @param int $accountId optional * @param bool $checkAccountAccessToCc optional * @param bool $grantAccountAccessToCc optional * @throws Scalr_Exception_InsufficientPermissions */ public function xSaveAction($ccId, $projectId, $name, $description, $billingCode, $leadEmail, $shared, $accountId = null, $checkAccountAccessToCc = true, $grantAccountAccessToCc = false) { $validator = new Validator(); $validator->validate($name, 'name', Validator::NOEMPTY); if ($projectId) { $project = $this->getContainer()->analytics->projects->get($projectId); if (!$project) { throw new Scalr_UI_Exception_NotFound(); } } else { $project = new ProjectEntity(); $project->createdById = $this->user->id; $project->createdByEmail = $this->user->getEmail(); $cc = $this->getContainer()->analytics->ccs->get($ccId); if (!$cc) { $validator->addError('ccId', 'Cost center ID should be set'); } $project->ccId = $ccId; } if ($shared == ProjectEntity::SHARED_WITHIN_ACCOUNT) { $project->shared = ProjectEntity::SHARED_WITHIN_ACCOUNT; $project->accountId = $accountId; } elseif ($shared == ProjectEntity::SHARED_WITHIN_CC) { $project->shared = ProjectEntity::SHARED_WITHIN_CC; $project->accountId = null; } else { throw new Scalr_UI_Exception_NotFound(); } if (!$validator->isValid($this->response)) { return; } if ($project->shared == ProjectEntity::SHARED_WITHIN_ACCOUNT) { if (!AccountCostCenterEntity::findOne([['accountId' => $project->accountId], ['ccId' => $ccId]])) { if ($checkAccountAccessToCc) { $this->response->data(['ccIsNotAllowedToAccount' => true]); $this->response->failure(); return; } elseif ($grantAccountAccessToCc) { //give account access to cc $accountCcEntity = new AccountCostCenterEntity($project->accountId, $ccId); $accountCcEntity->save(); } } } $project->name = $name; $this->db->BeginTrans(); try { $project->save(); //NOTE please take into account the presence of the usage->createHostedScalrAccountCostCenter() method $project->saveProperty(ProjectPropertyEntity::NAME_BILLING_CODE, $billingCode); $project->saveProperty(ProjectPropertyEntity::NAME_DESCRIPTION, $description); $project->saveProperty(ProjectPropertyEntity::NAME_LEAD_EMAIL, $leadEmail); $this->db->CommitTrans(); } catch (Exception $e) { $this->db->RollbackTrans(); throw $e; } $this->response->data(['project' => $this->getProjectData($project)]); $this->response->success('Project has been successfully saved'); }
/** * @param RawData $password * @param RawData $cpassword * @param $securityIpWhitelist * @param RawData $currentPassword optional */ public function xSecuritySaveAction(RawData $password, RawData $cpassword, $securityIpWhitelist, RawData $currentPassword = null) { $validator = new Validator(); if ($password != '******') { $validator->addErrorIf(!$this->user->checkPassword($currentPassword), ['currentPassword'], 'Invalid password'); } $validator->validate($password, 'password', Validator::NOEMPTY); $validator->validate($cpassword, 'cpassword', Validator::NOEMPTY); $validator->addErrorIf($password && $cpassword && $password != $cpassword, ['password', 'cpassword'], 'Two passwords are not equal'); $subnets = array(); $securityIpWhitelist = trim($securityIpWhitelist); if ($securityIpWhitelist) { $whitelist = explode(',', $securityIpWhitelist); foreach ($whitelist as $mask) { $sub = Scalr_Util_Network::convertMaskToSubnet($mask); if ($sub) { $subnets[] = $sub; } else { $validator->addError('securityIpWhitelist', sprintf('Not valid mask: %s', $mask)); } } } if (count($subnets) && !Scalr_Util_Network::isIpInSubnets($this->request->getRemoteAddr(), $subnets)) { $validator->addError('securityIpWhitelist', 'New IP access whitelist doesn\'t correspond your current IP address'); } if ($validator->isValid($this->response)) { $updateSession = false; if ($password != '******') { $this->user->updatePassword($password); $updateSession = true; // Send notification E-mail $this->getContainer()->mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/password_change_notification.eml', array('{{fullname}}' => $this->user->fullname ? $this->user->fullname : $this->user->getEmail()), $this->user->getEmail(), $this->user->fullname); } $this->user->setVar(Scalr_Account_User::VAR_SECURITY_IP_WHITELIST, count($subnets) ? serialize($subnets) : ''); $this->user->save(); if ($updateSession) { Scalr_Session::create($this->user->getId()); $this->response->data(['specialToken' => Scalr_Session::getInstance()->getToken()]); } $this->response->success('Security settings successfully updated'); } }
/** * @param string $webhookId * @param string $name * @param JsonData $endpoints * @param JsonData $events * @param JsonData $farms * @param int $timeout * @param int $attempts * @param boolean $skipPrivateGv * @param string $postData * @throws Exception */ public function xSaveAction($webhookId, $name, JsonData $endpoints, JsonData $events, JsonData $farms, $timeout = 3, $attempts = 3, $skipPrivateGv = 0, $postData = '') { if (!$webhookId) { $webhook = new WebhookConfig(); $webhook->setScope($this->request->getScope(), $this->user->getAccountId(), $this->getEnvironmentId(true)); } else { $webhook = WebhookConfig::findPk($webhookId); if (!$this->canManageWebhook($webhook)) { throw new Scalr_Exception_Core('Insufficient permissions to edit webhook'); } } $validator = new Validator(); $validator->validate($name, 'name', Validator::NOEMPTY); if (!$validator->isValid($this->response)) { return; } $webhook->name = $name; $webhook->postData = $postData; $webhook->skipPrivateGv = $skipPrivateGv; $webhook->timeout = $timeout; $webhook->attempts = $attempts; $webhook->save(); //save endpoints $endpoints = (array) $endpoints; foreach (WebhookConfigEndpoint::findByWebhookId($webhook->webhookId) as $webhookConfigEndpoint) { $index = array_search($webhookConfigEndpoint->endpointId, $endpoints); if ($index === false) { $webhookConfigEndpoint->delete(); } else { unset($endpoints[$index]); } } if (!empty($endpoints)) { $criteria = []; $criteria[] = ['endpointId' => ['$in' => $endpoints]]; switch ($this->request->getScope()) { case WebhookConfig::SCOPE_ENVIRONMENT: $criteria[] = ['$or' => [['$and' => [['accountId' => $this->user->getAccountId()], ['envId' => $this->getEnvironmentId()], ['level' => WebhookConfig::LEVEL_ENVIRONMENT]]], ['$and' => [['accountId' => $this->user->getAccountId()], ['envId' => null], ['level' => WebhookConfig::LEVEL_ACCOUNT]]], ['$and' => [['accountId' => null], ['envId' => null], ['level' => WebhookConfig::LEVEL_SCALR]]]]]; break; case WebhookConfig::SCOPE_ACCOUNT: $criteria[] = ['$or' => [['$and' => [['accountId' => $this->user->getAccountId()], ['envId' => null], ['level' => WebhookConfig::LEVEL_ACCOUNT]]], ['$and' => [['accountId' => null], ['envId' => null], ['level' => WebhookConfig::LEVEL_SCALR]]]]]; break; case WebhookConfig::SCOPE_SCALR: $criteria[] = ['level' => WebhookConfig::LEVEL_SCALR]; $criteria[] = ['envId' => null]; $criteria[] = ['accountId' => null]; break; } foreach (WebhookEndpoint::find($criteria) as $endpoint) { $configEndpoint = new WebhookConfigEndpoint(); $configEndpoint->webhookId = $webhook->webhookId; $configEndpoint->setEndpoint($endpoint); $configEndpoint->save(); } } //save events $allEvents = $this->getEventsList(); $events = (array) $events; foreach (WebhookConfigEvent::findByWebhookId($webhook->webhookId) as $event) { $index = array_search($event->eventType, $events); if ($index === false) { if (isset($allEvents[$event->eventType])) { //20486-rebundlecomplete-emails - we shouldn't remove some events(RebundleComplete...) $event->delete(); } } else { unset($events[$index]); } } foreach ($events as $event) { /*if (!isset(EVENT_TYPE::getScriptingEvents()[$event])) { continue; }*/ $configEvent = new WebhookConfigEvent(); $configEvent->webhookId = $webhook->webhookId; $configEvent->eventType = $event; $configEvent->save(); } //save farms $farms = (array) $farms; if (empty($farms)) { $farms = [0]; } foreach (WebhookConfigFarm::findByWebhookId($webhook->webhookId) as $farm) { $index = array_search($farm->farmId, $farms); if ($index === false) { $farm->delete(); } else { unset($farms[$index]); } } foreach ($farms as $farmId) { $configFarm = new WebhookConfigFarm(); $configFarm->webhookId = $webhook->webhookId; $configFarm->farmId = $farmId; $configFarm->save(); } $endpoints = []; foreach ($webhook->getEndpoints() as $endpoint) { $endpoints[] = $endpoint->endpointId; } $events = []; foreach ($webhook->getEvents() as $event) { $events[] = $event->eventType; } $farms = []; foreach ($webhook->getFarms() as $farm) { if ($farm->farmId) { $farms[] = $farm->farmId; } } $this->response->success('Webhook successfully saved'); $this->response->data(array('webhook' => array('webhookId' => $webhook->webhookId, 'name' => $webhook->name, 'postData' => $webhook->postData, 'timeout' => $webhook->timeout, 'attempts' => $webhook->attempts, 'skipPrivateGv' => $webhook->skipPrivateGv, 'endpoints' => $endpoints, 'events' => $events, 'farms' => $farms, 'scope' => $webhook->getScope()))); }
/** * Add or update announcement message * * @param string $msg Announcement's text * @param string $title Announcement's title * @param int $id optional Announcement's ID * @throws Exception * @throws Scalr_Exception_Core * @throws Scalr_Exception_InsufficientPermissions * @throws \Scalr\Exception\ModelException */ public function xSaveAction($msg, $title, $id = null) { $this->request->restrictAccess(Acl::RESOURCE_ANNOUNCEMENTS); /* @var $announcement Scalr\Model\Entity\Announcement */ if (empty($id)) { $announcement = new Announcement(); /* @var $user Scalr\Model\Entity\Account\User */ $user = $this->getUser(); $announcement->accountId = $user->accountId ?: null; $announcement->createdById = $user->id; $announcement->createdByEmail = $user->email; $announcement->added = new \DateTime(); } else { $announcement = Announcement::findPk($id); if (!$announcement) { throw new Exception('Announcement was not found'); } $this->request->checkPermissions($announcement, true); } $validator = new Validator(); $validator->validate($msg, 'msg', $validator::NOEMPTY); $validator->validate($title, 'title', $validator::NOEMPTY); $validator->addErrorIf(strlen($title) > 100, 'title', 'Maximum length for this field is 100'); if (!$validator->isValid($this->response)) { return; } $announcement->title = $title; $announcement->msg = $msg; $announcement->save(); $this->response->data(['announcement' => $this->prepareDataForList($announcement)]); $this->response->success("Announcement saved"); }
/** * @param $password * @param $cpassword * @param $securityIpWhitelist */ public function xSecuritySaveAction($password, $cpassword, $securityIpWhitelist) { $validator = new Validator(); $validator->validate($password, 'password', Validator::NOEMPTY); $validator->validate($cpassword, 'cpassword', Validator::NOEMPTY); $validator->addErrorIf($password && $cpassword && $password != $cpassword, ['password', 'cpassword'], 'Two passwords are not equal'); $subnets = array(); $securityIpWhitelist = trim($securityIpWhitelist); if ($securityIpWhitelist) { $whitelist = explode(',', $securityIpWhitelist); foreach ($whitelist as $mask) { $sub = Scalr_Util_Network::convertMaskToSubnet($mask); if ($sub) { $subnets[] = $sub; } else { $validator->addError('securityIpWhitelist', sprintf('Not valid mask: %s', $mask)); } } } if (count($subnets) && !Scalr_Util_Network::isIpInSubnets($this->request->getRemoteAddr(), $subnets)) { $validator->addError('securityIpWhitelist', 'New IP access whitelist doesn\'t correspond your current IP address'); } if ($validator->isValid($this->response)) { $updateSession = false; if ($password != '******') { $this->user->updatePassword($password); $updateSession = true; } $this->user->setVar(Scalr_Account_User::VAR_SECURITY_IP_WHITELIST, count($subnets) ? serialize($subnets) : ''); $this->user->save(); if ($updateSession) { Scalr_Session::create($this->user->getId()); } $this->response->success('Security settings successfully updated'); } }
/** * * @param array $farmSettings * @param array $roles * @return bool */ private function isFarmConfigurationValid($farmId, $farmSettings, array $roles = array()) { $this->errors = array('error_count' => 0); $farmVariables = new Scalr_Scripting_GlobalVariables($this->user->getAccountId(), $this->getEnvironmentId(), ScopeInterface::SCOPE_FARM); $farmRoleVariables = new Scalr_Scripting_GlobalVariables($this->user->getAccountId(), $this->getEnvironmentId(), ScopeInterface::SCOPE_FARMROLE); $name = $this->request->stripValue($farmSettings['name']); if (empty($name)) { $this->setBuildError('name', 'Farm name is invalid'); } if ($farmSettings['variables']) { $result = $farmVariables->validateValues(is_array($farmSettings['variables']) ? $farmSettings['variables'] : [], 0, $farmId); if ($result !== TRUE) { $this->setBuildError('variables', $result); } } if (is_numeric($farmSettings['owner'])) { try { $u = (new Scalr_Account_User())->loadById($farmSettings['owner']); if ($u->getAccountId() != $this->user->getAccountId()) { throw new Exception('User not found'); } } catch (Exception $e) { $this->setBuildError('owner', $e->getMessage()); } } if (is_numeric($farmSettings['teamOwner']) && $farmSettings['teamOwner'] > 0) { if ($this->user->canManageAcl()) { $teams = $this->db->getAll('SELECT id, name FROM account_teams WHERE account_id = ?', array($this->user->getAccountId())); } else { $teams = $this->user->getTeams(); } if (!in_array($farmSettings['teamOwner'], array_map(function ($t) { return $t['id']; }, $teams))) { if ($this->db->GetOne('SELECT team_id FROM farms WHERE id = ?', [$farmId]) != $farmSettings['teamOwner']) { $this->setBuildError('teamOwner', 'Team not found'); } } } if (!empty($roles)) { $hasVpcRouter = false; $vpcRouterRequired = false; $governance = new Scalr_Governance($this->getEnvironmentId()); foreach ($roles as $role) { $dbRole = DBRole::loadById($role['role_id']); if (!$this->hasPermissions($dbRole->__getNewRoleObject())) { $this->setBuildError($dbRole->name, 'You don\'t have access to this role'); } try { $dbRole->__getNewRoleObject()->getImage($role['platform'], $role['cloud_location']); } catch (Exception $e) { $this->setBuildError($dbRole->name, sprintf("Role '%s' is not available in %s on %s", $dbRole->name, $role['platform'], $role['cloud_location'])); } if ($role['alias']) { if (!preg_match("/^[[:alnum:]](?:-*[[:alnum:]])*\$/", $role['alias'])) { $this->setBuildError('alias', 'Alias should start and end with letter or number and contain only letters, numbers and dashes.', $role['farm_role_id']); } } // Validate deployments if (isset($role[Scalr_Role_Behavior::ROLE_DM_APPLICATION_ID])) { $application = Scalr_Dm_Application::init()->loadById($role[Scalr_Role_Behavior::ROLE_DM_APPLICATION_ID]); $this->user->getPermissions()->validate($application); if (!$role[Scalr_Role_Behavior::ROLE_DM_REMOTE_PATH]) { $this->setBuildError(Scalr_Role_Behavior::ROLE_DM_REMOTE_PATH, 'Remote path is required for deployment', $role['farm_role_id']); } } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::VPC_ROUTER)) { $hasVpcRouter = true; } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::RABBITMQ)) { $role['settings'][Entity\FarmRoleSetting::SCALING_MAX_INSTANCES] = $role['settings'][Entity\FarmRoleSetting::SCALING_MIN_INSTANCES]; $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO] = (int) $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO]; if ($role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO] < 1 || $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO] > 100) { $this->setBuildError(Scalr_Role_Behavior_RabbitMQ::ROLE_NODES_RATIO, 'Nodes ratio should be an integer between 1 and 100', $role['farm_role_id']); } else { $this->checkInteger($role['farm_role_id'], Scalr_Role_Behavior_RabbitMQ::ROLE_DATA_STORAGE_EBS_SIZE, $role['settings'][Scalr_Role_Behavior_RabbitMQ::ROLE_DATA_STORAGE_EBS_SIZE], 'Storage size', 1, 1000); } } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::MONGODB)) { if ($role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_ENGINE] == 'ebs') { if ($role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_EBS_SIZE] < 10 || $role['settings'][Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_EBS_SIZE] > 1000) { $this->setBuildError(Scalr_Role_Behavior_MongoDB::ROLE_DATA_STORAGE_EBS_SIZE, sprintf("EBS size for mongoDB role should be between 10 and 1000 GB", $dbRole->name), $role['farm_role_id']); } } } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::NGINX)) { $proxies = (array) @json_decode($role['settings'][Scalr_Role_Behavior_Nginx::ROLE_PROXIES], true); foreach ($proxies as $proxyIndex => $proxy) { if ($proxy['ssl'] == 1) { if (empty($proxy['ssl_certificate_id'])) { $this->setBuildError(Scalr_Role_Behavior_Nginx::ROLE_PROXIES, ['message' => 'SSL certificate is required', 'invalidIndex' => $proxyIndex], $role['farm_role_id']); break; } if ($proxy['port'] == $proxy['ssl_port']) { $this->setBuildError(Scalr_Role_Behavior_Nginx::ROLE_PROXIES, ['message' => 'HTTP and HTTPS ports cannot be the same', 'invalidIndex' => $proxyIndex], $role['farm_role_id']); } } if (count($proxy['backends']) > 0) { foreach ($proxy['backends'] as $backend) { if (empty($backend['farm_role_id']) && empty($backend['farm_role_alias']) && empty($backend['host'])) { $this->setBuildError(Scalr_Role_Behavior_Nginx::ROLE_PROXIES, ['message' => 'Destination is required', 'invalidIndex' => $proxyIndex], $role['farm_role_id']); break; } } } } } /* Validate scaling */ if (!$dbRole->hasBehavior(ROLE_BEHAVIORS::VPC_ROUTER) && !$dbRole->hasBehavior(ROLE_BEHAVIORS::MONGODB)) { $minCount = $this->checkInteger($role['farm_role_id'], Entity\FarmRoleSetting::SCALING_MIN_INSTANCES, $role['settings'][Entity\FarmRoleSetting::SCALING_MIN_INSTANCES], 'Min instances', 0, 400); $maxCount = $this->checkInteger($role['farm_role_id'], Entity\FarmRoleSetting::SCALING_MAX_INSTANCES, $role['settings'][Entity\FarmRoleSetting::SCALING_MAX_INSTANCES], 'Max instances', 1, 400); if ($minCount !== false && $maxCount !== false && $maxCount < $minCount) { $this->setBuildError(Entity\FarmRoleSetting::SCALING_MAX_INSTANCES, 'Max instances should be greater than or equal to Min instances', $role['farm_role_id']); } $this->checkInteger($role['farm_role_id'], Entity\FarmRoleSetting::SCALING_POLLING_INTERVAL, $role['settings'][Entity\FarmRoleSetting::SCALING_POLLING_INTERVAL], 'Polling interval', 1, 50); if (array_key_exists(Entity\FarmRoleSetting::SCALING_UPSCALE_TIMEOUT_ENABLED, $role["settings"]) && $role['settings'][Entity\FarmRoleSetting::SCALING_UPSCALE_TIMEOUT_ENABLED] == 1) { $this->checkInteger($role['farm_role_id'], Entity\FarmRoleSetting::SCALING_UPSCALE_TIMEOUT, $role['settings'][Entity\FarmRoleSetting::SCALING_UPSCALE_TIMEOUT], 'Upscale timeout', 1); } if (array_key_exists(Entity\FarmRoleSetting::SCALING_DOWNSCALE_TIMEOUT_ENABLED, $role["settings"]) && $role['settings'][Entity\FarmRoleSetting::SCALING_DOWNSCALE_TIMEOUT_ENABLED] == 1) { $this->checkInteger($role['farm_role_id'], Entity\FarmRoleSetting::SCALING_DOWNSCALE_TIMEOUT, $role['settings'][Entity\FarmRoleSetting::SCALING_DOWNSCALE_TIMEOUT], 'Downscale timeout', 1); } if (is_array($role['scaling'])) { foreach ($role['scaling'] as $metricId => $metricSettings) { $hasError = false; if ($metricId == Entity\ScalingMetric::METRIC_URL_RESPONSE_TIME_ID) { $hasError = Validator::validateUrl($metricSettings['url']) !== true || Validator::validateInteger($metricSettings['min']) !== true || Validator::validateInteger($metricSettings['max']) !== true; } elseif ($metricId == Entity\ScalingMetric::METRIC_SQS_QUEUE_SIZE_ID) { $hasError = Validator::validateNotEmpty($metricSettings['queue_name']) !== true || Validator::validateInteger($metricSettings['min']) !== true || Validator::validateInteger($metricSettings['max']) !== true; } elseif (in_array($metricId, [Entity\ScalingMetric::METRIC_LOAD_AVERAGES_ID, Entity\ScalingMetric::METRIC_FREE_RAM_ID, Entity\ScalingMetric::METRIC_BANDWIDTH_ID])) { $hasError = Validator::validateFloat($metricSettings['min']) !== true || Validator::validateFloat($metricSettings['max']) !== true; } if ($hasError) { $this->setBuildError('scaling', ['message' => 'Scaling metric settings are invalid', 'invalidIndex' => $metricId], $role['farm_role_id']); break; } } } } /* Validate advanced settings */ if (!$dbRole->hasBehavior(ROLE_BEHAVIORS::VPC_ROUTER)) { if (isset($role['settings'][Scalr_Role_Behavior::ROLE_BASE_API_PORT])) { $this->checkInteger($role['farm_role_id'], Scalr_Role_Behavior::ROLE_BASE_API_PORT, $role['settings'][Scalr_Role_Behavior::ROLE_BASE_API_PORT], 'Scalarizr API port', 1, 65535); } if (isset($role['settings'][Scalr_Role_Behavior::ROLE_BASE_MESSAGING_PORT])) { $this->checkInteger($role['farm_role_id'], Scalr_Role_Behavior::ROLE_BASE_MESSAGING_PORT, $role['settings'][Scalr_Role_Behavior::ROLE_BASE_MESSAGING_PORT], 'Scalarizr control port', 1, 65535); } if (isset($role['settings'][Entity\FarmRoleSetting::SYSTEM_REBOOT_TIMEOUT])) { $this->checkInteger($role['farm_role_id'], Entity\FarmRoleSetting::SYSTEM_REBOOT_TIMEOUT, $role['settings'][Entity\FarmRoleSetting::SYSTEM_REBOOT_TIMEOUT], 'Reboot timeout', 1); } if (isset($role['settings'][Entity\FarmRoleSetting::SYSTEM_LAUNCH_TIMEOUT])) { $this->checkInteger($role['farm_role_id'], Entity\FarmRoleSetting::SYSTEM_LAUNCH_TIMEOUT, $role['settings'][Entity\FarmRoleSetting::SYSTEM_LAUNCH_TIMEOUT], 'Launch timeout', 1); } } /* Validate chef settings */ if ($dbRole->hasBehavior(ROLE_BEHAVIORS::CHEF)) { if ($role['settings'][Scalr_Role_Behavior_Chef::ROLE_CHEF_BOOTSTRAP] == 1) { if (empty($role['settings'][Scalr_Role_Behavior_Chef::ROLE_CHEF_COOKBOOK_URL]) && empty($role['settings'][Scalr_Role_Behavior_Chef::ROLE_CHEF_SERVER_ID])) { $this->setBuildError(Scalr_Role_Behavior_Chef::ROLE_CHEF_SERVER_ID, 'Chef Server or Chef Solo must be setup if using Chef to bootstrap Role', $role['farm_role_id']); } elseif ($role['settings'][Scalr_Role_Behavior_Chef::ROLE_CHEF_COOKBOOK_URL_TYPE] == 'http' && !empty($role['settings'][Scalr_Role_Behavior_Chef::ROLE_CHEF_COOKBOOK_URL]) && Validator::validateUrl($role['settings'][Scalr_Role_Behavior_Chef::ROLE_CHEF_COOKBOOK_URL]) !== true) { $this->setBuildError(Scalr_Role_Behavior_Chef::ROLE_CHEF_COOKBOOK_URL, 'Cookbook URL is invalid.', $role['farm_role_id']); } } elseif ($dbRole->getProperty(Scalr_Role_Behavior_Chef::ROLE_CHEF_BOOTSTRAP) == 1 && $dbRole->getProperty(Scalr_Role_Behavior_Chef::ROLE_CHEF_SERVER_ID)) { if (strpos($role['farm_role_id'], "virtual_") !== false) { $chefGovernance = $governance->getValue(Scalr_Governance::CATEGORY_GENERAL, Scalr_Governance::GENERAL_CHEF, 'servers'); if ($chefGovernance !== null && !isset($chefGovernance[$dbRole->getProperty(Scalr_Role_Behavior_Chef::ROLE_CHEF_SERVER_ID)])) { $this->setBuildError(Scalr_Role_Behavior_Chef::ROLE_CHEF_SERVER_ID, 'Chef server is not allowed by Governance.', $role['farm_role_id']); } } if (empty($dbRole->getProperty(Scalr_Role_Behavior_Chef::ROLE_CHEF_ENVIRONMENT)) && empty($role['settings'][Scalr_Role_Behavior_Chef::ROLE_CHEF_ENVIRONMENT])) { $this->setBuildError(Scalr_Role_Behavior_Chef::ROLE_CHEF_ENVIRONMENT, 'Chef Environment is required', $role['farm_role_id']); } } } /** Validate platform specified settings **/ switch ($role['platform']) { case SERVER_PLATFORMS::EC2: if (!empty($role['settings'][Entity\FarmRoleSetting::AWS_TAGS_LIST])) { $reservedBaseCustomTags = ['scalr-meta', 'Name']; $baseCustomTags = @explode("\n", $role['settings'][Entity\FarmRoleSetting::AWS_TAGS_LIST]); foreach ((array) $baseCustomTags as $tag) { $tag = trim($tag); $tagChunks = explode("=", $tag); if (in_array(trim($tagChunks[0]), $reservedBaseCustomTags)) { $this->setBuildError(Entity\FarmRoleSetting::AWS_TAGS_LIST, "Avoid using Scalr-reserved tag names.", $role['farm_role_id']); } } } if ($dbRole->hasBehavior(ROLE_BEHAVIORS::MYSQL)) { if ($role['settings'][Entity\FarmRoleSetting::MYSQL_DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::EBS) { if ($dbRole->generation != 2 && isset($role['settings'][Entity\FarmRoleSetting::AWS_AVAIL_ZONE])) { if ($role['settings'][Entity\FarmRoleSetting::AWS_AVAIL_ZONE] == "" || $role['settings'][Entity\FarmRoleSetting::AWS_AVAIL_ZONE] == "x-scalr-diff" || stristr($role['settings'][Entity\FarmRoleSetting::AWS_AVAIL_ZONE], 'x-scalr-custom')) { $this->setBuildError(Entity\FarmRoleSetting::AWS_AVAIL_ZONE, 'Requirement for EBS MySQL data storage is specific \'Placement\' parameter', $role['farm_role_id']); } } } } if ($dbRole->getDbMsrBehavior()) { if ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::EPH) { if (!$role['settings'][Scalr_Db_Msr::DATA_STORAGE_EPH_DISK] && !$role['settings'][Scalr_Db_Msr::DATA_STORAGE_EPH_DISKS]) { $this->setBuildError(Scalr_Db_Msr::DATA_STORAGE_EPH_DISK, 'Ephemeral disk settings is required', $role['farm_role_id']); } } elseif ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::EBS) { if (array_key_exists(Scalr_Db_Msr::DATA_STORAGE_EBS_TYPE, $role["settings"])) { if ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_TYPE] == CreateVolumeRequestData::VOLUME_TYPE_STANDARD) { $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_STORAGE_EBS_SIZE, $role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_SIZE], 'Storage size', 1, 1024); } elseif ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_TYPE] == CreateVolumeRequestData::VOLUME_TYPE_GP2) { $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_STORAGE_EBS_SIZE, $role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_SIZE], 'Storage size', 1, 16384); } elseif ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_TYPE] == CreateVolumeRequestData::VOLUME_TYPE_IO1) { $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_STORAGE_EBS_SIZE, $role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_SIZE], 'Storage size', 4, 16384); $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_STORAGE_EBS_IOPS, $role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_IOPS], 'IOPS', 100, 20000); } } } if (array_key_exists(Scalr_Db_Msr::DATA_STORAGE_EBS_ENABLE_ROTATION, $role["settings"]) && $role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_ENABLE_ROTATION] == 1) { $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_STORAGE_EBS_ROTATE, $role['settings'][Scalr_Db_Msr::DATA_STORAGE_EBS_ROTATE], 'Snapshot rotation limit', 1); } if ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::LVM) { if (!$role['settings'][Scalr_Role_DbMsrBehavior::ROLE_DATA_STORAGE_LVM_VOLUMES]) { $this->setBuildError(Scalr_Role_DbMsrBehavior::ROLE_DATA_STORAGE_LVM_VOLUMES, 'LVM storage settings is required', $role['farm_role_id']); } } } if ($role['settings'][Entity\FarmRoleSetting::AWS_AVAIL_ZONE] == 'x-scalr-custom=') { $this->setBuildError(Entity\FarmRoleSetting::AWS_AVAIL_ZONE, 'Availability zone should be selected', $role['farm_role_id']); } if (!empty($farmSettings['vpc_id'])) { $sgs = @json_decode($role['settings'][Entity\FarmRoleSetting::AWS_SECURITY_GROUPS_LIST]); if (!$governance->getValue(SERVER_PLATFORMS::EC2, Scalr_Governance::AWS_SECURITY_GROUPS) && !$dbRole->hasBehavior(ROLE_BEHAVIORS::VPC_ROUTER) && empty($sgs) && empty($role['settings'][Entity\FarmRoleSetting::AWS_SG_LIST])) { $this->setBuildError(Entity\FarmRoleSetting::AWS_SECURITY_GROUPS_LIST, 'Security group(s) should be selected', $role['farm_role_id']); } $subnets = @json_decode($role['settings'][Entity\FarmRoleSetting::AWS_VPC_SUBNET_ID]); if (empty($subnets)) { $this->setBuildError(Entity\FarmRoleSetting::AWS_VPC_SUBNET_ID, 'VPC Subnet(s) should be selected', $role['farm_role_id']); } if (\Scalr::config('scalr.instances_connection_policy') != 'local' && empty($role['settings'][Scalr_Role_Behavior_Router::ROLE_VPC_SCALR_ROUTER_ID])) { try { if (!empty($subnets[0])) { $platform = PlatformFactory::NewPlatform(SERVER_PLATFORMS::EC2); $info = $platform->listSubnets($this->getEnvironment(), $role['cloud_location'], $farmSettings['vpc_id'], true, $subnets[0]); if (!empty($info["type"]) && $info['type'] == 'private') { $vpcRouterRequired = $role['farm_role_id']; } } } catch (Exception $e) { } } } break; case SERVER_PLATFORMS::CLOUDSTACK: if (!$role['settings'][Entity\FarmRoleSetting::CLOUDSTACK_SERVICE_OFFERING_ID]) { $this->setBuildError(Entity\FarmRoleSetting::CLOUDSTACK_SERVICE_OFFERING_ID, 'Service offering should be selected', $role['farm_role_id']); } break; case SERVER_PLATFORMS::RACKSPACE: if (!$role['settings'][Entity\FarmRoleSetting::RS_FLAVOR_ID]) { $this->setBuildError(Entity\FarmRoleSetting::CLOUDSTACK_SERVICE_OFFERING_ID, 'Flavor should be selected', $role['farm_role_id']); } break; case SERVER_PLATFORMS::GCE: if ($dbRole->getDbMsrBehavior()) { if ($role['settings'][Scalr_Db_Msr::DATA_STORAGE_ENGINE] == MYSQL_STORAGE_ENGINE::GCE_PERSISTENT) { $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_STORAGE_GCED_SIZE, $role['settings'][Scalr_Db_Msr::DATA_STORAGE_GCED_SIZE], 'Storage size', 1); } } break; } if ($dbRole->getDbMsrBehavior()) { if (array_key_exists(Scalr_Db_Msr::DATA_BUNDLE_ENABLED, $role["settings"]) && $role['settings'][Scalr_Db_Msr::DATA_BUNDLE_ENABLED] == 1) { $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_BUNDLE_EVERY, $role['settings'][Scalr_Db_Msr::DATA_BUNDLE_EVERY], 'Bundle period', 1); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_START_HH, $role['settings'][Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_START_HH], 'Preferred bundle window start HH is invalid', '/^([0-1][0-9])|(2[0-4])$/'); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_START_MM, $role['settings'][Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_START_MM], 'Preferred bundle window start MM is invalid', '/^[0-5][0-9]$/'); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_END_HH, $role['settings'][Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_END_HH], 'Preferred bundle window end HH is invalid', '/^([0-1][0-9])|(2[0-4])$/'); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_END_MM, $role['settings'][Scalr_Db_Msr::DATA_BUNDLE_TIMEFRAME_END_MM], 'Preferred bundle window end MM is invalid', '/^[0-5][0-9]$/'); } if (array_key_exists(Scalr_Db_Msr::DATA_BACKUP_ENABLED, $role["settings"]) && $role['settings'][Scalr_Db_Msr::DATA_BACKUP_ENABLED] == 1) { $this->checkInteger($role['farm_role_id'], Scalr_Db_Msr::DATA_BACKUP_EVERY, $role['settings'][Scalr_Db_Msr::DATA_BACKUP_EVERY], 'Backup period', 1); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_START_HH, $role['settings'][Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_START_HH], 'Preferred backup window start HH is invalid', '/^([0-1][0-9])|(2[0-4])$/'); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_START_MM, $role['settings'][Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_START_MM], 'Preferred backup window start MM is invalid', '/^[0-5][0-9]$/'); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_END_HH, $role['settings'][Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_END_HH], 'Preferred backup window end HH is invalid', '/^([0-1][0-9])|(2[0-4])$/'); $this->checkString($role['farm_role_id'], Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_END_MM, $role['settings'][Scalr_Db_Msr::DATA_BACKUP_TIMEFRAME_END_MM], 'Preferred backup window end MM is invalid', '/^[0-5][0-9]$/'); } } if (!empty($role['settings'][Scalr_Role_Behavior::ROLE_BASE_CUSTOM_TAGS]) && PlatformFactory::isOpenstack($role['platform'])) { $reservedBaseCustomTags = ['scalr-meta', 'farmid', 'role', 'httpproto', 'region', 'hash', 'realrolename', 'szr_key', 'serverid', 'p2p_producer_endpoint', 'queryenv_url', 'behaviors', 'farm_roleid', 'roleid', 'env_id', 'platform', 'server_index', 'cloud_server_id', 'cloud_location_zone', 'owner_email']; $baseCustomTags = @explode("\n", $role['settings'][Scalr_Role_Behavior::ROLE_BASE_CUSTOM_TAGS]); foreach ((array) $baseCustomTags as $tag) { $tag = trim($tag); $tagChunks = explode("=", $tag); if (in_array(trim($tagChunks[0]), $reservedBaseCustomTags)) { $this->setBuildError(Scalr_Role_Behavior::ROLE_BASE_CUSTOM_TAGS, "Avoid using Scalr-reserved metadata names.", $role['farm_role_id']); } } } if (!empty($role['settings'][Scalr_Role_Behavior::ROLE_BASE_HOSTNAME_FORMAT])) { if (!preg_match('/^[\\w\\{\\}\\.-]+$/', $role['settings'][Scalr_Role_Behavior::ROLE_BASE_HOSTNAME_FORMAT])) { $this->setBuildError(Scalr_Role_Behavior::ROLE_BASE_HOSTNAME_FORMAT, "server hostname format for role'{$dbRole->name}' should contain only [a-z0-9-] chars. First char should not be hypen.", $role['farm_role_id']); } } if (!empty($role['settings'][Entity\FarmRoleSetting::DNS_CREATE_RECORDS])) { if ($role['settings'][Entity\FarmRoleSetting::DNS_EXT_RECORD_ALIAS]) { if (!preg_match('/^[\\w\\{\\}\\.-]+$/', $role['settings'][Entity\FarmRoleSetting::DNS_EXT_RECORD_ALIAS])) { $this->setBuildError(Entity\FarmRoleSetting::DNS_EXT_RECORD_ALIAS, "ext- record alias for role '{$dbRole->name}' should contain only [A-Za-z0-9-] chars. First and last char should not be hypen.", $role['farm_role_id']); } } if ($role['settings'][Entity\FarmRoleSetting::DNS_INT_RECORD_ALIAS]) { if (!preg_match('/^[\\w\\{\\}\\.-]+$/', $role['settings'][Entity\FarmRoleSetting::DNS_INT_RECORD_ALIAS])) { $this->setBuildError(Entity\FarmRoleSetting::DNS_INT_RECORD_ALIAS, "int- record alias for role '{$dbRole->name}' should contain only [A-Za-z0-9-] chars. First and last char should not by hypen.", $role['farm_role_id']); } } } // Validate Global variables if (!strstr($role['farm_role_id'], 'virtual_')) { $farmRole = DBFarmRole::LoadByID($role['farm_role_id']); } else { $farmRole = null; if ($dbRole->isDeprecated == 1) { $this->setBuildError('roleId', 'This role has been deprecated and cannot be added', $role['farm_role_id']); } if (!empty($envs = $dbRole->__getNewRoleObject()->getAllowedEnvironments())) { if (!in_array($this->getEnvironmentId(), $envs)) { $this->setBuildError('roleId', "You don't have access to this role", $role['farm_role_id']); } } } if (isset($role['storages']['configs'])) { // TODO: refactor, get rid of using DBFarmRole in constructor $fr = $farmRole ? $farmRole : new DBFarmRole(0); foreach ($fr->getStorage()->validateConfigs($role['storages']['configs']) as $index => $message) { $this->setBuildError('storages', ['message' => $message, 'invalidIndex' => $index], $role['farm_role_id']); break; } } $result = $farmRoleVariables->validateValues(is_array($role['variables']) ? $role['variables'] : [], $dbRole->id, $farmId, $farmRole ? $farmRole->ID : 0); if ($result !== TRUE) { $this->setBuildError('variables', $result, $role['farm_role_id']); } } } if ($farmSettings['vpc_id']) { if (!$hasVpcRouter && $vpcRouterRequired) { $this->setBuildError(Entity\FarmRoleSetting::AWS_VPC_SUBNET_ID, 'You must select a VPC Router for Farm Roles launched in a Private VPC Subnet', $vpcRouterRequired); } } if ($this->getContainer()->analytics->enabled) { if ($farmSettings['projectId']) { $project = $this->getContainer()->analytics->projects->get($farmSettings['projectId']); if (!$project) { $this->setBuildError('projectId', 'Project not found', null); } else { if ($project->ccId != $this->getEnvironment()->getPlatformConfigValue(Scalr_Environment::SETTING_CC_ID)) { $this->setBuildError('projectId', 'Invalid project identifier. Project should correspond to the Environment\'s cost center.', null); } } } else { $this->setBuildError('projectId', 'Project field is required', null); } } return $this->errors['error_count'] == 0 ? true : false; }