/** * {@inheritdoc} * @see \Scalr\Modules\PlatformModuleInterface::LaunchServer() */ public function LaunchServer(DBServer $DBServer, \Scalr_Server_LaunchOptions $launchOptions = null) { $runInstanceRequest = new RunInstancesRequestData(isset($launchOptions->imageId) ? $launchOptions->imageId : null, 1, 1); $environment = $DBServer->GetEnvironmentObject(); $governance = new \Scalr_Governance($DBServer->envId); $placementData = null; $noSecurityGroups = false; if (!$launchOptions) { $launchOptions = new \Scalr_Server_LaunchOptions(); $dbFarmRole = $DBServer->GetFarmRoleObject(); $DBRole = $dbFarmRole->GetRoleObject(); $runInstanceRequest->setMonitoring($dbFarmRole->GetSetting(\DBFarmRole::SETTING_AWS_ENABLE_CW_MONITORING)); $image = $DBRole->__getNewRoleObject()->getImage(SERVER_PLATFORMS::EC2, $dbFarmRole->CloudLocation); $launchOptions->imageId = $image->imageId; // Need OS Family to get block device mapping for OEL roles $launchOptions->osFamily = $image->getImage()->getOs()->family; $launchOptions->cloudLocation = $dbFarmRole->CloudLocation; $akiId = $DBServer->GetProperty(EC2_SERVER_PROPERTIES::AKIID); if (!$akiId) { $akiId = $dbFarmRole->GetSetting(\DBFarmRole::SETTING_AWS_AKI_ID); } if ($akiId) { $runInstanceRequest->kernelId = $akiId; } $ariId = $DBServer->GetProperty(EC2_SERVER_PROPERTIES::ARIID); if (!$ariId) { $ariId = $dbFarmRole->GetSetting(\DBFarmRole::SETTING_AWS_ARI_ID); } if ($ariId) { $runInstanceRequest->ramdiskId = $ariId; } $iType = $dbFarmRole->GetSetting(\DBFarmRole::SETTING_AWS_INSTANCE_TYPE); $launchOptions->serverType = $iType; // Check governance of instance types $types = $governance->getValue('ec2', 'aws.instance_type'); if (count($types) > 0) { if (!in_array($iType, $types)) { throw new Exception(sprintf("Instance type '%s' was prohibited to use by scalr account owner", $iType)); } } $iamProfileArn = $dbFarmRole->GetSetting(\DBFarmRole::SETTING_AWS_IAM_INSTANCE_PROFILE_ARN); if ($iamProfileArn) { $iamInstanceProfile = new IamInstanceProfileRequestData($iamProfileArn); $runInstanceRequest->setIamInstanceProfile($iamInstanceProfile); } if ($dbFarmRole->GetSetting(\DBFarmRole::SETTING_AWS_EBS_OPTIMIZED) == 1) { $runInstanceRequest->ebsOptimized = true; } else { $runInstanceRequest->ebsOptimized = false; } // Custom user-data (base.custom_user_data) $u_data = ''; foreach ($DBServer->GetCloudUserData() as $k => $v) { $u_data .= "{$k}={$v};"; } $u_data = trim($u_data, ";"); $customUserData = $dbFarmRole->GetSetting('base.custom_user_data'); if ($customUserData) { $repos = $DBServer->getScalarizrRepository(); $userData = str_replace(array('{SCALR_USER_DATA}', '{RPM_REPO_URL}', '{DEB_REPO_URL}'), array($u_data, $repos['rpm_repo_url'], $repos['deb_repo_url']), $customUserData); } else { $userData = $u_data; } $runInstanceRequest->userData = base64_encode($userData); $vpcId = $dbFarmRole->GetFarmObject()->GetSetting(DBFarm::SETTING_EC2_VPC_ID); if ($vpcId) { if ($DBRole->hasBehavior(ROLE_BEHAVIORS::VPC_ROUTER)) { $networkInterface = new InstanceNetworkInterfaceSetRequestData(); $networkInterface->networkInterfaceId = $dbFarmRole->GetSetting(\Scalr_Role_Behavior_Router::ROLE_VPC_NID); $networkInterface->deviceIndex = 0; $networkInterface->deleteOnTermination = false; $runInstanceRequest->setNetworkInterface($networkInterface); $noSecurityGroups = true; } else { $vpcSubnetId = $dbFarmRole->GetSetting(\DBFarmRole::SETTING_AWS_VPC_SUBNET_ID); // VPC Support v2 if ($vpcSubnetId && substr($vpcSubnetId, 0, 6) != 'subnet') { $subnets = json_decode($vpcSubnetId); $servers = $DBServer->GetFarmRoleObject()->GetServersByFilter(array("status" => array(SERVER_STATUS::RUNNING, SERVER_STATUS::INIT, SERVER_STATUS::PENDING))); $subnetsDistribution = array(); foreach ($servers as $cDbServer) { if ($cDbServer->serverId != $DBServer->serverId) { $subnetsDistribution[$cDbServer->GetProperty(EC2_SERVER_PROPERTIES::SUBNET_ID)]++; } } $sCount = 1000000; foreach ($subnets as $subnet) { if ((int) $subnetsDistribution[$subnet] <= $sCount) { $sCount = (int) $subnetsDistribution[$subnet]; $selectedSubnetId = $subnet; } } } else { $vpcInternetAccess = $dbFarmRole->GetSetting(\DBFarmRole::SETTING_AWS_VPC_INTERNET_ACCESS); if (!$vpcSubnetId) { $aws = $environment->aws($launchOptions->cloudLocation); $subnet = $this->AllocateNewSubnet($aws->ec2, $vpcId, $dbFarmRole->GetSetting(\DBFarmRole::SETTING_AWS_VPC_AVAIL_ZONE), 24); try { $subnet->createTags(array(array('key' => "scalr-id", 'value' => SCALR_ID), array('key' => "scalr-sn-type", 'value' => $vpcInternetAccess), array('key' => "Name", 'value' => 'Scalr System Subnet'))); } catch (Exception $e) { } try { $routeTableId = $dbFarmRole->GetSetting(\DBFarmRole::SETTING_AWS_VPC_ROUTING_TABLE_ID); \Logger::getLogger('VPC')->warn(new \FarmLogMessage($DBServer->farmId, "Internet access: {$vpcInternetAccess}")); if (!$routeTableId) { if ($vpcInternetAccess == \Scalr_Role_Behavior_Router::INTERNET_ACCESS_OUTBOUND) { $routerRole = $DBServer->GetFarmObject()->GetFarmRoleByBehavior(ROLE_BEHAVIORS::VPC_ROUTER); if (!$routerRole) { if (\Scalr::config('scalr.instances_connection_policy') != 'local') { throw new Exception("Outbound access require VPC router role in farm"); } } $networkInterfaceId = $routerRole->GetSetting(\Scalr_Role_Behavior_Router::ROLE_VPC_NID); \Logger::getLogger('EC2')->warn(new \FarmLogMessage($DBServer->farmId, "Requesting outbound routing table. NID: {$networkInterfaceId}")); $routeTableId = $this->getRoutingTable($vpcInternetAccess, $aws, $networkInterfaceId, $vpcId); \Logger::getLogger('EC2')->warn(new \FarmLogMessage($DBServer->farmId, "Routing table ID: {$routeTableId}")); } elseif ($vpcInternetAccess == \Scalr_Role_Behavior_Router::INTERNET_ACCESS_FULL) { $routeTableId = $this->getRoutingTable($vpcInternetAccess, $aws, null, $vpcId); } } $aws->ec2->routeTable->associate($routeTableId, $subnet->subnetId); } catch (Exception $e) { \Logger::getLogger('EC2')->warn(new \FarmLogMessage($DBServer->farmId, "Removing allocated subnet, due to routing table issues")); $aws->ec2->subnet->delete($subnet->subnetId); throw $e; } $selectedSubnetId = $subnet->subnetId; $dbFarmRole->SetSetting(\DBFarmRole::SETTING_AWS_VPC_SUBNET_ID, $selectedSubnetId, \DBFarmRole::TYPE_LCL); } else { $selectedSubnetId = $vpcSubnetId; } } if ($selectedSubnetId) { $networkInterface = new InstanceNetworkInterfaceSetRequestData(); $networkInterface->deviceIndex = 0; $networkInterface->deleteOnTermination = true; // //Check network private or public // // We don't need public IP for private subnets $info = $this->listSubnets($environment, $launchOptions->cloudLocation, $vpcId, true, $selectedSubnetId); if ($info && $info['type'] == 'public') { $networkInterface->associatePublicIpAddress = true; } $networkInterface->subnetId = $selectedSubnetId; $aws = $environment->aws($launchOptions->cloudLocation); $sgroups = $this->GetServerSecurityGroupsList($DBServer, $aws->ec2, $vpcId, $governance); $networkInterface->setSecurityGroupId($sgroups); $runInstanceRequest->setNetworkInterface($networkInterface); $noSecurityGroups = true; //$runInstanceRequest->subnetId = $selectedSubnetId; } else { throw new Exception("Unable to define subnetId for role in VPC"); } } } $rootDevice = json_decode($DBServer->GetFarmRoleObject()->GetSetting(\Scalr_Role_Behavior::ROLE_BASE_ROOT_DEVICE_CONFIG), true); if ($rootDevice && $rootDevice['settings']) { $rootDeviceSettings = $rootDevice['settings']; } $instanceInitiatedShutdownBehavior = $dbFarmRole->GetSetting(\DBFarmRole::SETTING_AWS_SHUTDOWN_BEHAVIOR); } else { $instanceInitiatedShutdownBehavior = null; $runInstanceRequest->userData = base64_encode(trim($launchOptions->userData)); } $aws = $environment->aws($launchOptions->cloudLocation); if (!$vpcId) { $vpcId = $this->getDefaultVpc($environment, $launchOptions->cloudLocation); } // Set AMI, AKI and ARI ids $runInstanceRequest->imageId = $launchOptions->imageId; $runInstanceRequest->instanceInitiatedShutdownBehavior = $instanceInitiatedShutdownBehavior ?: 'terminate'; if (!$noSecurityGroups) { foreach ($this->GetServerSecurityGroupsList($DBServer, $aws->ec2, $vpcId, $governance) as $sgroup) { $runInstanceRequest->appendSecurityGroupId($sgroup); } if (!$runInstanceRequest->subnetId) { // Set availability zone if (!$launchOptions->availZone) { $avail_zone = $this->GetServerAvailZone($DBServer, $aws->ec2, $launchOptions); if ($avail_zone) { $placementData = new PlacementResponseData($avail_zone); } } else { $placementData = new PlacementResponseData($launchOptions->availZone); } } } $runInstanceRequest->minCount = 1; $runInstanceRequest->maxCount = 1; // Set instance type $runInstanceRequest->instanceType = $launchOptions->serverType; if ($rootDeviceSettings) { $ebs = new EbsBlockDeviceData($rootDeviceSettings[FarmRoleStorageConfig::SETTING_EBS_SIZE], null, $rootDeviceSettings[FarmRoleStorageConfig::SETTING_EBS_TYPE], $rootDeviceSettings[FarmRoleStorageConfig::SETTING_EBS_IOPS], true, null); $rootBlockDevice = new BlockDeviceMappingData('/dev/sda1', null, null, $ebs); $runInstanceRequest->appendBlockDeviceMapping($rootBlockDevice); } if (substr($launchOptions->serverType, 0, 2) == 'm3' || substr($launchOptions->serverType, 0, 2) == 'm4' || substr($launchOptions->serverType, 0, 2) == 'i2' || substr($launchOptions->serverType, 0, 2) == 'r3' || substr($launchOptions->serverType, 0, 2) == 'd2' || $launchOptions->serverType == 'hi1.4xlarge' || $launchOptions->serverType == 'cc2.8xlarge' || $launchOptions->serverType == 'hs1.8xlarge' || $launchOptions->osFamily == 'oel') { foreach ($this->GetBlockDeviceMapping($launchOptions->serverType) as $bdm) { $runInstanceRequest->appendBlockDeviceMapping($bdm); } } if (in_array($runInstanceRequest->instanceType, array('c3.large', 'c3.xlarge', 'c3.2xlarge', 'c3.4xlarge', 'c3.8xlarge', 'cc2.8xlarge', 'cg1.4xlarge', 'g2.2xlarge', 'g2.8xlarge', 'cr1.8xlarge', 'r3.large', 'r3.xlarge', 'r3.2xlarge', 'r3.4xlarge', 'r3.8xlarge', 'hi1.4xlarge', 'hs1.8xlarge', 'i2.xlarge', 'i2.2xlarge', 'i2.4xlarge', 'i2.8xlarge', 'd2.xlarge', 'd2.2xlarge', 'd2.4xlarge', 'd2.8xlarge'))) { $placementGroup = $DBServer->GetFarmRoleObject()->GetSetting(\DBFarmRole::SETTING_AWS_CLUSTER_PG); if ($placementGroup) { if ($placementData === null) { $placementData = new PlacementResponseData(null, $placementGroup); } else { $placementData->groupName = $placementGroup; } } } if ($placementData !== null) { $runInstanceRequest->setPlacement($placementData); } $sshKey = \Scalr_SshKey::init(); if ($DBServer->status == SERVER_STATUS::TEMPORARY) { $keyName = "SCALR-ROLESBUILDER-" . SCALR_ID; if (!$sshKey->loadGlobalByName($keyName, $launchOptions->cloudLocation, $DBServer->envId, SERVER_PLATFORMS::EC2)) { $keyName = "SCALR-ROLESBUILDER-" . SCALR_ID . "-{$DBServer->envId}"; } $farmId = NULL; } else { $keyName = $governance->getValue(SERVER_PLATFORMS::EC2, \Scalr_Governance::AWS_KEYPAIR); if ($keyName) { $skipKeyValidation = true; } else { $keyName = "FARM-{$DBServer->farmId}-" . SCALR_ID; $farmId = $DBServer->farmId; $oldKeyName = "FARM-{$DBServer->farmId}"; if ($sshKey->loadGlobalByName($oldKeyName, $launchOptions->cloudLocation, $DBServer->envId, SERVER_PLATFORMS::EC2)) { $keyName = $oldKeyName; $skipKeyValidation = true; } } } if (!$skipKeyValidation && !$sshKey->loadGlobalByName($keyName, $launchOptions->cloudLocation, $DBServer->envId, SERVER_PLATFORMS::EC2)) { $result = $aws->ec2->keyPair->create($keyName); if ($result->keyMaterial) { $sshKey->farmId = $farmId; $sshKey->envId = $DBServer->envId; $sshKey->type = \Scalr_SshKey::TYPE_GLOBAL; $sshKey->cloudLocation = $launchOptions->cloudLocation; $sshKey->cloudKeyName = $keyName; $sshKey->platform = SERVER_PLATFORMS::EC2; $sshKey->setPrivate($result->keyMaterial); $sshKey->setPublic($sshKey->generatePublicKey()); $sshKey->save(); } } $runInstanceRequest->keyName = $keyName; try { $result = $aws->ec2->instance->run($runInstanceRequest); } catch (Exception $e) { if (stristr($e->getMessage(), "The key pair") && stristr($e->getMessage(), "does not exist")) { $sshKey->delete(); throw $e; } if (stristr($e->getMessage(), "The requested Availability Zone is no longer supported") || stristr($e->getMessage(), "is not supported in your requested Availability Zone") || stristr($e->getMessage(), "capacity in the Availability Zone you requested") || stristr($e->getMessage(), "Our system will be working on provisioning additional capacity") || stristr($e->getMessage(), "is currently constrained and we are no longer accepting new customer requests")) { $availZone = $runInstanceRequest->getPlacement() ? $runInstanceRequest->getPlacement()->availabilityZone : null; if ($availZone) { $DBServer->GetEnvironmentObject()->setPlatformConfig(array("aws.{$launchOptions->cloudLocation}.{$availZone}.unavailable" => time())); } throw $e; } else { throw $e; } } if ($result->instancesSet->get(0)->instanceId) { $DBServer->SetProperties([EC2_SERVER_PROPERTIES::REGION => $launchOptions->cloudLocation, EC2_SERVER_PROPERTIES::AVAIL_ZONE => $result->instancesSet->get(0)->placement->availabilityZone, EC2_SERVER_PROPERTIES::INSTANCE_ID => $result->instancesSet->get(0)->instanceId, EC2_SERVER_PROPERTIES::INSTANCE_TYPE => $runInstanceRequest->instanceType, EC2_SERVER_PROPERTIES::AMIID => $runInstanceRequest->imageId, EC2_SERVER_PROPERTIES::VPC_ID => $result->instancesSet->get(0)->vpcId, EC2_SERVER_PROPERTIES::SUBNET_ID => $result->instancesSet->get(0)->subnetId, EC2_SERVER_PROPERTIES::ARCHITECTURE => $result->instancesSet->get(0)->architecture]); $DBServer->setOsType($result->instancesSet->get(0)->platform ? $result->instancesSet->get(0)->platform : 'linux'); $DBServer->cloudLocation = $launchOptions->cloudLocation; $DBServer->cloudLocationZone = $result->instancesSet->get(0)->placement->availabilityZone; $DBServer->imageId = $launchOptions->imageId; // we set server history here $DBServer->getServerHistory(); return $DBServer; } else { throw new Exception(sprintf(_("Cannot launch new instance. %s"), serialize($result))); } }
/** * @test */ public function testFunctionalEc2() { $this->skipIfEc2PlatformDisabled(); $aws = $this->getContainer()->aws(AwsTestCase::REGION); $aws->ec2->enableEntityManager(); //We should use different ec2 instance for another region $aws2 = $this->getContainer()->aws(Aws::REGION_US_WEST_2); $nameTag = new ResourceTagSetData(self::TAG_NAME_KEY, self::getTestName(self::NAME_TAG_VALUE)); $subnetList = $aws->ec2->subnet->describe(); $this->assertInstanceOf($this->getEc2ClassName('DataType\\SubnetList'), $subnetList); unset($subnetList); $imageList = $aws->ec2->image->describe(null, 'self'); $this->assertInstanceOf($this->getEc2ClassName('DataType\\ImageList'), $imageList); unset($imageList); $volumeList = $aws->ec2->volume->describe(); $this->assertInstanceOf($this->getEc2ClassName('DataType\\VolumeList'), $volumeList); unset($volumeList); $snapshotList = $aws->ec2->snapshot->describe(null, 'self', new SnapshotFilterData(SnapshotFilterNameType::tag(self::TAG_NAME_KEY), self::getTestName(self::NAME_TAG_VALUE))); $this->assertInstanceOf($this->getEc2ClassName('DataType\\SnapshotList'), $snapshotList); /* @var $sn SnapshotList */ foreach ($snapshotList as $sn) { $sn->delete(); } unset($snapshotList); $reservationsList = $aws->ec2->instance->describe(null, new InstanceFilterData(InstanceFilterNameType::tag(self::TAG_NAME_KEY), self::getTestName(self::NAME_TAG_VALUE))); $this->assertInstanceOf($this->getEc2ClassName('DataType\\ReservationList'), $reservationsList); foreach ($reservationsList as $r) { /* @var $i InstanceData */ foreach ($r->instancesSet as $i) { $ds = $i->describeStatus(); if ($ds->instanceState->name == InstanceStateData::NAME_RUNNING) { //Whether the elastic ip is still associated with the instance $adlist = $aws->ec2->address->describe(null, null, array(array('name' => AddressFilterNameType::instanceId(), 'value' => $i->instanceId))); foreach ($adlist as $v) { //Removes associated elastic IP address $aws->ec2->address->disassociate($v->publicIp); $aws->ec2->address->release($v->publicIp); } unset($adlist); } else { if ($ds->instanceState->name == InstanceStateData::NAME_TERMINATED || $ds->instanceState->name == InstanceStateData::NAME_SHUTTING_DOWN) { continue; } } $i->terminate(); $i = $i->refresh(); for ($t = time(); time() - $t < 100 && isset($i->instanceState) && !in_array($i->instanceState->name, array(InstanceStateData::NAME_TERMINATED)); sleep(5)) { $i = $i->refresh(); } } } $placementGroups = $aws->ec2->placementGroup->describe(null, new PlacementGroupFilterData(PlacementGroupFilterNameType::groupName(), self::getTestName('placement-group'))); $this->assertInstanceOf($this->getEc2ClassName('DataType\\PlacementGroupList'), $placementGroups); /* @var $pg PlacementGroupData */ foreach ($placementGroups as $pg) { $pg->delete(); unset($pg); } unset($placementGroups); $reservedInstancesList = $aws->ec2->reservedInstance->describe(); $this->assertInstanceOf($this->getEc2ClassName('DataType\\ReservedInstanceList'), $reservedInstancesList); $availabilityZoneList = $aws->ec2->availabilityZone->describe('us-east-1a', array(array('name' => AvailabilityZoneFilterNameType::state(), 'value' => array('available')))); $this->assertInstanceOf($this->getEc2ClassName('DataType\\AvailabilityZoneList'), $availabilityZoneList); $this->assertEquals(1, count($availabilityZoneList)); $this->assertInstanceOf($this->getAwsClassName('Ec2'), $availabilityZoneList->getEc2()); $this->assertNotEmpty($availabilityZoneList->getRequestId()); $this->assertEquals('us-east-1a', $availabilityZoneList[0]->getZoneName()); $this->assertEquals('available', $availabilityZoneList[0]->getZoneState()); $this->assertEquals('us-east-1', $availabilityZoneList[0]->getRegionName()); $ml = $availabilityZoneList[0]->getMessageSet(); $this->assertInstanceOf($this->getEc2ClassName('DataType\\AvailabilityZoneMessageList'), $ml); $this->assertInstanceOf($this->getAwsClassName('Ec2'), $ml->getEc2()); unset($ml); $al = $aws->ec2->address->describe(null, null, array(array('name' => AddressFilterNameType::domain(), 'value' => 'standard'))); $this->assertInstanceOf($this->getEc2ClassName('DataType\\AddressList'), $al); unset($al); //Describes keypair $keyname = self::getTestName('keyname'); $kplist = $aws->ec2->keyPair->describe(null, array('key-name' => $keyname)); $this->assertInstanceOf($this->getEc2ClassName('DataType\\KeyPairList'), $kplist); if (count($kplist) > 0) { foreach ($kplist as $kp) { $kp->delete(); } } unset($kplist); //Creates keypair $kp = $aws->ec2->keyPair->create($keyname); $this->assertInstanceOf($this->getEc2ClassName('DataType\\KeyPairData'), $kp); $this->assertEquals($keyname, $kp->keyName); $this->assertNotNull($kp->keyFingerprint); $this->assertNotNull($kp->keyMaterial); //We should be assured that group which is used for the test does not exists $list = $aws->ec2->securityGroup->describe(null, null, new SecurityGroupFilterData(SecurityGroupFilterNameType::groupName(), self::getTestName('security-group'))); if (count($list) > 0) { foreach ($list as $v) { $v->delete(); } } unset($list); //Creates security group $securityGroupId = $aws->ec2->securityGroup->create(self::getTestName('security-group'), self::getTestName('security-group') . ' description'); $this->assertNotEmpty($securityGroupId); sleep(2); /* @var $sg SecurityGroupData */ $sg = $aws->ec2->securityGroup->describe(null, $securityGroupId)->get(0); $this->assertInstanceOf($this->getEc2ClassName('DataType\\SecurityGroupData'), $sg); $this->assertNotEmpty($sg->groupId); $this->assertEquals(self::getTestName('security-group'), $sg->groupName); $this->assertContains(self::getTestName('security-group'), $sg->groupDescription); $ret = $sg->createTags($nameTag); $this->assertTrue($ret); //Verifies that security group entity which is stored in manager is the same object $sgMirror = $aws->ec2->securityGroup->get($sg->groupId); $this->assertSame($sg, $sgMirror); unset($sgMirror); //Athorizes Security Group Ingress $ipperm = new IpPermissionData('tcp', 80, 80, new IpRangeList(array(new IpRangeData('192.0.2.0/24'), new IpRangeData('192.51.100.0/24')))); $ret = $sg->authorizeIngress($ipperm); $this->assertTrue($ret); $ipperm2 = new IpPermissionData('tcp', 8080, 8080, new IpRangeList(array(new IpRangeData('192.66.12.0/24')))); $ret = $sg->authorizeIngress($ipperm2); $this->assertTrue($ret); $ret = $sg->revokeIngress($ipperm2); $this->assertTrue($ret); //Describes itself $sg->refresh(); $this->assertContains(self::TAG_NAME_KEY, $sg->tagSet->getQueryArrayBare('Tag')); //Creates placement group $ret = $aws->ec2->placementGroup->create(self::getTestName('placement-group')); $this->assertTrue($ret); //Sometimes it takes a moment sleep(3); $pg = $aws->ec2->placementGroup->describe(self::getTestName('placement-group'))->get(0); $this->assertInstanceOf($this->getEc2ClassName('DataType\\PlacementGroupData'), $pg); $this->assertEquals(self::getTestName('placement-group'), $pg->groupName); $this->assertSame($pg, $aws->ec2->placementGroup->get($pg->groupName)); //RunInstance test $request = new RunInstancesRequestData(self::INSTANCE_IMAGE_ID, 1, 1); $request->instanceType = self::INSTANCE_TYPE; //Placement groups may not be used with instances of type 'm1.small'. $request->setPlacement(new PlacementResponseData(AwsTestCase::AVAILABILITY_ZONE_C)); $request->setMonitoring(true); $request->ebsOptimized = false; $request->userData = base64_encode("test=26;"); $request->appendSecurityGroupId($securityGroupId); $request->appendBlockDeviceMapping(new BlockDeviceMappingData("/dev/sdb", 'ephemeral0', null, new EbsBlockDeviceData(1, null, null, null, true, true))); $request->keyName = $keyname; $rd = $aws->ec2->instance->run($request); $this->assertInstanceOf($this->getEc2ClassName('DataType\\ReservationData'), $rd); /* @var $ind InstanceData */ $ind = $rd->instancesSet[0]; unset($request); //Monitors instance $ret = $ind->monitor(); $this->assertInstanceOf($this->getEc2ClassName('DataType\\MonitorInstancesResponseSetList'), $ret); $this->assertContains($ret->get(0)->monitoring->state, array(InstanceMonitoringStateData::STATE_PENDING, InstanceMonitoringStateData::STATE_ENABLED)); unset($ret); //Instance state must be in the running state for ($t = time(), $s = 5; time() - $t < 300 && $ind->instanceState->name !== InstanceStateData::NAME_RUNNING; $s += 5) { sleep($s); $ind = $ind->refresh(); } $this->assertEquals(InstanceStateData::NAME_RUNNING, $ind->instanceState->name); // route53 test $dns = self::getTestName('testname') . '.com'; // clean up $listZones = $aws->route53->zone->describe(); $this->assertInstanceOf($this->getRoute53ClassName('DataType\\ZoneList'), $listZones); /* @var $zone \Scalr\Service\Aws\Route53\DataType\ZoneData */ foreach ($listZones as $zone) { $this->assertNotNull($zone->zoneId); if ($dns . '.' == $zone->name) { $rrsRequest = new ChangeRecordSetsRequestData(); $rrsCnahgeList = new ChangeRecordSetList(); $rrsCnahgeListData = new ChangeRecordSetData('DELETE'); $rrsData = new RecordSetData($dns, 'A', 60); $rrsData->setResourceRecord([['value' => $ind->ipAddress]]); $rrsCnahgeListData->setRecordSet($rrsData); $rrsCnahgeList->append($rrsCnahgeListData); $rrsRequest->setChange($rrsCnahgeList); $changeRequest = $aws->route53->record->update($zone->zoneId, $rrsRequest); $this->assertInstanceOf($this->getRoute53ClassName('DataType\\ChangeData'), $changeRequest); $zone->delete($zone->zoneId); } unset($zone); } unset($listZones); $list = $aws->route53->health->describe(); $this->assertInstanceOf($this->getRoute53ClassName('DataType\\HealthList'), $list); foreach ($list as $check) { /* @var $check \Scalr\Service\Aws\Route53\DataType\HealthData */ $this->assertInstanceOf($this->getRoute53ClassName('DataType\\HealthConfigData'), $check->healthConfig); $this->assertNotNull($check->healthId); $this->assertNotNull($check->healthConfig->domainName); if ($dns . '.' == $check->healthConfig->domainName) { $check->delete($check->healthId); } unset($check); } unset($list); // create hosted zone $config = new ZoneData($dns); $hostedZone = $aws->route53->zone->create($config); $this->assertInstanceOf($this->getRoute53ClassName('DataType\\ZoneData'), $hostedZone); $this->assertNotNull($hostedZone->zoneId); $zoneId = (string) $hostedZone->zoneId; // create record set for hosted zone $rrsRequest = new ChangeRecordSetsRequestData(); $rrsCnahgeList = new ChangeRecordSetList(); $rrsCnahgeListData = new ChangeRecordSetData('CREATE'); $rrsData = new RecordSetData($dns, 'A', 60); $rrsData->setResourceRecord([['value' => $ind->ipAddress]]); $rrsCnahgeListData->setRecordSet($rrsData); $rrsCnahgeList->append($rrsCnahgeListData); $rrsRequest->setChange($rrsCnahgeList); $changeRequest = $aws->route53->record->update($zoneId, $rrsRequest); $this->assertInstanceOf($this->getRoute53ClassName('DataType\\ChangeData'), $changeRequest); $this->assertNotNull($changeRequest->changeId); $getChange = $aws->route53->record->fetch($changeRequest->changeId); $this->assertEquals($changeRequest->changeId, $getChange->changeId); // create health check using record set's idAddress $healthData = new HealthData(); $healthConfig = new HealthConfigData($ind->ipAddress, 80, 'HTTP', '/index.html', $dns); $healthData->setHealthConfig($healthConfig); $healthCheck = $aws->route53->health->create($healthData); $this->assertNotNull($healthCheck->healthId); $list = $aws->route53->health->describe(); $this->assertInstanceOf($this->getRoute53ClassName('DataType\\HealthList'), $list); foreach ($list as $check) { $this->assertInstanceOf($this->getRoute53ClassName('DataType\\HealthConfigData'), $check->healthConfig); $this->assertNotNull($check->healthId); $this->assertNotNull($check->healthConfig->domainName); if ($dns == $check->healthConfig->domainName) { $getCheck = $aws->route53->health->fetch($check->healthId); $this->assertEquals($check->healthId, $getCheck->healthId); $check->delete($check->healthId); } unset($check); } unset($list); // clean up $listZones = $aws->route53->zone->describe(); $this->assertInstanceOf($this->getRoute53ClassName('DataType\\ZoneList'), $listZones); foreach ($listZones as $zone) { /* @var $zone \Scalr\Service\Aws\Route53\DataType\ZoneData */ $this->assertNotNull($zone->zoneId); if ($dns . '.' == $zone->name) { $rrsRequest = new ChangeRecordSetsRequestData(); $rrsCnahgeList = new ChangeRecordSetList(); $rrsCnahgeListData = new ChangeRecordSetData('DELETE'); $rrsData = new RecordSetData($dns, 'A', 60); $rrsData->setResourceRecord([['value' => $ind->ipAddress]]); $rrsCnahgeListData->setRecordSet($rrsData); $rrsCnahgeList->append($rrsCnahgeListData); $rrsRequest->setChange($rrsCnahgeList); $changeRequest = $aws->route53->record->update($zone->zoneId, $rrsRequest); $this->assertInstanceOf($this->getRoute53ClassName('DataType\\ChangeData'), $changeRequest); $getZone = $aws->route53->zone->fetch($zone->zoneId); $this->assertEquals($zone->zoneId, $getZone->zoneId); $zone->delete($zone->zoneId); } unset($zone); } unset($listZones); //Creates the tag for the instance $res = $ind->createTags(array($nameTag, array('key' => 'Extratag', 'value' => 'extravalue'))); $this->assertTrue($res); //Verifies that tag has been successfully set. $ind->refresh(); $this->assertContains(self::TAG_NAME_KEY, $ind->tagSet->getQueryArrayBare()); $this->assertContains('Extratag', $ind->tagSet->getQueryArrayBare()); //Removes an extratag $ind->deleteTags(array(array('key' => 'Extratag', 'value' => null))); $this->assertEquals(self::INSTANCE_TYPE, $ind->instanceType); $this->assertEquals(self::INSTANCE_IMAGE_ID, $ind->imageId); $this->assertEquals(false, $ind->ebsOptimized); $this->assertContains($ind->monitoring->state, array('enabled', 'pending')); $this->assertEquals(AwsTestCase::AVAILABILITY_ZONE_C, $ind->placement->availabilityZone); $this->assertEquals($keyname, $ind->keyName); $this->assertContains($securityGroupId, array_map(function ($arr) { return $arr->groupId; }, iterator_to_array($ind->groupSet, false))); $this->assertContains(array("/dev/sdb", ''), array_map(function ($arr) { return array($arr->deviceName, $arr->virtualName); }, iterator_to_array($ind->blockDeviceMapping, false))); //Creates AMI // $cr = new CreateImageRequestData($ind->instanceId, sprintf(self::getTestName('i%s'), $ind->instanceId)); // $cr->description = 'It is supposed to be removed immediately after creation.'; // $imageId = $aws->ec2->image->create($cr); // sleep(3); // $ami = $aws->ec2->image->describe($imageId); // $this->assertInstanceOf($this->getEc2ClassName('DataType\\ImageData'), $ami); // $this->assertNotNull($ami->imageId); // //Waits while snapshot is created. // for ($t = time(), $s = 5; time() - $t < 300 && $ami->imageState === ImageData::STATE_PENDING; $s += 5) { // sleep($s); // $ami = $ami->refresh(); // } // $this->assertTrue(in_array($ami->imageState, array(ImageData::STATE_AVAILABLE, SnapshotData::STATUS_ERROR))); // unset($cr); // $ami->createTags($nameTag); // //Copy // $copyImageId = $ami->copy(substr(AwsTestCase::AVAILABILITY_ZONE_A, 0, -1), null, 'phpunit copied AMI', null, Aws::REGION_US_WEST_2); // $this->assertNotNull($copyImageId); // /* @var $ami2 ImageData */ // $ami2 = $aws2->ec2->image->describe($copyImageId)->get(0); // $this->assertNotNull($ami2); // $ami2->deregister(); // //Deregisters an AMI // $ami->deregister(); //Creates Elastic IP Address $address = $aws->ec2->address->allocate(); $this->assertInstanceOf($this->getEc2ClassName('DataType\\AddressData'), $address); $this->assertNotNull($address->publicIp); $ret = $aws->ec2->address->associate(new AssociateAddressRequestData($ind->instanceId, $address->publicIp)); $this->assertTrue($ret); //DescribeAddress should return allocated addres $adlist = $aws->ec2->address->describe($address->publicIp, null, array(array('name' => AddressFilterNameType::instanceId(), 'value' => $ind->instanceId))); $this->assertInstanceOf($this->getEc2ClassName('DataType\\AddressList'), $adlist); $this->assertEquals(1, count($adlist)); $this->assertEquals($address->publicIp, $adlist->get(0)->publicIp); //It must be associated with the instance $this->assertEquals($ind->instanceId, $adlist->get(0)->instanceId); $this->assertEquals($address->domain, $adlist->get(0)->domain); //Dissassociates address $ret = $aws->ec2->address->disassociate($address->publicIp); $this->assertTrue($ret); //Releases address $ret = $aws->ec2->address->release($address->publicIp); $this->assertTrue($ret); unset($adlist); unset($address); //Creates the volume $cvRequest = new CreateVolumeRequestData(AwsTestCase::AVAILABILITY_ZONE_C); $cvRequest->encrypted = true; $cvRequest->setSize(2)->setVolumeType(CreateVolumeRequestData::VOLUME_TYPE_STANDARD); $vd = $aws->ec2->volume->create($cvRequest); $this->assertInstanceOf($this->getEc2ClassName('DataType\\VolumeData'), $vd); $volumeid = $vd->volumeId; $this->assertTrue($vd->encrypted); unset($cvRequest); $res = $vd->createTags($nameTag); $this->assertTrue($res); //Volume must be in the Available status for ($t = time(), $s = 2; time() - $t < 300 && $vd->status !== VolumeData::STATUS_AVAILABLE; $s += 5) { sleep($s); $vd = $vd->refresh(); } $this->assertEquals(VolumeData::STATUS_AVAILABLE, $vd->status); //Attaching the volume $at = $vd->attach($ind->instanceId, '/dev/sdh'); $this->assertInstanceOf($this->getEc2ClassName('DataType\\AttachmentSetResponseData'), $at); //Creates snapshot $sn = $vd->createSnapshot(self::getTestName(self::NAME_SNAPSHOT)); $this->assertTrue($sn->encrypted); $this->assertInstanceOf($this->getEc2ClassName('DataType\\SnapshotData'), $sn); $this->assertNotEmpty($sn->snapshotId); $sn->createTags($nameTag); //Waits while snapshot is created. for ($t = time(), $s = 2; time() - $t < 300 && $sn->status === SnapshotData::STATUS_PENDING; $s += 5) { sleep($s); $sn->refresh(); } $this->assertTrue(in_array($sn->status, array(SnapshotData::STATUS_COMPLETED, SnapshotData::STATUS_ERROR))); //Copies snapshot to different region $copySnapshotId = $sn->copy($aws->getRegion(), 'phpunit copied encrypted snapshot', Aws::REGION_US_WEST_2, $aws->getPresignedUrl('ec2', 'CopySnapshot', Aws::REGION_US_WEST_2, $sn->snapshotId)); $this->assertNotNull($copySnapshotId); $aws2->ec2->tag->create($copySnapshotId, $nameTag); $csn = $aws2->ec2->snapshot->describe($copySnapshotId)->get(0); $this->assertInstanceOf($this->getEc2ClassName('DataType\\SnapshotData'), $csn); //Waits while snapshot is created. for ($t = time(), $s = 2; time() - $t < 600 && $csn->status === SnapshotData::STATUS_PENDING; $s += 5) { sleep($s); $csn = $csn->refresh(); } $this->assertTrue($csn->status == SnapshotData::STATUS_COMPLETED); $this->assertTrue($csn->encrypted); //Removes snapshot $ret = $sn->delete(); $this->assertTrue($ret); //Removes copied snapshot $ret = $csn->delete(); $this->assertTrue($ret); //Detaching the volume $at = $vd->detach(); $this->assertInstanceOf($this->getEc2ClassName('DataType\\AttachmentSetResponseData'), $at); $maxTimeout = 200; $interval = 2; while ($maxTimeout > 0) { if (count($vd->attachmentSet) == 0 || $vd->attachmentSet[0]->status == AttachmentSetResponseData::STATUS_DETACHED) { break; } sleep($interval); $maxTimeout -= $interval; $interval *= 2; $vd->refresh(); } if (isset($vd->attachmentSet[0]->status) && $vd->attachmentSet[0]->status !== AttachmentSetResponseData::STATUS_DETACHED) { $this->assertTrue(false, sprintf('The volume %s has not been detached from the instance %s yet.', $volumeid, $ind->instanceId)); } $vd->refresh(); $this->assertContains(self::TAG_NAME_KEY, $vd->tagSet->getQueryArrayBare('Tag')); //Deletes the volume. $ret = $vd->delete(); $this->assertTrue($ret); $this->assertNull($aws->ec2->volume->get($volumeid)); unset($volumeid); unset($vd); unset($at); $ind->refresh(); //Verifies that extratag has been successfully removed $this->assertNotContains('Extratag', $ind->tagSet->getQueryArrayBare()); $consoleOutput = $ind->getConsoleOutput(); $this->assertInstanceOf($this->getEc2ClassName('DataType\\GetConsoleOutputResponseData'), $consoleOutput); unset($consoleOutput); //Reboots the instance $ret = $ind->reboot(); $this->assertTrue($ret); //Stoping the instance $scList = $ind->stop(true); $this->assertInstanceOf($this->getEc2ClassName('DataType\\InstanceStateChangeList'), $scList); $this->assertEquals(1, count($scList)); unset($scList); for ($t = time(); time() - $t < 300 && $ind->instanceState->name !== InstanceStateData::NAME_STOPPED; sleep(5)) { $ind = $ind->refresh(); } $this->assertEquals(InstanceStateData::NAME_STOPPED, $ind->instanceState->name); //For an each attributes it will get it values foreach (InstanceAttributeType::getAllowedValues() as $attibute) { //This is allowed only for VPC instances, so we have to skip if ($attibute == InstanceAttributeType::TYPE_SOURCE_DEST_CHECK) { continue; } $attrValue = $ind->describeAttribute($attibute); } //Modifies instance attribute //Instance is required to be stopped. $ret = $ind->modifyAttribute(InstanceAttributeType::userData(), base64_encode('user data')); $this->assertTrue($ret); //Starts the instance $scList = $ind->start(); $this->assertInstanceOf($this->getEc2ClassName('DataType\\InstanceStateChangeList'), $scList); unset($scList); $ind = $ind->refresh(); for ($t = time(), $s = 5; time() - $t < 200 && $ind->instanceState->name !== InstanceStateData::NAME_RUNNING; $s += 5) { sleep($s); $ind = $ind->refresh(); } $this->assertEquals(InstanceStateData::NAME_RUNNING, $ind->instanceState->name); //Unmonitors instance $ret = $ind->unmonitor(); $this->assertInstanceOf($this->getEc2ClassName('DataType\\MonitorInstancesResponseSetList'), $ret); $this->assertContains($ret->get(0)->monitoring->state, array(InstanceMonitoringStateData::STATE_DISABLING, InstanceMonitoringStateData::STATE_DISABLED)); unset($ret); //Terminates the instance $st = $ind->terminate(); $this->assertInstanceOf($this->getEc2ClassName('DataType\\InstanceStateChangeList'), $st); $this->assertEquals(1, count($st)); $this->assertEquals($rd->instancesSet[0]->instanceId, $st[0]->getInstanceId()); for ($t = time(); time() - $t < 200 && $ind && $ind->instanceState->name != InstanceStateData::NAME_TERMINATED; sleep(5)) { $ind = $ind->refresh(); } $this->assertTrue(!$ind || $ind->instanceState->name == InstanceStateData::NAME_TERMINATED); if (isset($ind)) { unset($ind); } //Removes keypair $ret = $kp->delete(); $this->assertTrue($ret); unset($kp); //Removes security group $sg->delete(); //Verifies that security group is detached from the storage $sgMirror = $aws->ec2->securityGroup->get($sg->groupId); $this->assertNull($sgMirror); unset($sg); //Deletes placement group. $ret = $pg->delete(); $this->assertTrue($ret); $this->assertNull($aws->ec2->placementGroup->get(self::getTestName('placement-group'))); //Releases all memory $aws->getEntityManager()->detachAll(); }
/** * {@inheritdoc} * @see IPlatformModule::LaunchServer() */ public function LaunchServer(DBServer $DBServer, Scalr_Server_LaunchOptions $launchOptions = null) { $runInstanceRequest = new RunInstancesRequestData(isset($launchOptions->imageId) ? $launchOptions->imageId : null, 1, 1); $environment = $DBServer->GetEnvironmentObject(); $placementData = null; $noSecurityGroups = false; if (!$launchOptions) { $launchOptions = new Scalr_Server_LaunchOptions(); $DBRole = DBRole::loadById($DBServer->roleId); $dbFarmRole = $DBServer->GetFarmRoleObject(); $runInstanceRequest->setMonitoring($dbFarmRole->GetSetting(DBFarmRole::SETTING_AWS_ENABLE_CW_MONITORING)); $launchOptions->imageId = $DBRole->getImageId(SERVER_PLATFORMS::EC2, $dbFarmRole->CloudLocation); // Need OS Family to get block device mapping for OEL roles $imageInfo = $DBRole->getImageDetails(SERVER_PLATFORMS::EC2, $dbFarmRole->CloudLocation); $launchOptions->osFamily = $imageInfo['os_family']; $launchOptions->cloudLocation = $dbFarmRole->CloudLocation; $akiId = $DBServer->GetProperty(EC2_SERVER_PROPERTIES::AKIID); if (!$akiId) { $akiId = $dbFarmRole->GetSetting(DBFarmRole::SETTING_AWS_AKI_ID); } if ($akiId) { $runInstanceRequest->kernelId = $akiId; } $ariId = $DBServer->GetProperty(EC2_SERVER_PROPERTIES::ARIID); if (!$ariId) { $ariId = $dbFarmRole->GetSetting(DBFarmRole::SETTING_AWS_ARI_ID); } if ($ariId) { $runInstanceRequest->ramdiskId = $ariId; } $i_type = $dbFarmRole->GetSetting(DBFarmRole::SETTING_AWS_INSTANCE_TYPE); if (!$i_type) { $DBRole = DBRole::loadById($DBServer->roleId); $i_type = $DBRole->getProperty(EC2_SERVER_PROPERTIES::INSTANCE_TYPE); } $launchOptions->serverType = $i_type; if ($dbFarmRole->GetSetting(DBFarmRole::SETTING_AWS_EBS_OPTIMIZED) == 1) { $runInstanceRequest->ebsOptimized = true; } else { $runInstanceRequest->ebsOptimized = false; } foreach ($DBServer->GetCloudUserData() as $k => $v) { $u_data .= "{$k}={$v};"; } $runInstanceRequest->userData = base64_encode(trim($u_data, ";")); $vpcId = $dbFarmRole->GetFarmObject()->GetSetting(DBFarm::SETTING_EC2_VPC_ID); if ($vpcId) { if ($DBRole->hasBehavior(ROLE_BEHAVIORS::VPC_ROUTER)) { $networkInterface = new InstanceNetworkInterfaceSetRequestData(); $networkInterface->networkInterfaceId = $dbFarmRole->GetSetting(Scalr_Role_Behavior_Router::ROLE_VPC_NID); $networkInterface->deviceIndex = 0; $networkInterface->deleteOnTermination = false; $runInstanceRequest->setNetworkInterface($networkInterface); $noSecurityGroups = true; } else { $vpcSubnetId = $dbFarmRole->GetSetting(DBFarmRole::SETTING_AWS_VPC_SUBNET_ID); $vpcInternetAccess = $dbFarmRole->GetSetting(DBFarmRole::SETTING_AWS_VPC_INTERNET_ACCESS); if (!$vpcSubnetId) { $aws = $environment->aws($launchOptions->cloudLocation); $subnet = $this->AllocateNewSubnet($aws->ec2, $vpcId, $dbFarmRole->GetSetting(DBFarmRole::SETTING_AWS_VPC_AVAIL_ZONE), 24); try { $subnet->createTags(array(array('key' => "scalr-id", 'value' => SCALR_ID), array('key' => "scalr-sn-type", 'value' => $vpcInternetAccess), array('key' => "Name", 'value' => 'Scalr System Subnet'))); } catch (Exception $e) { } try { $routeTableId = $dbFarmRole->GetSetting(DBFarmRole::SETTING_AWS_VPC_ROUTING_TABLE_ID); Logger::getLogger('VPC')->warn(new FarmLogMessage($DBServer->farmId, "Internet access: {$vpcInternetAccess}")); if (!$routeTableId) { if ($vpcInternetAccess == Scalr_Role_Behavior_Router::INTERNET_ACCESS_OUTBOUND) { $routerRole = $DBServer->GetFarmObject()->GetFarmRoleByBehavior(ROLE_BEHAVIORS::VPC_ROUTER); if (!$routerRole) { if (\Scalr::config('scalr.instances_connection_policy') != 'local') { throw new Exception("Outbound access require VPC router role in farm"); } } $networkInterfaceId = $routerRole->GetSetting(Scalr_Role_Behavior_Router::ROLE_VPC_NID); Logger::getLogger('EC2')->warn(new FarmLogMessage($DBServer->farmId, "Requesting outbound routing table. NID: {$networkInterfaceId}")); $routeTableId = $this->getRoutingTable($vpcInternetAccess, $aws, $networkInterfaceId, $vpcId); Logger::getLogger('EC2')->warn(new FarmLogMessage($DBServer->farmId, "Routing table ID: {$routeTableId}")); } elseif ($vpcInternetAccess == Scalr_Role_Behavior_Router::INTERNET_ACCESS_FULL) { $routeTableId = $this->getRoutingTable($vpcInternetAccess, $aws, null, $vpcId); } } $aws->ec2->routeTable->associate($routeTableId, $subnet->subnetId); } catch (Exception $e) { Logger::getLogger('EC2')->warn(new FarmLogMessage($DBServer->farmId, "Removing allocated subnet, due to routing table issues")); $aws->ec2->subnet->delete($subnet->subnetId); throw $e; } $vpcSubnetId = $subnet->subnetId; $dbFarmRole->SetSetting(DBFarmRole::SETTING_AWS_VPC_SUBNET_ID, $vpcSubnetId, DBFarmRole::TYPE_LCL); } if ($vpcSubnetId) { $runInstanceRequest->subnetId = $vpcSubnetId; } else { throw new Exception("Unable to define subnetId for role in VPC"); } } } } else { $runInstanceRequest->userData = base64_encode(trim($launchOptions->userData)); } $governance = new Scalr_Governance($DBServer->envId); $aws = $environment->aws($launchOptions->cloudLocation); if (!$vpcId) { $vpcId = $environment->getPlatformConfigValue(self::DEFAULT_VPC_ID . ".{$launchOptions->cloudLocation}"); if ($vpcId === null || $vpcId === false) { $vpcId = ""; $list = $aws->ec2->describeAccountAttributes(array('default-vpc')); foreach ($list as $item) { if ($item->attributeName == 'default-vpc') { $vpcId = $item->attributeValueSet[0]->attributeValue; } } if ($vpcId == 'none') { $vpcId = ''; } $environment->setPlatformConfig(array(self::DEFAULT_VPC_ID . ".{$launchOptions->cloudLocation}" => $vpcId)); } } // Set AMI, AKI and ARI ids $runInstanceRequest->imageId = $launchOptions->imageId; $runInstanceRequest->instanceInitiatedShutdownBehavior = 'terminate'; if (!$noSecurityGroups) { foreach ($this->GetServerSecurityGroupsList($DBServer, $aws->ec2, $vpcId, $governance) as $sgroup) { $runInstanceRequest->appendSecurityGroupId($sgroup); } if (!$runInstanceRequest->subnetId) { // Set availability zone if (!$launchOptions->availZone) { $avail_zone = $this->GetServerAvailZone($DBServer, $aws->ec2, $launchOptions); if ($avail_zone) { $placementData = new PlacementResponseData($avail_zone); } } else { $placementData = new PlacementResponseData($launchOptions->availZone); } } } $runInstanceRequest->minCount = 1; $runInstanceRequest->maxCount = 1; // Set instance type $runInstanceRequest->instanceType = $launchOptions->serverType; if ($launchOptions->serverType == 'hi1.4xlarge' || $launchOptions->serverType == 'cc2.8xlarge' || $launchOptions->osFamily == 'oel') { foreach ($this->GetBlockDeviceMapping($launchOptions->serverType) as $bdm) { $runInstanceRequest->appendBlockDeviceMapping($bdm); } } if (in_array($runInstanceRequest->instanceType, array('cc1.4xlarge', 'cg1.4xlarge', 'cc2.8xlarge', 'hi1.4xlarge'))) { $placementGroup = $DBServer->GetFarmRoleObject()->GetSetting(DBFarmRole::SETTING_AWS_CLUSTER_PG); if (!$placementGroup && $runInstanceRequest->instanceType != 'hi1.4xlarge') { $placementGroup = "scalr-role-{$DBServer->farmRoleId}"; try { $aws->ec2->placementGroup->create($placementGroup); } catch (Exception $e) { if (!stristr($e->getMessage(), "already exists")) { throw new Exception(sprintf(_("Cannot launch new instance. Unable to create placement group: %s"), $result->faultstring)); } } $DBServer->GetFarmRoleObject()->SetSetting(DBFarmRole::SETTING_AWS_CLUSTER_PG, $placementGroup, DBFarmRole::TYPE_LCL); } if ($placementGroup) { if ($placementData === null) { $placementData = new PlacementResponseData(null, $placementGroup); } else { $placementData->groupName = $placementGroup; } } } if ($placementData !== null) { $runInstanceRequest->setPlacement($placementData); } $sshKey = Scalr_SshKey::init(); if ($DBServer->status == SERVER_STATUS::TEMPORARY) { $keyName = "SCALR-ROLESBUILDER-" . SCALR_ID; $farmId = 0; } else { $keyName = $governance->getValue(Scalr_Governance::AWS_KEYPAIR); if ($keyName) { $skipKeyValidation = true; } else { $keyName = "FARM-{$DBServer->farmId}-" . SCALR_ID; $farmId = $DBServer->farmId; $oldKeyName = "FARM-{$DBServer->farmId}"; if ($sshKey->loadGlobalByName($oldKeyName, $launchOptions->cloudLocation, $DBServer->envId, SERVER_PLATFORMS::EC2)) { $keyName = $oldKeyName; $skipKeyValidation = true; } } } if (!$skipKeyValidation && !$sshKey->loadGlobalByName($keyName, $launchOptions->cloudLocation, $DBServer->envId, SERVER_PLATFORMS::EC2)) { $result = $aws->ec2->keyPair->create($keyName); if ($result->keyMaterial) { $sshKey->farmId = $farmId; $sshKey->clientId = $DBServer->clientId; $sshKey->envId = $DBServer->envId; $sshKey->type = Scalr_SshKey::TYPE_GLOBAL; $sshKey->cloudLocation = $launchOptions->cloudLocation; $sshKey->cloudKeyName = $keyName; $sshKey->platform = SERVER_PLATFORMS::EC2; $sshKey->setPrivate($result->keyMaterial); $sshKey->setPublic($sshKey->generatePublicKey()); $sshKey->save(); } } $runInstanceRequest->keyName = $keyName; try { $result = $aws->ec2->instance->run($runInstanceRequest); } catch (Exception $e) { if (stristr($e->getMessage(), "The key pair") && stristr($e->getMessage(), "does not exist")) { $sshKey->delete(); throw $e; } if (stristr($e->getMessage(), "The requested Availability Zone is no longer supported") || stristr($e->getMessage(), "is not supported in your requested Availability Zone") || stristr($e->getMessage(), "is currently constrained and we are no longer accepting new customer requests")) { $availZone = $runInstanceRequest->getPlacement() ? $runInstanceRequest->getPlacement()->availabilityZone : null; if ($availZone) { $DBServer->GetEnvironmentObject()->setPlatformConfig(array("aws.{$launchOptions->cloudLocation}.{$availZone}.unavailable" => time())); } throw $e; } else { throw $e; } } if ($result->instancesSet->get(0)->instanceId) { $DBServer->SetProperty(EC2_SERVER_PROPERTIES::AVAIL_ZONE, $result->instancesSet->get(0)->placement->availabilityZone); $DBServer->SetProperty(EC2_SERVER_PROPERTIES::INSTANCE_ID, $result->instancesSet->get(0)->instanceId); $DBServer->SetProperty(EC2_SERVER_PROPERTIES::INSTANCE_TYPE, $runInstanceRequest->instanceType); $DBServer->SetProperty(EC2_SERVER_PROPERTIES::AMIID, $runInstanceRequest->imageId); $DBServer->SetProperty(EC2_SERVER_PROPERTIES::REGION, $launchOptions->cloudLocation); $DBServer->SetProperty(EC2_SERVER_PROPERTIES::VPC_ID, $result->instancesSet->get(0)->vpcId); $DBServer->SetProperty(EC2_SERVER_PROPERTIES::SUBNET_ID, $result->instancesSet->get(0)->subnetId); $DBServer->SetProperty(EC2_SERVER_PROPERTIES::ARCHITECTURE, $result->instancesSet->get(0)->architecture); $DBServer->osType = $result->instancesSet->get(0)->platform ? $result->instancesSet->get(0)->platform : 'linux'; return $DBServer; } else { throw new Exception(sprintf(_("Cannot launch new instance. %s"), serialize($result))); } }