/** * Returns prepared orchestration log data for response * * @param EntityIterator $logs List of Orchestration Log objects * @return array */ private function prepareOrchestrationLogData($logs) { $farmIds = []; $serverIds = []; $taskIds = []; $eventIds = []; $ids = []; foreach ($logs as $row) { /* @var $row OrchestrationLog */ $farmIds[] = $row->farmId; $serverIds[] = $row->serverId; if ($row->eventServerId) { $serverIds[] = $row->eventServerId; } if ($row->taskId) { $taskIds[] = $row->taskId; } if ($row->eventId) { $eventIds[] = $row->eventId; } if ($row->type == OrchestrationLog::TYPE_MANUAL) { $ids[] = $row->id; } } if (!empty($farmIds)) { $farms = Farm::find([['id' => ['$in' => array_unique($farmIds)]]]); foreach ($farms as $farm) { /* @var $farm Farm */ $farmData[$farm->id] = $farm->name; } } if (!empty($serverIds)) { $servers = Server::find([['serverId' => ['$in' => array_unique($serverIds)]]]); $farmRoleIds = []; $serverFarmIds = []; foreach ($servers as $server) { /* @var $server Server */ $serverData[$server->serverId]['serverIndex'] = $server->index; $farmRoleIds[$server->serverId] = $server->farmRoleId; $serverFarmIds[$server->serverId] = $server->farmId; } $farms = Farm::find([['id' => ['$in' => array_unique(array_values($serverFarmIds))]]]); foreach ($farms as $farm) { /* @var $farm Farm */ foreach ($serverFarmIds as $serverId => $farmId) { if ($farmId == $farm->id) { $serverData[$serverId]['farmName'] = $farm->name; $serverData[$serverId]['farmId'] = $farm->id; } } } $farmRoles = FarmRole::find([['id' => ['$in' => array_unique(array_values($farmRoleIds))]]]); foreach ($farmRoles as $farmRole) { /* @var $farmRole FarmRole */ foreach ($farmRoleIds as $serverId => $farmRoleId) { if ($farmRoleId == $farmRole->id) { $serverData[$serverId]['alias'] = $farmRole->alias; $serverData[$serverId]['farmRoleId'] = $farmRole->id; } } } } if (!empty($taskIds)) { $tasks = SchedulerTask::find([['id' => ['$in' => array_unique($taskIds)]]]); foreach ($tasks as $task) { /* @var $task SchedulerTask */ $taskData[$task->id] = $task->name; } } if (!empty($eventIds)) { $events = Event::find([['eventId' => ['$in' => array_unique($eventIds)]]]); foreach ($events as $event) { /* @var $event Event */ $eventData[$event->eventId] = $event->type; } } if (!empty($ids)) { $manualLogs = OrchestrationLogManualScript::find([['orchestrationLogId' => ['$in' => array_unique($ids)]]]); foreach ($manualLogs as $manualLog) { /* @var $manualLog OrchestrationLogManualScript */ $scriptData[$manualLog->orchestrationLogId] = $manualLog->userEmail; } } $data = []; foreach ($logs as $row) { /* @var $row OrchestrationLog */ $dataRow = get_object_vars($row); $dataRow['targetFarmName'] = isset($farmData[$row->farmId]) ? $farmData[$row->farmId] : null; $dataRow['targetFarmId'] = $row->farmId; $dataRow['targetServerId'] = $row->serverId; $dataRow['targetServerIndex'] = isset($serverData[$row->serverId]['serverIndex']) ? $serverData[$row->serverId]['serverIndex'] : null; $dataRow['targetFarmRoleId'] = isset($serverData[$row->serverId]['farmRoleId']) ? $serverData[$row->serverId]['farmRoleId'] : null; $dataRow['targetRoleName'] = isset($serverData[$row->serverId]['alias']) ? $serverData[$row->serverId]['alias'] : null; $dataRow['added'] = Scalr_Util_DateTime::convertTz($row->added); if (\Scalr::config('scalr.system.scripting.logs_storage') == 'scalr') { $dataRow['executionId'] = null; } if ($dataRow['message']) { $dataRow['message'] = nl2br(htmlspecialchars($dataRow['message'])); } if ($row->eventServerId) { $dataRow['eventFarmName'] = isset($serverData[$row->eventServerId]['farmName']) ? $serverData[$row->eventServerId]['farmName'] : null; $dataRow['eventFarmId'] = isset($serverData[$row->eventServerId]['farmId']) ? $serverData[$row->eventServerId]['farmId'] : null; $dataRow['eventFarmRoleId'] = isset($serverData[$row->eventServerId]['farmRoleId']) ? $serverData[$row->eventServerId]['farmRoleId'] : null; $dataRow['eventRoleName'] = isset($serverData[$row->eventServerId]['alias']) ? $serverData[$row->eventServerId]['alias'] : null; $dataRow['eventServerIndex'] = isset($serverData[$row->eventServerId]['serverIndex']) ? $serverData[$row->eventServerId]['serverIndex'] : null; } $dataRow['event'] = null; if ($row->taskId) { $dataRow['event'] = isset($taskData[$row->taskId]) ? $taskData[$row->taskId] : null; } if ($row->eventId) { $dataRow['event'] = isset($eventData[$row->eventId]) ? $eventData[$row->eventId] : null; } if ($row->type == OrchestrationLog::TYPE_MANUAL) { $dataRow['event'] = isset($scriptData[$row->id]) ? $scriptData[$row->id] : null; } $data[] = $dataRow; } return $data; }
/** * {@inheritdoc} * @see ApiEntityAdapter::validateEntity() */ public function validateEntity($entity) { if (!$entity instanceof Farm) { throw new InvalidArgumentException(sprintf("First argument must be instance of Scalr\\Model\\Entity\\Farm class")); } if ($entity->id !== null) { if (!Farm::findPk($entity->id)) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, sprintf("Could not find out the Farm with ID: %d", $entity->id)); } } else { if (empty($entity->name)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property name"); } $criteria = $this->controller->getScopeCriteria(); $criteria[] = ['name' => $entity->name]; if (count(Farm::find($criteria))) { throw new ApiErrorException(409, ErrorMessage::ERR_UNICITY_VIOLATION, "Farm with name '{$entity->name}' already exists"); } } if (!empty($entity->settings[FarmSetting::EC2_VPC_REGION])) { $region = $entity->settings[FarmSetting::EC2_VPC_REGION]; $vpcId = $entity->settings[FarmSetting::EC2_VPC_ID]; if (!in_array($region, Aws::getCloudLocations())) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Unknown VPC region"); } $gov = new Scalr_Governance($this->controller->getEnvironment()->id); $vpcGovernanceRegions = $gov->getValue(SERVER_PLATFORMS::EC2, Scalr_Governance::AWS_VPC, 'regions'); if (isset($vpcGovernanceRegions)) { if (!array_key_exists($region, $vpcGovernanceRegions)) { $regions = array_keys($vpcGovernanceRegions); throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, sprintf("Only %s %s allowed according to governance settings", ...count($regions) > 1 ? [implode(', ', $regions), 'regions are'] : [array_shift($regions), 'region is'])); } $vpcGovernanceIds = $vpcGovernanceRegions[$region]['ids']; if (!empty($vpcGovernanceIds) && !in_array($vpcId, $vpcGovernanceIds)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, sprintf("Only %s %s allowed according to governance settings", ...count($vpcGovernanceIds) > 1 ? [implode(', ', $vpcGovernanceIds), 'vpcs are'] : [array_shift($vpcGovernanceIds), 'vpc is'])); } } $found = null; /* @var $vpc VpcData */ //TODO rewrite aws service usage foreach ($this->controller->getContainer()->aws($region, $this->controller->getEnvironment())->ec2->vpc->describe() as $vpc) { if ($vpcId == $vpc->vpcId) { $found = $vpc; } } if (empty($found)) { throw new ApiErrorException(400, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Could not find out the VPC with ID '{$vpcId}' in region '{$region}'"); } } else { if (!empty($entity->settings[FarmSetting::EC2_VPC_ID])) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property vpc.region"); } } if (\Scalr::config('scalr.analytics.enabled')) { if (isset($entity->settings[FarmSetting::PROJECT_ID])) { if (!$this->controller->getContainer()->analytics->projects->get($entity->settings[FarmSetting::PROJECT_ID])) { throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "The project is not allowed for you"); } } else { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property project"); } } if (!$this->controller->hasPermissions($entity, true)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } }
/** * Creates clone for the farm * * @param int $farmId Unique farm identifier * * @return ResultEnvelope * * @throws ApiErrorException */ public function cloneAction($farmId) { $farm = $this->getFarm($farmId, Acl::PERM_FARMS_CLONE); if (!$this->getUser()->getAccount()->checkLimit(Limit::ACCOUNT_FARMS, 1)) { throw new ApiErrorException(400, ErrorMessage::ERR_LIMIT_EXCEEDED, "Farms limit for your account exceeded"); } $object = $this->request->getJsonBody(); if (empty($object->name)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property name"); } $name = FarmAdapter::convertInputValue('string', $object->name, 'name'); $criteria = $this->getScopeCriteria(); $criteria[] = ['name' => $name]; if (count(Farm::find($criteria))) { throw new ApiErrorException(409, ErrorMessage::ERR_UNICITY_VIOLATION, "Farm with name '{$name}' already exists"); } $clone = $farm->cloneFarm($name, $this->getUser()); return $this->result($this->adapter('farm')->toData($clone)); }
/** * @param string $platform Name of platform * @param string $cloudLocation Name of location * @param array $ids The list of the identifiers of the cloud instances * @param int $roleId optional Identifier of Role * @return array * @throws Exception */ public function checkStatus($platform, $cloudLocation, $ids, $roleId = null) { if (!in_array($platform, $this->allowedPlatforms)) { throw new Exception(sprintf("Platform '%s' is not supported", $platform)); } if (!$this->environment->isPlatformEnabled($platform)) { throw new Exception(sprintf("Platform '%s' is not enabled", $platform)); } if (empty($ids) || empty($ids[0])) { throw new Exception("You should provide at least one instanceId"); } $instances = PlatformFactory::NewPlatform($platform)->getOrphanedServers($this->getEnvironmentEntity(), $cloudLocation, $ids); $status = ['instances' => $instances]; $imageIds = array_unique(array_map(function ($item) { return $item->imageId; }, $instances)); if (count($imageIds) != 1) { $status['compatibility'] = ['success' => false]; return $status; } /* @var $instance OrphanedServer */ $instance = $instances[0]; $status['compatibility'] = ['success' => true]; // Check vpc compatibility if ($instance->vpcId && $instance->subnetId) { $gov = new Scalr_Governance($this->getEnvironmentId()); $vpcGovernanceRegions = $gov->getValue(SERVER_PLATFORMS::EC2, Scalr_Governance::AWS_VPC, 'regions'); if (isset($vpcGovernanceRegions)) { if (!array_key_exists($cloudLocation, $vpcGovernanceRegions)) { $status['compatibility']['success'] = false; $status['compatibility']['message'] = sprintf('Region <b>%s</b> is not allowed by the Governance.', $cloudLocation); } else { $vpcGovernanceIds = $vpcGovernanceRegions[$cloudLocation]['ids']; if (!empty($vpcGovernanceIds) && !in_array($instance->vpcId, $vpcGovernanceIds)) { $status['compatibility']['success'] = false; $status['compatibility']['message'] = sprintf('VPC <b>%s</b> is not allowed by the Governance.', $instance->vpcId); } else { $vpcGovernanceIds = $gov->getValue(SERVER_PLATFORMS::EC2, Scalr_Governance::AWS_VPC, 'ids'); /* @var $platformObject Ec2PlatformModule */ $platformObject = PlatformFactory::NewPlatform(SERVER_PLATFORMS::EC2); $subnet = $platformObject->listSubnets($this->getEnvironment(), $cloudLocation, $instance->vpcId, true, $instance->subnetId); if (isset($vpcGovernanceIds[$instance->vpcId])) { if (!empty($vpcGovernanceIds[$instance->vpcId]) && is_array($vpcGovernanceIds[$instance->vpcId]) && !in_array($instance->subnetId, $vpcGovernanceIds[$instance->vpcId])) { $status['compatibility']['success'] = false; $status['compatibility']['message'] = sprintf('Subnet <b>%s</b> is prohibited by the Governance.', $instance->subnetId); } else { if ($vpcGovernanceIds[$instance->vpcId] == "outbound-only" && $subnet['type'] != 'private') { $status['compatibility']['success'] = false; $status['compatibility']['message'] = 'Only private subnets are allowed by the Governance.'; } else { if ($vpcGovernanceIds[$instance->vpcId] == "full" && $subnet['type'] != 'public') { $status['compatibility']['success'] = false; $status['compatibility']['message'] = 'Only public subnets are allowed by the Governance.'; } } } } } } } } if (!$status['compatibility']['success']) { return $status; } $scopeCriteria = ['$or' => [['accountId' => null], ['$and' => [['accountId' => $this->getUser()->accountId], ['$or' => [['envId' => null], ['envId' => $this->getEnvironment()->id]]]]]]]; /* @var $image Entity\Image */ $image = Entity\Image::findOne([['platform' => $platform], ['cloudLocation' => $cloudLocation], ['id' => $instance->imageId], $scopeCriteria]); $status['image'] = ['success' => !!$image, 'data' => ['id' => $instance->imageId]]; if ($image) { if ($image->isScalarized) { $status['image']['success'] = false; $status['image']['isScalarized'] = true; return $status; } $status['image']['data'] = ['hash' => $image->hash, 'name' => $image->name, 'id' => $image->id, 'scope' => $image->getScope()]; $criteria = [['platform' => $platform], ['imageId' => $image->id]]; if (!($platform == SERVER_PLATFORMS::GCE || $platform == SERVER_PLATFORMS::AZURE)) { $criteria[] = ['cloudLocation' => $cloudLocation]; } $roleIds = []; foreach (Entity\RoleImage::find($criteria) as $ri) { $roleIds[] = $ri->roleId; } if (count($roleIds)) { $roles = Entity\Role::find([['id' => ['$in' => $roleIds]], ['isScalarized' => false], $scopeCriteria]); $status['role'] = ['availableRoles' => [], 'image' => Scalr_UI_Controller_Images::controller()->convertEntityToArray($image)]; $selectedRole = null; if (count($roles) == 1) { $selectedRole = $roles->current(); } else { if ($roleId && in_array($roleId, $roleIds)) { foreach ($roles as $role) { /* @var $role Entity\Role */ if ($role->id == $roleId) { $selectedRole = $role; break; } } } } foreach ($roles as $role) { /* @var $role Entity\Role */ $status['role']['availableRoles'][] = ['id' => $role->id, 'name' => $role->name, 'scope' => $role->getScope()]; } if ($selectedRole) { $status['role']['success'] = true; $status['role']['data'] = ['id' => $selectedRole->id, 'name' => $selectedRole->name, 'scope' => $selectedRole->getScope()]; $farms = []; $status['farmrole'] = ['instance' => ['instanceType' => $instance->instanceType, 'vpcId' => $instance->vpcId, 'subnetId' => $instance->subnetId, 'roleName' => $selectedRole->name]]; foreach (Entity\Farm::find([['envId' => $this->getEnvironment()->id], ['status' => FARM_STATUS::RUNNING]]) as $farm) { /* @var $farm Entity\Farm */ if ($this->request->hasPermissions($farm, Acl::PERM_FARMS_UPDATE) && $this->request->hasPermissions($farm, Acl::PERM_FARMS_SERVERS)) { // cloud specific (EC2) if ($farm->settings[Entity\FarmSetting::EC2_VPC_ID] == $instance->vpcId) { $farms[$farm->id] = ['id' => $farm->id, 'name' => $farm->name, 'farmroles' => []]; } } } foreach (Entity\FarmRole::find([['farmId' => ['$in' => array_keys($farms)]], ['roleId' => $selectedRole->id]]) as $farmRole) { /* @var $farmRole Entity\FarmRole */ if (isset($farms[$farmRole->farmId])) { if (!$instance->subnetId || $instance->subnetId && in_array($instance->subnetId, json_decode($farmRole->settings[Entity\FarmRoleSetting::AWS_VPC_SUBNET_ID]))) { $farms[$farmRole->farmId]['farmroles'][] = ['id' => $farmRole->id, 'name' => $farmRole->alias, 'tags' => $farmRole->getCloudTags(true)]; } } } $status['farmrole']['data'] = array_values($farms); $status['farmrole']['success'] = false; } else { if (count($roles) > 1) { $status['role']['success'] = false; } else { $status['role']['success'] = false; } } } else { $status['role']['success'] = false; $status['role']['image'] = Scalr_UI_Controller_Images::controller()->convertEntityToArray($image); } } return $status; }
/** * Get information about role * * @param int $roleId Identifier of role * @param bool $extended Get extended information about role * @param array $canAddImage Array of platform, cloudLocation to check if role has image in that location * @return array * @throws Exception * @throws Scalr_Exception_Core * @throws Scalr_Exception_InsufficientPermissions */ private function getInfo($roleId, $extended = false, $canAddImage = null) { /* @var $role Role */ $role = Role::findPk($roleId); if (!$role) { throw new Scalr_Exception_Core(sprintf(_("Role ID#%s not found in database"), $roleId)); } $this->request->checkPermissions($role); $usedBy = $role->getFarmsCount($this->user->getAccountId(), $this->getEnvironmentId(true)); $platforms = array_keys($role->fetchImagesArray()); $allPlatforms = array_flip(array_keys(SERVER_PLATFORMS::GetList())); usort($platforms, function ($a, $b) use($allPlatforms) { return $allPlatforms[$a] > $allPlatforms[$b] ? 1 : -1; }); $result = array('name' => $role->name, 'behaviors' => $role->getBehaviors(), 'id' => $role->id, 'accountId' => $role->accountId, 'envId' => $role->envId, 'catId' => $role->catId, 'status' => $usedBy > 0 ? 'In use' : 'Not used', 'scope' => $role->getScope(), 'os' => $role->getOs()->name, 'osId' => $role->osId, 'osFamily' => $role->getOs()->family, 'dtAdded' => $role->added ? Scalr_Util_DateTime::convertTz($role->added) : NULL, 'dtLastUsed' => $role->lastUsed ? Scalr_Util_DateTime::convertTz($role->lastUsed) : NULL, 'isQuickStart' => $role->isQuickStart, 'isDeprecated' => $role->isDeprecated, 'isScalarized' => $role->isScalarized, 'platforms' => $platforms, 'environments' => !empty($envs = $role->getAllowedEnvironments()) ? $this->db->GetCol("SELECT name FROM client_environments WHERE id IN(" . join(',', $envs) . ")") : []); if ($canAddImage) { try { $role->getImage($canAddImage['platform'], $canAddImage['cloudLocation']); $result['canAddImage'] = false; } catch (Exception $e) { $result['canAddImage'] = true; } } if ($extended) { $result['description'] = $role->description; $result['images'] = []; foreach (RoleImage::find([['roleId' => $role->id]]) as $image) { /* @var $image RoleImage */ $im = $image->getImage(); $ext = []; if ($im) { $ext = get_object_vars($im); $ext['software'] = $im->getSoftwareAsString(); } $result['images'][] = ['imageId' => $image->imageId, 'platform' => $image->platform, 'cloudLocation' => $image->cloudLocation, 'extended' => $ext]; } if ($result['status'] == 'In use' && $this->getEnvironmentId(true)) { $farms = []; $f = []; foreach (FarmRole::find([['roleId' => $role->id]]) as $farmRole) { /* @var $farmRole FarmRole */ $f[] = $farmRole->farmId; } $f = array_unique($f); if (count($f)) { foreach (Farm::find([['id' => ['$in' => $f]], ['envId' => $this->getEnvironmentId()]]) as $fm) { /* @var $fm Farm */ $farms[] = ['id' => $fm->id, 'name' => $fm->name]; } } $result['usedBy'] = ['farms' => $farms, 'cnt' => count($farms)]; } } return $result; }