This is an automated email from the ASF dual-hosted git repository. pearl11594 pushed a commit to branch netris-update-vpc-and-tier-names in repository https://gitbox.apache.org/repos/asf/cloudstack.git
commit f54cb50d17854be0cc74583eb510d14ba2663109 Author: Pearl Dsilva <pearl1...@gmail.com> AuthorDate: Thu Jan 9 10:24:45 2025 -0500 Release NAT IP subnet when VPC is removed or IP is released (#44) * Release NAT IP subnet when VPC is removed or IP is released * add license --- .../com/cloud/network/element/NetworkElement.java | 7 +++++ .../com/cloud/network/netris/NetrisService.java | 2 ++ .../network/vpc/dao/VpcOfferingServiceMapDao.java | 2 ++ .../vpc/dao/VpcOfferingServiceMapDaoImpl.java | 10 ++++++++ .../networkservice/BaremetalDhcpElement.java | 6 +++++ .../networkservice/BaremetalPxeElement.java | 6 +++++ .../networkservice/BaremetalUserdataElement.java | 6 +++++ .../network/element/CiscoNexusVSMElement.java | 7 ++++- .../cloud/network/element/BigSwitchBcfElement.java | 6 +++++ .../cloud/network/element/BrocadeVcsElement.java | 6 +++++ .../cloud/network/element/CiscoVnmcElement.java | 5 ++++ .../cloudstack/network/element/DnsNotifier.java | 6 +++++ .../element/ElasticLoadBalancerElement.java | 6 +++++ .../cloudstack/element/GloboDnsElement.java | 6 +++++ .../element/InternalLoadBalancerElement.java | 6 +++++ .../contrail/management/ContrailElementImpl.java | 5 ++++ .../cloudstack/agent/api/ReleaseNatIpCommand.java | 30 ++++++++++++++++++++++ .../apache/cloudstack/resource/NetrisResource.java | 11 ++++++++ .../apache/cloudstack/service/NetrisApiClient.java | 2 ++ .../cloudstack/service/NetrisApiClientImpl.java | 26 +++++++++++++++++++ .../apache/cloudstack/service/NetrisElement.java | 5 ++++ .../cloudstack/service/NetrisServiceImpl.java | 8 ++++++ .../cloud/network/element/NetscalerElement.java | 5 ++++ .../cloud/network/element/NiciraNvpElement.java | 5 ++++ .../org/apache/cloudstack/service/NsxElement.java | 5 ++++ .../network/opendaylight/OpendaylightElement.java | 6 +++++ .../java/com/cloud/network/element/OvsElement.java | 6 +++++ .../element/PaloAltoExternalFirewallElement.java | 6 +++++ .../cloudstack/network/element/SspElement.java | 6 +++++ .../network/tungsten/service/TungstenElement.java | 6 +++++ .../com/cloud/network/IpAddressManagerImpl.java | 30 ++++++++++++++++++++++ .../network/element/ConfigDriveNetworkElement.java | 6 +++++ .../network/element/SecurityGroupElement.java | 6 +++++ .../network/element/VirtualRouterElement.java | 6 +++++ .../vpc/dao/MockVpcOfferingServiceMapDaoImpl.java | 5 ++++ .../cloudstack/service/NetrisServiceMockTest.java | 5 ++++ 36 files changed, 276 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/com/cloud/network/element/NetworkElement.java b/api/src/main/java/com/cloud/network/element/NetworkElement.java index fa67575edd3..00c530ce114 100644 --- a/api/src/main/java/com/cloud/network/element/NetworkElement.java +++ b/api/src/main/java/com/cloud/network/element/NetworkElement.java @@ -23,6 +23,7 @@ import com.cloud.deploy.DeployDestination; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; @@ -87,6 +88,12 @@ public interface NetworkElement extends Adapter { boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException; + /** + * Release IP from the network provider if reserved + * @param ipAddress + */ + boolean releaseIp(IpAddress ipAddress); + /** * The network is being shutdown. * @param network diff --git a/api/src/main/java/com/cloud/network/netris/NetrisService.java b/api/src/main/java/com/cloud/network/netris/NetrisService.java index 355586f7d91..6fd860f26be 100644 --- a/api/src/main/java/com/cloud/network/netris/NetrisService.java +++ b/api/src/main/java/com/cloud/network/netris/NetrisService.java @@ -46,4 +46,6 @@ public interface NetrisService { boolean addOrUpdateStaticRoute(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId, boolean updateRoute); boolean deleteStaticRoute(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId); + + boolean releaseNatIp(long zoneId, String publicIp); } diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDao.java b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDao.java index 9519cd08a0b..020536e97ec 100644 --- a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDao.java +++ b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDao.java @@ -40,4 +40,6 @@ public interface VpcOfferingServiceMapDao extends GenericDao<VpcOfferingServiceM boolean isProviderForVpcOffering(Network.Provider provider, long vpcOfferingId); + List<VpcOfferingServiceMapVO> listProvidersForServiceForVpcOffering(long vpcOfferingId, Service service); + } diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java index 672955a3ecc..dcb1becf9e8 100644 --- a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java @@ -119,4 +119,14 @@ public class VpcOfferingServiceMapDaoImpl extends GenericDaoBase<VpcOfferingServ sc.setParameters("provider", provider.getName()); return findOneBy(sc) != null; } + + @Override + public List<VpcOfferingServiceMapVO> listProvidersForServiceForVpcOffering(long vpcOfferingId, Service service) { + SearchCriteria<VpcOfferingServiceMapVO> sc = AllFieldsSearch.create(); + + sc.setParameters("vpcOffId", vpcOfferingId); + sc.setParameters("service", service.getName()); + + return customSearch(sc, null); + } } diff --git a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalDhcpElement.java b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalDhcpElement.java index e39b40cfc68..2e9d6989550 100644 --- a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalDhcpElement.java +++ b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalDhcpElement.java @@ -34,6 +34,7 @@ import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.host.Host; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.GuestType; @@ -125,6 +126,11 @@ public class BaremetalDhcpElement extends AdapterBase implements DhcpServiceProv return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { return true; diff --git a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalPxeElement.java b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalPxeElement.java index fa708e7be4c..adcb96f6116 100644 --- a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalPxeElement.java +++ b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalPxeElement.java @@ -29,6 +29,7 @@ import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.GuestType; @@ -161,6 +162,11 @@ public class BaremetalPxeElement extends AdapterBase implements NetworkElement { return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + private void releaseVlan(Network network, VirtualMachineProfile vm) { vlanMgr.releaseVlan(network, vm); } diff --git a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalUserdataElement.java b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalUserdataElement.java index d2c9731ddd1..2ec05d443aa 100644 --- a/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalUserdataElement.java +++ b/plugins/hypervisors/baremetal/src/main/java/com/cloud/baremetal/networkservice/BaremetalUserdataElement.java @@ -30,6 +30,7 @@ import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; @@ -124,6 +125,11 @@ public class BaremetalUserdataElement extends AdapterBase implements NetworkElem return false; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { // TODO Auto-generated method stub diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/network/element/CiscoNexusVSMElement.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/network/element/CiscoNexusVSMElement.java index 2503e0ac7fd..441bdb83854 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/network/element/CiscoNexusVSMElement.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/network/element/CiscoNexusVSMElement.java @@ -24,7 +24,7 @@ import java.util.Set; import javax.inject.Inject; - +import com.cloud.network.IpAddress; import com.cloud.api.commands.DeleteCiscoNexusVSMCmd; import com.cloud.api.commands.DisableCiscoNexusVSMCmd; import com.cloud.api.commands.EnableCiscoNexusVSMCmd; @@ -106,6 +106,11 @@ public class CiscoNexusVSMElement extends CiscoNexusVSMDeviceManagerImpl impleme return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { return true; diff --git a/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/element/BigSwitchBcfElement.java b/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/element/BigSwitchBcfElement.java index 5fc9480c610..f3624ebeb40 100644 --- a/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/element/BigSwitchBcfElement.java +++ b/plugins/network-elements/bigswitch/src/main/java/com/cloud/network/element/BigSwitchBcfElement.java @@ -29,6 +29,7 @@ import java.util.UUID; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.network.IpAddress; import org.springframework.stereotype.Component; import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; import org.apache.commons.net.util.SubnetUtils; @@ -318,6 +319,11 @@ NetworkACLServiceProvider, FirewallServiceProvider, ResourceStateAdapter { return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { if (!canHandle(network, Service.Connectivity)) { diff --git a/plugins/network-elements/brocade-vcs/src/main/java/com/cloud/network/element/BrocadeVcsElement.java b/plugins/network-elements/brocade-vcs/src/main/java/com/cloud/network/element/BrocadeVcsElement.java index daf9c1c4e08..510900cc105 100644 --- a/plugins/network-elements/brocade-vcs/src/main/java/com/cloud/network/element/BrocadeVcsElement.java +++ b/plugins/network-elements/brocade-vcs/src/main/java/com/cloud/network/element/BrocadeVcsElement.java @@ -27,6 +27,7 @@ import java.util.UUID; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.network.IpAddress; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; import org.springframework.stereotype.Component; @@ -194,6 +195,11 @@ public class BrocadeVcsElement extends AdapterBase implements NetworkElement, Re return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { if (!canHandle(network, Service.Connectivity)) { diff --git a/plugins/network-elements/cisco-vnmc/src/main/java/com/cloud/network/element/CiscoVnmcElement.java b/plugins/network-elements/cisco-vnmc/src/main/java/com/cloud/network/element/CiscoVnmcElement.java index bea5a2c3f25..352eba4674d 100644 --- a/plugins/network-elements/cisco-vnmc/src/main/java/com/cloud/network/element/CiscoVnmcElement.java +++ b/plugins/network-elements/cisco-vnmc/src/main/java/com/cloud/network/element/CiscoVnmcElement.java @@ -434,6 +434,11 @@ public class CiscoVnmcElement extends AdapterBase implements SourceNatServicePro return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + private boolean cleanupLogicalEdgeFirewall(long vlanId, long hostId) { CleanupLogicalEdgeFirewallCommand cmd = new CleanupLogicalEdgeFirewallCommand(vlanId); Answer answer = _agentMgr.easySend(hostId, cmd); diff --git a/plugins/network-elements/dns-notifier/src/main/java/org/apache/cloudstack/network/element/DnsNotifier.java b/plugins/network-elements/dns-notifier/src/main/java/org/apache/cloudstack/network/element/DnsNotifier.java index 0b96aa35150..04f092648c2 100644 --- a/plugins/network-elements/dns-notifier/src/main/java/org/apache/cloudstack/network/element/DnsNotifier.java +++ b/plugins/network-elements/dns-notifier/src/main/java/org/apache/cloudstack/network/element/DnsNotifier.java @@ -26,6 +26,7 @@ import com.cloud.deploy.DeployDestination; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; @@ -86,6 +87,11 @@ public class DnsNotifier extends AdapterBase implements NetworkElement { return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { return true; diff --git a/plugins/network-elements/elastic-loadbalancer/src/main/java/com/cloud/network/element/ElasticLoadBalancerElement.java b/plugins/network-elements/elastic-loadbalancer/src/main/java/com/cloud/network/element/ElasticLoadBalancerElement.java index c1ea7823811..f512a08dffd 100644 --- a/plugins/network-elements/elastic-loadbalancer/src/main/java/com/cloud/network/element/ElasticLoadBalancerElement.java +++ b/plugins/network-elements/elastic-loadbalancer/src/main/java/com/cloud/network/element/ElasticLoadBalancerElement.java @@ -24,6 +24,7 @@ import java.util.Set; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.network.IpAddress; import org.springframework.stereotype.Component; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; @@ -136,6 +137,11 @@ public class ElasticLoadBalancerElement extends AdapterBase implements LoadBalan return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { // TODO kill all loadbalancer vms by calling the ElasticLoadBalancerManager diff --git a/plugins/network-elements/globodns/src/main/java/com/globo/globodns/cloudstack/element/GloboDnsElement.java b/plugins/network-elements/globodns/src/main/java/com/globo/globodns/cloudstack/element/GloboDnsElement.java index 09830d9a810..c83a913a61c 100644 --- a/plugins/network-elements/globodns/src/main/java/com/globo/globodns/cloudstack/element/GloboDnsElement.java +++ b/plugins/network-elements/globodns/src/main/java/com/globo/globodns/cloudstack/element/GloboDnsElement.java @@ -26,6 +26,7 @@ import java.util.Set; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.network.IpAddress; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.springframework.stereotype.Component; @@ -175,6 +176,11 @@ public class GloboDnsElement extends AdapterBase implements ResourceStateAdapter return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { return true; diff --git a/plugins/network-elements/internal-loadbalancer/src/main/java/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java b/plugins/network-elements/internal-loadbalancer/src/main/java/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java index 0a9b4a7131a..dc48d70f8a7 100644 --- a/plugins/network-elements/internal-loadbalancer/src/main/java/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java +++ b/plugins/network-elements/internal-loadbalancer/src/main/java/org/apache/cloudstack/network/element/InternalLoadBalancerElement.java @@ -26,6 +26,7 @@ import java.util.Set; import javax.inject.Inject; +import com.cloud.network.IpAddress; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -221,6 +222,11 @@ public class InternalLoadBalancerElement extends AdapterBase implements LoadBala return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { List<? extends VirtualRouter> internalLbVms = _routerDao.listByNetworkAndRole(network.getId(), Role.INTERNAL_LB_VM); diff --git a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailElementImpl.java b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailElementImpl.java index 44cbc6c305f..fb832bf1d82 100644 --- a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailElementImpl.java +++ b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailElementImpl.java @@ -244,6 +244,11 @@ public class ContrailElementImpl extends AdapterBase return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return false; + } + /** * Network disable */ diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/ReleaseNatIpCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/ReleaseNatIpCommand.java new file mode 100644 index 00000000000..ac3a4faba4d --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/ReleaseNatIpCommand.java @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.agent.api; + +public class ReleaseNatIpCommand extends NetrisCommand { + private String natIp; + + public ReleaseNatIpCommand(long zoneId, Long accountId, Long domainId, String name, Long id, boolean isVpc, String natIp) { + super(zoneId, accountId, domainId, name, id, isVpc); + this.natIp = natIp; + } + + public String getNatIp() { + return natIp; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java index 4507eb7d82b..349b83132c7 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java @@ -38,6 +38,7 @@ import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand; import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; import org.apache.cloudstack.agent.api.NetrisAnswer; import org.apache.cloudstack.StartupNetrisCommand; +import org.apache.cloudstack.agent.api.ReleaseNatIpCommand; import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand; import org.apache.cloudstack.service.NetrisApiClient; import org.apache.cloudstack.service.NetrisApiClientImpl; @@ -109,6 +110,8 @@ public class NetrisResource implements ServerResource { return executeRequest((DeleteNetrisStaticRouteCommand) cmd); } else if (cmd instanceof AddOrUpdateNetrisStaticRouteCommand) { return executeRequest((AddOrUpdateNetrisStaticRouteCommand) cmd); + } else if (cmd instanceof ReleaseNatIpCommand) { + return executeRequest((ReleaseNatIpCommand) cmd); } else { return Answer.createUnsupportedCommandAnswer(cmd); } @@ -319,6 +322,14 @@ public class NetrisResource implements ServerResource { return new NetrisAnswer(cmd, true, "OK"); } + private Answer executeRequest(ReleaseNatIpCommand cmd) { + boolean result = netrisApiClient.releaseNatIp(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Failed to release NAT IP: %s", cmd.getNatIp())); + } + return new NetrisAnswer(cmd, true, "OK"); + } + @Override public boolean start() { return true; diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java index 59c2c9342a9..83e8b5fe0a3 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java @@ -28,6 +28,7 @@ import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand; import org.apache.cloudstack.agent.api.DeleteNetrisStaticRouteCommand; import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand; import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; +import org.apache.cloudstack.agent.api.ReleaseNatIpCommand; import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand; import java.util.List; @@ -78,4 +79,5 @@ public interface NetrisApiClient { boolean deleteNatRule(DeleteNetrisNatRuleCommand cmd); boolean addOrUpdateStaticRoute(AddOrUpdateNetrisStaticRouteCommand cmd); boolean deleteStaticRoute(DeleteNetrisStaticRouteCommand cmd); + boolean releaseNatIp(ReleaseNatIpCommand cmd); } diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java index 2c409482a19..8d6d088407e 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java @@ -88,6 +88,7 @@ import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand; import org.apache.cloudstack.agent.api.DeleteNetrisStaticRouteCommand; import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand; import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; +import org.apache.cloudstack.agent.api.ReleaseNatIpCommand; import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand; import org.apache.cloudstack.resource.NetrisResourceObjectUtils; import org.apache.commons.collections.CollectionUtils; @@ -441,6 +442,31 @@ public class NetrisApiClientImpl implements NetrisApiClient { return false; } + @Override + public boolean releaseNatIp(ReleaseNatIpCommand cmd) { + String natIp = cmd.getNatIp() + "/32"; + try { + VPCListing systemVpc = getSystemVpc(); + IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class); + FilterByVpc vpcFilter = new FilterByVpc(); + vpcFilter.add(systemVpc.getId()); + SubnetResBody subnetResponse = ipamApi.apiV2IpamSubnetsGet(vpcFilter); + if (subnetResponse == null || !subnetResponse.isIsSuccess()) { + String reason = subnetResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("Failed to retrieve Netris Public NAT IPs due to {}", reason); + throw new CloudRuntimeException(reason); + } + List<IpTreeSubnet> natIps = subnetResponse.getData().stream().filter(ip -> ip.getPrefix().equals(natIp)).collect(Collectors.toList()); + if (!natIps.isEmpty()) { + ipamApi.apiV2IpamTypeIdDelete("subnet", natIps.get(0).getId().intValue()); + } + + } catch (ApiException e) { + logAndThrowException("Failed to release Netris IP", e); + } + return true; + } + private Pair<Boolean, RoutesGetBody> staticRouteExists(Integer netrisVpcId, String prefix, String nextHop, String description) { try { FilterByVpc vpcFilter = new FilterByVpc(); diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java index 44339e38628..96b7379d285 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java @@ -320,6 +320,11 @@ public class NetrisElement extends AdapterBase implements DhcpServiceProvider, D return false; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return netrisService.releaseNatIp(ipAddress.getDataCenterId(), ipAddress.getAddress().addr()); + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { return canHandle(network, Network.Service.Connectivity); diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java index 6d97f850243..cb2047e32e8 100644 --- a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java @@ -52,6 +52,7 @@ import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand; import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; import org.apache.cloudstack.agent.api.NetrisAnswer; import org.apache.cloudstack.agent.api.NetrisCommand; +import org.apache.cloudstack.agent.api.ReleaseNatIpCommand; import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.framework.config.ConfigKey; @@ -354,6 +355,13 @@ public class NetrisServiceImpl implements NetrisService, Configurable { return answer.getResult(); } + @Override + public boolean releaseNatIp(long zoneId, String publicIp) { + ReleaseNatIpCommand cmd = new ReleaseNatIpCommand(zoneId, null, null, null, null, false, publicIp); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + private String getResourceSuffix(Long vpcId, Long networkId, boolean isForVpc) { String suffix; if (isForVpc) { diff --git a/plugins/network-elements/netscaler/src/main/java/com/cloud/network/element/NetscalerElement.java b/plugins/network-elements/netscaler/src/main/java/com/cloud/network/element/NetscalerElement.java index 48b9006f34c..34df6e95482 100644 --- a/plugins/network-elements/netscaler/src/main/java/com/cloud/network/element/NetscalerElement.java +++ b/plugins/network-elements/netscaler/src/main/java/com/cloud/network/element/NetscalerElement.java @@ -420,6 +420,11 @@ IpDeployer, StaticNatServiceProvider, GslbServiceProvider { return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network guestConfig, ReservationContext context, boolean cleanup) throws ResourceUnavailableException, ConcurrentOperationException { diff --git a/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/element/NiciraNvpElement.java b/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/element/NiciraNvpElement.java index 356b452a9e4..5ab85910dc9 100644 --- a/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/element/NiciraNvpElement.java +++ b/plugins/network-elements/nicira-nvp/src/main/java/com/cloud/network/element/NiciraNvpElement.java @@ -448,6 +448,11 @@ NiciraNvpElementService, ResourceStateAdapter, IpDeployer { return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { if (!canHandle(network, Service.Connectivity)) { diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java index 753d0cf822e..a57868f864e 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java @@ -284,6 +284,11 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns return false; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { return canHandle(network, Network.Service.Connectivity); diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/OpendaylightElement.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/OpendaylightElement.java index b35190217d3..00d9ca8360b 100644 --- a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/OpendaylightElement.java +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/OpendaylightElement.java @@ -27,6 +27,7 @@ import java.util.Set; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.network.IpAddress; import org.springframework.stereotype.Component; import org.apache.cloudstack.network.opendaylight.agent.commands.StartupOpenDaylightControllerCommand; @@ -102,6 +103,11 @@ public class OpendaylightElement extends AdapterBase implements ConnectivityProv return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { return true; diff --git a/plugins/network-elements/ovs/src/main/java/com/cloud/network/element/OvsElement.java b/plugins/network-elements/ovs/src/main/java/com/cloud/network/element/OvsElement.java index 69891954264..85877292c95 100644 --- a/plugins/network-elements/ovs/src/main/java/com/cloud/network/element/OvsElement.java +++ b/plugins/network-elements/ovs/src/main/java/com/cloud/network/element/OvsElement.java @@ -25,6 +25,7 @@ import java.util.Set; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.network.IpAddress; import org.apache.cloudstack.network.topology.NetworkTopology; import org.apache.cloudstack.network.topology.NetworkTopologyContext; @@ -208,6 +209,11 @@ StaticNatServiceProvider, IpDeployer { return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(final Network network, final ReservationContext context, final boolean cleanup) throws ConcurrentOperationException, diff --git a/plugins/network-elements/palo-alto/src/main/java/com/cloud/network/element/PaloAltoExternalFirewallElement.java b/plugins/network-elements/palo-alto/src/main/java/com/cloud/network/element/PaloAltoExternalFirewallElement.java index c81ac5f5f0c..e27fd88b5a8 100644 --- a/plugins/network-elements/palo-alto/src/main/java/com/cloud/network/element/PaloAltoExternalFirewallElement.java +++ b/plugins/network-elements/palo-alto/src/main/java/com/cloud/network/element/PaloAltoExternalFirewallElement.java @@ -25,6 +25,7 @@ import java.util.Set; import javax.inject.Inject; +import com.cloud.network.IpAddress; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; @@ -174,6 +175,11 @@ public class PaloAltoExternalFirewallElement extends ExternalFirewallDeviceManag return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ResourceUnavailableException, ConcurrentOperationException { DataCenter zone = _entityMgr.findById(DataCenter.class, network.getDataCenterId()); diff --git a/plugins/network-elements/stratosphere-ssp/src/main/java/org/apache/cloudstack/network/element/SspElement.java b/plugins/network-elements/stratosphere-ssp/src/main/java/org/apache/cloudstack/network/element/SspElement.java index bfe9de2c837..978eb114588 100644 --- a/plugins/network-elements/stratosphere-ssp/src/main/java/org/apache/cloudstack/network/element/SspElement.java +++ b/plugins/network-elements/stratosphere-ssp/src/main/java/org/apache/cloudstack/network/element/SspElement.java @@ -30,6 +30,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.network.IpAddress; import org.apache.cloudstack.api.commands.AddSspCmd; import org.apache.cloudstack.api.commands.DeleteSspCmd; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; @@ -510,6 +511,11 @@ public class SspElement extends AdapterBase implements ConnectivityProvider, Ssp return deleteNicEnv(network, nic, context); } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + /* (non-Javadoc) * Destroy a network implementation. * diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java index 106cf5180c3..18275f2e9d4 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java @@ -41,6 +41,7 @@ import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor; +import com.cloud.network.IpAddress; import com.cloud.network.IpAddressManager; import com.cloud.network.Network; import com.cloud.network.NetworkMigrationResponder; @@ -689,6 +690,11 @@ public class TungstenElement extends AdapterBase return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException { diff --git a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java index 2c54a5d890c..e52eeb84fbd 100644 --- a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java +++ b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java @@ -43,6 +43,10 @@ import com.cloud.network.dao.Site2SiteVpnGatewayDao; import com.cloud.network.element.NetrisProviderVO; import com.cloud.network.element.NsxProviderVO; import com.cloud.network.vo.PublicIpQuarantineVO; +import com.cloud.network.vpc.Vpc; +import com.cloud.network.vpc.VpcOffering; +import com.cloud.network.vpc.VpcOfferingServiceMapVO; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; import com.cloud.resourcelimit.CheckedReservation; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; @@ -275,6 +279,8 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage @Inject NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao; @Inject + VpcOfferingServiceMapDao vpcOfferingServiceMapDao; + @Inject PhysicalNetworkDao _physicalNetworkDao; @Inject PhysicalNetworkServiceProviderDao _pNSPDao; @@ -806,6 +812,30 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage } else if (publicIpQuarantine != null) { removePublicIpAddressFromQuarantine(publicIpQuarantine.getId(), "Public IP address removed from quarantine as there was an error while disassociating it."); } + Network network = _networksDao.findById(ipToBeDisassociated.getAssociatedWithNetworkId()); + Vpc vpc = _vpcDao.findById(ip.getVpcId()); + if (ObjectUtils.allNull(network, vpc)) { + return success; + } + List<String> providers; + if (Objects.nonNull(network)) { + NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); + providers = _ntwkOfferingSrvcDao.listProvidersForServiceForNetworkOffering(offering.getId(), Service.NetworkACL); + } else { + VpcOffering offering = vpcOfferingDao.findById(vpc.getVpcOfferingId()); + List<VpcOfferingServiceMapVO> servicesMap = vpcOfferingServiceMapDao.listProvidersForServiceForVpcOffering(offering.getId(), Service.NetworkACL); + providers = servicesMap.stream().map(VpcOfferingServiceMapVO::getProvider).collect(Collectors.toList()); + } + + if (providers.isEmpty()) { + throw new InvalidParameterValueException("Unable to find the provider for this network"); + } + + String provider = providers.get(0); + NetworkElement element = _networkModel.getElementImplementingProvider(provider); + if (element != null) { + element.releaseIp(ipToBeDisassociated); + } } finally { _ipAddressDao.releaseFromLockTable(addrId); } diff --git a/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java b/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java index 3449f1f5d00..07a40c95b4a 100644 --- a/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java +++ b/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java @@ -25,6 +25,7 @@ import java.util.Set; import javax.inject.Inject; +import com.cloud.network.IpAddress; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; @@ -179,6 +180,11 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle } } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { return true; // assume that the agent will remove userdata etc diff --git a/server/src/main/java/com/cloud/network/element/SecurityGroupElement.java b/server/src/main/java/com/cloud/network/element/SecurityGroupElement.java index 86c862bf072..c2e3317487c 100644 --- a/server/src/main/java/com/cloud/network/element/SecurityGroupElement.java +++ b/server/src/main/java/com/cloud/network/element/SecurityGroupElement.java @@ -25,6 +25,7 @@ import com.cloud.deploy.DeployDestination; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; @@ -77,6 +78,11 @@ public class SecurityGroupElement extends AdapterBase implements NetworkElement return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { return true; diff --git a/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java b/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java index 53cf838ca87..92ee5f76c16 100644 --- a/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java @@ -24,6 +24,7 @@ import java.util.Set; import javax.inject.Inject; +import com.cloud.network.IpAddress; import org.apache.cloudstack.network.BgpPeer; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; @@ -943,6 +944,11 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ return true; } + @Override + public boolean releaseIp(IpAddress ipAddress) { + return true; + } + @Override public boolean configDhcpSupportForSubnet(final Network network, final NicProfile nic, final VirtualMachineProfile vm, final DeployDestination dest, diff --git a/server/src/test/java/com/cloud/vpc/dao/MockVpcOfferingServiceMapDaoImpl.java b/server/src/test/java/com/cloud/vpc/dao/MockVpcOfferingServiceMapDaoImpl.java index 3d45d8e839f..27aba5c013c 100644 --- a/server/src/test/java/com/cloud/vpc/dao/MockVpcOfferingServiceMapDaoImpl.java +++ b/server/src/test/java/com/cloud/vpc/dao/MockVpcOfferingServiceMapDaoImpl.java @@ -68,6 +68,11 @@ public class MockVpcOfferingServiceMapDaoImpl extends GenericDaoBase<VpcOffering return false; } + @Override + public List<VpcOfferingServiceMapVO> listProvidersForServiceForVpcOffering(long vpcOfferingId, Service service) { + return List.of(); + } + @Override public VpcOfferingServiceMapVO persist(VpcOfferingServiceMapVO vo) { return vo; diff --git a/server/src/test/java/org/apache/cloudstack/service/NetrisServiceMockTest.java b/server/src/test/java/org/apache/cloudstack/service/NetrisServiceMockTest.java index b4e4509dc3a..05a6cd20213 100644 --- a/server/src/test/java/org/apache/cloudstack/service/NetrisServiceMockTest.java +++ b/server/src/test/java/org/apache/cloudstack/service/NetrisServiceMockTest.java @@ -86,4 +86,9 @@ public class NetrisServiceMockTest implements NetrisService { public boolean deleteStaticRoute(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId) { return true; } + + @Override + public boolean releaseNatIp(long zoneId, String publicIp) { + return true; + } }