Userdata to display static NAT as public ip instead of VR ip (#3862)

* Userdata to display static NAT as public ip instead of VR ip

If static nat is enabled on VM then metadata service should return
the static nat instead of gateway IP.
If static not is not enabled then it should return the gateway IP
as the public IP

Test results:

Step to reproduce:

1. Create a vm
2. Ssh to vm.
3. Run the below command inside the vm
wget http://<VR public ip>/latest/meta-data/public-ipv4

Note down the output of the above command
4. Now acquire a new public and enable static NAT on that IP to this vm
5. Now run the same command mentioned above in the VM
This should display the static NAT ip instead of VR public IP

Output:

Before enabling static nat

wget http://10.10.10.40/latest/meta-data/public-ipv4
$ cat public-ipv4
10.10.10.29

After enabling static nat

wget http://10.10.10.40/latest/meta-data/public-ipv4
$ cat public-ipv4
10.11.10.30

* server: apply vm user data when release a public ip

Co-authored-by: Wei Zhou <ustcweizhou@gmail.com>
This commit is contained in:
Andrija Panic 2020-03-05 12:49:17 +01:00 committed by GitHub
parent 897224a319
commit 9c6b02fd8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 11 deletions

View File

@ -188,9 +188,11 @@ public class CommandSetupHelper {
public void createVmDataCommand(final VirtualRouter router, final UserVm vm, final NicVO nic, final String publicKey, final Commands cmds) { public void createVmDataCommand(final VirtualRouter router, final UserVm vm, final NicVO nic, final String publicKey, final Commands cmds) {
final String serviceOffering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId()).getDisplayText(); final String serviceOffering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId()).getDisplayText();
final String zoneName = _dcDao.findById(router.getDataCenterId()).getName(); final String zoneName = _dcDao.findById(router.getDataCenterId()).getName();
final IPAddressVO staticNatIp = _ipAddressDao.findByVmIdAndNetworkId(nic.getNetworkId(), vm.getId());
cmds.addCommand( cmds.addCommand(
"vmdata", "vmdata",
generateVmDataCommand(router, nic.getIPv4Address(), vm.getUserData(), serviceOffering, zoneName, nic.getIPv4Address(), vm.getHostName(), vm.getInstanceName(), generateVmDataCommand(router, nic.getIPv4Address(), vm.getUserData(), serviceOffering, zoneName,
staticNatIp == null || staticNatIp.getState() != IpAddress.State.Allocated ? null : staticNatIp.getAddress().addr(), vm.getHostName(), vm.getInstanceName(),
vm.getId(), vm.getUuid(), publicKey, nic.getNetworkId())); vm.getId(), vm.getUuid(), publicKey, nic.getNetworkId()));
} }
@ -1035,7 +1037,7 @@ public class CommandSetupHelper {
} }
private VmDataCommand generateVmDataCommand(final VirtualRouter router, final String vmPrivateIpAddress, final String userData, final String serviceOffering, private VmDataCommand generateVmDataCommand(final VirtualRouter router, final String vmPrivateIpAddress, final String userData, final String serviceOffering,
final String zoneName, final String guestIpAddress, final String vmName, final String vmInstanceName, final long vmId, final String vmUuid, final String publicKey, final String zoneName, final String publicIpAddress, final String vmName, final String vmInstanceName, final long vmId, final String vmUuid, final String publicKey,
final long guestNetworkId) { final long guestNetworkId) {
final VmDataCommand cmd = new VmDataCommand(vmPrivateIpAddress, vmName, _networkModel.getExecuteInSeqNtwkElmtCmd()); final VmDataCommand cmd = new VmDataCommand(vmPrivateIpAddress, vmName, _networkModel.getExecuteInSeqNtwkElmtCmd());
@ -1049,18 +1051,21 @@ public class CommandSetupHelper {
cmd.addVmData("userdata", "user-data", userData); cmd.addVmData("userdata", "user-data", userData);
cmd.addVmData("metadata", "service-offering", StringUtils.unicodeEscape(serviceOffering)); cmd.addVmData("metadata", "service-offering", StringUtils.unicodeEscape(serviceOffering));
cmd.addVmData("metadata", "availability-zone", StringUtils.unicodeEscape(zoneName)); cmd.addVmData("metadata", "availability-zone", StringUtils.unicodeEscape(zoneName));
cmd.addVmData("metadata", "local-ipv4", guestIpAddress); cmd.addVmData("metadata", "local-ipv4", vmPrivateIpAddress);
cmd.addVmData("metadata", "local-hostname", StringUtils.unicodeEscape(vmName)); cmd.addVmData("metadata", "local-hostname", StringUtils.unicodeEscape(vmName));
if (dcVo.getNetworkType() == NetworkType.Basic) {
cmd.addVmData("metadata", "public-ipv4", guestIpAddress); Network network = _networkDao.findById(guestNetworkId);
if (dcVo.getNetworkType() == NetworkType.Basic || network.getGuestType() == Network.GuestType.Shared) {
cmd.addVmData("metadata", "public-ipv4", vmPrivateIpAddress);
cmd.addVmData("metadata", "public-hostname", StringUtils.unicodeEscape(vmName)); cmd.addVmData("metadata", "public-hostname", StringUtils.unicodeEscape(vmName));
} else { } else {
if (router.getPublicIpAddress() == null) { if (publicIpAddress != null) {
cmd.addVmData("metadata", "public-ipv4", guestIpAddress); cmd.addVmData("metadata", "public-ipv4", publicIpAddress);
} else { cmd.addVmData("metadata", "public-hostname", publicIpAddress);
} else if (router.getPublicIpAddress() != null) {
cmd.addVmData("metadata", "public-ipv4", router.getPublicIpAddress()); cmd.addVmData("metadata", "public-ipv4", router.getPublicIpAddress());
cmd.addVmData("metadata", "public-hostname", router.getPublicIpAddress());
} }
cmd.addVmData("metadata", "public-hostname", router.getPublicIpAddress());
} }
if (vmUuid == null) { if (vmUuid == null) {
cmd.addVmData("metadata", "instance-id", vmInstanceName); cmd.addVmData("metadata", "instance-id", vmInstanceName);

View File

@ -24,6 +24,12 @@ import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
import com.cloud.network.element.UserDataServiceProvider;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.vm.NicProfile;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.VirtualMachineProfileImpl;
import org.apache.cloudstack.api.command.user.firewall.ListPortForwardingRulesCmd; import org.apache.cloudstack.api.command.user.firewall.ListPortForwardingRulesCmd;
import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
@ -145,6 +151,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
LoadBalancerVMMapDao _loadBalancerVMMapDao; LoadBalancerVMMapDao _loadBalancerVMMapDao;
@Inject @Inject
VpcService _vpcSvc; VpcService _vpcSvc;
@Inject
VMTemplateDao _templateDao;
protected void checkIpAndUserVm(IpAddress ipAddress, UserVm userVm, Account caller, Boolean ignoreVmState) { protected void checkIpAndUserVm(IpAddress ipAddress, UserVm userVm, Account caller, Boolean ignoreVmState) {
if (ipAddress == null || ipAddress.getAllocatedTime() == null || ipAddress.getAllocatedToAccountId() == null) { if (ipAddress == null || ipAddress.getAllocatedTime() == null || ipAddress.getAllocatedToAccountId() == null) {
@ -597,6 +605,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
// enable static nat on the backend // enable static nat on the backend
s_logger.trace("Enabling static nat for ip address " + ipAddress + " and vm id=" + vmId + " 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)) { if (applyStaticNatForIp(ipId, false, caller, false)) {
applyUserData(vmId, network, guestNic);
performedIpAssoc = false; // ignor unassignIPFromVpcNetwork in finally block performedIpAssoc = false; // ignor unassignIPFromVpcNetwork in finally block
return true; return true;
} else { } else {
@ -620,6 +629,24 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
return false; return false;
} }
protected void applyUserData(long vmId, Network network, Nic guestNic) throws ResourceUnavailableException {
UserVmVO vm = _vmDao.findById(vmId);
VMTemplateVO template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId());
NicProfile nicProfile = new NicProfile(guestNic, network, null, null, null,
_networkModel.isSecurityGroupSupportedInNetwork(network),
_networkModel.getNetworkTag(template.getHypervisorType(), network));
VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl(vm);
UserDataServiceProvider element = _networkModel.getUserDataUpdateProvider(network);
if (element == null) {
s_logger.error("Can't find network element for " + Service.UserData.getName() + " provider needed for UserData update");
} else {
boolean result = element.saveUserData(network, nicProfile, vmProfile);
if (!result) {
s_logger.error("Failed to update userdata for vm " + vm + " and nic " + guestNic);
}
}
}
protected void isIpReadyForStaticNat(long vmId, IPAddressVO ipAddress, String vmIp, Account caller, long callerUserId) throws NetworkRuleConflictException, protected void isIpReadyForStaticNat(long vmId, IPAddressVO ipAddress, String vmIp, Account caller, long callerUserId) throws NetworkRuleConflictException,
ResourceUnavailableException { ResourceUnavailableException {
if (ipAddress.isSourceNat()) { if (ipAddress.isSourceNat()) {
@ -1096,6 +1123,10 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
revokeStaticNatRuleInternal(rule.getId(), caller, userId, false); revokeStaticNatRuleInternal(rule.getId(), caller, userId, false);
} }
IPAddressVO ipAddress = _ipAddressDao.findById(ipId);
Long vmId = ipAddress.getAssociatedWithVmId();
Long networkId = ipAddress.getAssociatedWithNetworkId();
boolean success = true; boolean success = true;
// revoke all port forwarding rules // revoke all port forwarding rules
@ -1105,7 +1136,17 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
success = success && applyStaticNatRulesForIp(ipId, _ipAddrMgr.RulesContinueOnError.value(), caller, true); success = success && applyStaticNatRulesForIp(ipId, _ipAddrMgr.RulesContinueOnError.value(), caller, true);
// revoke static nat for the ip address // revoke static nat for the ip address
success = success && applyStaticNatForIp(ipId, false, caller, true); if (vmId != null && networkId != null) {
Network guestNetwork = _networkModel.getNetwork(networkId);
Nic guestNic = _networkModel.getNicInNetwork(vmId, guestNetwork.getId());
if (applyStaticNatForIp(ipId, false, caller, true)) {
if (ipAddress.getState() == IpAddress.State.Releasing) {
applyUserData(vmId, guestNetwork, guestNic);
}
} else {
success = false;
}
}
// Now we check again in case more rules have been inserted. // Now we check again in case more rules have been inserted.
rules.addAll(_portForwardingDao.listByIpAndNotRevoked(ipId)); rules.addAll(_portForwardingDao.listByIpAndNotRevoked(ipId));
@ -1243,7 +1284,12 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
} }
} }
return disableStaticNat(ipId, caller, ctx.getCallingUserId(), false); if (disableStaticNat(ipId, caller, ctx.getCallingUserId(), false)) {
Nic guestNic = _networkModel.getNicInNetworkIncludingRemoved(vmId, guestNetwork.getId());
applyUserData(vmId, guestNetwork, guestNic);
return true;
}
return false;
} }
@Override @Override