getCloudLocations() public static method

Gets defined AWS cloud locations
public static getCloudLocations ( ) : array
return array
Ejemplo n.º 1
0
 /**
  * {@inheritdoc}
  * @see \Scalr\System\Zmq\Cron\TaskInterface::enqueue()
  */
 public function enqueue()
 {
     $queue = new ArrayObject([]);
     if (!\Scalr::getContainer()->analytics->enabled) {
         $this->log("INFO", "Terminating the process as Cost analytics is disabled in the config.");
         exit;
     }
     if (SettingEntity::getValue(SettingEntity::ID_FORBID_AUTOMATIC_UPDATE_AWS_PRICES)) {
         $this->log("INFO", "Terminating the process because of overriding AWS prices has been forbidden by financial admin.");
         exit;
     }
     $now = new DateTime('now', new DateTimeZone('UTC'));
     $urls = array('https://a0.awsstatic.com/pricing/1/ec2/linux-od.min.js', 'https://a0.awsstatic.com/pricing/1/ec2/mswin-od.min.js', 'https://a0.awsstatic.com/pricing/1/ec2/previous-generation/linux-od.min.js', 'https://a0.awsstatic.com/pricing/1/ec2/previous-generation/mswin-od.min.js');
     $availableLocations = Aws::getCloudLocations();
     foreach ($urls as $link) {
         $json = trim(preg_replace('/^.+?callback\\((.+?)\\);\\s*$/sU', '\\1', $this->getPricingContent($link)));
         $data = json_decode(preg_replace('/(\\w+):/', '"\\1":', $json));
         if (!empty($data->config->regions)) {
             foreach ($data->config->regions as $rd) {
                 $rd->url = basename($link);
                 $queue->append($rd);
             }
         }
     }
     return $queue;
 }
Ejemplo n.º 2
0
 private function saveEc2()
 {
     $pars = [];
     $enabled = false;
     $envAutoEnabled = false;
     $bNew = !$this->env->isPlatformEnabled(SERVER_PLATFORMS::EC2);
     $currentCloudCredentials = $this->env->keychain(SERVER_PLATFORMS::EC2);
     $ccProps = $currentCloudCredentials->properties;
     if ($this->getParam('ec2_is_enabled')) {
         $enabled = true;
         $pars[Entity\CloudCredentialsProperty::AWS_ACCOUNT_TYPE] = trim($this->checkVar(Entity\CloudCredentialsProperty::AWS_ACCOUNT_TYPE, 'string', "AWS Account Type required", SERVER_PLATFORMS::EC2));
         $pars[Entity\CloudCredentialsProperty::AWS_ACCESS_KEY] = trim($this->checkVar(Entity\CloudCredentialsProperty::AWS_ACCESS_KEY, 'string', "AWS Access Key required", SERVER_PLATFORMS::EC2));
         $pars[Entity\CloudCredentialsProperty::AWS_SECRET_KEY] = trim($this->checkVar(Entity\CloudCredentialsProperty::AWS_SECRET_KEY, 'password', "AWS Access Key required", SERVER_PLATFORMS::EC2));
         $pars[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY] = $this->checkVar(Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY, 'file', '', SERVER_PLATFORMS::EC2);
         $pars[Entity\CloudCredentialsProperty::AWS_CERTIFICATE] = $this->checkVar(Entity\CloudCredentialsProperty::AWS_CERTIFICATE, 'file', '', SERVER_PLATFORMS::EC2);
         if ($this->getContainer()->analytics->enabled) {
             $pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_ENABLED] = $this->checkVar2(Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_ENABLED, 'bool', '', SERVER_PLATFORMS::EC2);
             if (!empty($pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_ENABLED])) {
                 $pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_BUCKET] = $this->checkVar(Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_BUCKET, 'string', "Detailed billing bucket name is required", SERVER_PLATFORMS::EC2);
                 $pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_PAYER_ACCOUNT] = $this->checkVar2(Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_PAYER_ACCOUNT, 'string', '', SERVER_PLATFORMS::EC2);
                 $pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_REGION] = $this->checkVar(Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_REGION, 'string', "Aws region is required", SERVER_PLATFORMS::EC2);
             } else {
                 $pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_BUCKET] = false;
                 $pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_PAYER_ACCOUNT] = false;
                 $pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_REGION] = false;
             }
         }
         // user can mull certificate and private key, check it
         if (strpos($pars[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY], 'BEGIN CERTIFICATE') !== FALSE && strpos($pars[Entity\CloudCredentialsProperty::AWS_CERTIFICATE], 'BEGIN PRIVATE KEY') !== FALSE) {
             // swap it
             $key = $pars[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY];
             $pars[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY] = $pars[Entity\CloudCredentialsProperty::AWS_CERTIFICATE];
             $pars[Entity\CloudCredentialsProperty::AWS_CERTIFICATE] = $key;
         }
         if ($pars[Entity\CloudCredentialsProperty::AWS_ACCOUNT_TYPE] == Entity\CloudCredentialsProperty::AWS_ACCOUNT_TYPE_GOV_CLOUD) {
             $region = \Scalr\Service\Aws::REGION_US_GOV_WEST_1;
         } else {
             if ($pars[Entity\CloudCredentialsProperty::AWS_ACCOUNT_TYPE] == Entity\CloudCredentialsProperty::AWS_ACCOUNT_TYPE_CN_CLOUD) {
                 $region = \Scalr\Service\Aws::REGION_CN_NORTH_1;
             } else {
                 $region = \Scalr\Service\Aws::REGION_US_EAST_1;
             }
         }
         if (!count($this->checkVarError)) {
             if ($pars[Entity\CloudCredentialsProperty::AWS_ACCESS_KEY] != $ccProps[Entity\CloudCredentialsProperty::AWS_ACCESS_KEY] or $pars[Entity\CloudCredentialsProperty::AWS_SECRET_KEY] != $ccProps[Entity\CloudCredentialsProperty::AWS_SECRET_KEY] or $pars[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY] != $ccProps[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY] or $pars[Entity\CloudCredentialsProperty::AWS_CERTIFICATE] != $ccProps[Entity\CloudCredentialsProperty::AWS_CERTIFICATE]) {
                 $aws = $this->env->aws($region, $pars[Entity\CloudCredentialsProperty::AWS_ACCESS_KEY], $pars[Entity\CloudCredentialsProperty::AWS_SECRET_KEY], !empty($pars[Entity\CloudCredentialsProperty::AWS_CERTIFICATE]) ? $pars[Entity\CloudCredentialsProperty::AWS_CERTIFICATE] : null, !empty($pars[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY]) ? $pars[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY] : null);
                 //Validates private key and certificate if they are provided
                 if (!empty($pars[Entity\CloudCredentialsProperty::AWS_CERTIFICATE]) || !empty($pars[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY])) {
                     try {
                         //SOAP is not supported anymore
                         //$aws->validateCertificateAndPrivateKey();
                     } catch (Exception $e) {
                         throw new Exception(_("Incorrect format of X.509 certificate or private key. Make sure that you are using files downloaded from AWS profile. ({$e->getMessage()})"));
                     }
                 }
                 //Validates both access and secret keys
                 try {
                     $buckets = $aws->s3->bucket->getList();
                 } catch (Exception $e) {
                     throw new Exception(sprintf(_("Failed to verify your EC2 access key and secret key: %s"), $e->getMessage()));
                 }
                 //Extract AWS Account ID
                 $pars[Entity\CloudCredentialsProperty::AWS_ACCOUNT_ID] = $aws->getAccountNumber();
                 try {
                     if ($ccProps[Entity\CloudCredentialsProperty::AWS_ACCOUNT_ID] != $pars[Entity\CloudCredentialsProperty::AWS_ACCOUNT_ID]) {
                         $this->db->Execute("DELETE FROM client_environment_properties WHERE name LIKE 'ec2.vpc.default%' AND env_id = ?", [$this->env->id]);
                     }
                 } catch (Exception $e) {
                 }
             } else {
                 $pars[Entity\CloudCredentialsProperty::AWS_ACCOUNT_ID] = $ccProps[Entity\CloudCredentialsProperty::AWS_ACCOUNT_ID];
             }
         } else {
             $this->response->failure();
             $this->response->data(['errors' => $this->checkVarError]);
             return;
         }
     }
     if ($enabled && $this->getContainer()->analytics->enabled && !empty($pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_BUCKET])) {
         try {
             $region = $pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_REGION];
             $aws = $this->env->aws($region, $pars[Entity\CloudCredentialsProperty::AWS_ACCESS_KEY], $pars[Entity\CloudCredentialsProperty::AWS_SECRET_KEY]);
             if (!empty($pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_PAYER_ACCOUNT]) && $aws->getAccountNumber() != $pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_PAYER_ACCOUNT]) {
                 $payerCredentials = $this->getUser()->getAccount()->cloudCredentialsList([SERVER_PLATFORMS::EC2], [], [Entity\CloudCredentialsProperty::AWS_ACCOUNT_ID => [['value' => $pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_PAYER_ACCOUNT]]]]);
                 if (count($payerCredentials) == 0) {
                     throw new Exception("Payer account not found!");
                 }
                 $payerCredentials = $payerCredentials->current();
                 $aws = $this->env->aws($region, $payerCredentials->properties[Entity\CloudCredentialsProperty::AWS_ACCESS_KEY], $payerCredentials->properties[Entity\CloudCredentialsProperty::AWS_SECRET_KEY], !empty($payerCredentials->properties[Entity\CloudCredentialsProperty::AWS_CERTIFICATE]) ? $payerCredentials->properties[Entity\CloudCredentialsProperty::AWS_CERTIFICATE] : null, !empty($payerCredentials->properties[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY]) ? $payerCredentials->properties[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY] : null);
             }
             try {
                 $bucketObjects = $aws->s3->bucket->listObjects($pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_BUCKET]);
             } catch (ClientException $e) {
                 if ($e->getErrorData() && $e->getErrorData()->getCode() == ErrorData::ERR_AUTHORIZATION_HEADER_MALFORMED && preg_match("/expecting\\s+'(.+?)'/", $e->getMessage(), $matches) && in_array($matches[1], Aws::getCloudLocations())) {
                     $expectingRegion = $matches[1];
                     if (isset($payerCredentials)) {
                         $aws = $this->env->aws($expectingRegion, $payerCredentials->properties[Entity\CloudCredentialsProperty::AWS_ACCESS_KEY], $payerCredentials->properties[Entity\CloudCredentialsProperty::AWS_SECRET_KEY], !empty($payerCredentials->properties[Entity\CloudCredentialsProperty::AWS_CERTIFICATE]) ? $payerCredentials->properties[Entity\CloudCredentialsProperty::AWS_CERTIFICATE] : null, !empty($payerCredentials->properties[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY]) ? $payerCredentials->properties[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY] : null);
                     } else {
                         $aws = $this->env->aws($expectingRegion, $pars[Entity\CloudCredentialsProperty::AWS_ACCESS_KEY], $pars[Entity\CloudCredentialsProperty::AWS_SECRET_KEY]);
                     }
                     $bucketObjects = $aws->s3->bucket->listObjects($pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_BUCKET]);
                     $pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_REGION] = $expectingRegion;
                 } else {
                     throw $e;
                 }
             }
             $objectName = (empty($pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_PAYER_ACCOUNT]) ? '' : "{$pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_PAYER_ACCOUNT]}-") . 'aws-billing-detailed-line-items-with-resources-and-tags';
             $objectExists = false;
             $bucketObjectName = null;
             foreach ($bucketObjects as $bucketObject) {
                 /* @var $bucketObject Scalr\Service\Aws\S3\DataType\ObjectData */
                 if (strpos($bucketObject->objectName, $objectName) !== false) {
                     $bucketObjectName = $bucketObject->objectName;
                     $pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_ENABLED] = 1;
                     $objectExists = true;
                     break;
                 }
             }
             if (!$objectExists) {
                 $this->response->failure();
                 $this->response->data(['errors' => [Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_PAYER_ACCOUNT => "Object with name '{$objectName}' does not exist."]]);
                 return;
             }
             $aws->s3->object->getMetadata($pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_BUCKET], $bucketObjectName);
         } catch (Exception $e) {
             $this->response->failure();
             $this->response->data(['errors' => [Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_BUCKET => sprintf("Cannot access billing bucket with name %s. Error: %s", $pars[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_BUCKET], $e->getMessage())]]);
             return;
         }
     }
     $this->db->BeginTrans();
     try {
         $this->env->enablePlatform(SERVER_PLATFORMS::EC2, $enabled);
         if ($enabled) {
             $this->makeCloudCredentials(SERVER_PLATFORMS::EC2, $pars);
             if ($this->getContainer()->analytics->enabled && $bNew) {
                 $this->getContainer()->analytics->notifications->onCloudAdd('ec2', $this->env, $this->user);
             }
         }
         if (!$this->user->getAccount()->getSetting(Scalr_Account::SETTING_DATE_ENV_CONFIGURED)) {
             $this->user->getAccount()->setSetting(Scalr_Account::SETTING_DATE_ENV_CONFIGURED, time());
         }
         //TODO: cloud suspension info must work with cloud credentials
         if ($enabled && $this->env->status == Scalr_Environment::STATUS_INACTIVE && $this->env->getPlatformConfigValue('system.auto-disable-reason')) {
             // env was inactive due invalid keys for amazon, activate it
             $this->env->status = Scalr_Environment::STATUS_ACTIVE;
             $this->env->save();
             $this->env->setPlatformConfig(['system.auto-disable-reason' => NULL]);
             $envAutoEnabled = true;
         }
         $this->db->CommitTrans();
     } catch (Exception $e) {
         $this->db->RollbackTrans();
         throw new Exception(_("Failed to save AWS settings: {$e->getMessage()}"));
     }
     $this->response->success('Cloud credentials have been ' . ($enabled ? 'saved' : 'removed from Scalr'));
     $this->response->data(['enabled' => $enabled, 'demoFarm' => $demoFarm, 'envAutoEnabled' => $envAutoEnabled]);
 }
Ejemplo n.º 3
0
 /**
  * {@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");
     }
 }
Ejemplo n.º 4
0
 /**
  * @test
  */
 public function testImagesFunctional()
 {
     $testName = str_replace('-', '', $this->getTestName());
     $images = null;
     $uri = self::getUserApiUrl('/images');
     do {
         $query = [];
         if (isset($images->pagination->next)) {
             $parts = parse_url($images->pagination->next);
             parse_str($parts['query'], $query);
         }
         $describe = $this->request($uri, Request::METHOD_GET, $query);
         $this->assertDescribeResponseNotEmpty($describe);
         $images = $describe->getBody();
         foreach ($images->data as $image) {
             $this->assertImageObjectNotEmpty($image);
             if (strpos($image->name, $testName) !== false) {
                 $delete = $this->request($uri . '/' . $image->id, Request::METHOD_DELETE);
                 $this->assertEquals(200, $delete->response->getStatus());
             }
         }
     } while (!empty($images->pagination->next));
     // test create action
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => 'invalid']);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid scope');
     $create = $this->request($uri, Request::METHOD_POST);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Invalid body');
     $create = $this->request($uri, Request::METHOD_POST, [], ['invalid' => 'value']);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'You are trying to set');
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => 'invalidName^$&&']);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid name of the Image');
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'architecture' => 'invalid', 'name' => $testName]);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid architecture of the Image');
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName]);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'OS must be provided with the request');
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName, 'os' => ['id' => 'invalidOsId']]);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Specified OS does not exist');
     $os = Os::findOne([['status' => Os::STATUS_ACTIVE]]);
     /* @var $os Os */
     $env = \Scalr_Environment::init()->loadById(static::$testEnvId);
     $platform = \SERVER_PLATFORMS::EC2;
     if ($env->isPlatformEnabled($platform)) {
         $env->setPlatformConfig([$platform . '.is_enabled' => 0]);
     }
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName, 'os' => ['id' => $os->id], 'cloudPlatform' => $platform]);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_VALUE, $create);
     $this->assertErrorMessageStatusEquals(400, $create);
     $env->setPlatformConfig([$platform . '.is_enabled' => 1]);
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName, 'os' => ['invalid'], 'cloudPlatform' => $platform]);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid identifier of the OS');
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName, 'os' => ['id' => $os->id], 'cloudPlatform' => $platform]);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Unable to find the requested image on the cloud');
     $region = null;
     $cloudImageId = null;
     foreach (Aws::getCloudLocations() as $cloudLocation) {
         $cloudImageId = $this->getNewImageId($env, $cloudLocation);
         if (!empty($cloudImageId)) {
             $region = $cloudLocation;
             break;
         }
     }
     $this->assertNotNull($cloudImageId);
     $this->assertNotNull($cloudLocation);
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName, 'os' => $os->id, 'cloudPlatform' => $platform, 'cloudLocation' => $region, 'cloudImageId' => $cloudImageId]);
     $this->assertFetchResponseNotEmpty($create);
     $imageBody = $create->getBody();
     $this->assertImageObjectNotEmpty($imageBody->data);
     $this->assertEquals(201, $create->response->getStatus());
     $this->assertNotEmpty($imageBody->data->id);
     $this->assertEquals(ScopeInterface::SCOPE_ENVIRONMENT, $imageBody->data->scope);
     $this->assertEquals($testName, $imageBody->data->name);
     $this->assertEquals($os->id, $imageBody->data->os->id);
     $this->assertEquals($platform, $imageBody->data->cloudPlatform);
     $this->assertEquals($region, $imageBody->data->cloudLocation);
     $this->assertEquals($cloudImageId, $imageBody->data->cloudImageId);
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName, 'os' => ['id' => $os->id], 'cloudPlatform' => $platform, 'cloudLocation' => $region, 'cloudImageId' => $cloudImageId]);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_UNICITY_VIOLATION, $create);
     $this->assertErrorMessageStatusEquals(409, $create);
     // test filtering
     $describe = $this->request($uri, Request::METHOD_GET, ['scope' => ScopeInterface::SCOPE_ENVIRONMENT]);
     $this->assertDescribeResponseNotEmpty($describe);
     foreach ($describe->getBody()->data as $data) {
         $this->assertImageObjectNotEmpty($data);
         $this->assertEquals(ScopeInterface::SCOPE_ENVIRONMENT, $data->scope);
     }
     $describe = $this->request($uri, Request::METHOD_GET, ['name' => $testName]);
     $this->assertDescribeResponseNotEmpty($describe);
     foreach ($describe->getBody()->data as $data) {
         $this->assertImageObjectNotEmpty($data);
         $this->assertEquals($testName, $data->name);
     }
     $describe = $this->request($uri, Request::METHOD_GET, ['id' => $imageBody->data->id]);
     $this->assertDescribeResponseNotEmpty($describe);
     foreach ($describe->getBody()->data as $data) {
         $this->assertImageObjectNotEmpty($data);
         $this->assertEquals($imageBody->data->id, $data->id);
     }
     $describe = $this->request($uri, Request::METHOD_GET, ['os' => $os->id]);
     $this->assertDescribeResponseNotEmpty($describe);
     foreach ($describe->getBody()->data as $data) {
         $this->assertImageObjectNotEmpty($data);
         $this->assertEquals($os->id, $data->os->id);
     }
     $describe = $this->request($uri, Request::METHOD_GET, ['os' => 'invalid*&^^%']);
     $this->assertErrorMessageContains($describe, 400, ErrorMessage::ERR_INVALID_VALUE, "Invalid identifier of the OS");
     $describe = $this->request($uri, Request::METHOD_GET, ['cloudPlatform' => $platform, 'cloudLocation' => $region]);
     $this->assertDescribeResponseNotEmpty($describe);
     foreach ($describe->getBody()->data as $data) {
         $this->assertImageObjectNotEmpty($data);
         $this->assertEquals($platform, $data->cloudPlatform);
         $this->assertEquals($region, $data->cloudLocation);
     }
     $describe = $this->request($uri, Request::METHOD_GET, ['cloudLocation' => $region]);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_STRUCTURE, $describe);
     $this->assertErrorMessageStatusEquals(400, $describe);
     $describe = $this->request($uri, Request::METHOD_GET, ['cloudImageId' => $cloudImageId]);
     $this->assertDescribeResponseNotEmpty($describe);
     foreach ($describe->getBody()->data as $data) {
         $this->assertImageObjectNotEmpty($data);
         $this->assertEquals($cloudImageId, $data->cloudImageId);
     }
     // test modify action
     $modify = $this->request($uri, Request::METHOD_PATCH, [], ['name' => $testName . 'modify']);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_ENDPOINT_NOT_FOUND, $modify);
     $this->assertErrorMessageStatusEquals(404, $modify);
     $modify = $this->request($uri . '/' . $imageBody->data->id, Request::METHOD_PATCH, [], ['invalid' => $testName . 'modify']);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_STRUCTURE, $modify);
     $this->assertErrorMessageStatusEquals(400, $modify);
     $modify = $this->request($uri . '/' . $imageBody->data->id, Request::METHOD_PATCH, [], ['id' => $testName . 'modify']);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_STRUCTURE, $modify);
     $this->assertErrorMessageStatusEquals(400, $modify);
     $modify = $this->request($uri . '/' . $imageBody->data->id, Request::METHOD_PATCH, [], ['scope' => $testName . 'modify']);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_VALUE, $modify);
     $this->assertErrorMessageStatusEquals(400, $modify);
     $notFoundId = '11111111-1111-1111-1111-111111111111';
     $modify = $this->request($uri . '/' . $notFoundId, Request::METHOD_PATCH, [], ['name' => $testName . 'modify']);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_OBJECT_NOT_FOUND, $modify);
     $this->assertErrorMessageStatusEquals(404, $modify);
     $entity = Image::findOne([['envId' => null], ['status' => Image::STATUS_ACTIVE]]);
     /* @var $entity Image */
     $this->assertNotEmpty($entity);
     $notAccessibleId = $entity->hash;
     $modify = $this->request($uri . '/' . $notAccessibleId, Request::METHOD_PATCH, [], ['name' => $testName . 'modify']);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_SCOPE_VIOLATION, $modify);
     $this->assertErrorMessageStatusEquals(403, $modify);
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ENVIRONMENT, 'name' => $testName, 'os' => ['id' => $entity->osId], 'cloudPlatform' => $entity->platform, 'cloudLocation' => $entity->cloudLocation, 'cloudImageId' => $entity->id]);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_UNICITY_VIOLATION, $create);
     $this->assertErrorMessageStatusEquals(409, $create);
     // test fetch action
     $fetch = $this->request($uri . '/' . $notFoundId, Request::METHOD_GET);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_OBJECT_NOT_FOUND, $fetch);
     $this->assertErrorMessageStatusEquals(404, $fetch);
     $fetch = $this->request($uri . '/' . $imageBody->data->id, Request::METHOD_GET);
     $this->assertFetchResponseNotEmpty($fetch);
     $fetchBody = $fetch->getBody();
     $this->assertImageObjectNotEmpty($fetchBody->data);
     $this->assertEquals($imageBody->data->id, $fetchBody->data->id);
     $fetch = $this->request($uri . '/' . $entity->hash, Request::METHOD_GET);
     $this->assertFetchResponseNotEmpty($fetch);
     $fetchBody = $fetch->getBody();
     $this->assertImageObjectNotEmpty($fetchBody->data);
     $this->assertEquals($entity->hash, $fetchBody->data->id);
     $modify = $this->request($uri . '/' . $imageBody->data->id, Request::METHOD_PATCH, [], ['name' => $testName . 'modify']);
     $this->assertEquals(200, $modify->response->getStatus());
     $this->assertImageObjectNotEmpty($modify->getBody()->data);
     $this->assertEquals($testName . 'modify', $modify->getBody()->data->name);
     // test copy action
     $copy = $this->request($uri . '/' . $imageBody->data->id . '/actions/copy', Request::METHOD_POST);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_STRUCTURE, $copy);
     $this->assertErrorMessageStatusEquals(400, $copy);
     $copy = $this->request($uri . '/' . $imageBody->data->id . '/actions/copy', Request::METHOD_POST, [], ['cloudLocation' => 'invalid', 'cloudPlatform' => 'ec2']);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_VALUE, $copy);
     $this->assertErrorMessageStatusEquals(400, $copy);
     $copy = $this->request($uri . '/' . $imageBody->data->id . '/actions/copy', Request::METHOD_POST, [], ['cloudLocation' => Aws::REGION_US_EAST_1, 'cloudPlatform' => 'gce']);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_VALUE, $copy);
     $this->assertErrorMessageStatusEquals(400, $copy);
     $copy = $this->request($uri . '/' . $imageBody->data->id . '/actions/copy', Request::METHOD_POST, [], ['cloudLocation' => $region, 'cloudPlatform' => 'ec2']);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_BAD_REQUEST, $copy);
     $this->assertErrorMessageStatusEquals(400, $copy);
     $awsRegions = Aws::getCloudLocations();
     $copyTo = null;
     foreach ($awsRegions as $awsRegion) {
         if ($awsRegion != $region) {
             $copyTo = $awsRegion;
             break;
         }
     }
     $this->assertNotNull($copyTo);
     $copy = $this->request($uri . '/' . $notAccessibleId . '/actions/copy', Request::METHOD_POST, [], ['cloudLocation' => $copyTo, 'cloudPlatform' => \SERVER_PLATFORMS::EC2]);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_SCOPE_VIOLATION, $copy);
     $this->assertErrorMessageStatusEquals(403, $copy);
     $copy = $this->request($uri . '/' . $imageBody->data->id . '/actions/copy', Request::METHOD_POST, [], ['cloudLocation' => $copyTo, 'cloudPlatform' => \SERVER_PLATFORMS::EC2]);
     $copyBody = $copy->getBody();
     $this->assertEquals(202, $copy->response->getStatus());
     $this->assertFetchResponseNotEmpty($copy);
     $this->assertImageObjectNotEmpty($copyBody->data);
     $this->assertEquals(\SERVER_PLATFORMS::EC2, $copyBody->data->cloudPlatform);
     $this->assertEquals($copyTo, $copyBody->data->cloudLocation);
     // test delete action
     $delete = $this->request($uri . '/' . $notFoundId, Request::METHOD_DELETE);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_OBJECT_NOT_FOUND, $delete);
     $this->assertErrorMessageStatusEquals(404, $delete);
     $delete = $this->request($uri . '/' . $entity->hash, Request::METHOD_DELETE);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_SCOPE_VIOLATION, $delete);
     $this->assertErrorMessageStatusEquals(403, $delete);
     $delete = $this->request($uri . '/' . $copyBody->data->id, Request::METHOD_DELETE);
     $this->assertEquals(200, $delete->response->getStatus());
     $delete = $this->request($uri . '/' . $imageBody->data->id, Request::METHOD_DELETE);
     $this->assertEquals(200, $delete->response->getStatus());
 }
Ejemplo n.º 5
0
 /**
  * @test
  */
 public function testAccountRolesFunctional()
 {
     $db = \Scalr::getDb();
     $testName = str_replace('-', '', static::getTestName());
     $roles = null;
     $uri = self::getAccountApiUrl('/roles');
     do {
         $query = [];
         if (isset($roles->pagination->next)) {
             $parts = parse_url($roles->pagination->next);
             parse_str($parts['query'], $query);
         }
         $describe = $this->request($uri, Request::METHOD_GET, $query);
         $this->assertDescribeResponseNotEmpty($describe);
         $this->assertNotEmpty($describe->getBody());
         $roles = $describe->getBody();
         foreach ($roles->data as $role) {
             $this->assertRolesObjectNotEmpty($role);
             if ($role->name == $testName) {
                 $delete = $this->request($uri . '/' . $role->id, Request::METHOD_DELETE);
                 $this->assertEquals(200, $delete->status);
             }
         }
     } while (!empty($roles->pagination->next));
     // test create action
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => 'invalid']);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid scope');
     $create = $this->request($uri, Request::METHOD_POST);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Invalid body');
     $create = $this->request($uri, Request::METHOD_POST, [], ['invalid' => 'value']);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'You are trying to set');
     $create = $this->request($uri, Request::METHOD_POST, [], ['id' => 'value']);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid name');
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => 'invalidName^$&&']);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid name of the Role');
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName, 'description' => 'invalidDesc<br/>']);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid description');
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName]);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Role category should be provided');
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName, 'category' => ['id' => 'not int']]);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid identifier of the category');
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName, 'category' => ['id' => -1]]);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'The Role category does not exist');
     $rolesCat = RoleCategory::findOne();
     /* @var $rolesCat RoleCategory */
     $this->assertNotEmpty($rolesCat);
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName, 'category' => ['id' => $rolesCat->id]]);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_STRUCTURE, "Missed property 'os.id'");
     $os = Os::findOne([['status' => Os::STATUS_ACTIVE], ['family' => 'ubuntu'], ['generation' => '12.04']]);
     /* @var $os Os */
     $this->assertNotEmpty($os);
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName, 'category' => ['id' => $rolesCat->id], 'os' => ['id' => -1]]);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, 'Invalid identifier of the OS');
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName, 'category' => ['id' => $rolesCat->id], 'os' => ['id' => 'invalid']]);
     $this->assertErrorMessageContains($create, 400, ErrorMessage::ERR_INVALID_VALUE, "OS with id 'invalid' not found.");
     $create = $this->request($uri, Request::METHOD_POST, [], ['scope' => ScopeInterface::SCOPE_ACCOUNT, 'name' => $testName, 'description' => $testName, 'category' => $rolesCat->id, 'os' => $os->id, 'quickStart' => true, 'deprecated' => true]);
     $body = $create->getBody();
     $this->assertEquals(201, $create->response->getStatus());
     $this->assertFetchResponseNotEmpty($create);
     $this->assertRolesObjectNotEmpty($body->data);
     $this->assertNotEmpty($body->data->id);
     $this->assertEquals($testName, $body->data->name);
     $this->assertEquals($testName, $body->data->description);
     $this->assertEquals(ScopeInterface::SCOPE_ACCOUNT, $body->data->scope);
     $this->assertEquals($rolesCat->id, $body->data->category->id);
     $this->assertEquals($os->id, $body->data->os->id);
     $this->assertEquals(true, $body->data->quickStart);
     $this->assertEquals(true, $body->data->deprecated);
     // test images actions
     $roleId = $body->data->id;
     $imagesUri = $uri . '/' . $roleId . '/images';
     $images = null;
     do {
         $query = [];
         if (isset($images->pagination->next)) {
             $parts = parse_url($images->pagination->next);
             parse_str($parts['query'], $query);
         }
         $describeImages = $this->request($imagesUri, Request::METHOD_GET, $query);
         $this->assertDescribeResponseNotEmpty($describeImages);
         $images = $describeImages->getBody();
         foreach ($images->data as $imageRole) {
             $this->assertRoleImageObjectNotEmpty($imageRole);
             $this->assertEquals($roleId, $imageRole->role->id);
             $image = Image::findPk($imageRole->image->id);
             /* @var $image Image */
             if ($image->name == $testName) {
                 $delete = $this->request($imagesUri . '/' . $imageRole->image->id, Request::METHOD_DELETE);
                 $this->assertEquals(200, $delete->status);
             }
         }
     } while (!empty($images->pagination->next));
     $env = \Scalr_Environment::init()->loadById(static::$testEnvId);
     $platform = \SERVER_PLATFORMS::EC2;
     if (!$env->isPlatformEnabled($platform)) {
         $env->setPlatformConfig([$platform . '.is_enabled' => 1]);
     }
     $region = null;
     $cloudImageId = null;
     foreach (Aws::getCloudLocations() as $cloudLocation) {
         $cloudImageId = $this->getNewImageId($env, $cloudLocation);
         if (!empty($cloudImageId)) {
             $region = $cloudLocation;
             break;
         }
     }
     $this->assertNotNull($cloudImageId);
     $this->assertNotNull($cloudLocation);
     $image = $this->createEntity(new Image(), ['accountId' => $this->getUser()->accountId, 'name' => $testName, 'osId' => $os->id, 'platform' => $platform, 'cloudLocation' => $region, 'id' => $cloudImageId, 'architecture' => 'x86_64', 'source' => Image::SOURCE_MANUAL, 'status' => Image::STATUS_ACTIVE]);
     $createRoleImage = $this->request($imagesUri, Request::METHOD_POST, [], ['role' => ['id' => $roleId + 10], 'image' => ['id' => $image->hash]]);
     $this->assertErrorMessageStatusEquals(400, $createRoleImage);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_VALUE, $createRoleImage);
     $createRoleImage = $this->request($imagesUri, Request::METHOD_POST, [], ['role' => ['id' => $roleId]]);
     $this->assertErrorMessageStatusEquals(400, $createRoleImage);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_STRUCTURE, $createRoleImage);
     $createRoleImage = $this->request($imagesUri, Request::METHOD_POST, [], ['role' => ['id' => $roleId], 'image' => ['id' => '11111111-1111-1111-1111-111111111111']]);
     $this->assertErrorMessageStatusEquals(404, $createRoleImage);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_INVALID_VALUE, $createRoleImage);
     $createRoleImage = $this->request($imagesUri, Request::METHOD_POST, [], ['role' => ['id' => $roleId], 'image' => ['id' => $image->hash]]);
     $createRoleImageBody = $createRoleImage->getBody();
     $this->assertEquals(201, $createRoleImage->response->getStatus());
     $this->assertFetchResponseNotEmpty($createRoleImage);
     $this->assertRoleImageObjectNotEmpty($createRoleImageBody->data);
     $createRoleImageError = $this->request($imagesUri, Request::METHOD_POST, [], ['role' => ['id' => $roleId], 'image' => ['id' => $image->hash]]);
     $this->assertErrorMessageStatusEquals(400, $createRoleImageError);
     $this->assertErrorMessageErrorEquals(ErrorMessage::ERR_BAD_REQUEST, $createRoleImageError);
     $fetchImage = $this->request($imagesUri . '/' . $createRoleImageBody->data->image->id, Request::METHOD_GET);
     $fetchImageBody = $fetchImage->getBody();
     $this->assertEquals(200, $fetchImage->response->getStatus());
     $this->assertFetchResponseNotEmpty($fetchImage);
     $this->assertImageObjectNotEmpty($fetchImageBody->data);
     $this->assertEquals($cloudImageId, $fetchImageBody->data->cloudImageId);
     $this->assertEquals($testName, $fetchImageBody->data->name);
     // test role images filtering
     $describeRoleImages = $this->request($imagesUri, Request::METHOD_GET, ['role' => $roleId]);
     $this->assertDescribeResponseNotEmpty($describeRoleImages);
     foreach ($describeRoleImages->getBody()->data as $data) {
         $this->assertRoleImageObjectNotEmpty($data);
         $this->assertEquals($roleId, $data->role->id);
     }
     $describeRoleImages = $this->request($imagesUri, Request::METHOD_GET, ['image' => $image->hash]);
     $this->assertDescribeResponseNotEmpty($describeRoleImages);
     foreach ($describeRoleImages->getBody()->data as $data) {
         $this->assertRoleImageObjectNotEmpty($data);
         $this->assertEquals($image->hash, $data->image->id);
     }
     $describeRoleImages = $this->request($imagesUri, Request::METHOD_GET, ['invalid' => 'value']);
     $this->assertErrorMessageContains($describeRoleImages, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Unsupported filter');
     $currentRole = Role::findPk($roleId);
     /* @var $currentRole Role */
     $this->assertNotEmpty($currentRole);
     $adminImages = Image::find([['envId' => null], ['status' => Image::STATUS_ACTIVE], ['cloudLocation' => $region]]);
     $this->assertNotEmpty($adminImages);
     $adminImage = null;
     foreach ($adminImages as $aImage) {
         /* @var $aImage Image */
         $imageOs = $aImage->getOs();
         if (!empty($imageOs) && $imageOs->generation == $currentRole->getOs()->generation && $imageOs->family == $currentRole->getOs()->family) {
             $adminImage = $aImage;
             break;
         }
     }
     /* @var $adminImage Image */
     $this->assertNotEmpty($adminImage);
     $this->assertNotEquals($createRoleImageBody->data->image->id, $adminImage->hash);
     $replaceImage = $this->request($imagesUri . '/' . $createRoleImageBody->data->image->id . '/actions/replace', Request::METHOD_POST, [], ['role' => $roleId, 'image' => $adminImage->hash]);
     $replaceImageBody = $replaceImage->getBody();
     $this->assertEquals(200, $replaceImage->response->getStatus());
     $this->assertFetchResponseNotEmpty($replaceImage);
     $this->assertRoleImageObjectNotEmpty($replaceImageBody->data);
     $this->assertEquals($adminImage->hash, $replaceImageBody->data->image->id);
     $deleteImage = $this->request($imagesUri . '/' . $replaceImageBody->data->image->id, Request::METHOD_DELETE);
     $this->assertEquals(200, $deleteImage->response->getStatus());
     $delete = $this->request(static::getAccountApiUrl("images/{$image->hash}"), Request::METHOD_DELETE);
     $this->assertEquals(200, $delete->response->getStatus());
     // test get action
     $notFoundRoleId = 10 + $db->GetOne("SELECT MAX(r.id) FROM roles r");
     $get = $this->request($uri . '/' . $notFoundRoleId, Request::METHOD_GET);
     $this->assertErrorMessageContains($get, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "The Role either does not exist or isn't in scope for the current Environment");
     $get = $this->request($uri . '/' . $body->data->id, Request::METHOD_GET);
     $getBody = $get->getBody();
     $this->assertEquals(200, $get->response->getStatus());
     $this->assertFetchResponseNotEmpty($get);
     $this->assertRolesObjectNotEmpty($getBody->data);
     $this->assertEquals($body->data->id, $getBody->data->id);
     $this->assertEquals($testName, $getBody->data->name);
     $this->assertEquals($testName, $getBody->data->description);
     $this->assertEquals(ScopeInterface::SCOPE_ACCOUNT, $getBody->data->scope);
     $this->assertEquals($rolesCat->id, $getBody->data->category->id);
     $this->assertEquals($os->id, $getBody->data->os->id);
     // test filters
     $describe = $this->request($uri, Request::METHOD_GET, ['description' => $testName]);
     $this->assertErrorMessageContains($describe, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Unsupported filter');
     $describe = $this->request($uri, Request::METHOD_GET, ['scope' => 'wrong<br>']);
     $this->assertErrorMessageContains($describe, 400, ErrorMessage::ERR_INVALID_VALUE, 'Unexpected scope value');
     $describe = $this->request($uri, Request::METHOD_GET, ['scope' => ScopeInterface::SCOPE_SCALR]);
     $this->assertDescribeResponseNotEmpty($describe);
     foreach ($describe->getBody()->data as $data) {
         $this->assertRolesObjectNotEmpty($data);
     }
     $describe = $this->request($uri, Request::METHOD_GET, ['scope' => ScopeInterface::SCOPE_ACCOUNT]);
     $this->assertDescribeResponseNotEmpty($describe);
     foreach ($describe->getBody()->data as $data) {
         $this->assertRolesObjectNotEmpty($data);
         $this->assertEquals(ScopeInterface::SCOPE_ACCOUNT, $data->scope);
     }
     $describe = $this->request($uri, Request::METHOD_GET, ['name' => $testName]);
     $this->assertDescribeResponseNotEmpty($describe);
     foreach ($describe->getBody()->data as $data) {
         $this->assertRolesObjectNotEmpty($data);
         $this->assertEquals($testName, $data->name);
     }
     $describe = $this->request($uri, Request::METHOD_GET, ['id' => $roleId]);
     $this->assertDescribeResponseNotEmpty($describe);
     foreach ($describe->getBody()->data as $data) {
         $this->assertRolesObjectNotEmpty($data);
         $this->assertEquals($roleId, $data->id);
     }
     $describe = $this->request($uri, Request::METHOD_GET, ['os' => $os->id]);
     $this->assertDescribeResponseNotEmpty($describe);
     foreach ($describe->getBody()->data as $data) {
         $this->assertRolesObjectNotEmpty($data);
         $this->assertEquals($os->id, $data->os->id);
     }
     $describe = $this->request($uri, Request::METHOD_GET, ['os' => 'invalid*&^^%']);
     $this->assertErrorMessageContains($describe, 400, ErrorMessage::ERR_INVALID_VALUE, "Invalid identifier of the OS");
     $describe = $this->request($uri, Request::METHOD_GET, ['category' => $rolesCat->id]);
     $this->assertDescribeResponseNotEmpty($describe);
     foreach ($describe->getBody()->data as $data) {
         $this->assertRolesObjectNotEmpty($data);
         $this->assertEquals($rolesCat->id, $data->category->id);
     }
     $describe = $this->request($uri, Request::METHOD_GET, ['category' => '']);
     $this->assertErrorMessageContains($describe, 400, ErrorMessage::ERR_INVALID_VALUE, "Invalid identifier of the category");
     // test modify action
     $modify = $this->request($uri . '/' . $body->data->id, Request::METHOD_PATCH);
     $this->assertErrorMessageContains($modify, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'Invalid body');
     $modify = $this->request($uri . '/' . $body->data->id, Request::METHOD_PATCH, [], ['id' => 123]);
     $this->assertErrorMessageContains($modify, 400, ErrorMessage::ERR_INVALID_STRUCTURE);
     $modify = $this->request($uri . '/' . $body->data->id, Request::METHOD_PATCH, [], ['invalid' => 'err']);
     $this->assertErrorMessageContains($modify, 400, ErrorMessage::ERR_INVALID_STRUCTURE, 'You are trying to set');
     $modify = $this->request($uri . '/' . $body->data->id, Request::METHOD_PATCH, [], ['scope' => 'environment']);
     $this->assertErrorMessageContains($modify, 400, ErrorMessage::ERR_INVALID_VALUE);
     $modify = $this->request($uri . '/' . $body->data->id, Request::METHOD_PATCH, [], ['description' => '']);
     $modifyBody = $modify->getBody();
     $this->assertEquals(200, $modify->response->getStatus());
     $this->assertFetchResponseNotEmpty($modify);
     $this->assertRolesObjectNotEmpty($modifyBody->data);
     $this->assertEquals($body->data->id, $modifyBody->data->id);
     $this->assertEquals($testName, $modifyBody->data->name);
     $this->assertEquals('', $modifyBody->data->description);
     $this->assertEquals(ScopeInterface::SCOPE_ACCOUNT, $modifyBody->data->scope);
     $this->assertEquals($rolesCat->id, $modifyBody->data->category->id);
     $this->assertEquals($os->id, $modifyBody->data->os->id);
     // test delete action
     $delete = $this->request(static::getAccountApiUrl("/roles/{$notFoundRoleId}"), Request::METHOD_DELETE);
     $this->assertErrorMessageContains($delete, 404, ErrorMessage::ERR_OBJECT_NOT_FOUND);
     $delete = $this->request($uri . '/' . $body->data->id, Request::METHOD_DELETE);
     $this->assertEquals(200, $delete->status);
     $db->Execute("INSERT INTO roles SET\n            name      = ?,\n            dtadded   = NOW(),\n            env_id\t  = NULL,\n            client_id = NULL,\n            generation = 2\n        ", [$testName]);
     $insertedId = $db->_insertid();
     $db->Execute("INSERT INTO role_images SET\n            role_id = ?,\n            platform = 'ec2',\n            image_id = 'test'\n        ", [$insertedId]);
     $delete = $this->request($uri . '/' . $insertedId, Request::METHOD_DELETE);
     $db->Execute("DELETE FROM roles WHERE name = ? AND id = ?", [$testName, $insertedId]);
     $this->assertErrorMessageContains($delete, 403, ErrorMessage::ERR_SCOPE_VIOLATION);
 }
Ejemplo n.º 6
0
 /**
  * Copies image to different location
  *
  * @param   string $imageId Unique identifier of the image (uuid)
  * @return \Scalr\Api\DataType\ResultEnvelope
  * @throws  ApiErrorException
  */
 public function copyAction($imageId)
 {
     $this->checkScopedPermissions('IMAGES', 'MANAGE');
     $object = $this->request->getJsonBody();
     if (empty($object->cloudLocation) || empty($object->cloudPlatform)) {
         throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_STRUCTURE, "Invalid body");
     }
     $locations = Aws::getCloudLocations();
     if (!in_array($object->cloudLocation, $locations)) {
         throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Invalid region");
     }
     if ($object->cloudPlatform !== 'ec2') {
         throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, "Only Ec2 cloud platform is supported");
     }
     $image = $this->getImage($imageId, true);
     $imageAdapter = $this->adapter('image');
     //Re-validates an Entity
     $imageAdapter->validateEntity($image);
     if ($image->cloudLocation == $object->cloudLocation) {
         throw new ApiErrorException(400, ErrorMessage::ERR_BAD_REQUEST, 'Destination region is the same as source one');
     }
     try {
         $newImage = $image->migrateEc2Location($object->cloudLocation, $this->getUser());
     } catch (NotEnabledPlatformException $e) {
         throw new ApiErrorException(400, ErrorMessage::ERR_NOT_ENABLED_PLATFORM, $e->getMessage());
     }
     $this->response->setStatus(202);
     return $this->result($imageAdapter->toData($newImage));
 }
Ejemplo n.º 7
0
 /**
  * {@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");
     }
 }
Ejemplo n.º 8
0
 /**
  * {@inheritdoc}
  * @see \Scalr\System\Pcntl\ProcessInterface::OnStartForking()
  */
 public function OnStartForking()
 {
     if (!\Scalr::getContainer()->analytics->enabled) {
         die("Terminating the process as Cost analytics is disabled in the config.\n");
     }
     if (SettingEntity::getValue(SettingEntity::ID_FORBID_AUTOMATIC_UPDATE_AWS_PRICES)) {
         die("Terminating the process because of overriding AWS prices has been forbidden by financial admin.\n");
     }
     $now = new DateTime('now', new DateTimeZone('UTC'));
     $urls = array('https://a0.awsstatic.com/pricing/1/ec2/linux-od.min.js', 'https://a0.awsstatic.com/pricing/1/ec2/mswin-od.min.js');
     $mapping = array('us-east' => 'us-east-1', 'us-west' => 'us-west-1', 'us-west-2' => 'us-west-2', 'eu-ireland' => 'eu-west-1', 'sa-east-1' => 'sa-east-1', 'apac-sin' => 'ap-southeast-1', 'apac-tokyo' => 'ap-northeast-1', 'apac-syd' => 'ap-southeast-2');
     $availableLocations = Aws::getCloudLocations();
     foreach ($urls as $link) {
         $json = trim(preg_replace('/^.+?callback\\((.+?)\\);\\s*$/sU', '\\1', file_get_contents($link)));
         $data = json_decode(preg_replace('/(\\w+):/', '"\\1":', $json));
         if (!empty($data->config->regions)) {
             $cadb = Scalr::getContainer()->cadb;
             foreach ($data->config->regions as $rd) {
                 foreach ($rd->instanceTypes as $it) {
                     if (!isset($mapping[$rd->region])) {
                         throw new Exception(sprintf("Region %s does not exist in the mapping.", $rd->region));
                     }
                     $region = $mapping[$rd->region];
                     $latest = array();
                     //Gets latest prices for all instance types from current region.
                     $res = $cadb->Execute("\n                            SELECT p.instance_type, ph.applied, p.os, p.name, HEX(p.price_id) `price_id`, p.cost\n                            FROM price_history ph\n                            JOIN prices p ON p.price_id = ph.price_id\n                            LEFT JOIN price_history ph2 ON ph2.platform = ph.platform\n                                AND ph2.cloud_location = ph.cloud_location\n                                AND ph2.account_id = ph.account_id\n                                AND ph2.url = ph.url\n                                AND ph2.applied > ph.applied AND ph2.applied <= ?\n                            LEFT JOIN prices p2 ON p2.price_id = ph2.price_id\n                                AND p2.instance_type = p.instance_type\n                                AND p2.os = p.os\n                            WHERE ph.account_id = 0 AND p2.price_id IS NULL\n                            AND ph.platform = 'ec2'\n                            AND ph.cloud_location = ?\n                            AND ph.url = ''\n                            AND ph.applied <= ?\n                        ", array($now->format('Y-m-d'), $region, $now->format('Y-m-d')));
                     while ($rec = $res->FetchRow()) {
                         $latest[$rec['instance_type']][$rec['os']] = array('applied' => $rec['applied'], 'price_id' => $rec['price_id'], 'cost' => $rec['cost']);
                     }
                     $upd = array();
                     $needUpdate = false;
                     foreach ($it->sizes as $sz) {
                         foreach ($sz->valueColumns as $v) {
                             $os = $v->name == 'linux' ? PriceEntity::OS_LINUX : PriceEntity::OS_WINDOWS;
                             if (!isset($latest[$sz->size][$os])) {
                                 $needUpdate = true;
                             } else {
                                 if (abs(($latest[$sz->size][$os]['cost'] - $v->prices->USD) / $v->prices->USD) > 1.0E-6) {
                                     $needUpdate = true;
                                     $latest[$sz->size][$os]['cost'] = $v->prices->USD;
                                 } else {
                                     continue;
                                 }
                             }
                             $latest[$sz->size][$os] = array('cost' => $v->prices->USD);
                         }
                     }
                     if ($needUpdate) {
                         $priceid = $cadb->GetOne("\n                                SELECT HEX(`price_id`) AS `price_id`\n                                FROM price_history\n                                WHERE platform = 'ec2'\n                                AND url = ''\n                                AND cloud_location = ?\n                                AND applied = ?\n                                AND account_id = 0\n                                LIMIT 1\n                            ", array($region, $now->format('Y-m-d')));
                         if (!$priceid) {
                             $priceid = str_replace('-', '', Scalr::GenerateUID());
                             $cadb->Execute("\n                                    INSERT price_history\n                                    SET price_id = UNHEX(?),\n                                        platform = 'ec2',\n                                        url = '',\n                                        cloud_location = ?,\n                                        account_id = 0,\n                                        applied = ?,\n                                        deny_override = 0\n                                ", array($priceid, $region, $now->format('Y-m-d')));
                         }
                         foreach ($latest as $instanceType => $ld) {
                             foreach ($ld as $os => $v) {
                                 $cadb->Execute("\n                                        REPLACE prices\n                                        SET price_id = UNHEX(?),\n                                            instance_type = ?,\n                                            name = ?,\n                                            os = ?,\n                                            cost = ?\n                                    ", array($priceid, $instanceType, $instanceType, $os, $v['cost']));
                             }
                         }
                     }
                 }
             }
         }
     }
     exit;
 }
Ejemplo n.º 9
0
 /**
  * @param Entity\CloudCredentials $entity
  *
  * @throws ApiErrorException
  */
 public function validateEntity($entity)
 {
     $container = $this->controller->getContainer();
     if ($container->analytics->enabled) {
         $ccProps = $entity->properties;
         if (!empty($ccProps[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_BUCKET])) {
             try {
                 $region = $ccProps[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_REGION];
                 $aws = $container->aws($region, $ccProps[Entity\CloudCredentialsProperty::AWS_ACCESS_KEY], $ccProps[Entity\CloudCredentialsProperty::AWS_SECRET_KEY]);
                 if (!empty($ccProps[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_PAYER_ACCOUNT]) && $aws->getAccountNumber() != $ccProps[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_PAYER_ACCOUNT]) {
                     $payerCredentials = $this->controller->getEnvironment()->cloudCredentialsList([SERVER_PLATFORMS::EC2], [['accountId' => $this->controller->getUser()->getAccountId()]], [['name' => Entity\CloudCredentialsProperty::AWS_ACCOUNT_ID], ['value' => $ccProps[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_PAYER_ACCOUNT]]]);
                     $payerCredentials = array_shift($payerCredentials) ?: $entity;
                     $payerCcProps = $payerCredentials->properties;
                     $aws = $container->aws($region, $payerCcProps[Entity\CloudCredentialsProperty::AWS_ACCESS_KEY], $payerCcProps[Entity\CloudCredentialsProperty::AWS_SECRET_KEY], !empty($payerCcProps[Entity\CloudCredentialsProperty::AWS_CERTIFICATE]) ? $payerCcProps[Entity\CloudCredentialsProperty::AWS_CERTIFICATE] : null, !empty($payerCcProps[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY]) ? $payerCcProps[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY] : null);
                 }
                 try {
                     $bucketObjects = $aws->s3->bucket->listObjects($ccProps[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_BUCKET]);
                 } catch (Exception $e) {
                     if (strpos($e->getMessage(), 'The authorization header is malformed') !== false) {
                         if (preg_match("/expecting\\s+'(.+?)'/i", $e->getMessage(), $matches) && in_array($matches[1], Aws::getCloudLocations())) {
                             $expectingRegion = $matches[1];
                             if (isset($payerCcProps)) {
                                 $aws = $container->aws($region, $payerCcProps[Entity\CloudCredentialsProperty::AWS_ACCESS_KEY], $payerCcProps[Entity\CloudCredentialsProperty::AWS_SECRET_KEY], !empty($payerCcProps[Entity\CloudCredentialsProperty::AWS_CERTIFICATE]) ? $payerCcProps[Entity\CloudCredentialsProperty::AWS_CERTIFICATE] : null, !empty($payerCcProps[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY]) ? $payerCcProps[Entity\CloudCredentialsProperty::AWS_PRIVATE_KEY] : null);
                             } else {
                                 $aws = $container->aws($expectingRegion, $ccProps[Entity\CloudCredentialsProperty::AWS_ACCESS_KEY], $ccProps[Entity\CloudCredentialsProperty::AWS_SECRET_KEY]);
                             }
                             $bucketObjects = $aws->s3->bucket->listObjects($ccProps[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_BUCKET]);
                             $ccProps[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_REGION] = $expectingRegion;
                         } else {
                             throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, $e->getMessage(), $e->getCode(), $e);
                         }
                     } else {
                         throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, $e->getMessage(), $e->getCode(), $e);
                     }
                 }
                 $objectName = (empty($ccProps[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_PAYER_ACCOUNT]) ? '' : "{$ccProps[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_PAYER_ACCOUNT]}-") . 'aws-billing-detailed-line-items-with-resources-and-tags';
                 $objectExists = false;
                 $bucketObjectName = null;
                 foreach ($bucketObjects as $bucketObject) {
                     /* @var $bucketObject ObjectData */
                     if (strpos($bucketObject->objectName, $objectName) !== false) {
                         $bucketObjectName = $bucketObject->objectName;
                         $ccProps[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_ENABLED] = 1;
                         $objectExists = true;
                         break;
                     }
                 }
                 if (!$objectExists) {
                     throw new ApiErrorException(404, ErrorMessage::ERR_OBJECT_NOT_FOUND, "Bucket with name '{$objectName}' does not exist");
                 }
                 $aws->s3->object->getMetadata($ccProps[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_BUCKET], $bucketObjectName);
             } catch (Exception $e) {
                 throw new ApiErrorException(400, ErrorMessage::ERR_INVALID_VALUE, sprintf("Cannot access billing bucket with name %s. Error: %s", $ccProps[Entity\CloudCredentialsProperty::AWS_DETAILED_BILLING_BUCKET], $e->getMessage()), $e->getCode(), $e);
             }
         }
     }
 }
Ejemplo n.º 10
0
 /**
  * {@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");
     }
 }