Scalr\Modules\Platforms\Cloudstack\Helpers\CloudstackHelper::setStaticNatForServer PHP Method

setStaticNatForServer() public static method

public static setStaticNatForServer ( DBServer $dbServer )
$dbServer DBServer
    public static function setStaticNatForServer(\DBServer $dbServer)
    {
        $db = \Scalr::getDb();
        try {
            $dbFarm = DBFarm::LoadByID($dbServer->farmId);
            $dbFarmRole = $dbServer->GetFarmRoleObject();
            if (!$dbFarmRole->GetSetting(Entity\FarmRoleSetting::CLOUDSTACK_USE_STATIC_NAT)) {
                return false;
            }
            $cs = $dbFarm->GetEnvironmentObject()->cloudstack($dbFarmRole->Platform);
        } catch (Exception $e) {
            \Scalr::getContainer()->logger(\LOG_CATEGORY::FARM)->fatal(new \FarmLogMessage($dbServer, sprintf(_("Cannot allocate elastic ip address for instance %s on farm %s (0)"), !empty($dbServer->serverId) ? $dbServer->serverId : null, !empty($dbFarm->Name) ? $dbFarm->Name : null)));
            return false;
        }
        $ip = $db->GetRow("\n            SELECT * FROM elastic_ips\n            WHERE farmid=?\n            AND ((farm_roleid=? AND instance_index=?) OR server_id = ?)\n            LIMIT 1\n        ", array($dbServer->farmId, $dbFarmRole->ID, $dbServer->index, $dbServer->serverId));
        if ($ip['ipaddress']) {
            if (!self::checkStaticNatIp($ip['ipaddress'], $cs)) {
                \Scalr::getContainer()->logger(\LOG_CATEGORY::FARM)->warn(new \FarmLogMessage($dbServer, sprintf(_("Static NAT IP '%s' does not belong to you. Allocating new one."), !empty($ip['ipaddress']) ? $ip['ipaddress'] : null)));
                $db->Execute("DELETE FROM elastic_ips WHERE ipaddress=?", array($ip['ipaddress']));
                $ip = false;
            }
        }
        if ($ip && $ip['ipaddress'] == $dbServer->remoteIp) {
            return $ip['ipaddress'];
        }
        // If free IP not found we must allocate new IP
        if (!$ip) {
            $alocatedIps = $db->GetOne("SELECT COUNT(*) FROM elastic_ips WHERE farm_roleid = ?", array($dbFarmRole->ID));
            // Check elastic IPs limit. We cannot allocate more than 'Max instances' option for role
            if ($alocatedIps < $dbFarmRole->GetSetting(Entity\FarmRoleSetting::SCALING_MAX_INSTANCES)) {
                try {
                    $requestObject = new AssociateIpAddressData();
                    $requestObject->zoneid = $dbFarmRole->CloudLocation;
                    $ipResult = $cs->associateIpAddress($requestObject);
                    $ipId = !empty($ipResult->id) ? $ipResult->id : null;
                    if ($ipId) {
                        while (true) {
                            $requestObject = new ListIpAddressesData();
                            $requestObject->id = $ipId;
                            $ipInfo = $cs->listPublicIpAddresses($requestObject);
                            $ipInfo = count($ipInfo) > 0 ? $ipInfo[0] : null;
                            if (!$ipInfo) {
                                throw new Exception("Cannot allocate IP address: listPublicIpAddresses -> failed");
                            }
                            if ($ipInfo->state == 'Allocated') {
                                break;
                            } else {
                                if ($ipInfo->state == 'Allocating') {
                                    sleep(1);
                                } else {
                                    throw new Exception("Cannot allocate IP address: ipAddress->state = {$ipInfo->state}");
                                }
                            }
                        }
                    } else {
                        throw new Exception("Cannot allocate IP address: associateIpAddress -> failed");
                    }
                } catch (Exception $e) {
                    \Scalr::getContainer()->logger(\LOG_CATEGORY::FARM)->error(new \FarmLogMessage($dbServer, sprintf(_("Cannot allocate new elastic ip for instance '%s': %s"), !empty($dbServer->serverId) ? $dbServer->serverId : null, $e->getMessage())));
                    return false;
                }
                // Add allocated IP address to database
                $db->Execute("INSERT INTO elastic_ips SET\n                    env_id=?,\n                    farmid=?,\n                    farm_roleid=?,\n                    ipaddress=?,\n                    clientid=?,\n                    instance_index=?,\n                    allocation_id=?,\n                    state='0', server_id=''\n                ", array($dbServer->envId, $dbServer->farmId, $dbServer->farmRoleId, $ipInfo->ipaddress, $dbServer->clientId, $dbServer->index, $ipId));
                $ip = array('ipaddress' => $ipInfo->ipaddress, 'allocation_id' => $ipId);
                \Scalr::getContainer()->logger(\LOG_CATEGORY::FARM)->info(new \FarmLogMessage($dbServer, sprintf(_("Allocated new IP: %s"), $ip['ipaddress'])));
                // Waiting...
                sleep(5);
            } else {
                \Scalr::getContainer()->logger(__CLASS__)->fatal(_("Limit for elastic IPs reached. Check zomby records in database."));
            }
        }
        if ($ip['ipaddress']) {
            self::associateIpAddress($dbServer, $ip['ipaddress'], $ip['allocation_id']);
            // Update leastic IPs table
            $db->Execute("UPDATE elastic_ips SET state='1', server_id=? WHERE ipaddress=?", array($dbServer->serverId, $ip['ipaddress']));
            \Scalr::FireEvent($dbServer->farmId, new \IPAddressChangedEvent($dbServer, $ip['ipaddress'], $dbServer->localIp));
        } else {
            \Scalr::getContainer()->logger(\LOG_CATEGORY::FARM)->fatal(new \FarmLogMessage($dbServer, sprintf(_("Cannot allocate elastic ip address for instance %s on farm %s (2)"), !empty($dbServer->serverId) ? $dbServer->serverId : null, !empty($dbFarm->Name) ? $dbFarm->Name : null)));
            return false;
        }
        return $ip['ipaddress'];
    }

Usage Example

 public function OnHostInit(\HostInitEvent $event)
 {
     if (!in_array($event->DBServer->platform, array(\SERVER_PLATFORMS::CLOUDSTACK, \SERVER_PLATFORMS::IDCF))) {
         return;
     }
     if ($event->DBServer->farmRoleId) {
         $dbFarmRole = $event->DBServer->GetFarmRoleObject();
         if ($dbFarmRole->GetSetting(\DBFarmRole::SETIING_CLOUDSTACK_USE_STATIC_NAT)) {
             CloudstackHelper::setStaticNatForServer($event->DBServer);
             return true;
         }
         $networkType = $dbFarmRole->GetSetting(\DBFarmRole::SETTING_CLOUDSTACK_NETWORK_TYPE);
         $networkId = $dbFarmRole->GetSetting(\DBFarmRole::SETTING_CLOUDSTACK_NETWORK_ID);
         if ($networkType == 'Direct' || !$networkId) {
             return true;
         }
         if ($networkId == 'SCALR_MANUAL') {
             $map = $dbFarmRole->GetSetting(\DBFarmRole::SETIING_CLOUDSTACK_STATIC_NAT_PRIVATE_MAP);
             $map = explode(";", $map);
             foreach ($map as $ipMapping) {
                 $ipInfo = explode("=", $ipMapping);
                 if ($ipInfo[0] == $event->DBServer->localIp) {
                     $event->DBServer->remoteIp = $ipInfo[1];
                     $event->DBServer->Save();
                 }
             }
         }
         $sharedIpId = $dbFarmRole->GetSetting(\DBFarmRole::SETTING_CLOUDSTACK_SHARED_IP_ID);
     }
     $platform = PlatformFactory::NewPlatform($event->DBServer->platform);
     try {
         $environment = $event->DBServer->GetEnvironmentObject();
         $cloudLocation = $event->DBServer->GetCloudLocation();
         if (!$sharedIpId) {
             $sharedIpId = $platform->getConfigVariable(CloudstackPlatformModule::SHARED_IP_ID . ".{$cloudLocation}", $environment, false);
         }
         if (!$sharedIpId) {
             return true;
         }
         $cs = $environment->cloudstack($event->DBServer->platform);
         // Create port forwarding rules for scalarizr
         $port = $platform->getConfigVariable(CloudstackPlatformModule::SZR_PORT_COUNTER . ".{$cloudLocation}.{$sharedIpId}", $environment, false);
         if (!$port) {
             $port1 = 30000;
             $port2 = 30001;
             $port3 = 30002;
             $port4 = 30003;
         } else {
             $port1 = $port + 1;
             $port2 = $port1 + 1;
             $port3 = $port2 + 1;
             $port4 = $port3 + 1;
         }
         $result2 = $cs->firewall->createPortForwardingRule(array('ipaddressid' => $sharedIpId, 'privateport' => 8014, 'protocol' => "udp", 'publicport' => $port1, 'virtualmachineid' => $event->DBServer->GetProperty(\CLOUDSTACK_SERVER_PROPERTIES::SERVER_ID)));
         $result1 = $cs->firewall->createPortForwardingRule(array('ipaddressid' => $sharedIpId, 'privateport' => 8013, 'protocol' => "tcp", 'publicport' => $port1, 'virtualmachineid' => $event->DBServer->GetProperty(\CLOUDSTACK_SERVER_PROPERTIES::SERVER_ID)));
         $result3 = $cs->firewall->createPortForwardingRule(array('ipaddressid' => $sharedIpId, 'privateport' => 8010, 'protocol' => "tcp", 'publicport' => $port3, 'virtualmachineid' => $event->DBServer->GetProperty(\CLOUDSTACK_SERVER_PROPERTIES::SERVER_ID)));
         $result4 = $cs->firewall->createPortForwardingRule(array('ipaddressid' => $sharedIpId, 'privateport' => 8008, 'protocol' => "tcp", 'publicport' => $port2, 'virtualmachineid' => $event->DBServer->GetProperty(\CLOUDSTACK_SERVER_PROPERTIES::SERVER_ID)));
         $result5 = $cs->firewall->createPortForwardingRule(array('ipaddressid' => $sharedIpId, 'privateport' => 22, 'protocol' => "tcp", 'publicport' => $port4, 'virtualmachineid' => $event->DBServer->GetProperty(\CLOUDSTACK_SERVER_PROPERTIES::SERVER_ID)));
         $event->DBServer->SetProperties(array(\SERVER_PROPERTIES::SZR_CTRL_PORT => $port1, \SERVER_PROPERTIES::SZR_SNMP_PORT => $port1, \SERVER_PROPERTIES::SZR_API_PORT => $port3, \SERVER_PROPERTIES::SZR_UPDC_PORT => $port2, \SERVER_PROPERTIES::CUSTOM_SSH_PORT => $port4));
         $platform->setConfigVariable(array(CloudstackPlatformModule::SZR_PORT_COUNTER . ".{$cloudLocation}.{$sharedIpId}" => $port4), $environment, false);
     } catch (\Exception $e) {
         $this->Logger->fatal(new \FarmLogMessage($this->FarmID, sprintf(_("Cloudstack handler failed: %s."), $e->getMessage())));
     }
 }