/** * @test * @functional */ public function testComplex() { $user = $this->getUser(); $environment = $this->getEnvironment(); $fictionController = new ApiController(); /* @var $farm Farm */ $farm = static::createEntity(new Farm(), ['changedById' => $user->getId(), 'name' => "{$this->uuid}-farm", 'comments' => "{$this->uuid}-description", 'envId' => $environment->id, 'accountId' => $user->getAccountId(), 'ownerId' => $user->getId()]); /* @var $roles EntityIterator */ /* @var $role Role */ $roles = Role::findByName('base-ubuntu1404'); if (empty($roles) || !count($roles)) { $this->markTestSkipped("Not found suitable role, required role - 'base-ubuntu1404'"); } else { $role = $roles->current(); } //test Governance $this->getGovernance(); /* @var $vpcList VpcList */ $vpcList = \Scalr::getContainer()->aws(self::TEST_REGION, $this->getEnvironment())->ec2->vpc->describe(self::TEST_VPC_ID); /* @var $vpc VpcData */ $vpc = $vpcList->current(); /* @var $subnetList SubnetList */ $subnetList = \Scalr::getContainer()->aws(self::TEST_REGION, $this->getEnvironment())->ec2->subnet->describe(null, [['name' => SubnetFilterNameType::vpcId(), 'value' => $vpc->vpcId]]); /* @var $subnet SubnetData */ $subnet = $subnetList->current(); //setup test governance $vpcId = $vpc->vpcId; $subnetId = $subnet->subnetId; $governanceConfiguration = [SERVER_PLATFORMS::EC2 => [Scalr_Governance::INSTANCE_TYPE => ['enabled' => true, 'limits' => ['value' => ['t1.micro', 't2.small', 't2.medium', 't2.large'], 'default' => ['t2.small']]], Scalr_Governance::AWS_VPC => ['enabled' => true, 'limits' => ['regions' => [self::TEST_REGION => ['default' => true, 'ids' => [$vpcId]]], 'ids' => [$vpcId => [$subnetId]]]]]]; $this->setupGovernanceConfiguration($governanceConfiguration); //farm role data $data = ['role' => ['id' => $role->id], 'alias' => 't-ps', 'platform' => SERVER_PLATFORMS::EC2, 'placement' => ['placementConfigurationType' => FarmRoles::AWS_CLASSIC_PLACEMENT_CONFIGURATION, 'region' => static::TEST_REGION], 'scaling' => ['enabled' => true, 'minInstances' => 2, 'maxInstances' => 3], 'instance' => ['instanceConfigurationType' => FarmRoles::AWS_INSTANCE_CONFIGURATION, 'instanceType' => ['id' => 't1.micro']]]; //create farmRole with wrong instance type $data['instance']['instanceType']['id'] = 'm1.small'; $response = $this->postFarmRole($farm->id, $data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_VALUE); //Add AWS VPC settings $farm->settings[FarmSetting::EC2_VPC_ID] = $vpc->vpcId; $farm->settings[FarmSetting::EC2_VPC_REGION] = self::TEST_REGION; $farm->save(); //create farm role with AwsClassicPlacementConfiguration $data['instance']['instanceType']['id'] = 't2.small'; $response = $this->postFarmRole($farm->id, $data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_STRUCTURE); //create farm role with incorrect subnet $subnetList->next(); /* @var $incorrectSubnet SubnetData */ $incorrectSubnet = $subnetList->current(); $data['placement'] = ['region' => self::TEST_REGION, 'placementConfigurationType' => 'AwsVpcPlacementConfiguration', 'subnets' => [['id' => $incorrectSubnet->subnetId]]]; $response = $this->postFarmRole($farm->id, $data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_VALUE); //create farm role with incorrect region $data['placement'] = ['region' => Aws::REGION_US_WEST_1, 'placementConfigurationType' => 'AwsVpcPlacementConfiguration', 'subnets' => [['id' => $subnetId]]]; $response = $this->postFarmRole($farm->id, $data); $this->assertErrorMessageContains($response, 400, ErrorMessage::ERR_INVALID_VALUE); //post farm role correct data $data['placement']['region'] = self::TEST_REGION; $data['alias'] = 't-ps-1'; $response = $this->postFarmRole($farm->id, $data); $this->assertEquals(201, $response->status, $this->printResponseError($response)); $farmRoleId = $response->getBody()->data->id; /* @var $farmRole FarmRole */ $farmRole = FarmRole::findPk($farmRoleId); $this->assertNotEmpty($farmRole); $this->farmRoleToDelete($farmRoleId); $data['scaling']['rules'] = []; $this->assertObjectEqualsEntity($data, $farmRole); //Reset AWS VPC settings $farm->settings[FarmSetting::EC2_VPC_ID] = null; $farm->settings[FarmSetting::EC2_VPC_REGION] = null; $farm->save(); //set default governance settings $this->restoreGovernanceConfiguration(); //test farm roles post $data = ['role' => ['id' => $role->id], 'alias' => 't-ps-2', 'platform' => SERVER_PLATFORMS::EC2, 'placement' => ['placementConfigurationType' => FarmRoles::AWS_CLASSIC_PLACEMENT_CONFIGURATION, 'region' => static::TEST_REGION], 'scaling' => ['enabled' => true, 'minInstances' => 2, 'maxInstances' => 3], 'instance' => ['instanceConfigurationType' => FarmRoles::AWS_INSTANCE_CONFIGURATION, 'instanceType' => ['id' => 't1.micro']]]; $response = $this->postFarmRole($farm->id, $data); $this->assertEquals(201, $response->status, $this->printResponseError($response)); $farmRoleId = $response->getBody()->data->id; /* @var $farmRole FarmRole */ $farmRole = FarmRole::findPk($farmRoleId); $this->assertNotEmpty($farmRole); $this->farmRoleToDelete($farmRoleId); $data['placement']['availabilityZones'] = ''; $data['scaling']['rules'] = []; $this->assertObjectEqualsEntity($data, $farmRole); //test farm role modify scaling $data = ['scaling' => ['enabled' => false]]; $response = $this->modifyFarmRole($farmRole->id, $data); $this->assertEquals(200, $response->status, $this->printResponseError($response)); $farmRoleData = $response->getBody()->data; $this->assertObjectHasAttribute('scaling', $farmRoleData); $scalingConfiguration = $farmRoleData->scaling; $this->assertObjectNotHasAttribute('enabled', $scalingConfiguration); //test modify instance $data = ['instance' => ['instanceConfigurationType' => FarmRoles::AWS_INSTANCE_CONFIGURATION, 'instanceType' => 'm3.medium']]; $response = $this->modifyFarmRole($farmRole->id, $data); $this->assertEquals(200, $response->status, $this->printResponseError($response)); $farmRoleData = $response->getBody()->data; $this->assertObjectHasAttribute('instance', $farmRoleData); $instanceConfiguration = $farmRoleData->instance; $this->assertObjectHasAttribute('instanceType', $instanceConfiguration); $instanceType = $instanceConfiguration->instanceType; $this->assertObjectHasAttribute('id', $instanceType); $this->assertEquals('m3.medium', $instanceType->id); //test list farm roles filters $farmRoles = $this->listFarmRoles($farm->id); $farmRoleAdapter = $this->getAdapter('farmRole'); $filterable = $farmRoleAdapter->getRules()[ApiEntityAdapter::RULE_TYPE_FILTERABLE]; /* @var $farmRole FarmRole */ foreach ($farmRoles as $farmRole) { foreach ($filterable as $property) { $filterValue = $farmRole->{$property}; $listResult = $this->listFarmRoles($farm->id, [$property => $filterValue]); if (!static::isRecursivelyEmpty($filterValue)) { foreach ($listResult as $filtered) { $this->assertEquals($filterValue, $filtered->{$property}, "Property '{$property}' mismatch"); } } } $response = $this->getFarmRole($farmRole->id); $this->assertEquals(200, $response->status, $this->printResponseError($response)); $dbFarmRole = FarmRole::findPk($farmRole->id); $this->assertObjectEqualsEntity($response->getBody()->data, $dbFarmRole, $farmRoleAdapter); } }
/** * Get FarmRole entity * * @return FarmRole|null */ public function getFarmRole() { if (empty($this->_farmRole) && !empty($this->farmRoleId)) { $this->_farmRole = FarmRole::findPk($this->farmRoleId); } return $this->_farmRole; }
/** * Gets specified Farm Role taking into account both scope and authentication token * * @param string $farmRoleId Numeric identifier of the Farm role * @param int $farmId optional Identifier of the Farm containing Farm role * @param bool $modify optional Flag checking write permissions * * @return FarmRole Returns the Script Entity on success * @throws ApiErrorException */ public function getFarmRole($farmRoleId, $farmId = null, $modify = false) { /* @var $role FarmRole */ $role = FarmRole::findPk($farmRoleId); if (!$role) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Requested Farm Role either does not exist or is not owned by your environment."); } if (isset($farmId)) { if ($role->farmId != $farmId) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Invalid identifier of the farm"); } } else { $farmId = $role->farmId; } $this->getFarm($farmId, $modify); if (!$this->hasPermissions($role, $modify)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } return $role; }
/** * @param string $platform Name of platform * @param string $instanceId The identifier of the cloud instance * @param int $farmRoleId The identifier of farmRole * @param JsonData $tags Additional tags * @throws Exception */ public function xImportAction($platform, $instanceId, $farmRoleId, JsonData $tags) { 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($instanceId)) { throw new Exception('InstanceId cannot be empty'); } /* @var $farmRole Entity\FarmRole */ if (!$farmRoleId || !($farmRole = Entity\FarmRole::findPk($farmRoleId))) { throw new Exception('FarmRole was not found'); } $this->request->checkPermissions($farmRole, true); $this->request->checkPermissions($farmRole->getFarm(), Acl::PERM_FARMS_UPDATE); $this->request->checkPermissions($farmRole->getFarm(), Acl::PERM_FARMS_SERVERS); $farmRole->settings[Entity\FarmRoleSetting::SCALING_ENABLED] = 0; $farmRole->settings->save(); $farmRole->getServerImport($this->getUser())->import($instanceId, (array) $tags); $this->response->success(); }
/** * @return Image */ public function createImageEntity() { $snapshot = $this->getSnapshotDetails(); $envId = $this->envId; /* @var Entity\Server $server */ $server = Entity\Server::findOneByServerId($this->serverId); if (!empty($server->farmRoleId)) { /* @var Entity\FarmRole $farmRole */ $farmRole = Entity\FarmRole::findPk($server->farmRoleId); if (!empty($farmRole->roleId)) { /* @var Entity\Role $role */ $role = Entity\Role::findPk($farmRole->roleId); $envId = $role->getScope() == ScopeInterface::SCOPE_ACCOUNT ? NULL : $envId; } } $image = new Image(); $image->id = $this->snapshotId; $image->accountId = $this->clientId; $image->envId = $envId; $image->bundleTaskId = $this->id; $image->platform = $this->platform; $image->cloudLocation = $this->cloudLocation; $image->createdById = $this->createdById; $image->createdByEmail = $this->createdByEmail; $image->architecture = is_null($snapshot['os']->arch) ? 'x86_64' : $snapshot['os']->arch; $image->source = Image::SOURCE_BUNDLE_TASK; $image->status = Image::STATUS_ACTIVE; $image->agentVersion = $snapshot['szr_version']; $image->checkImage(); if (!$image->name) { $image->name = $this->roleName . '-' . date('YmdHi'); } $image->osId = $this->osId; $image->save(); if ($snapshot['software']) { $software = []; foreach ((array) $snapshot['software'] as $soft) { $software[$soft->name] = $soft->version; } $image->setSoftware($software); } return $image; }
/** * {@inheritdoc} * @see ApiEntityAdapter::validateEntity() */ public function validateEntity($entity) { if (!$entity instanceof FarmRole) { throw new InvalidArgumentException(sprintf("First argument must be instance of Scalr\\Model\\Entity\\FarmRole class")); } if ($entity->id !== null) { if (!FarmRole::findPk($entity->id)) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, sprintf("Could not find out the Farm with ID: %d", $entity->id)); } } if (empty($entity->farmId)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property farm.id"); } else { $farm = $this->controller->getFarm($entity->farmId, true); } if (empty($entity->roleId)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property role.id"); } if (empty($entity->platform)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property platform"); } switch ($entity->platform) { case SERVER_PLATFORMS::EC2: if (empty($entity->settings[FarmRoleSetting::AWS_INSTANCE_TYPE])) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Missed property instance.type"); } /* @var $platform Ec2PlatformModule */ $platform = PlatformFactory::NewPlatform(SERVER_PLATFORMS::EC2); if (!in_array($entity->settings[FarmRoleSetting::AWS_INSTANCE_TYPE], $platform->getInstanceTypes())) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Wrong instance type"); } $gov = new Scalr_Governance($this->controller->getEnvironment()->id); $allowGovernanceIns = $gov->getValue(SERVER_PLATFORMS::EC2, Scalr_Governance::AWS_INSTANCE_TYPE); if (isset($allowGovernanceIns) && !in_array($entity->settings[FarmRoleSetting::AWS_INSTANCE_TYPE], $allowGovernanceIns)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, sprintf("Only %s %s allowed according to governance settings", ...count($allowGovernanceIns) > 1 ? [implode(', ', $allowGovernanceIns), 'instances are'] : [array_shift($allowGovernanceIns), 'instance is'])); } if (!in_array($entity->cloudLocation, Aws::getCloudLocations())) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Unknown region"); } $vpcGovernanceRegions = $gov->getValue(SERVER_PLATFORMS::EC2, Scalr_Governance::AWS_VPC, 'regions'); if (isset($vpcGovernanceRegions) && !array_key_exists($entity->cloudLocation, $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'])); } $env = Scalr_Environment::init()->loadById($this->controller->getEnvironment()->id); $aws = $this->controller->getContainer()->aws($entity->cloudLocation, $env); if (!empty($entity->settings[FarmRoleSetting::AWS_AVAIL_ZONE]) && $entity->settings[FarmRoleSetting::AWS_AVAIL_ZONE] !== 'x-scalr-diff') { $availZones = explode(":", str_replace("x-scalr-custom=", '', $entity->settings[FarmRoleSetting::AWS_AVAIL_ZONE])); $ec2availabilityZones = []; foreach ($aws->ec2->availabilityZone->describe() as $zone) { /* @var $zone AvailabilityZoneData */ if (stristr($zone->zoneState, 'available')) { $ec2availabilityZones[] = $zone->zoneName; } } $diffZones = array_diff($availZones, $ec2availabilityZones); if (!empty($diffZones)) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, sprintf('%s %s available. Available zones are %s', ...count($diffZones) > 1 ? [implode(', ', $diffZones), 'zones are not', implode(', ', $ec2availabilityZones)] : [array_shift($diffZones), 'zone is not', implode(', ', $ec2availabilityZones)])); } } if (!empty($entity->settings[FarmRoleSetting::AWS_VPC_SUBNET_ID])) { $vpcId = $farm->settings[FarmSetting::EC2_VPC_ID]; $subnets = $platform->listSubnets($env, $entity->cloudLocation, $vpcId, true); $vpcGovernanceIds = $gov->getValue(SERVER_PLATFORMS::EC2, Scalr_Governance::AWS_VPC, 'ids'); $subnetType = null; foreach (json_decode($entity->settings[FarmRoleSetting::AWS_VPC_SUBNET_ID]) as $subnetId) { $found = false; foreach ($subnets as $subnet) { if ($subnet['id'] == $subnetId) { if ($subnetType == null) { $subnetType = $subnet['type']; } else { if ($subnet['type'] != $subnetType) { throw new ApiErrorException(409, ErrorMessage::ERR_UNICITY_VIOLATION, "All subnets must be a same type"); } } //check governance subnet settings if (isset($vpcGovernanceIds[$vpcId])) { if (!empty($vpcGovernanceIds[$vpcId]) && is_array($vpcGovernanceIds[$vpcId]) && !in_array($subnetId, $vpcGovernanceIds[$vpcId])) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, sprintf("Only %s %s allowed by governance settings", ...count($vpcGovernanceIds[$vpcId]) > 1 ? [implode(', ', $vpcGovernanceIds[$vpcId]), 'subnets are'] : [array_shift($vpcGovernanceIds[$vpcId]), 'subnet is'])); } elseif ($vpcGovernanceIds[$vpcId] == "outbound-only" && $subnetType != 'private') { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Only private subnets allowed by governance settings"); } elseif ($vpcGovernanceIds[$vpcId] == "full" && $subnetType != 'public') { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Only public subnets allowed by governance settings"); } } $found = true; } } if (!$found) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Subnet with id '{$subnetId}' not found"); } } if (!empty($entity->settings[Scalr_Role_Behavior_Router::ROLE_VPC_SCALR_ROUTER_ID])) { $router = $this->controller->getFarmRole($entity->settings[Scalr_Role_Behavior_Router::ROLE_VPC_SCALR_ROUTER_ID]); if (empty($router->settings[Scalr_Role_Behavior_Router::ROLE_VPC_NID])) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Farm-role with id '{$router->id}' is not a valid router"); } } else { if ($subnetType == 'private') { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "You must describe a VPC Router"); } } } else { if ($farm->settings[FarmSetting::EC2_VPC_ID]) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "VPC Subnet(s) should be described"); } } break; default: if (in_array($entity->platform, SERVER_PLATFORMS::GetList())) { throw new ApiErrorException(501, ErrorMessage::ERR_NOT_IMPLEMENTED, "Platform '{$entity->platform}' is not supported yet"); } else { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Unknown platform '{$entity->platform}'"); } } if (!$this->controller->hasPermissions($entity, true)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } }
/** * {@inheritdoc} * @see ApiEntityAdapter::validateEntity() */ public function validateEntity($entity) { if (!$entity instanceof FarmRole) { throw new InvalidArgumentException(sprintf("First argument must be instance of Scalr\\Model\\Entity\\FarmRole class")); } if ($entity->id !== null) { if (!FarmRole::findPk($entity->id)) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, sprintf("Could not find out the Farm with ID: %d", $entity->id)); } } if (empty($entity->farmId)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property farm.id"); } else { /* @var $farm Farm */ $farm = $this->controller->getFarm($entity->farmId, true); } if (empty($entity->alias)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property alias"); } if (!preg_match("/^[[:alnum:]](?:-*[[:alnum:]])*\$/", $entity->alias)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Alias should start and end with letter or number and contain only letters, numbers and dashes."); } if (empty($entity->roleId)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property role.id"); } $roleBehaviors = $entity->getRole()->getBehaviors(); $uniqueBehaviors = array_intersect($roleBehaviors, array_merge(...array_values(static::$uniqueFarmBehaviors))); if (!empty($uniqueBehaviors)) { //farm can include only one mysql or percona role if (array_intersect($uniqueBehaviors, static::$uniqueFarmBehaviors[ROLE_BEHAVIORS::MYSQL])) { $uniqueBehaviors = array_merge($uniqueBehaviors, array_diff(static::$uniqueFarmBehaviors[ROLE_BEHAVIORS::MYSQL], $uniqueBehaviors)); } $farmRoleEntity = new FarmRole(); $roleEntity = new Role(); /* @var $conflicts EntityIterator */ $conflicts = Role::find([AbstractEntity::STMT_FROM => "{$roleEntity->table()} JOIN {$farmRoleEntity->table('fr')} ON {$farmRoleEntity->columnRoleId('fr')} = {$roleEntity->columnId()}", AbstractEntity::STMT_WHERE => "{$farmRoleEntity->columnFarmId('fr')} = {$farmRoleEntity->qstr('farmId', $entity->farmId)} " . (empty($entity->id) ? '' : " AND {$farmRoleEntity->columnId('fr')} <> {$farmRoleEntity->qstr('id', $entity->id)}"), ['behaviors' => ['$regex' => implode('|', $uniqueBehaviors)]]]); if ($conflicts->count() > 0) { $conflictedBehaviors = []; /* @var $role Role */ foreach ($conflicts as $role) { $conflictedBehaviors = array_merge($conflictedBehaviors, array_intersect($uniqueBehaviors, $role->getBehaviors())); } if (!empty(array_intersect($conflictedBehaviors, static::$uniqueFarmBehaviors[ROLE_BEHAVIORS::MYSQL]))) { $conflictedBehaviors = array_diff($conflictedBehaviors, static::$uniqueFarmBehaviors[ROLE_BEHAVIORS::MYSQL]); $conflictedBehaviors[] = 'mysql/percona'; } $conflictedBehaviors = RoleAdapter::behaviorsToData($conflictedBehaviors); throw new ApiErrorException(409, ErrorMessage::ERR_UNICITY_VIOLATION, sprintf('Only one [%s] role can be added to farm', implode(', ', $conflictedBehaviors))); } } if (empty($entity->platform)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property platform"); } switch ($entity->platform) { case SERVER_PLATFORMS::EC2: if (empty($entity->settings[FarmRoleSetting::INSTANCE_TYPE])) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Missed property instance.type"); } /* @var $platform Ec2PlatformModule */ $platform = PlatformFactory::NewPlatform(SERVER_PLATFORMS::EC2); if (!in_array($entity->settings[FarmRoleSetting::INSTANCE_TYPE], $platform->getInstanceTypes())) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Wrong instance type"); } $gov = new Scalr_Governance($this->controller->getEnvironment()->id); $allowGovernanceIns = $gov->getValue(SERVER_PLATFORMS::EC2, Scalr_Governance::INSTANCE_TYPE); if (isset($allowGovernanceIns) && !in_array($entity->settings[FarmRoleSetting::INSTANCE_TYPE], $allowGovernanceIns)) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, sprintf("Only %s %s allowed according to governance settings", ...count($allowGovernanceIns) > 1 ? [implode(', ', $allowGovernanceIns), 'instances are'] : [array_shift($allowGovernanceIns), 'instance is'])); } if (!in_array($entity->cloudLocation, Aws::getCloudLocations())) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Unknown region"); } $vpcGovernanceRegions = $gov->getValue(SERVER_PLATFORMS::EC2, Scalr_Governance::AWS_VPC, 'regions'); if (isset($vpcGovernanceRegions) && !array_key_exists($entity->cloudLocation, $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'])); } $env = Scalr_Environment::init()->loadById($this->controller->getEnvironment()->id); $aws = $this->controller->getContainer()->aws($entity->cloudLocation, $env); if (!empty($entity->settings[FarmRoleSetting::AWS_AVAIL_ZONE]) && $entity->settings[FarmRoleSetting::AWS_AVAIL_ZONE] !== 'x-scalr-diff') { $availZones = explode(":", str_replace("x-scalr-custom=", '', $entity->settings[FarmRoleSetting::AWS_AVAIL_ZONE])); $ec2availabilityZones = []; foreach ($aws->ec2->availabilityZone->describe() as $zone) { /* @var $zone AvailabilityZoneData */ if (stristr($zone->zoneState, 'available')) { $ec2availabilityZones[] = $zone->zoneName; } } $diffZones = array_diff($availZones, $ec2availabilityZones); if (!empty($diffZones)) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, sprintf('%s %s available. Available zones are %s', ...count($diffZones) > 1 ? [implode(', ', $diffZones), 'zones are not', implode(', ', $ec2availabilityZones)] : [array_shift($diffZones), 'zone is not', implode(', ', $ec2availabilityZones)])); } } if (!empty($farm->settings[FarmSetting::EC2_VPC_ID])) { if (empty($entity->settings[FarmRoleSetting::AWS_VPC_SUBNET_ID])) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "VPC Subnet(s) should be described"); } $vpcId = $farm->settings[FarmSetting::EC2_VPC_ID]; $subnets = $platform->listSubnets($env, $entity->cloudLocation, $vpcId, true); $vpcGovernanceIds = $gov->getValue(SERVER_PLATFORMS::EC2, Scalr_Governance::AWS_VPC, 'ids'); $subnetType = null; foreach (json_decode($entity->settings[FarmRoleSetting::AWS_VPC_SUBNET_ID]) as $subnetId) { $found = false; foreach ($subnets as $subnet) { if ($subnet['id'] == $subnetId) { if ($subnetType == null) { $subnetType = $subnet['type']; } else { if ($subnet['type'] != $subnetType) { throw new ApiErrorException(409, ErrorMessage::ERR_UNICITY_VIOLATION, "All subnets must be a same type"); } } //check governance subnet settings if (isset($vpcGovernanceIds[$vpcId])) { if (!empty($vpcGovernanceIds[$vpcId]) && is_array($vpcGovernanceIds[$vpcId]) && !in_array($subnetId, $vpcGovernanceIds[$vpcId])) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, sprintf("Only %s %s allowed by governance settings", ...count($vpcGovernanceIds[$vpcId]) > 1 ? [implode(', ', $vpcGovernanceIds[$vpcId]), 'subnets are'] : [array_shift($vpcGovernanceIds[$vpcId]), 'subnet is'])); } else { if ($vpcGovernanceIds[$vpcId] == "outbound-only" && $subnetType != 'private') { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Only private subnets allowed by governance settings"); } else { if ($vpcGovernanceIds[$vpcId] == "full" && $subnetType != 'public') { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Only public subnets allowed by governance settings"); } } } } $found = true; } } if (!$found) { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Subnet with id '{$subnetId}' not found"); } } if (!empty($entity->settings[Scalr_Role_Behavior_Router::ROLE_VPC_SCALR_ROUTER_ID])) { $router = $this->controller->getFarmRole($entity->settings[Scalr_Role_Behavior_Router::ROLE_VPC_SCALR_ROUTER_ID]); if (empty($router->settings[Scalr_Role_Behavior_Router::ROLE_VPC_NID])) { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Farm-role with id '{$router->id}' is not a valid router"); } } else { if (\Scalr::config('scalr.instances_connection_policy') != 'local' && $subnetType == 'private') { throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "You must describe a VPC Router"); } } } break; default: if (isset(SERVER_PLATFORMS::GetList()[$entity->platform])) { throw new ApiErrorException(501, ErrorMessage::ERR_NOT_IMPLEMENTED, "Platform '{$entity->platform}' is not supported yet"); } else { throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Unknown platform '{$entity->platform}'"); } } if (!$this->controller->hasPermissions($entity, true)) { //Checks entity level write access permissions throw new ApiErrorException(403, ErrorMessage::ERR_PERMISSION_VIOLATION, "Insufficient permissions"); } }
/** * {@inheritdoc} * @see OrchestrationRule::hasAccessPermissions() */ public function hasAccessPermissions($user, $environment = null, $modify = null) { return FarmRole::findPk($this->farmRoleId)->hasAccessPermissions($user, $environment, $modify); }