/** * Gets a list of environments by key * * @param string $query Search query * @return array Returns array of environments */ private function getEnvironmentsList($query = null) { $envs = []; $environments = $this->user->getEnvironments($query); if (count($environments) > 0) { $iterator = ChartPeriodIterator::create('month', gmdate('Y-m-01'), null, 'UTC'); //It calculates usage for all provided enviroments $usage = $this->getContainer()->analytics->usage->getFarmData($this->user->getAccountId(), [], $iterator->getStart(), $iterator->getEnd(), [TagEntity::TAG_ID_ENVIRONMENT, TagEntity::TAG_ID_FARM]); //It calculates usage for previous period same days $prevusage = $this->getContainer()->analytics->usage->getFarmData($this->user->getAccountId(), [], $iterator->getPreviousStart(), $iterator->getPreviousEnd(), [TagEntity::TAG_ID_ENVIRONMENT, TagEntity::TAG_ID_FARM]); foreach ($environments as $env) { if (isset($usage['data'][$env['id']]['data'])) { $envs[$env['id']]['topSpender'] = $this->getFarmTopSpender($usage['data'][$env['id']]['data']); } else { $envs[$env['id']]['topSpender'] = null; } $envs[$env['id']]['name'] = $env['name']; $envs[$env['id']]['envId'] = $env['id']; $ccId = \Scalr_Environment::init()->loadById($env['id'])->getPlatformConfigValue(\Scalr_Environment::SETTING_CC_ID); if (!empty($ccId)) { $envs[$env['id']]['ccId'] = $ccId; $envs[$env['id']]['ccName'] = CostCentreEntity::findPk($ccId)->name; } $totalCost = round(isset($usage['data'][$env['id']]) ? $usage['data'][$env['id']]['cost'] : 0, 2); $prevCost = round(isset($prevusage['data'][$env['id']]) ? $prevusage['data'][$env['id']]['cost'] : 0, 2); $envs[$env['id']] = $this->getWrappedUsageData(['iterator' => $iterator, 'usage' => $totalCost, 'prevusage' => $prevCost]) + $envs[$env['id']]; } } return array_values($envs); }
/** * Gets specified Script taking into account both scope and authentication token * * @param string $ccId Unique identifier of the Cost-Center * * @return CostCentreEntity Returns the Project Entity on success * * @throws ApiErrorException * */ public function getCostCenter($ccId) { /* @var $cc CostCentreEntity */ $cc = CostCentreEntity::findPk($ccId); if (!$cc) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Requested Cost Center either does not exist or is not owned by your environment."); } if (!$this->hasPermissions($cc)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } return $cc; }
/** * @test */ public function textComplex() { $ccs = $this->listCostCenters(); $adapter = $this->getAdapter('costCenter'); foreach ($ccs as $cc) { foreach ($adapter->getRules()[ApiEntityAdapter::RULE_TYPE_FILTERABLE] as $property) { foreach ($this->listCostCenters([$property => $cc->{$property}]) as $filteredProject) { $this->assertEquals($cc->{$property}, $filteredProject->{$property}); } } $response = $this->getCostCenter($cc->id); $this->assertEquals(200, $response->status, $this->printResponseError($response)); $dbProject = CostCentreEntity::findPk($cc->id); $this->assertObjectEqualsEntity($response->getBody()->data, $dbProject, $adapter); } }
/** * Edit project action * * @param string $projectId * @throws Scalr_UI_Exception_NotFound */ public function editAction($projectId = null) { $scope = $this->request->getScope(); $this->request->restrictAccess(Acl::RESOURCE_ANALYTICS_ACCOUNT, Acl::PERM_ANALYTICS_ACCOUNT_MANAGE_PROJECTS); if (!empty($projectId)) { $project = $this->getContainer()->analytics->projects->get($projectId); if ($project->shared != ProjectEntity::SHARED_WITHIN_ACCOUNT || $project->accountId != $this->user->getAccountId()) { throw new Scalr_Exception_InsufficientPermissions(); } $cc = $project->getCostCenter(); $projectData = $this->getProjectData($project, true); //Check whether it can be removed try { $projectData['removable'] = $project->checkRemoval(); } catch (AnalyticsException $e) { $projectData['removable'] = false; $projectData['warning'] = $e->getMessage(); } } else { if ($scope == 'environment') { $cc = $this->getContainer()->analytics->ccs->get($this->getEnvironment()->getPlatformConfigValue(\Scalr_Environment::SETTING_CC_ID)); } $projectData = []; } $ccs = []; if ($scope == 'environment') { $accountCcs = AccountCostCenterEntity::findOne([['accountId' => $this->user->getAccountId()], ['ccId' => $cc->ccId]]); if ($accountCcs instanceof AccountCostCenterEntity) { $ccs[$cc->ccId] = ['ccId' => $cc->ccId, 'name' => $cc->name, 'billingCode' => $cc->getProperty(CostCentrePropertyEntity::NAME_BILLING_CODE)]; } } elseif ($scope == 'account') { foreach ($this->user->getEnvironments() as $row) { $env = \Scalr_Environment::init()->loadById($row['id']); $ccEntity = CostCentreEntity::findPk($env->getPlatformConfigValue(\Scalr_Environment::SETTING_CC_ID)); /* @var $ccEntity \Scalr\Stats\CostAnalytics\Entity\CostCentreEntity */ if ($ccEntity) { $accountCcs = AccountCostCenterEntity::findOne([['accountId' => $env->clientId], ['ccId' => $ccEntity->ccId]]); if ($accountCcs instanceof AccountCostCenterEntity) { $ccs[$ccEntity->ccId] = ['ccId' => $ccEntity->ccId, 'name' => $ccEntity->name, 'billingCode' => $ccEntity->getProperty(CostCentrePropertyEntity::NAME_BILLING_CODE)]; } } } } $this->response->page('ui/admin/analytics/projects/edit.js', array('project' => $projectData, 'ccs' => $ccs, 'scope' => 'account')); }
/** * Gets specified Script taking into account both scope and authentication token * * @param string $ccId Unique identifier of the Cost-Center * * @return CostCentreEntity Returns the Project Entity on success * * @throws ApiErrorException * */ public function getCostCenter($ccId) { //TODO: correct ACL resource $this->checkPermissions(Acl::RESOURCE_ANALYTICS_PROJECTS); if ($ccId != $this->getEnvironmentCostCenterId()) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Requested Cost Center either does not exist or is not owned by your environment."); } /* @var $cc CostCentreEntity */ $cc = CostCentreEntity::findPk($ccId); if (!$cc) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Requested Cost Center either does not exist or is not owned by your environment."); } if (!$this->hasPermissions($cc)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } return $cc; }
public function applyGlobalVarsToValue($value) { if (empty($this->globalVariablesCache)) { $formats = \Scalr::config("scalr.system.global_variables.format"); $at = new Entity\Account\Team(); $ft = new Entity\FarmTeam(); $teams = Entity\Account\Team::find([\Scalr\Model\AbstractEntity::STMT_FROM => "{$at->table()} JOIN {$ft->table()} ON {$ft->columnTeamId} = {$at->columnId}", \Scalr\Model\AbstractEntity::STMT_WHERE => "{$ft->columnFarmId} = '{$this->ID}'"])->map(function ($t) { return $t->name; }); $systemVars = array('env_id' => $this->EnvID, 'env_name' => $this->GetEnvironmentObject()->name, 'farm_team' => join(",", $teams), 'farm_id' => $this->ID, 'farm_name' => $this->Name, 'farm_hash' => $this->Hash, 'farm_owner_email' => $this->createdByUserEmail); if (\Scalr::getContainer()->analytics->enabled) { $projectId = $this->GetSetting(Entity\FarmSetting::PROJECT_ID); if ($projectId) { $project = ProjectEntity::findPk($projectId); /* @var $project ProjectEntity */ $systemVars['project_id'] = $projectId; $systemVars['project_bc'] = $project->getProperty(ProjectPropertyEntity::NAME_BILLING_CODE); $systemVars['project_name'] = $project->name; $ccId = $project->ccId; } if ($ccId) { $cc = CostCentreEntity::findPk($ccId); if ($cc) { /* @var $cc CostCentreEntity */ $systemVars['cost_center_id'] = $ccId; $systemVars['cost_center_bc'] = $cc->getProperty(CostCentrePropertyEntity::NAME_BILLING_CODE); $systemVars['cost_center_name'] = $cc->name; } else { throw new Exception("Cost center {$ccId} not found"); } } } // Get list of Server system vars foreach ($systemVars as $name => $val) { $name = "SCALR_" . strtoupper($name); $val = trim($val); if (isset($formats[$name])) { $val = @sprintf($formats[$name], $val); } $this->globalVariablesCache[$name] = $val; } // Add custom variables $gv = new Scalr_Scripting_GlobalVariables($this->ClientID, $this->EnvID, ScopeInterface::SCOPE_FARM); $vars = $gv->listVariables(0, $this->ID); foreach ($vars as $v) { $this->globalVariablesCache[$v['name']] = $v['value']; } } //Parse variable $keys = array_keys($this->globalVariablesCache); $keys = array_map(function ($item) { return '{' . $item . '}'; }, $keys); $values = array_values($this->globalVariablesCache); $retval = str_replace($keys, $values, $value); // Strip undefined variables & return value return preg_replace("/{[A-Za-z0-9_-]+}/", "", $retval); }
/** * * @return array */ public function GetScriptingVars() { $dbFarmRole = $this->GetFarmRoleObject(); $roleId = $dbFarmRole->RoleID; $dbRole = DBRole::loadById($roleId); $isDbMsr = $dbRole->getDbMsrBehavior(); if ($isDbMsr) { $isMaster = $this->GetProperty(Scalr_Db_Msr::REPLICATION_MASTER); } else { $isMaster = $this->GetProperty(\SERVER_PROPERTIES::DB_MYSQL_MASTER); } $retval = array('image_id' => $dbRole->__getNewRoleObject()->getImage($this->platform, $dbFarmRole->CloudLocation)->imageId, 'external_ip' => $this->remoteIp, 'internal_ip' => $this->localIp, 'role_name' => $dbRole->name, 'isdbmaster' => $isMaster, 'instance_index' => $this->index, 'instance_farm_index' => $this->farmIndex, 'server_type' => $this->type, 'server_hostname' => $this->GetProperty(Scalr_Role_Behavior::SERVER_BASE_HOSTNAME), 'server_id' => $this->serverId, 'farm_id' => $this->farmId, 'farm_role_id' => $this->farmRoleId, 'farm_role_alias' => $this->GetFarmRoleObject()->Alias, 'farm_name' => $this->GetFarmObject()->Name, 'farm_hash' => $this->GetFarmObject()->Hash, 'farm_owner_email' => $this->GetFarmObject()->createdByUserEmail, 'farm_team' => $this->GetFarmObject()->teamId ? (new Scalr_Account_Team())->loadById($this->GetFarmObject()->teamId)->name : '', 'behaviors' => implode(",", $dbRole->getBehaviors()), 'env_id' => $this->GetEnvironmentObject()->id, 'env_name' => $this->GetEnvironmentObject()->name, 'cloud_location' => $this->GetCloudLocation(), 'cloud_server_id' => $this->GetCloudServerID()); if ($this->cloudLocationZone) { $retval['cloud_location_zone'] = $this->cloudLocationZone; } if ($this->platform == SERVER_PLATFORMS::EC2) { $retval['instance_id'] = $this->GetProperty(EC2_SERVER_PROPERTIES::INSTANCE_ID); $retval['ami_id'] = $this->GetProperty(EC2_SERVER_PROPERTIES::AMIID); $retval['region'] = $this->GetProperty(EC2_SERVER_PROPERTIES::REGION); $retval['avail_zone'] = $this->GetProperty(EC2_SERVER_PROPERTIES::AVAIL_ZONE); if ($dbFarmRole->GetSetting(Entity\FarmRoleSetting::AWS_ELB_ENABLED)) { $elbId = $dbFarmRole->GetSetting(Entity\FarmRoleSetting::AWS_ELB_ID); $retval['aws_elb_name'] = $elbId; } } if (\Scalr::getContainer()->analytics->enabled) { $ccId = $this->GetProperty(\SERVER_PROPERTIES::ENV_CC_ID); if ($ccId) { $cc = CostCentreEntity::findPk($ccId); if ($cc) { /* @var $cc CostCentreEntity */ $retval['cost_center_id'] = $ccId; $retval['cost_center_bc'] = $cc->getProperty(CostCentrePropertyEntity::NAME_BILLING_CODE); $retval['cost_center_name'] = $cc->name; } else { throw new Exception("Cost center {$ccId} not found"); } } $projectId = $this->GetProperty(\SERVER_PROPERTIES::FARM_PROJECT_ID); if ($projectId) { $project = ProjectEntity::findPk($projectId); /* @var $project ProjectEntity */ $retval['project_id'] = $projectId; $retval['project_bc'] = $project->getProperty(ProjectPropertyEntity::NAME_BILLING_CODE); $retval['project_name'] = $project->name; } } return $retval; }
/** * Checks if user has access to project or cost center * * @param string $projectId optional Id of the project * @param string $ccId optional Id of the cost center * @return boolean Returns false if user is not lead of the subject */ public function isSubjectLead($projectId = null, $ccId = null) { if (!empty($projectId)) { $project = ProjectEntity::findPk($projectId); if (empty($project) || $project->getProperty(ProjectPropertyEntity::NAME_LEAD_EMAIL) !== $this->getEmail()) { return false; } } else { if (!empty($ccId)) { $ccs = CostCentreEntity::findPk($ccId); if (empty($ccs) || $ccs->getProperty(CostCentrePropertyEntity::NAME_LEAD_EMAIL) !== $this->getEmail()) { return false; } } } return true; }
/** * Gets parent Cost Center * * @return CostCentreEntity Returns cost centre entity */ public function getCostCenter() { if ($this->_cc === null || $this->_cc->ccId != $this->ccId) { $this->_cc = CostCentreEntity::findPk($this->ccId); } return $this->_cc; }
public function applyGlobalVarsToValue($value) { if (empty($this->globalVariablesCache)) { $formats = \Scalr::config("scalr.system.global_variables.format"); $systemVars = array('env_id' => $this->EnvID, 'env_name' => $this->GetEnvironmentObject()->name, 'farm_id' => $this->ID, 'farm_name' => $this->Name, 'farm_hash' => $this->Hash, 'farm_owner_email' => $this->createdByUserEmail); if (\Scalr::getContainer()->analytics->enabled) { $projectId = $this->GetSetting(DBFarm::SETTING_PROJECT_ID); if ($projectId) { $project = ProjectEntity::findPk($projectId); /* @var $project ProjectEntity */ $systemVars['project_id'] = $projectId; $systemVars['project_bc'] = $project->getProperty(ProjectPropertyEntity::NAME_BILLING_CODE); $systemVars['project_name'] = $project->name; $ccId = $project->ccId; } if ($ccId) { $cc = CostCentreEntity::findPk($ccId); if ($cc) { /* @var $cc CostCentreEntity */ $systemVars['cost_center_id'] = $ccId; $systemVars['cost_center_bc'] = $cc->getProperty(CostCentrePropertyEntity::NAME_BILLING_CODE); $systemVars['cost_center_name'] = $cc->name; } else { throw new Exception("Cost center {$ccId} not found"); } } } // Get list of Server system vars foreach ($systemVars as $name => $val) { $name = "SCALR_" . strtoupper($name); $val = trim($val); if (isset($formats[$name])) { $val = @sprintf($formats[$name], $val); } $this->globalVariablesCache[$name] = $val; } // Add custom variables $gv = new Scalr_Scripting_GlobalVariables($this->ClientID, $this->EnvID, Scalr_Scripting_GlobalVariables::SCOPE_FARM); $vars = $gv->listVariables(0, $this->ID); foreach ($vars as $v) { $this->globalVariablesCache[$v['name']] = $v['value']; } } //Parse variable $keys = array_keys($this->globalVariablesCache); $f = create_function('$item', 'return "{".$item."}";'); $keys = array_map($f, $keys); $values = array_values($this->globalVariablesCache); $retval = str_replace($keys, $values, $value); // Strip undefined variables & return value return preg_replace("/{[A-Za-z0-9_-]+}/", "", $retval); }
public function xSaveAction() { $this->request->defineParams(array('ccId' => ['type' => 'string'], 'projectId' => ['type' => 'string'], 'year' => ['type' => 'int'], 'quarters' => ['type' => 'json'], 'selectedQuarter' => ['type' => 'string'])); $year = $this->getParam('year'); $selectedQuarter = $this->getParam('selectedQuarter'); if ($selectedQuarter !== 'year' && ($selectedQuarter < 1 || $selectedQuarter > 4)) { throw new OutOfBoundsException(sprintf("Invalid selectedQuarter number.")); } $quarterReq = []; foreach ($this->getParam('quarters') as $q) { if (!isset($q['quarter'])) { throw new InvalidArgumentException(sprintf("Missing quarter property for quarters data set in the request.")); } if ($q['quarter'] < 1 || $q['quarter'] > 4) { throw new OutOfRangeException(sprintf("Quarter value should be between 1 and 4.")); } if (!isset($q['budget'])) { throw new InvalidArgumentException(sprintf("Missing budget property for quarters data set in the request.")); } $quarterReq[$q['quarter']] = $q; } if ($this->getParam('projectId')) { $subjectType = QuarterlyBudgetEntity::SUBJECT_TYPE_PROJECT; $subjectId = $this->getParam('projectId'); } else { if ($this->getParam('ccId')) { $subjectType = QuarterlyBudgetEntity::SUBJECT_TYPE_CC; $subjectId = $this->getParam('ccId'); } else { throw new InvalidArgumentException(sprintf('Either ccId or projectId must be provided with the request.')); } } if (!preg_match("/^[[:xdigit:]-]{36}\$/", $subjectId)) { throw new InvalidArgumentException(sprintf("Invalid UUID has been passed.")); } if (!preg_match('/^\\d{4}$/', $year)) { throw new InvalidArgumentException(sprintf("Invalid year has been passed.")); } //Fetches the previous state of the entities from database if ($subjectType == QuarterlyBudgetEntity::SUBJECT_TYPE_CC) { $collection = QuarterlyBudgetEntity::getCcBudget($year, $subjectId); } else { $collection = QuarterlyBudgetEntity::getProjectBudget($year, $subjectId); } $quarters = new Quarters(SettingEntity::getQuarters(true)); //Updates|creates entities for ($quarter = 1; $quarter <= 4; ++$quarter) { if (!isset($quarterReq[$quarter])) { continue; } $period = $quarters->getPeriodForQuarter($quarter, $year); //Checks if period has already been closed and forbids update if ($period->end->format('Y-m-d') < gmdate('Y-m-d')) { continue; } $entity = current($collection->filterByQuarter($quarter)); if ($entity instanceof QuarterlyBudgetEntity) { //We should update an entity $entity->budget = abs((double) $quarterReq[$quarter]['budget']); } else { //We should create a new one. $entity = new QuarterlyBudgetEntity($year, $quarter); $entity->subjectType = $subjectType; $entity->subjectId = $subjectId; $entity->budget = abs((double) $quarterReq[$quarter]['budget']); } $entity->save(); } if ($selectedQuarter == 'year') { $selectedPeriod = $quarters->getPeriodForYear($year); } else { $selectedPeriod = $quarters->getPeriodForQuarter($selectedQuarter, $year); } if ($subjectType == QuarterlyBudgetEntity::SUBJECT_TYPE_PROJECT) { $data = $this->getProjectData(ProjectEntity::findPk($subjectId), $selectedPeriod, true); $budgetInfo = $this->getBudgetInfo($year, $data['ccId'], $data['projectId']); } else { $data = $this->getCostCenterData(CostCentreEntity::findPk($subjectId), $selectedPeriod); $budgetInfo = $this->getBudgetInfo($year, $subjectId); } $this->response->data(['data' => $data, 'budgetInfo' => $budgetInfo]); $this->response->success('Budget changes have been saved'); }
public function xSaveAction() { if (!$this->user->isAccountSuperAdmin() && !$this->request->isAllowed(Acl::RESOURCE_ENV_CLOUDS_ENVIRONMENT)) { throw new Scalr_Exception_InsufficientPermissions(); } $params = array('envId' => array('type' => 'int'), 'teams' => array('type' => 'json')); if ($this->user->isAccountOwner() || $this->user->isAccountSuperAdmin()) { $params['name'] = array('type' => 'string', 'validator' => array(Scalr_Validator::REQUIRED => true, Scalr_Validator::NOHTML => true)); } $this->request->defineParams($params); $this->request->validate(); if ($this->getContainer()->analytics->enabled) { if ($this->getParam('ccId')) { if (!$this->getContainer()->analytics->ccs->get($this->getParam('ccId'))) { $this->request->addValidationErrors('ccId', 'Invalid cost center ID'); } } else { $this->request->addValidationErrors('ccId', 'Cost center is required field'); } } if ($this->request->isValid()) { $isNew = false; if (!$this->getParam('envId')) { //create new environment if (!$this->user->isAccountOwner() && !$this->user->isAccountSuperAdmin()) { throw new Scalr_Exception_InsufficientPermissions(); } $this->user->getAccount()->validateLimit(Scalr_Limits::ACCOUNT_ENVIRONMENTS, 1); $env = $this->user->getAccount()->createEnvironment($this->getParam('name')); $isNew = true; } else { $env = Scalr_Environment::init()->loadById($this->getParam('envId')); } $this->user->getPermissions()->validate($env); if (!$this->user->isAccountSuperAdmin() && !$this->user->getAclRolesByEnvironment($env->id)->isAllowed(Acl::RESOURCE_ENV_CLOUDS_ENVIRONMENT)) { throw new Scalr_Exception_InsufficientPermissions(); } //set name, status and defaultPriority if ($this->user->isAccountOwner() || $this->user->isAccountSuperAdmin()) { $env->name = $this->getParam('name'); } if ($this->user->canManageAcl()) { $env->status = $this->getParam('status') == Scalr_Environment::STATUS_ACTIVE ? Scalr_Environment::STATUS_ACTIVE : Scalr_Environment::STATUS_INACTIVE; $env->defaultPriority = $this->getParam('defaultPriority'); } $env->save(); if ($this->user->canManageAcl()) { if ($this->getContainer()->analytics->enabled && $this->getParam('ccId')) { $oldCcId = $env->getPlatformConfigValue(Scalr_Environment::SETTING_CC_ID); $env->setPlatformConfig(array(Scalr_Environment::SETTING_CC_ID => $this->getParam('ccId'))); if ($isNew || $oldCcId != $this->getParam('ccId')) { $cc = CostCentreEntity::findPk($this->getParam('ccId')); $email = $cc->getProperty(CostCentrePropertyEntity::NAME_LEAD_EMAIL); $emailData = ['envName' => $env->name, 'ccName' => $cc->name]; if (!empty($email)) { \Scalr::getContainer()->mailer->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/analytics_on_cc_add.eml.php', $emailData, $email); } } if ($isNew || empty($oldCcId)) { $this->getContainer()->analytics->events->fireAssignCostCenterEvent($env, $this->getParam('ccId')); } elseif ($oldCcId != $this->getParam('ccId')) { $this->getContainer()->analytics->events->fireReplaceCostCenterEvent($env, $this->getParam('ccId'), $oldCcId); } } //set teams if ($this->getContainer()->config->get('scalr.auth_mode') == 'ldap') { $teams = array_map('trim', $this->getParam('teams')); $ldapGroups = null; if ($this->getContainer()->config->get('scalr.connections.ldap.user')) { $ldap = $this->getContainer()->ldap(null, null); $ldapGroups = $ldap->getGroupsDetails($teams); foreach ($teams as $team) { if (!isset($ldapGroups[$team])) { throw new \Exception(sprintf("Team '%s' is not found on the directory server", $team)); } } } $env->clearTeams(); foreach ($teams as $name) { $name = trim($name); if ($name) { $id = $this->db->GetOne('SELECT id FROM account_teams WHERE name = ? AND account_id = ? LIMIT 1', array($name, $this->user->getAccountId())); if (!$id) { $team = new Scalr_Account_Team(); $team->name = $name; $team->accountId = $this->user->getAccountId(); if ($ldapGroups !== null && $ldapGroups[$name] != $name) { $team->description = $ldapGroups[$name]; } $team->save(); $id = $team->id; } elseif ($ldapGroups !== null) { // Update team description $team = new Scalr_Account_Team(); $team->loadById($id); if ($team->description != $ldapGroups[$name] && $ldapGroups[$name] != $name) { $team->description = $ldapGroups[$name]; $team->save(); } } $env->addTeam($id); } } if ($this->getContainer()->config->get('scalr.connections.ldap.user')) { $user = strtok($this->user->getEmail(), '@'); $ldap = $this->getContainer()->ldap($user, null); if ($ldap->isValidUsername()) { $this->user->applyLdapGroups($ldap->getUserGroups()); } } } else { $env->clearTeams(); foreach ($this->getParam('teams') as $id) { $env->addTeam($id); } } } $this->response->success($isNew ? 'Environment successfully created' : 'Environment saved'); $env = Scalr_Environment::init()->loadById($env->id); //reload env to be sure we have actual params $teams = array(); foreach ($env->getTeams() as $teamId) { if ($this->getContainer()->config->get('scalr.auth_mode') == 'ldap') { $team = new Scalr_Account_Team(); $team->loadById($teamId); $teams[] = $team->name; } else { $teams[] = $teamId; } } $this->response->data(array('env' => array('id' => $env->id, 'name' => $env->name, 'status' => $env->status, 'defaultPriority' => $env->defaultPriority, 'platforms' => $env->getEnabledPlatforms(), 'teams' => $teams, 'ccId' => $env->getPlatformConfigValue(Scalr_Environment::SETTING_CC_ID)))); } else { $this->response->failure($this->request->getValidationErrorsMessage(), true); } }
/** * @test */ public function textAccountComplex() { $ccsArch = $this->createCostCenter(['name' => $this->getTestName(), 'archived' => CostCentreEntity::ARCHIVED]); $ccs = $this->listCostCenters([], false); $adapter = $this->getAdapter('costCenter'); $filterable = $adapter->getRules()[ApiEntityAdapter::RULE_TYPE_FILTERABLE]; foreach ($ccs as $cc) { foreach ($filterable as $property) { $filterValue = $cc->{$property}; $listResult = $this->listCostCenters([$property => $filterValue], false); if (!static::isRecursivelyEmpty($filterValue)) { foreach ($listResult as $filtered) { $this->assertEquals($filterValue, $filtered->{$property}, "Property '{$property}' mismatch"); } } } $response = $this->getCostCenter($cc->id, false); $this->assertEquals(200, $response->status, $this->printResponseError($response)); /* @var $dbCc CostCentreEntity */ $dbCc = CostCentreEntity::findPk($cc->id); /* @var $acCs AccountCostCenterEntity */ $acCs = AccountCostCenterEntity::findOne([['ccId' => $dbCc->ccId]]); $this->assertFalse($dbCc->archived); $this->assertEquals($this->getUser()->accountId, $acCs->accountId); $this->assertObjectEqualsEntity($response->getBody()->data, $dbCc, $adapter); } $filterByName = $this->listCostCenters(['name' => $ccsArch->name], false); $this->assertNotEmpty($filterByName); foreach ($filterByName as $cc) { $this->assertObjectEqualsEntity($cc, $ccsArch, $adapter); $this->assertNotContains($cc, $ccs, "List of Cost Centers shouldn't have an archived project", false, false); } $filterByBillingCode = $this->listCostCenters(['billingCode' => $ccsArch->getProperty(CostCentrePropertyEntity::NAME_BILLING_CODE)], false); $this->assertNotEmpty($filterByBillingCode); foreach ($filterByBillingCode as $cc) { $this->assertObjectEqualsEntity($cc, $ccsArch, $adapter); $this->assertNotContains($cc, $ccs, "List of Cost Centers shouldn't have an archived project", false, false); } }
protected function isApplied1($stage) { return CostCentreEntity::findPk(Usage::DEFAULT_CC_ID) !== null && ProjectEntity::findPk(Usage::DEFAULT_PROJECT_ID) !== null; }
/** * xMoveProjectsAction * * @param JsonData $projects Projects that should be moved * @throws AnalyticsException * @throws Exception * @throws \Scalr\Exception\ModelException */ public function xMoveProjectsAction(JsonData $projects = null) { $envChange = []; $accountChange = []; $projectChange = []; $ccEntityCache = []; $collisions = []; foreach ($projects as $project) { $projectEntity = ProjectEntity::findPk($project['projectId']); /* @var $projectEntity ProjectEntity */ if (empty($ccEntity)) { $ccEntity = $projectEntity->getCostCenter(); } if ($ccEntity->ccId == $project['ccId']) { continue; } if (empty($ccEntityCache[$project['ccId']])) { $newCcEntity = CostCentreEntity::findPk($project['ccId']); /* @var $newCcEntity CostCentreEntity */ if (!$newCcEntity) { throw new Exception(sprintf("Cost center with id %s has not been found.", $project['ccId']), 404); } $ccEntityCache[$project['ccId']] = $newCcEntity->ccId; } $farms[$projectEntity->projectId] = $projectEntity->getFarmsList(); foreach ($farms[$projectEntity->projectId] as $farmId => $farmName) { $farmEntity = Farm::findPk($farmId); /* @var $farmEntity Farm */ if (empty($accountChange[$farmEntity->accountId])) { $accountCss = AccountCostCenterEntity::findOne([['accountId' => $farmEntity->accountId], ['ccId' => $newCcEntity->ccId]]); if (!$accountCss) { $accountChange[$farmEntity->accountId] = $newCcEntity->ccId; } } if (empty($envChange[$farmEntity->envId])) { $project['name'] = $projectEntity->name; $envChange[$farmEntity->envId] = $project; } else { if ($envChange[$farmEntity->envId]['ccId'] != $project['ccId']) { if (!in_array($projectEntity->name, $collisions)) { $collisions[] = $projectEntity->name; } if (!in_array($envChange[$farmEntity->envId]['name'], $collisions)) { $collisions[] = $envChange[$farmEntity->envId]['name']; } continue; } } } $projectEntity->ccId = $project['ccId']; $projectChange[$projectEntity->projectId] = $projectEntity; } $remainningEnvs = []; $projectsCount = count($projectChange); if ($projectsCount) { if (isset($ccEntity)) { $envList = $ccEntity->getEnvironmentsList(); foreach ($envList as $envId => $name) { if (isset($envChange[$envId])) { $ccProjects = $this->getContainer()->analytics->projects->getUsedInEnvironment($envId); foreach ($ccProjects as $project) { /* @var $project ProjectEntity */ if (!isset($farms[$project->projectId])) { $farms[$project->projectId] = $project->getFarmsList(); } if (count($farms[$project->projectId]) > 0 && !isset($projectChange[$project->projectId])) { if (!in_array($envId, $remainningEnvs)) { $remainningEnvs[] = $envId; } } } } } } $this->db->BeginTrans(); try { foreach ($accountChange as $accountId => $ccId) { $accountCss = new AccountCostCenterEntity($accountId, $ccId); $accountCss->save(); } if (empty($remainningEnvs) && empty($collisions)) { foreach ($envChange as $envId => $data) { $envProp = EnvironmentProperty::findOne([['envId' => $envId], ['name' => EnvironmentProperty::SETTING_CC_ID]]); /* @var $envProp EnvironmentProperty */ $envProp->value = $data['ccId']; $envProp->save(); } } foreach ($projectChange as $project) { /* @var $project ProjectEntity */ $project->save(); } $this->db->CommitTrans(); } catch (Exception $e) { $this->db->RollbackTrans(); throw $e; } } if (count($collisions) > 0) { $this->response->warning(sprintf("%d Project%s %s been moved however collision occurred. Projects '%s' are used in the Farms from the same Environment however they have been moved to different Cost Centers.", $projectsCount, $projectsCount > 1 ? 's' : '', $projectsCount > 1 ? 'have' : 'has', implode("', '", $collisions))); } else { if (count($remainningEnvs) > 0) { $this->response->warning(sprintf("%d Project%s %s been moved however some Projects don't correspond to Cost Centers assigned to Environments '%s'.", $projectsCount, $projectsCount > 1 ? 's' : '', $projectsCount > 1 ? 'have' : 'has', implode("', '", $remainningEnvs))); } else { $this->response->success(sprintf("%d Project%s %s been moved to other Cost Center.", $projectsCount, $projectsCount > 1 ? 's' : '', $projectsCount > 1 ? 'have' : 'has')); } } }
/** * Creates default Cost Center and Project from the fixture */ public function createDefaultCostCenter() { $fixture = $this->fixture(); foreach ($fixture as $i => $c) { $ccId = key($c); $cc = CostCentreEntity::findPk($ccId); if (!$cc) { $cc = new CostCentreEntity(); $cc->ccId = $ccId; $cc->name = sprintf('Cost center %02d', $i + 1); $cc->save(); $cc->saveProperty(CostCentrePropertyEntity::NAME_DESCRIPTION, 'This Cost Center was added automatically.'); $cc->saveProperty(CostCentrePropertyEntity::NAME_BILLING_CODE, sprintf('CC-%02d', $i)); $cc->saveProperty(CostCentrePropertyEntity::NAME_LEAD_EMAIL, ''); $this->cadb->Execute("\n INSERT IGNORE `account_tag_values` (`account_id`, `tag_id`, `value_id`, `value_name`)\n VALUES (0, ?, ?, ?)\n ", [TagEntity::TAG_ID_COST_CENTRE, $cc->ccId, $cc->name]); } foreach ($fixture[$i][$ccId] as $j => $projectId) { $pr = ProjectEntity::findPk($projectId); if (!$pr) { $pr = new ProjectEntity(); $pr->projectId = $projectId; $pr->ccId = $ccId; $pr->name = sprintf('Project %d%d', $i, $j + 1); $pr->save(); $pr->saveProperty(ProjectPropertyEntity::NAME_DESCRIPTION, 'This Project was added automatically.'); $pr->saveProperty(ProjectPropertyEntity::NAME_BILLING_CODE, sprintf('PR-%02d-%02d', $i, $j)); $pr->saveProperty(ProjectPropertyEntity::NAME_LEAD_EMAIL, ''); $this->cadb->Execute("\n INSERT IGNORE `account_tag_values` (`account_id`, `tag_id`, `value_id`, `value_name`)\n VALUES (0, ?, ?, ?)\n ", [TagEntity::TAG_ID_PROJECT, $pr->projectId, $pr->name]); } } } }
/** * xGetPeriodLogAction * * @param string $mode The mode (week, month, quarter, year) * @param string $startDate The start date of the period in UTC ('Y-m-d') * @param string $endDate The end date of the period in UTC ('Y-m-d') * @param string $type Type of the data gathered in log file (farms, clouds, projects) * @param string $ccId optional The identifier of the cost center * @param string $projectId optional The identifier of the project */ public function xGetPeriodCsvAction($mode, $startDate, $endDate, $type, $ccId = null, $projectId = null) { $name = 'Cloud'; if (!empty($ccId) && empty($projectId)) { $data = $this->getContainer()->analytics->usage->getCostCenterPeriodData($ccId, $mode, $startDate, $endDate); $entity = CostCentreEntity::findPk($ccId); if ($type !== 'clouds') { $name = 'Project'; $extraFields = 'Cost Center name;Billing code;Lead email address;'; } } else { if (!empty($projectId)) { $data = $this->getContainer()->analytics->usage->getProjectPeriodData($projectId, $mode, $startDate, $endDate); $entity = ProjectEntity::findPk($projectId); if ($type !== 'clouds') { $name = 'Farm'; $extraFields = 'Project name;Billing code;Lead email address;'; } } else { throw new \InvalidArgumentException(sprintf("Method %s requires both ccId or projectId to be specified.", __METHOD__)); } } $extraData = [$entity->name, $entity->getProperty('billing.code'), $entity->getProperty('lead.email')]; $head[] = $name; $end[] = "Total spent"; if (isset($extraFields)) { $head = array_merge($head, $extraData); $end = array_merge($end, $extraData); } $totals = 0; foreach ($data['timeline'] as $timeline) { $totals += $timeline['cost']; $head[] = $timeline['label']; $end[] = $timeline['cost']; } $head[] = 'Total'; $end[] = $totals; $temp = tmpfile(); fputcsv($temp, $head); foreach ($data[$type] as $item) { $row = []; $row[] = $item['name']; $dataCost = []; foreach ($data['timeline'] as $key => $value) { $dataCost[] = isset($item['data'][$key]['cost']) ? $item['data'][$key]['cost'] : 0; } $itemTotal = array_sum($dataCost); if (isset($extraFields)) { $row = array_merge($row, $extraData); } $row = array_merge($row, $dataCost); $row[] = $itemTotal; fputcsv($temp, $row); } fputcsv($temp, $end); $metadata = stream_get_meta_data($temp); $label = Scalr_Util_DateTime::convertTz(time(), 'M_j_Y_H:i:s'); $fileName = $entity->name . '.' . $entity->getProperty('billing.code') . '.' . $type . '.' . $label; $bad = array_merge(array_map('chr', range(0, 31)), ["<", ">", ":", '"', "/", "\\", "|", "?", "*"]); $fileName = str_replace($bad, "", $fileName); $this->response->setHeader('Content-Encoding', 'utf-8'); $this->response->setHeader('Content-Type', 'text/csv', true); $this->response->setHeader('Expires', 'Mon, 10 Jan 1997 08:00:00 GMT'); $this->response->setHeader('Pragma', 'no-cache'); $this->response->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate'); $this->response->setHeader('Cache-Control', 'post-check=0, pre-check=0'); $this->response->setHeader('Content-Disposition', 'attachment; filename=' . $fileName . ".csv"); $this->response->setResponse(file_get_contents($metadata['uri'])); fclose($temp); }
/** * Initializes default cost centres and projects according to fixtures * * @return void */ public function initDefault() { $fixture = $this->fixture(); foreach ($fixture as $i => $c) { $ccId = key($c); $cc = CostCentreEntity::findPk($ccId); if (!$cc) { $cc = new CostCentreEntity(); $cc->ccId = $ccId; $cc->name = sprintf('Cost center %02d', $i + 1); $cc->save(); $cc->saveProperty(CostCentrePropertyEntity::NAME_DESCRIPTION, 'This is the automatically added cost center'); $cc->saveProperty(CostCentrePropertyEntity::NAME_BILLING_CODE, sprintf('CC-%02d', $i)); $cc->saveProperty(CostCentrePropertyEntity::NAME_LEAD_EMAIL, ''); $this->cadb->Execute("\n INSERT IGNORE `account_tag_values` (`account_id`, `tag_id`, `value_id`, `value_name`)\n VALUES (0, ?, ?, ?)\n ", [TagEntity::TAG_ID_COST_CENTRE, $cc->ccId, $cc->name]); } foreach ($fixture[$i][$ccId] as $j => $projectId) { $pr = ProjectEntity::findPk($projectId); if (!$pr) { $pr = new ProjectEntity(); $pr->projectId = $projectId; $pr->ccId = $ccId; $pr->name = sprintf('Project %d%d', $i, $j + 1); $pr->save(); $pr->saveProperty(ProjectPropertyEntity::NAME_DESCRIPTION, 'This is the automatically generated project'); $pr->saveProperty(ProjectPropertyEntity::NAME_BILLING_CODE, sprintf('PR-%02d-%02d', $i, $j)); $pr->saveProperty(ProjectPropertyEntity::NAME_LEAD_EMAIL, ''); $this->cadb->Execute("\n INSERT IGNORE `account_tag_values` (`account_id`, `tag_id`, `value_id`, `value_name`)\n VALUES (0, ?, ?, ?)\n ", [TagEntity::TAG_ID_PROJECT, $pr->projectId, $pr->name]); } } } //Assigns cost centre to each environment $res = $this->db->Execute("SELECT id FROM client_environments"); while ($rec = $res->FetchRow()) { try { $environment = \Scalr_Environment::init()->loadById($rec['id']); } catch (Exception $e) { continue; } $environment->setPlatformConfig(array(\Scalr_Environment::SETTING_CC_ID => $this->autoCostCentre($environment->id))); } //Assigns project to each farm $res = $this->db->Execute("SELECT id, env_id, clientid FROM farms"); while ($rec = $res->FetchRow()) { try { $dbFarm = DBFarm::LoadByID($rec['id']); } catch (Exception $e) { continue; } $dbFarm->SetSetting(DBFarm::SETTING_PROJECT_ID, $this->autoProject($dbFarm->EnvID, $dbFarm->ID)); } //Initializes servers properties $res = $this->db->Execute("\n SELECT DISTINCT s.server_id, s.env_id, s.farm_id\n FROM servers s\n LEFT JOIN server_properties p ON p.server_id = s.server_id AND p.name = ?\n LEFT JOIN server_properties p2 ON p2.server_id = s.server_id AND p2.name = ?\n WHERE p.server_id IS NULL OR p.`value` IS NULL\n OR (s.farm_id IS NOT NULL AND (p2.server_id IS NULL OR p2.`value` IS NULL))\n ", [SERVER_PROPERTIES::ENV_CC_ID, SERVER_PROPERTIES::FARM_PROJECT_ID]); while ($rec = $res->FetchRow()) { $ccid = $this->autoCostCentre($rec['env_id']); $this->db->Execute("\n INSERT `server_properties` (`server_id`, `name`, `value`)\n VALUE (?, ?, ?)\n ON DUPLICATE KEY UPDATE `value` = IFNULL(`value`, ?)\n ", [$rec['server_id'], SERVER_PROPERTIES::ENV_CC_ID, $ccid, $ccid]); //Farm may not exist for bundle task servers if ($rec['farm_id']) { $projectid = $this->autoProject($rec['env_id'], $rec['farm_id']); $this->db->Execute("\n INSERT `server_properties` (`server_id`, `name`, `value`)\n VALUE (?, ?, ?)\n ON DUPLICATE KEY UPDATE `value` = IFNULL(`value`, ?)\n ", [$rec['server_id'], SERVER_PROPERTIES::FARM_PROJECT_ID, $projectid, $projectid]); } } }
/** * Gets budgeted cost for all quarters of specified year * * @param int $year The year * @param string $ccId optional The identifier of the cost centre or parent cost centre * @param string $projectId optional The identifier of the project * @throws InvalidArgumentException */ protected function getBudgetInfo($year, $ccId = null, $projectId = null) { if (!empty($projectId)) { $subjectId = $projectId; $subjectType = QuarterlyBudgetEntity::SUBJECT_TYPE_PROJECT; $subjectEntity = ProjectEntity::findPk($projectId); } else { if (!empty($ccId)) { $subjectId = $ccId; $subjectType = QuarterlyBudgetEntity::SUBJECT_TYPE_CC; $subjectEntity = CostCentreEntity::findPk($ccId); } } if ($subjectEntity->accountId !== $this->user->getAccountId()) { //throw new Scalr_Exception_InsufficientPermissions(); } if (empty($subjectId) || !preg_match('/^[[:xdigit:]-]{36}$/', $subjectId)) { throw new InvalidArgumentException(sprintf("Invalid identifier of the project or cost center.")); } if (!preg_match('/^\\d{4}$/', $year)) { throw new InvalidArgumentException(sprintf("Invalid year.")); } if ($subjectType == QuarterlyBudgetEntity::SUBJECT_TYPE_CC) { $collection = QuarterlyBudgetEntity::getCcBudget($year, $subjectId); $prevCollection = QuarterlyBudgetEntity::getCcBudget($year - 1, $subjectId); } else { $collection = QuarterlyBudgetEntity::getProjectBudget($year, $subjectId); $prevCollection = QuarterlyBudgetEntity::getProjectBudget($year - 1, $subjectId); } $quarters = new Quarters(SettingEntity::getQuarters(true)); $today = new DateTime('now', new DateTimeZone('UTC')); //Start dates for an each quarter $startDates = $quarters->getDays(); $budgets = []; for ($quarter = 1; $quarter <= 4; ++$quarter) { $period = $quarters->getPeriodForQuarter($quarter, $year); $prevPeriod = $quarters->getPeriodForQuarter($quarter, $year - 1); //Finds budget for specified quarter in the collection $entity = current($collection->filterByQuarter($quarter)); //Previous Year entity $prevEntity = current($prevCollection->filterByQuarter($quarter)); if ($entity instanceof QuarterlyBudgetEntity) { $budget = ['budget' => round($entity->budget), 'budgetFinalSpent' => round($entity->cumulativespend), 'spentondate' => $entity->spentondate instanceof DateTime ? $entity->spentondate->format('Y-m-d') : null, 'budgetSpent' => round($entity->cumulativespend)]; if ($budget['budget']) { $budget['budgetOverspend'] = max(round($entity->cumulativespend - $entity->budget), 0); $budget['budgetOverspendPct'] = round($budget['budgetOverspend'] / $budget['budget'] * 100); } } else { //Budget has not been set yet. $budget = ['budget' => 0, 'budgetFinalSpent' => 0, 'spentondate' => null, 'budgetSpent' => 0, 'budgetOverspend' => 0, 'budgetOverspendPct' => 0]; } $budget['year'] = $year; $budget['quarter'] = $quarter; $budget['startDate'] = $startDates[$quarter - 1]; //Whether this quarter has been closed or not $budget['closed'] = $period->end->format('Y-m-d') < gmdate('Y-m-d'); //The number of the days in the current quarter $daysInQuarter = $period->start->diff($period->end, true)->days + 1; //In case quarter is closed projection should be calculated if (!$budget['closed']) { $daysPassed = $period->start->diff($today, true)->days + 1; $budget['dailyAverage'] = $daysPassed == 0 ? 0 : round($budget['budgetSpent'] / $daysPassed, 2); $budget['projection'] = round($daysInQuarter * $budget['dailyAverage']); } else { $budget['dailyAverage'] = $daysInQuarter == 0 ? 0 : round($budget['budgetFinalSpent'] / $daysInQuarter, 2); } $budget['costVariance'] = round((isset($budget['projection']) ? $budget['projection'] : $budget['budgetSpent']) - $budget['budget'], 2); $budget['costVariancePct'] = $budget['budget'] == 0 ? null : round(abs($budget['costVariance']) / $budget['budget'] * 100); $budget['monthlyAverage'] = round($budget['dailyAverage'] * 30); if ($prevEntity instanceof QuarterlyBudgetEntity) { $budget['prev'] = ['budget' => $prevEntity->budget, 'budgetFinalSpent' => $prevEntity->cumulativespend, 'spentondate' => $prevEntity->spentondate instanceof DateTime ? $prevEntity->spentondate->format('Y-m-d') : null, 'closed' => $prevPeriod->end->format('Y-m-d') < gmdate('Y-m-d'), 'costVariance' => $prevEntity->cumulativespend - $prevEntity->budget, 'costVariancePct' => $prevEntity->budget == 0 ? null : round(abs($prevEntity->cumulativespend - $prevEntity->budget) / $prevEntity->budget * 100)]; } else { $budget['prev'] = ['budget' => null, 'budgetFinalSpent' => 0, 'spentondate' => null, 'closed' => $prevPeriod->end->format('Y-m-d') < gmdate('Y-m-d'), 'budgetSpent' => 0, 'costVariance' => 0, 'costVariancePct' => 0]; } $budgets[] = $budget; } $result = ['budgets' => $budgets, 'ccId' => $ccId, 'projectId' => $projectId, 'quarter' => $quarters->getQuarterForDate(), 'year' => $year]; if (!empty($projectId)) { $result['shared'] = $subjectEntity->shared; } return $result; }
/** * Gets the list of the Cost Centers which correspond to Account * * @return \Scalr\Model\Collections\ArrayCollection Returns collection of the entities */ public function getCostCenters() { $ccs = new ArrayCollection(); foreach (AccountCostCenterEntity::findByAccountId($this->id) as $accountCc) { $cc = CostCentreEntity::findPk($accountCc->ccId); if (!$cc instanceof CostCentreEntity) { continue; } $ccs->append($cc); } return $ccs; }