public function LaunchServer(DBServer $DBServer, \Scalr_Server_LaunchOptions $launchOptions = null) { $environment = $DBServer->GetEnvironmentObject(); $ccProps = $environment->keychain(SERVER_PLATFORMS::GCE)->properties; $governance = new \Scalr_Governance($environment->id); $rootDeviceSettings = null; $ssdDisks = array(); $scopes = ["https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/compute", "https://www.googleapis.com/auth/devstorage.full_control"]; if (!$launchOptions) { $launchOptions = new \Scalr_Server_LaunchOptions(); $DBRole = $DBServer->GetFarmRoleObject()->GetRoleObject(); $launchOptions->imageId = $DBRole->__getNewRoleObject()->getImage(\SERVER_PLATFORMS::GCE, $DBServer->GetProperty(\GCE_SERVER_PROPERTIES::CLOUD_LOCATION))->imageId; $launchOptions->serverType = $DBServer->GetFarmRoleObject()->GetSetting(Entity\FarmRoleSetting::INSTANCE_TYPE); $launchOptions->cloudLocation = $DBServer->GetFarmRoleObject()->CloudLocation; $userData = $DBServer->GetCloudUserData(); $launchOptions->architecture = 'x86_64'; $networkName = $DBServer->GetFarmRoleObject()->GetSetting(Entity\FarmRoleSetting::GCE_NETWORK); $subnet = $DBServer->GetFarmRoleObject()->GetSetting(Entity\FarmRoleSetting::GCE_SUBNET); $onHostMaintenance = $DBServer->GetFarmRoleObject()->GetSetting(Entity\FarmRoleSetting::GCE_ON_HOST_MAINTENANCE); $osType = $DBRole->getOs()->family == 'windows' ? 'windows' : 'linux'; $rootDevice = json_decode($DBServer->GetFarmRoleObject()->GetSetting(\Scalr_Role_Behavior::ROLE_BASE_ROOT_DEVICE_CONFIG), true); if ($rootDevice && $rootDevice['settings']) { $rootDeviceSettings = $rootDevice['settings']; } $storage = new FarmRoleStorage($DBServer->GetFarmRoleObject()); $volumes = $storage->getVolumesConfigs($DBServer); if (!empty($volumes)) { foreach ($volumes as $volume) { if ($volume->type == FarmRoleStorageConfig::TYPE_GCE_EPHEMERAL) { array_push($ssdDisks, $volume); } } } if ($governance->isEnabled(\Scalr_Governance::CATEGORY_GENERAL, \Scalr_Governance::GENERAL_HOSTNAME_FORMAT)) { $hostNameFormat = $governance->getValue(\Scalr_Governance::CATEGORY_GENERAL, \Scalr_Governance::GENERAL_HOSTNAME_FORMAT); } else { $hostNameFormat = $DBServer->GetFarmRoleObject()->GetSetting(\Scalr_Role_Behavior::ROLE_BASE_HOSTNAME_FORMAT); } $hostname = !empty($hostNameFormat) ? $DBServer->applyGlobalVarsToValue($hostNameFormat) : ''; if ($hostname != '') { $DBServer->SetProperty(\Scalr_Role_Behavior::SERVER_BASE_HOSTNAME, $hostname); } $userScopes = json_decode($DBServer->GetFarmRoleObject()->GetSetting(Entity\FarmRoleSetting::GCE_INSTANCE_PERMISSIONS)); if (!empty($userScopes) && is_array($userScopes)) { $scopes = array_merge($scopes, $userScopes); } } else { $userData = array(); $networkName = 'default'; $osType = 'linux'; $hostname = ''; } if (!$onHostMaintenance) { $onHostMaintenance = 'MIGRATE'; } if ($DBServer->status == \SERVER_STATUS::TEMPORARY) { $keyName = "SCALR-ROLESBUILDER-" . SCALR_ID; } else { $keyName = "FARM-{$DBServer->farmId}-" . SCALR_ID; } $sshKey = (new SshKey())->loadGlobalByName($DBServer->envId, \SERVER_PLATFORMS::GCE, "", $keyName); if (!$sshKey) { $sshKey = new SshKey(); $keys = $sshKey->generateKeypair(); if ($keys['public']) { $sshKey->farmId = $DBServer->farmId; $sshKey->envId = $DBServer->envId; $sshKey->type = SshKey::TYPE_GLOBAL; $sshKey->platform = \SERVER_PLATFORMS::GCE; $sshKey->cloudLocation = ""; $sshKey->cloudKeyName = $keyName; $sshKey->save(); $publicKey = $keys['public']; } else { throw new Exception("Scalr unable to generate ssh keypair"); } } else { $publicKey = $sshKey->publicKey; } $gce = $this->getClient($environment); $projectId = $ccProps[Entity\CloudCredentialsProperty::GCE_PROJECT_ID]; // Check firewall $firewalls = $gce->firewalls->listFirewalls($projectId); $firewallFound = false; foreach ($firewalls->getItems() as $f) { if ($f->getName() == 'scalr-system') { $firewallFound = true; break; } } // Create scalr firewall if (!$firewallFound) { $firewall = new \Google_Service_Compute_Firewall(); $firewall->setName('scalr-system'); $firewall->setNetwork($this->getObjectUrl($networkName, 'networks', $projectId)); //Get scalr IP-pool IP list and set source ranges $firewall->setSourceRanges(\Scalr::config('scalr.aws.ip_pool')); // Set ports $tcp = new \Google_Service_Compute_FirewallAllowed(); $tcp->setIPProtocol('tcp'); $tcp->setPorts(array('1-65535')); $udp = new \Google_Service_Compute_FirewallAllowed(); $udp->setIPProtocol('udp'); $udp->setPorts(array('1-65535')); $firewall->setAllowed(array($tcp, $udp)); // Set target tags $firewall->setTargetTags(array('scalr')); $gce->firewalls->insert($projectId, $firewall); } $instance = new \Google_Service_Compute_Instance(); $instance->setKind("compute#instance"); // Set scheduling $scheduling = new \Google_Service_Compute_Scheduling(); $scheduling->setAutomaticRestart(true); $scheduling->setOnHostMaintenance($onHostMaintenance); $instance->setScheduling($scheduling); $accessConfig = new \Google_Service_Compute_AccessConfig(); $accessConfig->setName("External NAT"); $accessConfig->setType("ONE_TO_ONE_NAT"); $network = new \Google_Service_Compute_NetworkInterface(); $network->setNetwork($this->getObjectUrl($networkName, 'networks', $projectId)); if (!empty($subnet)) { $network->setSubnetwork($this->getObjectUrl($subnet, 'subnetworks', $projectId, $DBServer->GetFarmRoleObject()->GetSetting(Entity\FarmRoleSetting::GCE_REGION))); } $network->setAccessConfigs(array($accessConfig)); $instance->setNetworkInterfaces(array($network)); $serviceAccount = new \Google_Service_Compute_ServiceAccount(); $serviceAccount->setEmail("default"); $serviceAccount->setScopes($scopes); $instance->setServiceAccounts(array($serviceAccount)); if ($launchOptions->cloudLocation != 'x-scalr-custom') { $availZone = $launchOptions->cloudLocation; } else { $location = $DBServer->GetFarmRoleObject()->GetSetting(Entity\FarmRoleSetting::GCE_CLOUD_LOCATION); $availZones = array(); if (stristr($location, "x-scalr-custom")) { $zones = explode("=", $location); foreach (explode(":", $zones[1]) as $zone) { if ($zone != "") { array_push($availZones, $zone); } } } sort($availZones); $availZones = array_reverse($availZones); $servers = $DBServer->GetFarmRoleObject()->GetServersByFilter(array("status" => array(\SERVER_STATUS::RUNNING, \SERVER_STATUS::INIT, \SERVER_STATUS::PENDING))); $availZoneDistribution = array(); foreach ($servers as $cDbServer) { if ($cDbServer->serverId != $DBServer->serverId) { $availZoneDistribution[$cDbServer->GetProperty(\GCE_SERVER_PROPERTIES::CLOUD_LOCATION)]++; } } $sCount = 1000000; foreach ($availZones as $zone) { if ((int) $availZoneDistribution[$zone] <= $sCount) { $sCount = (int) $availZoneDistribution[$zone]; $availZone = $zone; } } $aZones = implode(",", $availZones); // Available zones $dZones = ""; // Zones distribution foreach ($availZoneDistribution as $zone => $num) { $dZones .= "({$zone}:{$num})"; } } $instance->setZone($this->getObjectUrl($availZone, 'zones', $projectId)); $instance->setMachineType($this->getObjectUrl($launchOptions->serverType, 'machineTypes', $projectId, $availZone)); //Create root disk $image = $this->getObjectUrl($launchOptions->imageId, 'images', $projectId); $disks = array(); $diskName = "root-{$DBServer->serverId}"; $initializeParams = new \Google_Service_Compute_AttachedDiskInitializeParams(); $initializeParams->sourceImage = $image; $initializeParams->diskName = $diskName; if ($rootDeviceSettings) { $initializeParams->diskType = $this->getObjectUrl($rootDeviceSettings[FarmRoleStorageConfig::SETTING_GCE_PD_TYPE] ? $rootDeviceSettings[FarmRoleStorageConfig::SETTING_GCE_PD_TYPE] : 'pd-standard', 'diskTypes', $projectId, $availZone); $initializeParams->diskSizeGb = $rootDeviceSettings[FarmRoleStorageConfig::SETTING_GCE_PD_SIZE]; } $attachedDisk = new \Google_Service_Compute_AttachedDisk(); $attachedDisk->setKind("compute#attachedDisk"); $attachedDisk->setBoot(true); $attachedDisk->setMode("READ_WRITE"); $attachedDisk->setType("PERSISTENT"); $attachedDisk->setDeviceName("root"); $attachedDisk->setAutoDelete(true); $attachedDisk->setInitializeParams($initializeParams); array_push($disks, $attachedDisk); if (count($ssdDisks) > 0) { foreach ($ssdDisks as $disk) { $attachedDisk = new \Google_Service_Compute_AttachedDisk(); $attachedDisk->setKind("compute#attachedDisk"); $attachedDisk->setBoot(false); $attachedDisk->setMode("READ_WRITE"); $attachedDisk->setType("SCRATCH"); $attachedDisk->setDeviceName(str_replace("google-", "", $disk->name)); $attachedDisk->setInterface('SCSI'); $attachedDisk->setAutoDelete(true); $initializeParams = new \Google_Service_Compute_AttachedDiskInitializeParams(); $initializeParams->diskType = $this->getObjectUrl('local-ssd', 'diskTypes', $projectId, $availZone); $attachedDisk->setInitializeParams($initializeParams); array_push($disks, $attachedDisk); } } $instance->setDisks($disks); $instance->setName($DBServer->serverId); $tags = array('scalr', "env-{$DBServer->envId}"); if ($DBServer->farmId) { $tags[] = "farm-{$DBServer->farmId}"; } if ($DBServer->farmRoleId) { $tags[] = "farmrole-{$DBServer->farmRoleId}"; } $gTags = new \Google_Service_Compute_Tags(); $gTags->setItems($tags); $instance->setTags($gTags); $metadata = new \Google_Service_Compute_Metadata(); $items = array(); // Set user data $uData = ''; foreach ($userData as $k => $v) { $uData .= "{$k}={$v};"; } $uData = trim($uData, ";"); if ($uData) { $item = new \Google_Service_Compute_MetadataItems(); $item->setKey('scalr'); $item->setValue($uData); $items[] = $item; } if ($osType == 'windows') { // Add Windows credentials $item = new \Google_Service_Compute_MetadataItems(); $item->setKey("gce-initial-windows-user"); $item->setValue("scalr"); $items[] = $item; $item = new \Google_Service_Compute_MetadataItems(); $item->setKey("gce-initial-windows-password"); $item->setValue(\Scalr::GenerateRandomKey(16) . rand(0, 9)); $items[] = $item; } else { // Add SSH Key $item = new \Google_Service_Compute_MetadataItems(); $item->setKey("sshKeys"); $item->setValue("scalr:{$publicKey}"); $items[] = $item; } //Set hostname if ($hostname != '') { $item = new \Google_Service_Compute_MetadataItems(); $item->setKey("hostname"); $item->setValue($hostname); $items[] = $item; } $metadata->setItems($items); $instance->setMetadata($metadata); try { $result = $gce->instances->insert($projectId, $availZone, $instance); } catch (Exception $e) { $json = json_decode($e->getMessage()); if (!empty($json->error->message)) { $message = $json->error->message; } else { $message = $e->getMessage(); } throw new Exception(sprintf(_("Cannot launch new instance. %s (%s, %s)"), $message, $image, $launchOptions->serverType)); } if ($result->id) { $instanceTypeInfo = $this->getInstanceType($launchOptions->serverType, $environment, $availZone); /* @var $instanceTypeInfo CloudInstanceType */ $DBServer->SetProperties([\GCE_SERVER_PROPERTIES::PROVISIONING_OP_ID => $result->name, \GCE_SERVER_PROPERTIES::SERVER_NAME => $DBServer->serverId, \GCE_SERVER_PROPERTIES::CLOUD_LOCATION => $availZone, \GCE_SERVER_PROPERTIES::CLOUD_LOCATION_ZONE => $availZone, \SERVER_PROPERTIES::ARCHITECTURE => $launchOptions->architecture, 'debug.region' => $result->region, 'debug.zone' => $result->zone, \SERVER_PROPERTIES::INFO_INSTANCE_VCPUS => $instanceTypeInfo ? $instanceTypeInfo->vcpus : null]); $DBServer->setOsType($osType); $DBServer->cloudLocation = $availZone; $DBServer->cloudLocationZone = $availZone; $DBServer->imageId = $launchOptions->imageId; $DBServer->update(['type' => $launchOptions->serverType, 'instanceTypeName' => $launchOptions->serverType]); // we set server history here $DBServer->getServerHistory()->update(['cloudServerId' => $DBServer->serverId]); return $DBServer; } else { throw new Exception(sprintf(_("Cannot launch new instance. %s (%s, %s)"), serialize($result), $launchOptions->imageId, $launchOptions->serverType)); } }
public function OnHostInit(\HostInitEvent $event) { $msg = new \Scalr_Messaging_Msg_HostInitResponse($event->DBServer->GetFarmObject()->GetSetting(Entity\FarmSetting::CRYPTO_KEY), $event->DBServer->index); $msg->cloudLocation = $event->DBServer->GetCloudLocation(); $msg->eventId = $event->GetEventID(); $msg->serverId = $event->DBServer->serverId; $dbServer = $event->DBServer; $dbFarmRole = $dbServer->GetFarmRoleObject(); if ($dbFarmRole) { foreach (\Scalr_Role_Behavior::getListForFarmRole($dbFarmRole) as $behavior) { $msg = $behavior->extendMessage($msg, $dbServer); } } $msg->setGlobalVariables($dbServer, true, $event); /** * TODO: Move everything to\\Scalr_Db_Msr_* */ if ($dbFarmRole->GetRoleObject()->hasBehavior(\ROLE_BEHAVIORS::MYSQL)) { $isMaster = (int) $dbServer->GetProperty(\SERVER_PROPERTIES::DB_MYSQL_MASTER); $msg->mysql = (object) array("replicationMaster" => $isMaster, "rootPassword" => $dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_ROOT_PASSWORD), "replPassword" => $dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_REPL_PASSWORD), "statPassword" => $dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_STAT_PASSWORD), "logFile" => $dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_LOG_FILE), "logPos" => $dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_LOG_POS)); if ($event->DBServer->IsSupported("0.7")) { if ($dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_SCALR_VOLUME_ID) && $isMaster) { try { $volume = \Scalr_Storage_Volume::init()->loadById($dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_SCALR_VOLUME_ID)); $msg->mysql->volumeConfig = $volume->getConfig(); } catch (\Exception $e) { } } /*** * For Rackspace we ALWAYS need snapsjot_config for mysql * ***/ if ($dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_SCALR_SNAPSHOT_ID)) { try { $snapshotConfig = \Scalr_Storage_Snapshot::init()->loadById($dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_SCALR_SNAPSHOT_ID)); $msg->mysql->snapshotConfig = $snapshotConfig->getConfig(); } catch (\Exception $e) { $this->Logger->error(new \FarmLogMessage($event->DBServer->farmId, "Cannot get snaphotConfig for hostInit message: {$e->getMessage()}", !empty($event->DBServer->serverId) ? $event->DBServer->serverId : null)); } } if (!$msg->mysql->snapshotConfig && $dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_SNAPSHOT_ID)) { $msg->mysql->snapshotConfig = new \stdClass(); $msg->mysql->snapshotConfig->type = $dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_DATA_STORAGE_ENGINE); $msg->mysql->snapshotConfig->id = $dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_SNAPSHOT_ID); } if ($isMaster && !$msg->mysql->volumeConfig) { $msg->mysql->volumeConfig = new \stdClass(); $msg->mysql->volumeConfig->type = $dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_DATA_STORAGE_ENGINE); if (!$dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_MASTER_EBS_VOLUME_ID)) { if (in_array($dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_DATA_STORAGE_ENGINE), array(\MYSQL_STORAGE_ENGINE::EBS, \MYSQL_STORAGE_ENGINE::CSVOL))) { $msg->mysql->volumeConfig->size = $dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_EBS_VOLUME_SIZE); if ($dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_DATA_STORAGE_ENGINE) == \MYSQL_STORAGE_ENGINE::EBS) { $msg->mysql->volumeConfig->volumeType = $dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_EBS_TYPE); if ($msg->mysql->volumeConfig->volumeType == 'io1') { $msg->mysql->volumeConfig->iops = $dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_EBS_IOPS); } } } elseif ($dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_DATA_STORAGE_ENGINE) == \MYSQL_STORAGE_ENGINE::EPH) { //$msg->mysql->volumeConfig->snap_backend = "cf://mysql-data-bundle/scalr-{$dbFarmRole->GetFarmObject()->Hash}"; $msg->mysql->volumeConfig->snap_backend = sprintf("cf://scalr-%s-%s/data-bundles/%s/mysql/", $event->DBServer->envId, $event->DBServer->GetCloudLocation(), $event->DBServer->farmId); $msg->mysql->volumeConfig->vg = 'mysql'; $msg->mysql->volumeConfig->disk = new \stdClass(); $msg->mysql->volumeConfig->disk->type = 'loop'; $msg->mysql->volumeConfig->disk->size = '75%root'; } } else { $msg->mysql->volumeConfig->id = $dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_MASTER_EBS_VOLUME_ID); } } } else { if ($isMaster) { $msg->mysql->volumeId = $dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_MASTER_EBS_VOLUME_ID); } $msg->mysql->snapshotId = $dbFarmRole->GetSetting(Entity\FarmRoleSetting::MYSQL_SNAPSHOT_ID); } } // Create ssh keypair for rackspace if ($event->DBServer->IsSupported("0.7")) { $authSshKey = $event->DBServer->platform == \SERVER_PLATFORMS::AZURE || $event->DBServer->isCloudstack(); if ($event->DBServer->isOpenstack()) { $isKeyPairsSupported = $event->DBServer->GetEnvironmentObject()->cloudCredentials($event->DBServer->platform)->properties[Entity\CloudCredentialsProperty::OPENSTACK_EXT_KEYPAIRS_ENABLED]; if ($isKeyPairsSupported != 1) { $authSshKey = true; } } if ($authSshKey && $dbServer->osType == 'linux') { $sshKey = (new SshKey())->loadGlobalByFarmId($event->DBServer->envId, $event->DBServer->platform, $event->DBServer->GetFarmRoleObject()->CloudLocation, $event->DBServer->farmId); if (!$sshKey) { $keyName = "FARM-{$event->DBServer->farmId}-" . SCALR_ID; $sshKey = new SshKey(); $sshKey->generateKeypair(); $sshKey->farmId = $event->DBServer->farmId; $sshKey->envId = $event->DBServer->envId; $sshKey->type = SshKey::TYPE_GLOBAL; $sshKey->platform = $event->DBServer->platform; $sshKey->cloudLocation = $event->DBServer->isCloudstack() || $event->DBServer->platform == \SERVER_PLATFORMS::AZURE || $event->DBServer->platform == \SERVER_PLATFORMS::GCE ? "" : $event->DBServer->GetFarmRoleObject()->CloudLocation; $sshKey->cloudKeyName = $keyName; $sshKey->save(); } $sshKeysMsg = new \Scalr_Messaging_Msg_UpdateSshAuthorizedKeys(array($sshKey->publicKey), array()); $event->DBServer->SendMessage($sshKeysMsg, false, true); } } // Send HostInitResponse to target server $event->DBServer->SendMessage($msg); // Send broadcast HostInit $servers = \DBFarm::LoadByID($this->FarmID)->GetServersByFilter(array('status' => array(\SERVER_STATUS::INIT, \SERVER_STATUS::RUNNING))); $event->msgExpected = count($servers); foreach ((array) $servers as $DBServer) { if (!$DBServer->IsSupported('0.5')) { $event->msgExpected--; continue; } if ($DBServer->status == \SERVER_STATUS::INIT && $DBServer->serverId != $event->DBServer->serverId) { $event->msgExpected--; continue; } $hiMsg = new \Scalr_Messaging_Msg_HostInit(); $hiMsg->setServerMetaData($event->DBServer); $hiMsg = \Scalr_Scripting_Manager::extendMessage($hiMsg, $event, $event->DBServer, $DBServer); if ($event->DBServer->farmRoleId != 0) { foreach (\Scalr_Role_Behavior::getListForFarmRole($event->DBServer->GetFarmRoleObject()) as $behavior) { $hiMsg = $behavior->extendMessage($hiMsg, $event->DBServer); } } $hiMsg = $DBServer->SendMessage($hiMsg, false, true); if ($hiMsg->dbMessageId) { $event->msgCreated++; } } }