diff --git a/core/src/com/cloud/network/resource/NetscalerResource.java b/core/src/com/cloud/network/resource/NetscalerResource.java index 70975eb6569..339d38c1b2e 100644 --- a/core/src/com/cloud/network/resource/NetscalerResource.java +++ b/core/src/com/cloud/network/resource/NetscalerResource.java @@ -256,9 +256,7 @@ public class NetscalerResource implements ServerResource { private void validateInterfaces(String publicInterface, String privateInterface) throws ExecutionException { try { - if (_isSdx) { - return; - } else { + if (!_isSdx && !_cloudManaged) { Interface publicIf = Interface.get(_netscalerService, publicInterface); Interface privateIf = Interface.get(_netscalerService, privateInterface); if (publicIf != null || privateIf != null) { @@ -266,7 +264,7 @@ public class NetscalerResource implements ServerResource { } else { throw new ExecutionException("Invalid interface name specified for public/private interfaces."); } - } + } } catch (nitro_exception e) { if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) { throw new ExecutionException("Invalid interface name specified for public and private interfaces."); @@ -280,7 +278,7 @@ public class NetscalerResource implements ServerResource { private void validateDeviceType(String deviceType) throws ExecutionException { try { - if (!_isSdx) { + if (!_isSdx && !_cloudManaged) { nshardware nsHw = com.citrix.netscaler.nitro.resource.config.ns.nshardware.get(_netscalerService); if (nsHw == null) { throw new ExecutionException("Failed to get the hardware description of the Netscaler device at " + _ip); @@ -291,7 +289,7 @@ public class NetscalerResource implements ServerResource { } throw new ExecutionException("Netscalar device type specified does not match with the actuall device type."); } - } else { + } else if (_isSdx) { mps serviceVM = mps.get(_netscalerSdxService); if (serviceVM != null) { if (serviceVM.get_platform().contains("SDX") || serviceVM.get_product().contains("SDX")) { @@ -656,10 +654,10 @@ public class NetscalerResource implements ServerResource { // wait for VPX instance to start-up long startTick = System.currentTimeMillis(); - long startWaitMins = 200000; - while(!newVpx.get_ns_state().equalsIgnoreCase("up") && System.currentTimeMillis() - startTick < startWaitMins) { + long startWaitMilliSeconds = 600000; + while(!newVpx.get_ns_state().equalsIgnoreCase("up") && System.currentTimeMillis() - startTick < startWaitMilliSeconds) { try { - Thread.sleep(1000); + Thread.sleep(10000); } catch(InterruptedException e) { } ns refreshNsObj = new ns(); @@ -669,16 +667,36 @@ public class NetscalerResource implements ServerResource { // if vpx instance never came up then error out if (!newVpx.get_ns_state().equalsIgnoreCase("up")) { - new Answer(cmd, new ExecutionException("Failed to start VPX instance " + vpxName + " created on the netscaler SDX device " + _ip)); + return new Answer(cmd, new ExecutionException("Failed to start VPX instance " + vpxName + " created on the netscaler SDX device " + _ip)); + } + + // wait till NS service in side VPX is actually ready + startTick = System.currentTimeMillis(); + boolean nsServiceUp = false; + long nsServiceWaitMilliSeconds = 60000; + while (System.currentTimeMillis() - startTick < nsServiceWaitMilliSeconds) { + try { + nitro_service _netscalerService = new nitro_service(cmd.getLoadBalancerIP(), "https"); + _netscalerService.set_credential(username, password); + _netscalerService.set_timeout(_timeout); + apiCallResult = _netscalerService.login(); + if (apiCallResult.errorcode == 0) { + nsServiceUp = true; + break; + } + } catch (Exception e) { + continue; + } + } + + if (!nsServiceUp) { + return new Answer(cmd, new ExecutionException("Failed to create VPX instance " + vpxName + " on the netscaler SDX device " + _ip)); } if (s_logger.isInfoEnabled()) { s_logger.info("Successfully provisioned VPX instance " + vpxName + " on the Netscaler SDX device " + _ip); } - // FIXME: once VPX comes up there is time lag before we can actually login to VPX, so wait - Thread.sleep(20000); - // physical interfaces on the SDX range from 10/1 to 10/8 of which two different port or same port can be used for public and private interfaces // However the VPX instances created will have interface range start from 10/1 but will only have as many interfaces enabled while creating the VPX instance @@ -816,8 +834,6 @@ public class NetscalerResource implements ServerResource { String vlanInterface = guestVlan ? _privateInterface : _publicInterface; throw new ExecutionException("Failed to bind vlan with tag:" + vlanTag + " with the interface " + vlanInterface + " due to " + apiCallResult.message); } - } else { - throw new ExecutionException("Failed to configure Netscaler device for vlan with tag " + vlanTag + " as vlan already exisits"); } } catch (nitro_exception e) { throw new ExecutionException("Failed to implement guest network on the Netscaler device due to " + e.getMessage()); diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java index 865c27d1361..954268ca54f 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java @@ -69,6 +69,7 @@ import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDetailsDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.ExternalLoadBalancerDeviceVO.LBDeviceAllocationState; import com.cloud.network.ExternalLoadBalancerDeviceVO.LBDeviceState; import com.cloud.network.ExternalNetworkDeviceManager.NetworkDevice; @@ -103,6 +104,7 @@ import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceStateAdapter; import com.cloud.resource.ServerResource; import com.cloud.resource.UnableDeleteHostException; +import com.cloud.resource.ResourceStateAdapter.DeleteHostAnswer; import com.cloud.server.api.response.ExternalLoadBalancerResponse; import com.cloud.user.Account; import com.cloud.user.AccountManager; @@ -469,27 +471,44 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase //we have provisioned load balancer so add the appliance as cloudstack provisioned external load balancer String dedicatedLb = offering.getDedicatedLB()?"true":"false"; - // acquire a public IP to associate with lb appliance (used as subnet IP to make the appliance part of private network) + //acquire a public IP to associate with lb appliance (used as subnet IP to make the appliance part of private network) PublicIp publicIp = _networkMgr.assignPublicIpAddress(guestConfig.getDataCenterId(), null, _accountMgr.getSystemAccount(), VlanType.VirtualNetwork, null, null); - IPAddressVO ipvo = _ipAddressDao.findById(publicIp.getId()); String publicIPNetmask = publicIp.getVlanNetmask(); String publicIPgateway = publicIp.getVlanGateway(); String publicIPVlanTag = publicIp.getVlanTag(); String publicIP = publicIp.getAddress().toString(); - + String url = "https://" + lbIP + "?publicinterface=" + publicIf + "&privateinterface=" + privateIf + "&lbdevicededicated=" + dedicatedLb + - "&cloudmanaged=true" + "&publicip=" + publicIP + "&publicipnetmask=" + publicIPNetmask + "&publicipvlan="+ publicIPVlanTag + "&publicipgateway=" + publicIPgateway; - ExternalLoadBalancerDeviceVO lbAppliance = addExternalLoadBalancer(physicalNetworkId, url, username, password, createLbAnswer.getDeviceName(), createLbAnswer.getServerResource()); + "&cloudmanaged=true" + "&publicip=" + publicIP + "&publicipnetmask=" + publicIPNetmask + "&publicipvlan="+ publicIPVlanTag + "&publicipgateway=" + publicIPgateway; + ExternalLoadBalancerDeviceVO lbAppliance = null; + try { + lbAppliance = addExternalLoadBalancer(physicalNetworkId, url, username, password, createLbAnswer.getDeviceName(), createLbAnswer.getServerResource()); + } catch (Exception e) { + s_logger.error("Failed to add load balancer appliance in to cloudstack due to " + e.getMessage() + ". So provisioned load balancer appliance will be destroyed."); + } if (lbAppliance != null) { - // mark the load balancer as cloudstack managed + // mark the load balancer as cloudstack managed and set parent host id on which lb appliance is provisioned ExternalLoadBalancerDeviceVO managedLb = _externalLoadBalancerDeviceDao.findById(lbAppliance.getId()); managedLb.setIsManagedDevice(true); - // set parent host id on which lb appliance is provisioned managedLb.setParentHostId(lbProviderDevice.getHostId()); _externalLoadBalancerDeviceDao.update(lbAppliance.getId(), managedLb); } else { - _networkMgr.releasePublicIpAddress(publicIp.getId(), _accountMgr.getSystemUser().getId(), _accountMgr.getSystemAccount()); + // failed to add the provisioned load balancer into cloudstack so destroy the appliance + DestroyLoadBalancerApplianceCommand lbDeleteCmd = new DestroyLoadBalancerApplianceCommand(lbIP); + DestroyLoadBalancerApplianceAnswer answer = null; + try { + answer = (DestroyLoadBalancerApplianceAnswer) _agentMgr.easySend(lbProviderDevice.getHostId(), lbDeleteCmd); + if (answer == null || !answer.getResult()) { + s_logger.warn("Failed to destroy load balancer appliance created"); + } else { + // release the public & private IP back to dc pool, as the load balancer appliance is now destroyed + _dcDao.releasePrivateIpAddress(lbIP, guestConfig.getDataCenterId(), null); + _networkMgr.releasePublicIpAddress(publicIp.getId(), _accountMgr.getSystemUser().getId(), _accountMgr.getSystemAccount()); + } + } catch (Exception e) { + s_logger.warn("Failed to destroy load balancer appliance created for the network" + guestConfig.getId() + " due to " + e.getMessage()); + } } } } @@ -607,8 +626,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase txn.commit(); if (!lbInUse && lbCloudManaged) { - // send DestroyLoadBalancerApplianceCommand to the host where load balancer appliance - // is provisioned as this is the last network using it + // send DestroyLoadBalancerApplianceCommand to the host where load balancer appliance is provisioned Host lbHost = _hostDao.findById(lbDevice.getHostId()); String lbIP = lbHost.getPrivateIpAddress(); DestroyLoadBalancerApplianceCommand lbDeleteCmd = new DestroyLoadBalancerApplianceCommand(lbIP); @@ -627,10 +645,16 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase } deviceMapLock.unlock(); + // remove the provisioned load balancer appliance from cloudstack + deleteExternalLoadBalancer(lbHost.getId()); + // release the private IP back to dc pool, as the load balancer appliance is now destroyed _dcDao.releasePrivateIpAddress(lbHost.getPrivateIpAddress(), guestConfig.getDataCenterId(), null); - - //FIXME : release the public IP allocated for this LB appliance + + // release the public IP allocated for this LB appliance + DetailVO publicIpDetail = _hostDetailDao.findDetail(lbHost.getId(), "publicip"); + IPAddressVO ipVo = _ipAddressDao.findByIpAndDcId(guestConfig.getDataCenterId(), publicIpDetail.toString()); + _networkMgr.releasePublicIpAddress(ipVo.getId(), _accountMgr.getSystemUser().getId(), _accountMgr.getSystemAccount()); } else { deviceMapLock.unlock(); } @@ -1213,7 +1237,9 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase @Override public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException { - // TODO Auto-generated method stub - return null; + if (host.getType() != com.cloud.host.Host.Type.ExternalLoadBalancer) { + return null; + } + return new DeleteHostAnswer(true); } } diff --git a/server/src/com/cloud/network/dao/IPAddressDao.java b/server/src/com/cloud/network/dao/IPAddressDao.java index 35c5c5f358e..19366f63bff 100755 --- a/server/src/com/cloud/network/dao/IPAddressDao.java +++ b/server/src/com/cloud/network/dao/IPAddressDao.java @@ -56,7 +56,9 @@ public interface IPAddressDao extends GenericDao { IPAddressVO findByAssociatedVmId(long vmId); IPAddressVO findByIpAndSourceNetworkId(long networkId, String ipAddress); - + + public IPAddressVO findByIpAndDcId(long dcId, String ipAddress); + List listByPhysicalNetworkId(long physicalNetworkId); long countFreeIPs(); diff --git a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java index 5ab849f26f6..49607e09063 100755 --- a/server/src/com/cloud/network/dao/IPAddressDaoImpl.java +++ b/server/src/com/cloud/network/dao/IPAddressDaoImpl.java @@ -208,7 +208,15 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen sc.setParameters("ipAddress", ipAddress); return findOneBy(sc); } - + + @Override + public IPAddressVO findByIpAndDcId(long dcId, String ipAddress) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("dataCenterId", dcId); + sc.setParameters("ipAddress", ipAddress); + return findOneBy(sc); + } + @Override public List listByDcId(long dcId) { SearchCriteria sc = AllFieldsSearch.create();