UserContext ctx = UserContext.current();
Account caller = ctx.getCaller();
UserContext.current().setEventDetails("Ip Id: " + ipId);
// Verify input parameters
IPAddressVO ipAddress = _ipAddressDao.findById(ipId);
if (ipAddress == null) {
throw new InvalidParameterValueException("Unable to find ip address by id " + ipId);
}
// Verify input parameters
boolean performedIpAssoc = false;
boolean isOneToOneNat = ipAddress.isOneToOneNat();
Long associatedWithVmId = ipAddress.getAssociatedWithVmId();
Nic guestNic;
NicSecondaryIpVO nicSecIp = null;
String dstIp = null;
try {
Network network = _networkModel.getNetwork(networkId);
if (network == null) {
throw new InvalidParameterValueException("Unable to find network by id");
}
// Check that vm has a nic in the network
guestNic = _networkModel.getNicInNetwork(vmId, networkId);
if (guestNic == null) {
throw new InvalidParameterValueException("Vm doesn't belong to the network with specified id");
}
dstIp = guestNic.getIp4Address();
if (!_networkModel.areServicesSupportedInNetwork(network.getId(), Service.StaticNat)) {
throw new InvalidParameterValueException("Unable to create static nat rule; StaticNat service is not " +
"supported in network with specified id");
}
if (!isSystemVm) {
UserVmVO vm = _vmDao.findById(vmId);
if (vm == null) {
throw new InvalidParameterValueException("Can't enable static nat for the address id=" + ipId +
", invalid virtual machine id specified (" + vmId + ").");
}
//associate ip address to network (if needed)
if (ipAddress.getAssociatedWithNetworkId() == null) {
boolean assignToVpcNtwk = network.getVpcId() != null
&& ipAddress.getVpcId() != null && ipAddress.getVpcId().longValue() == network.getVpcId();
if (assignToVpcNtwk) {
_networkModel.checkIpForService(ipAddress, Service.StaticNat, networkId);
s_logger.debug("The ip is not associated with the VPC network id="+ networkId + ", so assigning");
try {
ipAddress = _networkMgr.associateIPToGuestNetwork(ipId, networkId, false);
} catch (Exception ex) {
s_logger.warn("Failed to associate ip id=" + ipId + " to VPC network id=" + networkId + " as " +
"a part of enable static nat");
return false;
}
} else if (ipAddress.isPortable()) {
s_logger.info("Portable IP " + ipAddress.getUuid() + " is not associated with the network yet "
+ " so associate IP with the network " + networkId);
try {
// check if StaticNat service is enabled in the network
_networkModel.checkIpForService(ipAddress, Service.StaticNat, networkId);
// associate portable IP to vpc, if network is part of VPC
if (network.getVpcId() != null) {
_vpcMgr.associateIPToVpc(ipId, network.getVpcId());
}
// associate portable IP with guest network
ipAddress = _networkMgr.associatePortableIPToGuestNetwork(ipId, networkId, false);
} catch (Exception e) {
s_logger.warn("Failed to associate portable id=" + ipId + " to network id=" + networkId + " as " +
"a part of enable static nat");
return false;
}
}
} else if (ipAddress.getAssociatedWithNetworkId() != networkId) {
if (ipAddress.isPortable()) {
// check if destination network has StaticNat service enabled
_networkModel.checkIpForService(ipAddress, Service.StaticNat, networkId);
// check if portable IP can be transferred across the networks
if (_networkMgr.isPortableIpTransferableFromNetwork(ipId, ipAddress.getAssociatedWithNetworkId() )) {
try {
// transfer the portable IP and refresh IP details
_networkMgr.transferPortableIP(ipId, ipAddress.getAssociatedWithNetworkId(), networkId);
ipAddress = _ipAddressDao.findById(ipId);
} catch (Exception e) {
s_logger.warn("Failed to associate portable id=" + ipId + " to network id=" + networkId + " as " +
"a part of enable static nat");
return false;
}
} else {
throw new InvalidParameterValueException("Portable IP: " + ipId + " has associated services " +
"in network " + ipAddress.getAssociatedWithNetworkId() + " so can not be transferred to " +
" network " + networkId);
}
} else {
throw new InvalidParameterValueException("Invalid network Id=" + networkId + ". IP is associated with"
+ " a different network than passed network id");
}
} else {
_networkModel.checkIpForService(ipAddress, Service.StaticNat, null);
}
if (ipAddress.getAssociatedWithNetworkId() == null) {
throw new InvalidParameterValueException("Ip address " + ipAddress + " is not assigned to the network " + network);
}
// Check permissions
if (ipAddress.getSystem()) {
// when system is enabling static NAT on system IP's (for EIP) ignore VM state
checkIpAndUserVm(ipAddress, vm, caller, true);
} else {
checkIpAndUserVm(ipAddress, vm, caller, false);
}
//is static nat is for vm secondary ip
//dstIp = guestNic.getIp4Address();
if (vmGuestIp != null) {
//dstIp = guestNic.getIp4Address();
if (!dstIp.equals(vmGuestIp)) {
//check whether the secondary ip set to the vm or not
boolean secondaryIpSet = _networkMgr.isSecondaryIpSetForNic(guestNic.getId());
if (!secondaryIpSet) {
throw new InvalidParameterValueException("VM ip " + vmGuestIp + " address not belongs to the vm");
}
//check the ip belongs to the vm or not
nicSecIp = _nicSecondaryDao.findByIp4AddressAndNicId(vmGuestIp, guestNic.getId());
if (nicSecIp == null) {
throw new InvalidParameterValueException("VM ip " + vmGuestIp + " address not belongs to the vm");
}
dstIp = nicSecIp.getIp4Address();
// Set public ip column with the vm ip
}
}
// Verify ip address parameter
// checking vm id is not sufficient, check for the vm ip
isIpReadyForStaticNat(vmId, ipAddress, dstIp, caller, ctx.getCallerUserId());
}
ipAddress.setOneToOneNat(true);
ipAddress.setAssociatedWithVmId(vmId);
ipAddress.setVmIp(dstIp);
if (_ipAddressDao.update(ipAddress.getId(), ipAddress)) {
// enable static nat on the backend
s_logger.trace("Enabling static nat for ip address " + ipAddress + " and vm id=" + vmId + " on the backend");
if (applyStaticNatForIp(ipId, false, caller, false)) {
performedIpAssoc = false; // ignor unassignIPFromVpcNetwork in finally block
return true;
} else {
s_logger.warn("Failed to enable static nat rule for ip address " + ipId + " on the backend");
ipAddress.setOneToOneNat(isOneToOneNat);
ipAddress.setAssociatedWithVmId(associatedWithVmId);
ipAddress.setVmIp(null);
_ipAddressDao.update(ipAddress.getId(), ipAddress);
}
} else {
s_logger.warn("Failed to update ip address " + ipAddress + " in the DB as a part of enableStaticNat");
}
} finally {
if (performedIpAssoc) {
//if the rule is the last one for the ip address assigned to VPC, unassign it from the network
IpAddress ip = _ipAddressDao.findById(ipAddress.getId());
_vpcMgr.unassignIPFromVpcNetwork(ip.getId(), networkId);
}
}
return false;
}