mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
api: add ipaddress argument to disassociateIPAddress (#8222)
This PR adds argument 'ipadress' to the disassociateIpAddress api. IP address can be disassociated by directly giving the address instead of ID. Fixes: #8125
This commit is contained in:
parent
98d643efe6
commit
5c7e4b7edc
@ -114,6 +114,8 @@ public interface NetworkService {
|
|||||||
|
|
||||||
IpAddress getIp(long id);
|
IpAddress getIp(long id);
|
||||||
|
|
||||||
|
IpAddress getIp(String ipAddress);
|
||||||
|
|
||||||
Network updateGuestNetwork(final UpdateNetworkCmd cmd);
|
Network updateGuestNetwork(final UpdateNetworkCmd cmd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -46,10 +46,14 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
|
|||||||
//////////////// API parameters /////////////////////
|
//////////////// API parameters /////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = IPAddressResponse.class, required = true, description = "the ID of the public IP address"
|
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = IPAddressResponse.class, description = "the ID of the public IP address"
|
||||||
+ " to disassociate")
|
+ " to disassociate. Mutually exclusive with the ipaddress parameter")
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
@Parameter(name=ApiConstants.IP_ADDRESS, type=CommandType.STRING, since="4.19.0", description="IP Address to be disassociated."
|
||||||
|
+ " Mutually exclusive with the id parameter")
|
||||||
|
private String ipAddress;
|
||||||
|
|
||||||
// unexposed parameter needed for events logging
|
// unexposed parameter needed for events logging
|
||||||
@Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, expose = false)
|
@Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, expose = false)
|
||||||
private Long ownerId;
|
private Long ownerId;
|
||||||
@ -59,7 +63,18 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
|
|||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
||||||
public Long getIpAddressId() {
|
public Long getIpAddressId() {
|
||||||
return id;
|
if (id != null & ipAddress != null) {
|
||||||
|
throw new InvalidParameterValueException("id parameter is mutually exclusive with ipaddress parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id != null) {
|
||||||
|
return id;
|
||||||
|
} else if (ipAddress != null) {
|
||||||
|
IpAddress ip = getIpAddressByIp(ipAddress);
|
||||||
|
return ip.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidParameterValueException("Please specify either IP address or IP address ID");
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
@ -68,12 +83,13 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() throws InsufficientAddressCapacityException {
|
public void execute() throws InsufficientAddressCapacityException {
|
||||||
CallContext.current().setEventDetails("IP ID: " + getIpAddressId());
|
Long ipAddressId = getIpAddressId();
|
||||||
|
CallContext.current().setEventDetails("IP ID: " + ipAddressId);
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
if (!isPortable(id)) {
|
if (!isPortable()) {
|
||||||
result = _networkService.releaseIpAddress(getIpAddressId());
|
result = _networkService.releaseIpAddress(ipAddressId);
|
||||||
} else {
|
} else {
|
||||||
result = _networkService.releasePortableIpAddress(getIpAddressId());
|
result = _networkService.releasePortableIpAddress(ipAddressId);
|
||||||
}
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
SuccessResponse response = new SuccessResponse(getCommandName());
|
SuccessResponse response = new SuccessResponse(getCommandName());
|
||||||
@ -85,7 +101,7 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getEventType() {
|
public String getEventType() {
|
||||||
if (!isPortable(id)) {
|
if (!isPortable()) {
|
||||||
return EventTypes.EVENT_NET_IP_RELEASE;
|
return EventTypes.EVENT_NET_IP_RELEASE;
|
||||||
} else {
|
} else {
|
||||||
return EventTypes.EVENT_PORTABLE_IP_RELEASE;
|
return EventTypes.EVENT_PORTABLE_IP_RELEASE;
|
||||||
@ -100,10 +116,7 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
|
|||||||
@Override
|
@Override
|
||||||
public long getEntityOwnerId() {
|
public long getEntityOwnerId() {
|
||||||
if (ownerId == null) {
|
if (ownerId == null) {
|
||||||
IpAddress ip = getIpAddress(id);
|
IpAddress ip = getIpAddress();
|
||||||
if (ip == null) {
|
|
||||||
throw new InvalidParameterValueException("Unable to find IP address by ID=" + id);
|
|
||||||
}
|
|
||||||
ownerId = ip.getAccountId();
|
ownerId = ip.getAccountId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,11 +133,11 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long getSyncObjId() {
|
public Long getSyncObjId() {
|
||||||
IpAddress ip = getIpAddress(id);
|
IpAddress ip = getIpAddress();
|
||||||
return ip.getAssociatedWithNetworkId();
|
return ip.getAssociatedWithNetworkId();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IpAddress getIpAddress(long id) {
|
private IpAddress getIpAddressById(Long id) {
|
||||||
IpAddress ip = _entityMgr.findById(IpAddress.class, id);
|
IpAddress ip = _entityMgr.findById(IpAddress.class, id);
|
||||||
|
|
||||||
if (ip == null) {
|
if (ip == null) {
|
||||||
@ -134,6 +147,29 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IpAddress getIpAddressByIp(String ipAddress) {
|
||||||
|
IpAddress ip = _networkService.getIp(ipAddress);
|
||||||
|
if (ip == null) {
|
||||||
|
throw new InvalidParameterValueException("Unable to find IP address by IP address=" + ipAddress);
|
||||||
|
} else {
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IpAddress getIpAddress() {
|
||||||
|
if (id != null & ipAddress != null) {
|
||||||
|
throw new InvalidParameterValueException("id parameter is mutually exclusive with ipaddress parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id != null) {
|
||||||
|
return getIpAddressById(id);
|
||||||
|
} else if (ipAddress != null){
|
||||||
|
return getIpAddressByIp(ipAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidParameterValueException("Please specify either IP address or IP address ID");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApiCommandResourceType getApiResourceType() {
|
public ApiCommandResourceType getApiResourceType() {
|
||||||
return ApiCommandResourceType.IpAddress;
|
return ApiCommandResourceType.IpAddress;
|
||||||
@ -144,8 +180,8 @@ public class DisassociateIPAddrCmd extends BaseAsyncCmd {
|
|||||||
return getIpAddressId();
|
return getIpAddressId();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPortable(long id) {
|
private boolean isPortable() {
|
||||||
IpAddress ip = getIpAddress(id);
|
IpAddress ip = getIpAddress();
|
||||||
return ip.isPortable();
|
return ip.isPortable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2798,6 +2798,11 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||||||
return _ipAddressDao.findById(ipAddressId);
|
return _ipAddressDao.findById(ipAddressId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IpAddress getIp(String ipAddress) {
|
||||||
|
return _ipAddressDao.findByIp(ipAddress);
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean providersConfiguredForExternalNetworking(Collection<String> providers) {
|
protected boolean providersConfiguredForExternalNetworking(Collection<String> providers) {
|
||||||
for (String providerStr : providers) {
|
for (String providerStr : providers) {
|
||||||
Provider provider = Network.Provider.getProvider(providerStr);
|
Provider provider = Network.Provider.getProvider(providerStr);
|
||||||
|
|||||||
@ -275,6 +275,15 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.cloud.network.NetworkService#getIp(String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public IpAddress getIp(String ipAddress) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Network updateGuestNetwork(final UpdateNetworkCmd cmd) {
|
public Network updateGuestNetwork(final UpdateNetworkCmd cmd) {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
|
|||||||
@ -871,7 +871,7 @@ class TestReleaseIP(cloudstackTestCase):
|
|||||||
|
|
||||||
@attr(tags=["advanced", "advancedns", "smoke", "dvs"], required_hardware="false")
|
@attr(tags=["advanced", "advancedns", "smoke", "dvs"], required_hardware="false")
|
||||||
def test_releaseIP(self):
|
def test_releaseIP(self):
|
||||||
"""Test for release public IP address"""
|
"""Test for release public IP address using the ID"""
|
||||||
|
|
||||||
logger.debug("Deleting Public IP : %s" % self.ip_addr.id)
|
logger.debug("Deleting Public IP : %s" % self.ip_addr.id)
|
||||||
|
|
||||||
@ -930,6 +930,66 @@ class TestReleaseIP(cloudstackTestCase):
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@attr(tags=["advanced", "advancedns", "smoke", "dvs"], required_hardware="false")
|
||||||
|
def test_releaseIP_using_IP(self):
|
||||||
|
"""Test for release public IP address using the address"""
|
||||||
|
|
||||||
|
logger.debug("Deleting Public IP : %s" % self.ip_addr.ipaddress)
|
||||||
|
self.ip_address.delete_by_ip(self.apiclient)
|
||||||
|
|
||||||
|
retriesCount = 10
|
||||||
|
isIpAddressDisassociated = False
|
||||||
|
while retriesCount > 0:
|
||||||
|
listResponse = list_publicIP(
|
||||||
|
self.apiclient,
|
||||||
|
id=self.ip_addr.id,
|
||||||
|
state="Allocated"
|
||||||
|
)
|
||||||
|
if listResponse is None:
|
||||||
|
isIpAddressDisassociated = True
|
||||||
|
break
|
||||||
|
retriesCount -= 1
|
||||||
|
time.sleep(60)
|
||||||
|
# End while
|
||||||
|
|
||||||
|
self.assertTrue(
|
||||||
|
isIpAddressDisassociated,
|
||||||
|
"Failed to disassociate IP address")
|
||||||
|
|
||||||
|
# ListPortForwardingRules should not list
|
||||||
|
# associated rules with Public IP address
|
||||||
|
try:
|
||||||
|
list_nat_rule = list_nat_rules(
|
||||||
|
self.apiclient,
|
||||||
|
id=self.nat_rule.id
|
||||||
|
)
|
||||||
|
logger.debug("List NAT Rule response" + str(list_nat_rule))
|
||||||
|
except CloudstackAPIException:
|
||||||
|
logger.debug("Port Forwarding Rule is deleted")
|
||||||
|
|
||||||
|
# listLoadBalancerRules should not list
|
||||||
|
# associated rules with Public IP address
|
||||||
|
try:
|
||||||
|
list_lb_rule = list_lb_rules(
|
||||||
|
self.apiclient,
|
||||||
|
id=self.lb_rule.id
|
||||||
|
)
|
||||||
|
logger.debug("List LB Rule response" + str(list_lb_rule))
|
||||||
|
except CloudstackAPIException:
|
||||||
|
logger.debug("Port Forwarding Rule is deleted")
|
||||||
|
|
||||||
|
# SSH Attempt though public IP should fail
|
||||||
|
with self.assertRaises(Exception):
|
||||||
|
SshClient(
|
||||||
|
self.ip_addr.ipaddress,
|
||||||
|
self.services["natrule"]["publicport"],
|
||||||
|
self.virtual_machine.username,
|
||||||
|
self.virtual_machine.password,
|
||||||
|
retries=2,
|
||||||
|
delay=0
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
class TestDeleteAccount(cloudstackTestCase):
|
class TestDeleteAccount(cloudstackTestCase):
|
||||||
|
|
||||||
|
|||||||
@ -1879,12 +1879,19 @@ class PublicIPAddress:
|
|||||||
return PublicIPAddress(apiclient.associateIpAddress(cmd).__dict__)
|
return PublicIPAddress(apiclient.associateIpAddress(cmd).__dict__)
|
||||||
|
|
||||||
def delete(self, apiclient):
|
def delete(self, apiclient):
|
||||||
"""Dissociate Public IP address"""
|
"""Dissociate Public IP address using the given ID"""
|
||||||
cmd = disassociateIpAddress.disassociateIpAddressCmd()
|
cmd = disassociateIpAddress.disassociateIpAddressCmd()
|
||||||
cmd.id = self.ipaddress.id
|
cmd.id = self.ipaddress.id
|
||||||
apiclient.disassociateIpAddress(cmd)
|
apiclient.disassociateIpAddress(cmd)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def delete_by_ip(self, apiclient):
|
||||||
|
"""Dissociate Public IP address using the given IP address"""
|
||||||
|
cmd = disassociateIpAddress.disassociateIpAddressCmd()
|
||||||
|
cmd.ipaddress = self.ipaddress.ipaddress
|
||||||
|
apiclient.disassociateIpAddress(cmd)
|
||||||
|
return
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def list(cls, apiclient, **kwargs):
|
def list(cls, apiclient, **kwargs):
|
||||||
"""List all Public IPs matching criteria"""
|
"""List all Public IPs matching criteria"""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user