From bef2f533ec8b5cc8e6a83ba47b40086ecc8a9444 Mon Sep 17 00:00:00 2001 From: Rakesh Venkatesh Date: Thu, 20 Feb 2020 10:34:13 +0100 Subject: [PATCH 1/2] 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:///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 --- .../network/router/CommandSetupHelper.java | 23 ++++++++----- .../cloud/network/rules/RulesManagerImpl.java | 34 ++++++++++++++++++- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 0fe9dc32c8b5..163ecdd69cdc 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -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) { final String serviceOffering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId()).getDisplayText(); final String zoneName = _dcDao.findById(router.getDataCenterId()).getName(); + final IPAddressVO staticNatIp = _ipAddressDao.findByVmIdAndNetworkId(nic.getNetworkId(), vm.getId()); cmds.addCommand( "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 ? null : staticNatIp.getAddress().addr(), vm.getHostName(), vm.getInstanceName(), vm.getId(), vm.getUuid(), publicKey, nic.getNetworkId())); } @@ -1010,7 +1012,7 @@ public SetupGuestNetworkCommand createSetupGuestNetworkCommand(final DomainRoute } 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 VmDataCommand cmd = new VmDataCommand(vmPrivateIpAddress, vmName, _networkModel.getExecuteInSeqNtwkElmtCmd()); @@ -1024,18 +1026,21 @@ private VmDataCommand generateVmDataCommand(final VirtualRouter router, final St cmd.addVmData("userdata", "user-data", userData); cmd.addVmData("metadata", "service-offering", StringUtils.unicodeEscape(serviceOffering)); 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)); - 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)); } else { - if (router.getPublicIpAddress() == null) { - cmd.addVmData("metadata", "public-ipv4", guestIpAddress); - } else { + if (publicIpAddress != null) { + cmd.addVmData("metadata", "public-ipv4", publicIpAddress); + cmd.addVmData("metadata", "public-hostname", publicIpAddress); + } else if (router.getPublicIpAddress() != null) { cmd.addVmData("metadata", "public-ipv4", router.getPublicIpAddress()); + cmd.addVmData("metadata", "public-hostname", router.getPublicIpAddress()); } - cmd.addVmData("metadata", "public-hostname", router.getPublicIpAddress()); } if (vmUuid == null) { cmd.addVmData("metadata", "instance-id", vmInstanceName); diff --git a/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java b/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java index aea24a49ee5c..9532b61c9a24 100644 --- a/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java @@ -24,6 +24,12 @@ 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.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; @@ -145,6 +151,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules LoadBalancerVMMapDao _loadBalancerVMMapDao; @Inject VpcService _vpcSvc; + @Inject + VMTemplateDao _templateDao; protected void checkIpAndUserVm(IpAddress ipAddress, UserVm userVm, Account caller, Boolean ignoreVmState) { if (ipAddress == null || ipAddress.getAllocatedTime() == null || ipAddress.getAllocatedToAccountId() == null) { @@ -597,6 +605,7 @@ private boolean enableStaticNat(long ipId, long vmId, long networkId, boolean is // 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)) { + applyUserData(vmId, network, guestNic); performedIpAssoc = false; // ignor unassignIPFromVpcNetwork in finally block return true; } else { @@ -620,6 +629,24 @@ private boolean enableStaticNat(long ipId, long vmId, long networkId, boolean is 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, ResourceUnavailableException { if (ipAddress.isSourceNat()) { @@ -1243,7 +1270,12 @@ public boolean disableStaticNat(long ipId) throws ResourceUnavailableException, } } - 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 From e77d23e8f943d4fbb6912573598ff584d377e60c Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 24 Feb 2020 20:46:23 +0000 Subject: [PATCH 2/2] server: apply vm user data when release a public ip --- .../cloud/network/router/CommandSetupHelper.java | 2 +- .../cloud/network/rules/RulesManagerImpl.java | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 163ecdd69cdc..caf2e50ee86f 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -192,7 +192,7 @@ public void createVmDataCommand(final VirtualRouter router, final UserVm vm, fin cmds.addCommand( "vmdata", generateVmDataCommand(router, nic.getIPv4Address(), vm.getUserData(), serviceOffering, zoneName, - staticNatIp == null ? null : staticNatIp.getAddress().addr(), vm.getHostName(), vm.getInstanceName(), + staticNatIp == null || staticNatIp.getState() != IpAddress.State.Allocated ? null : staticNatIp.getAddress().addr(), vm.getHostName(), vm.getInstanceName(), vm.getId(), vm.getUuid(), publicKey, nic.getNetworkId())); } diff --git a/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java b/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java index 9532b61c9a24..de567749043f 100644 --- a/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java @@ -1123,6 +1123,10 @@ public boolean revokeAllPFAndStaticNatRulesForIp(long ipId, long userId, Account revokeStaticNatRuleInternal(rule.getId(), caller, userId, false); } + IPAddressVO ipAddress = _ipAddressDao.findById(ipId); + Long vmId = ipAddress.getAssociatedWithVmId(); + Long networkId = ipAddress.getAssociatedWithNetworkId(); + boolean success = true; // revoke all port forwarding rules @@ -1132,7 +1136,17 @@ public boolean revokeAllPFAndStaticNatRulesForIp(long ipId, long userId, Account success = success && applyStaticNatRulesForIp(ipId, _ipAddrMgr.RulesContinueOnError.value(), caller, true); // 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. rules.addAll(_portForwardingDao.listByIpAndNotRevoked(ipId));