CLOUDSTACK-5861: networks that failed to implement can not be destroyed
introduces a force option in delete network to forcifully delete a
network. This comes handy in rare cases where network fails to implenet
and network is in shutdown state, but network shutdown to rollback
implement process fails as well.
Conflicts:
api/src/org/apache/cloudstack/api/command/user/network/DeleteNetworkCmd.java
server/src/com/cloud/user/DomainManagerImpl.java
diff --git a/api/src/com/cloud/network/NetworkService.java b/api/src/com/cloud/network/NetworkService.java
index 489bc6c..250121e 100755
--- a/api/src/com/cloud/network/NetworkService.java
+++ b/api/src/com/cloud/network/NetworkService.java
@@ -64,7 +64,7 @@
Pair<List<? extends Network>, 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 a48e01b..808051e 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 @@
@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 @@
return id;
}
+ public boolean isForced() {
+ return (forced != null) ? forced : false;
+ }
+
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@@ -65,7 +73,7 @@
@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 c036c99..a50c184 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 @@
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 7bf7841..85fa530 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 @@
@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 @@
// 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 fff4e5a..6996a28 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 @@
List<? extends Network> 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 fb6f3fd..056190f 100755
--- a/server/src/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/com/cloud/network/NetworkServiceImpl.java
@@ -1762,7 +1762,7 @@
@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 @@
// 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 3075189..2face90 100644
--- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java
@@ -1565,7 +1565,7 @@
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 20a6242..5204589 100755
--- a/server/src/com/cloud/user/AccountManagerImpl.java
+++ b/server/src/com/cloud/user/AccountManagerImpl.java
@@ -679,7 +679,7 @@
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 89a918e..b2a478e 100644
--- a/server/src/com/cloud/user/DomainManagerImpl.java
+++ b/server/src/com/cloud/user/DomainManagerImpl.java
@@ -395,8 +395,7 @@
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 be305de..846e2f5 100644
--- a/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
+++ b/server/test/com/cloud/vpc/MockNetworkManagerImpl.java
@@ -203,7 +203,7 @@
* @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 @@
* @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;
}