diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java index 489bc6cebf0..250121e452b 100755 --- a/api/src/com/cloud/network/NetworkService.java +++ b/api/src/com/cloud/network/NetworkService.java @@ -64,7 +64,7 @@ public interface NetworkService { Pair, Integer> searchForNetworks(ListNetworksCmd cmd); - boolean deleteNetwork(long networkId); + boolean deleteNetwork(long networkId, boolean forced); boolean restartNetwork(RestartNetworkCmd cmd, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; diff --git a/api/src/org/apache/cloudstack/api/command/user/network/DeleteNetworkCmd.java b/api/src/org/apache/cloudstack/api/command/user/network/DeleteNetworkCmd.java index a48e01b0d36..808051ecdef 100644 --- a/api/src/org/apache/cloudstack/api/command/user/network/DeleteNetworkCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/network/DeleteNetworkCmd.java @@ -45,6 +45,10 @@ public class DeleteNetworkCmd extends BaseAsyncCmd { @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = NetworkResponse.class, required = true, description = "the ID of the network") private Long id; + @Parameter(name = ApiConstants.FORCED, type = CommandType.BOOLEAN, required = false, description = "Force delete a network." + + " Network will be marked as 'Destroy' even when commands to shutdown and cleanup to the backend fails.") + private Boolean forced; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -53,6 +57,10 @@ public class DeleteNetworkCmd extends BaseAsyncCmd { return id; } + public boolean isForced() { + return (forced != null) ? forced : false; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -65,7 +73,7 @@ public class DeleteNetworkCmd extends BaseAsyncCmd { @Override public void execute() { CallContext.current().setEventDetails("Network Id: " + id); - boolean result = _networkService.deleteNetwork(id); + boolean result = _networkService.deleteNetwork(id, isForced()); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java index c036c99b63d..a50c184a5e0 100755 --- a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java +++ b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java @@ -125,7 +125,7 @@ public interface NetworkOrchestrationService { boolean shutdownNetwork(long networkId, ReservationContext context, boolean cleanupElements); - boolean destroyNetwork(long networkId, ReservationContext context); + boolean destroyNetwork(long networkId, ReservationContext context, boolean forced); Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, String networkDomain, Account owner, Long domainId, PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr, diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 7bf784110e3..85fa530e820 100755 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -2068,7 +2068,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra @Override @DB - public boolean destroyNetwork(long networkId, final ReservationContext context) { + public boolean destroyNetwork(long networkId, final ReservationContext context, boolean forced) { final Account callerAccount = context.getAccount(); NetworkVO network = _networksDao.findById(networkId); @@ -2111,7 +2111,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra // get updated state for the network network = _networksDao.findById(networkId); - if (network.getState() != Network.State.Allocated && network.getState() != Network.State.Setup) { + if (network.getState() != Network.State.Allocated && network.getState() != Network.State.Setup && !forced) { s_logger.debug("Network is not not in the correct state to be destroyed: " + network.getState()); return false; } diff --git a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/NetworkProviderTest.java b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/NetworkProviderTest.java index fff4e5a1395..6996a287302 100644 --- a/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/NetworkProviderTest.java +++ b/plugins/network-elements/juniper-contrail/test/org/apache/cloudstack/network/contrail/management/NetworkProviderTest.java @@ -179,7 +179,7 @@ public class NetworkProviderTest extends TestCase { List list = _networkService.getIsolatedNetworksOwnedByAccountInZone(zone.getId(), system); for (Network net : list) { s_logger.debug("Delete network " + net.getName()); - _networkService.deleteNetwork(net.getId()); + _networkService.deleteNetwork(net.getId(), false); } } diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java index fb6f3fd451a..056190f1c4a 100755 --- a/server/src/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/com/cloud/network/NetworkServiceImpl.java @@ -1762,7 +1762,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { @Override @ActionEvent(eventType = EventTypes.EVENT_NETWORK_DELETE, eventDescription = "deleting network", async = true) - public boolean deleteNetwork(long networkId) { + public boolean deleteNetwork(long networkId, boolean forced) { Account caller = CallContext.current().getCallingAccount(); @@ -1788,10 +1788,14 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService { // Perform permission check _accountMgr.checkAccess(caller, null, true, network); + if (forced && !_accountMgr.isRootAdmin(caller.getType())) { + throw new InvalidParameterValueException("Delete network with 'forced' option can only be called by root admins"); + } + User callerUser = _accountMgr.getActiveUser(CallContext.current().getCallingUserId()); ReservationContext context = new ReservationContextImpl(null, null, callerUser, owner); - return _networkMgr.destroyNetwork(networkId, context); + return _networkMgr.destroyNetwork(networkId, context, forced); } @Override diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 30751895e51..2face90a7a4 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -1565,7 +1565,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis User callerUser = _accountMgr.getActiveUser(CallContext.current().getCallingUserId()); Account owner = _accountMgr.getAccount(Account.ACCOUNT_ID_SYSTEM); ReservationContext context = new ReservationContextImpl(null, null, callerUser, owner); - _ntwkMgr.destroyNetwork(networkId, context); + _ntwkMgr.destroyNetwork(networkId, context, false); s_logger.debug("Deleted private network id=" + networkId); } diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 20a6242cfd6..52045897619 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -679,7 +679,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M ReservationContext context = new ReservationContextImpl(null, null, getActiveUser(callerUserId), caller); - if (!_networkMgr.destroyNetwork(network.getId(), context)) { + if (!_networkMgr.destroyNetwork(network.getId(), context, false)) { s_logger.warn("Unable to destroy network " + network + " as a part of account id=" + accountId + " cleanup."); accountCleanupNeeded = true; networksDeleted = false; diff --git a/server/src/com/cloud/user/DomainManagerImpl.java b/server/src/com/cloud/user/DomainManagerImpl.java index 89a918ee68e..b2a478ef096 100644 --- a/server/src/com/cloud/user/DomainManagerImpl.java +++ b/server/src/com/cloud/user/DomainManagerImpl.java @@ -395,8 +395,7 @@ public class DomainManagerImpl extends ManagerBase implements DomainManager, Dom ReservationContext context = new ReservationContextImpl(null, null, _accountMgr.getActiveUser(ctx.getCallingUserId()), ctx.getCallingAccount()); for (Long networkId : networkIds) { s_logger.debug("Deleting network id=" + networkId + " as a part of domain id=" + domainId + " cleanup"); - - if (!_networkMgr.destroyNetwork(networkId, context)) { + if (!_networkMgr.destroyNetwork(networkId, context, false)) { s_logger.warn("Unable to destroy network id=" + networkId + " as a part of domain id=" + domainId + " cleanup."); networksDeleted = false; } else { diff --git a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java index be305dee0f4..846e2f58d8e 100644 --- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java @@ -203,7 +203,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches * @see com.cloud.network.NetworkService#deleteNetwork(long) */ @Override - public boolean deleteNetwork(long networkId) { + public boolean deleteNetwork(long networkId, boolean forced) { // TODO Auto-generated method stub return false; } @@ -597,7 +597,7 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches * @see com.cloud.network.NetworkManager#destroyNetwork(long, com.cloud.vm.ReservationContext) */ @Override - public boolean destroyNetwork(long networkId, ReservationContext context) { + public boolean destroyNetwork(long networkId, ReservationContext context, boolean forced) { // TODO Auto-generated method stub return false; }