Scalr\Modules\Platforms\GoogleCE\GoogleCEPlatformModule::LaunchServer PHP Method

LaunchServer() public method

public LaunchServer ( DBServer $DBServer, Scalr_Server_LaunchOptions $launchOptions = null )
$DBServer DBServer
$launchOptions Scalr_Server_LaunchOptions
    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));
        }
    }