use of com.cloud.utils.db.TransactionCallbackWithException in project cloudstack by apache.
the class IpAddressManagerImpl method associateIpAddressListToAccount.
@Override
@DB
public boolean associateIpAddressListToAccount(long userId, final long accountId, final long zoneId, final Long vlanId, final Network guestNetworkFinal) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, ResourceAllocationException {
final Account owner = _accountMgr.getActiveAccountById(accountId);
if (guestNetworkFinal != null && guestNetworkFinal.getTrafficType() != TrafficType.Guest) {
throw new InvalidParameterValueException("Network " + guestNetworkFinal + " is not of a type " + TrafficType.Guest);
}
Ternary<Boolean, List<NetworkOfferingVO>, Network> pair = null;
try {
pair = Transaction.execute(new TransactionCallbackWithException<Ternary<Boolean, List<NetworkOfferingVO>, Network>, Exception>() {
@Override
public Ternary<Boolean, List<NetworkOfferingVO>, Network> doInTransaction(TransactionStatus status) throws InsufficientCapacityException, ResourceAllocationException {
boolean createNetwork = false;
Network guestNetwork = guestNetworkFinal;
if (guestNetwork == null) {
List<? extends Network> networks = getIsolatedNetworksWithSourceNATOwnedByAccountInZone(zoneId, owner);
if (networks.size() == 0) {
createNetwork = true;
} else if (networks.size() == 1) {
guestNetwork = networks.get(0);
} else {
throw new InvalidParameterValueException("Error, more than 1 Guest Isolated Networks with SourceNAT " + "service enabled found for this account, cannot assosiate the IP range, please provide the network ID");
}
}
// create new Virtual network (Isolated with SourceNAT) for the user if it doesn't exist
List<NetworkOfferingVO> requiredOfferings = _networkOfferingDao.listByAvailability(Availability.Required, false);
if (requiredOfferings.size() < 1) {
throw new CloudRuntimeException("Unable to find network offering with availability=" + Availability.Required + " to automatically create the network as part of createVlanIpRange");
}
if (createNetwork) {
if (requiredOfferings.get(0).getState() == NetworkOffering.State.Enabled) {
long physicalNetworkId = _networkModel.findPhysicalNetworkId(zoneId, requiredOfferings.get(0).getTags(), requiredOfferings.get(0).getTrafficType());
// Validate physical network
PhysicalNetwork physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId);
if (physicalNetwork == null) {
throw new InvalidParameterValueException("Unable to find physical network with id: " + physicalNetworkId + " and tag: " + requiredOfferings.get(0).getTags());
}
s_logger.debug("Creating network for account " + owner + " from the network offering id=" + requiredOfferings.get(0).getId() + " as a part of createVlanIpRange process");
guestNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(), owner.getAccountName() + "-network", owner.getAccountName() + "-network", null, null, null, null, owner, null, physicalNetwork, zoneId, ACLType.Account, null, null, null, null, true, null);
if (guestNetwork == null) {
s_logger.warn("Failed to create default Virtual network for the account " + accountId + "in zone " + zoneId);
throw new CloudRuntimeException("Failed to create a Guest Isolated Networks with SourceNAT " + "service enabled as a part of createVlanIpRange, for the account " + accountId + "in zone " + zoneId);
}
} else {
throw new CloudRuntimeException("Required network offering id=" + requiredOfferings.get(0).getId() + " is not in " + NetworkOffering.State.Enabled);
}
}
// Check if there is a source nat ip address for this account; if not - we have to allocate one
boolean allocateSourceNat = false;
List<IPAddressVO> sourceNat = _ipAddressDao.listByAssociatedNetwork(guestNetwork.getId(), true);
if (sourceNat.isEmpty()) {
allocateSourceNat = true;
}
// update all ips with a network id, mark them as allocated and update resourceCount/usage
List<IPAddressVO> ips = _ipAddressDao.listByVlanId(vlanId);
boolean isSourceNatAllocated = false;
for (IPAddressVO addr : ips) {
if (addr.getState() != State.Allocated) {
if (!isSourceNatAllocated && allocateSourceNat) {
addr.setSourceNat(true);
isSourceNatAllocated = true;
} else {
addr.setSourceNat(false);
}
addr.setAssociatedWithNetworkId(guestNetwork.getId());
addr.setVpcId(guestNetwork.getVpcId());
addr.setAllocatedTime(new Date());
addr.setAllocatedInDomainId(owner.getDomainId());
addr.setAllocatedToAccountId(owner.getId());
addr.setSystem(false);
addr.setState(IpAddress.State.Allocating);
markPublicIpAsAllocated(addr);
}
}
return new Ternary<Boolean, List<NetworkOfferingVO>, Network>(createNetwork, requiredOfferings, guestNetwork);
}
});
} catch (Exception e1) {
ExceptionUtil.rethrowRuntime(e1);
ExceptionUtil.rethrow(e1, InsufficientCapacityException.class);
ExceptionUtil.rethrow(e1, ResourceAllocationException.class);
throw new IllegalStateException(e1);
}
boolean createNetwork = pair.first();
List<NetworkOfferingVO> requiredOfferings = pair.second();
Network guestNetwork = pair.third();
// if the network offering has persistent set to true, implement the network
if (createNetwork && requiredOfferings.get(0).getIsPersistent()) {
DataCenter zone = _dcDao.findById(zoneId);
DeployDestination dest = new DeployDestination(zone, null, null, null);
Account callerAccount = CallContext.current().getCallingAccount();
UserVO callerUser = _userDao.findById(CallContext.current().getCallingUserId());
Journal journal = new Journal.LogJournal("Implementing " + guestNetwork, s_logger);
ReservationContext context = new ReservationContextImpl(UUID.randomUUID().toString(), journal, callerUser, callerAccount);
s_logger.debug("Implementing network " + guestNetwork + " as a part of network provision for persistent network");
try {
Pair<? extends NetworkGuru, ? extends Network> implementedNetwork = _networkMgr.implementNetwork(guestNetwork.getId(), dest, context);
if (implementedNetwork == null || implementedNetwork.first() == null) {
s_logger.warn("Failed to implement the network " + guestNetwork);
}
if (implementedNetwork != null) {
guestNetwork = implementedNetwork.second();
}
} catch (Exception ex) {
s_logger.warn("Failed to implement network " + guestNetwork + " elements and resources as a part of" + " network provision due to ", ex);
CloudRuntimeException e = new CloudRuntimeException("Failed to implement network (with specified id)" + " elements and resources as a part of network provision for persistent network");
e.addProxyObject(guestNetwork.getUuid(), "networkId");
throw e;
}
}
return true;
}
use of com.cloud.utils.db.TransactionCallbackWithException in project cloudstack by apache.
the class ExternalLoadBalancerDeviceManagerImpl method allocateLoadBalancerForNetwork.
@DB
protected ExternalLoadBalancerDeviceVO allocateLoadBalancerForNetwork(final Network guestConfig) throws InsufficientCapacityException {
boolean retry = true;
boolean tryLbProvisioning = false;
ExternalLoadBalancerDeviceVO lbDevice = null;
long physicalNetworkId = guestConfig.getPhysicalNetworkId();
NetworkOfferingVO offering = _networkOfferingDao.findById(guestConfig.getNetworkOfferingId());
String provider = _ntwkSrvcProviderDao.getProviderForServiceInNetwork(guestConfig.getId(), Service.Lb);
while (retry) {
GlobalLock deviceMapLock = GlobalLock.getInternLock("LoadBalancerAllocLock");
try {
if (deviceMapLock.lock(120)) {
try {
// does network offering supports a dedicated load balancer?
final boolean dedicatedLB = offering.getDedicatedLB();
try {
lbDevice = Transaction.execute(new TransactionCallbackWithException<ExternalLoadBalancerDeviceVO, InsufficientCapacityException>() {
@Override
public ExternalLoadBalancerDeviceVO doInTransaction(TransactionStatus status) throws InsufficientCapacityException {
// FIXME: should the device allocation be done during network implement phase or do a
// lazy allocation when first rule for the network is configured??
// find a load balancer device for this network as per the network offering
ExternalLoadBalancerDeviceVO lbDevice = findSuitableLoadBalancerForNetwork(guestConfig, dedicatedLB);
long lbDeviceId = lbDevice.getId();
// persist the load balancer device id that will be used for this network. Once a network
// is implemented on a LB device then later on all rules will be programmed on to same device
NetworkExternalLoadBalancerVO networkLB = new NetworkExternalLoadBalancerVO(guestConfig.getId(), lbDeviceId);
_networkExternalLBDao.persist(networkLB);
// mark device to be either dedicated or shared use
lbDevice.setAllocationState(dedicatedLB ? LBDeviceAllocationState.Dedicated : LBDeviceAllocationState.Shared);
_externalLoadBalancerDeviceDao.update(lbDeviceId, lbDevice);
return lbDevice;
}
});
// allocated load balancer for the network, so skip retry
tryLbProvisioning = false;
retry = false;
} catch (InsufficientCapacityException exception) {
// if already attempted to provision load balancer then throw out of capacity exception,
if (tryLbProvisioning) {
retry = false;
// TODO: throwing warning instead of error for now as its possible another provider can service this network
s_logger.warn("There are no load balancer device with the capacity for implementing this network");
throw exception;
} else {
// if possible provision a LB appliance in to the physical network
tryLbProvisioning = true;
}
}
} finally {
deviceMapLock.unlock();
}
}
} finally {
deviceMapLock.releaseRef();
}
// there are no LB devices or there is no free capacity on the devices in the physical network so provision a new LB appliance
if (tryLbProvisioning) {
// check if LB appliance can be dynamically provisioned
List<ExternalLoadBalancerDeviceVO> providerLbDevices = _externalLoadBalancerDeviceDao.listByProviderAndDeviceAllocationState(physicalNetworkId, provider, LBDeviceAllocationState.Provider);
if ((providerLbDevices != null) && (!providerLbDevices.isEmpty())) {
for (ExternalLoadBalancerDeviceVO lbProviderDevice : providerLbDevices) {
if (lbProviderDevice.getState() == LBDeviceState.Enabled) {
// acquire a private IP from the data center which will be used as management IP of provisioned LB appliance,
DataCenterIpAddressVO dcPrivateIp = _dcDao.allocatePrivateIpAddress(guestConfig.getDataCenterId(), lbProviderDevice.getUuid());
if (dcPrivateIp == null) {
throw new InsufficientNetworkCapacityException("failed to acquire a priavate IP in the zone " + guestConfig.getDataCenterId() + " needed for management IP of the load balancer appliance", DataCenter.class, guestConfig.getDataCenterId());
}
Pod pod = _podDao.findById(dcPrivateIp.getPodId());
String lbIP = dcPrivateIp.getIpAddress();
String netmask = NetUtils.getCidrNetmask(pod.getCidrSize());
String gateway = pod.getGateway();
// send CreateLoadBalancerApplianceCommand to the host capable of provisioning
CreateLoadBalancerApplianceCommand lbProvisionCmd = new CreateLoadBalancerApplianceCommand(lbIP, netmask, gateway);
CreateLoadBalancerApplianceAnswer createLbAnswer = null;
try {
createLbAnswer = (CreateLoadBalancerApplianceAnswer) _agentMgr.easySend(lbProviderDevice.getHostId(), lbProvisionCmd);
if (createLbAnswer == null || !createLbAnswer.getResult()) {
s_logger.error("Could not provision load balancer instance on the load balancer device " + lbProviderDevice.getId());
continue;
}
} catch (Exception agentException) {
s_logger.error("Could not provision load balancer instance on the load balancer device " + lbProviderDevice.getId() + " due to " + agentException.getMessage());
continue;
}
String username = createLbAnswer.getUsername();
String password = createLbAnswer.getPassword();
String publicIf = createLbAnswer.getPublicInterface();
String privateIf = createLbAnswer.getPrivateInterface();
// we have provisioned load balancer so add the appliance as cloudstack provisioned external load balancer
String dedicatedLb = offering.getDedicatedLB() ? "true" : "false";
String capacity = Long.toString(lbProviderDevice.getCapacity());
// acquire a public IP to associate with lb appliance (used as subnet IP to make the appliance part of private network)
PublicIp publicIp = _ipAddrMgr.assignPublicIpAddress(guestConfig.getDataCenterId(), null, _accountMgr.getSystemAccount(), VlanType.VirtualNetwork, null, null, false);
String publicIPNetmask = publicIp.getVlanNetmask();
String publicIPgateway = publicIp.getVlanGateway();
String publicIP = publicIp.getAddress().toString();
String publicIPVlanTag = "";
try {
publicIPVlanTag = BroadcastDomainType.getValue(publicIp.getVlanTag());
} catch (URISyntaxException e) {
s_logger.error("Failed to parse public ip vlan tag" + e.getMessage());
}
String url = "https://" + lbIP + "?publicinterface=" + publicIf + "&privateinterface=" + privateIf + "&lbdevicededicated=" + dedicatedLb + "&cloudmanaged=true" + "&publicip=" + publicIP + "&publicipnetmask=" + publicIPNetmask + "&lbdevicecapacity=" + capacity + "&publicipvlan=" + publicIPVlanTag + "&publicipgateway=" + publicIPgateway;
ExternalLoadBalancerDeviceVO lbAppliance = null;
try {
lbAppliance = addExternalLoadBalancer(physicalNetworkId, url, username, password, createLbAnswer.getDeviceName(), createLbAnswer.getServerResource(), false, false, null, null);
} 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 and set parent host id on which lb appliance is provisioned
ExternalLoadBalancerDeviceVO managedLb = _externalLoadBalancerDeviceDao.findById(lbAppliance.getId());
managedLb.setIsManagedDevice(true);
managedLb.setParentHostId(lbProviderDevice.getHostId());
_externalLoadBalancerDeviceDao.update(lbAppliance.getId(), managedLb);
} else {
// 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);
_ipAddrMgr.disassociatePublicIpAddress(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());
}
}
}
}
}
}
}
return lbDevice;
}
Aggregations