Scalr\Api\Service\User\V1beta0\Adapter\FarmRoleAdapter::validateEntity PHP Method

validateEntity() public method

See also: ApiEntityAdapter::validateEntity()
public validateEntity ( $entity )
    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");
        }
    }