@Override
@DB
public boolean destroyNetwork(long networkId, ReservationContext context) {
Account callerAccount = _accountMgr.getAccount(context.getCaller().getAccountId());
NetworkVO network = _networksDao.findById(networkId);
if (network == null) {
s_logger.debug("Unable to find network with id: " + networkId);
return false;
}
// Make sure that there are no user vms in the network that are not Expunged/Error
List<UserVmVO> userVms = _userVmDao.listByNetworkIdAndStates(networkId);
for (UserVmVO vm : userVms) {
if (!(vm.getState() == VirtualMachine.State.Expunging && vm.getRemoved() != null)) {
s_logger.warn("Can't delete the network, not all user vms are expunged. Vm " + vm + " is in " + vm.getState() + " state");
return false;
}
}
// Don't allow to delete network via api call when it has vms assigned to it
int nicCount = getActiveNicsInNetwork(networkId);
if (nicCount > 0) {
s_logger.debug("The network id=" + networkId + " has active Nics, but shouldn't.");
// at this point we have already determined that there are no active user vms in network
// if the op_networks table shows active nics, it's a bug in releasing nics updating op_networks
_networksDao.changeActiveNicsBy(networkId, (-1 * nicCount));
}
//In Basic zone, make sure that there are no non-removed console proxies and SSVMs using the network
DataCenter zone = _configMgr.getZone(network.getDataCenterId());
if (zone.getNetworkType() == NetworkType.Basic) {
List<VMInstanceVO> systemVms = _vmDao.listNonRemovedVmsByTypeAndNetwork(network.getId(),
Type.ConsoleProxy, Type.SecondaryStorageVm);
if (systemVms != null && !systemVms.isEmpty()) {
s_logger.warn("Can't delete the network, not all consoleProxy/secondaryStorage vms are expunged");
return false;
}
}
// Shutdown network first
shutdownNetwork(networkId, context, false);
// get updated state for the network
network = _networksDao.findById(networkId);
if (network.getState() != Network.State.Allocated && network.getState() != Network.State.Setup) {
s_logger.debug("Network is not not in the correct state to be destroyed: " + network.getState());
return false;
}
boolean success = true;
if (!cleanupNetworkResources(networkId, callerAccount, context.getCaller().getId())) {
s_logger.warn("Unable to delete network id=" + networkId + ": failed to cleanup network resources");
return false;
}
// get providers to destroy
List<Provider> providersToDestroy = getNetworkProviders(network.getId());
for (NetworkElement element : _networkElements) {
if (providersToDestroy.contains(element.getProvider())) {
try {
if (!_networkModel.isProviderEnabledInPhysicalNetwork(_networkModel.getPhysicalNetworkId(network), element.getProvider().getName())) {
s_logger.warn("Unable to complete destroy of the network elements due to element: " + element.getName() + " either doesn't exist or not enabled in the physical network "
+ _networkModel.getPhysicalNetworkId(network));
success = false;
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Sending destroy to " + element);
}
if (!element.destroy(network, context)) {
success = false;
s_logger.warn("Unable to complete destroy of the network: failed to destroy network element " + element.getName());
}
} catch (ResourceUnavailableException e) {
s_logger.warn("Unable to complete destroy of the network due to element: " + element.getName(), e);
success = false;
} catch (ConcurrentOperationException e) {
s_logger.warn("Unable to complete destroy of the network due to element: " + element.getName(), e);
success = false;
} catch (Exception e) {
s_logger.warn("Unable to complete destroy of the network due to element: " + element.getName(), e);
success = false;
}
}
}
if (success) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Network id=" + networkId + " is destroyed successfully, cleaning up corresponding resources now.");
}
NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName());
Account owner = _accountMgr.getAccount(network.getAccountId());
Transaction txn = Transaction.currentTxn();
txn.start();
guru.trash(network, _networkOfferingDao.findById(network.getNetworkOfferingId()), owner);
if (!deleteVlansInNetwork(network.getId(), context.getCaller().getId(), callerAccount)) {
success = false;
s_logger.warn("Failed to delete network " + network + "; was unable to cleanup corresponding ip ranges");
} else {
// commit transaction only when ips and vlans for the network are released successfully
try {
stateTransitTo(network, Event.DestroyNetwork);
} catch (NoTransitionException e) {
s_logger.debug(e.getMessage());
}
if (_networksDao.remove(network.getId())) {
NetworkDomainVO networkDomain = _networkDomainDao.getDomainNetworkMapByNetworkId(network.getId());
if (networkDomain != null)
_networkDomainDao.remove(networkDomain.getId());
NetworkAccountVO networkAccount = _networkAccountDao.getAccountNetworkMapByNetworkId(network.getId());
if (networkAccount != null)
_networkAccountDao.remove(networkAccount.getId());
}
NetworkOffering ntwkOff = _configMgr.getNetworkOffering(network.getNetworkOfferingId());
boolean updateResourceCount = resourceCountNeedsUpdate(ntwkOff, network.getAclType());
if (updateResourceCount) {
_resourceLimitMgr.decrementResourceCount(owner.getId(), ResourceType.network);
}
txn.commit();
}