From 1a0a61fd9f616213998bb767915d4b08cac4f38c Mon Sep 17 00:00:00 2001 From: Marcus Sorensen Date: Thu, 22 Sep 2022 03:44:21 -0600 Subject: [PATCH] Allow option of exposing VM domain info via instance metadata (#6710) This PR allows the cloud admin to set either a global or domain-specific value "metadata.allow.expose.domain", and when set this allows the VM to see the name and ID of the immediate domain that contains the VM in instance metadata. This can be useful or a variety of things such as bootstrapping VM configuration and access according to domain. This PR also deletes the CloudZonesNetworkElement because it isn't referred to anywhere, and there was initially some confusion as to whether this code needed to be updated when extending metadata. If it needs to be kept we can remove that delete from the PR. Signed-off-by: Marcus Sorensen Co-authored-by: Marcus Sorensen Co-authored-by: dahn Co-authored-by: Daniel Augusto Veronezi Salvador <38945620+GutoVeronezi@users.noreply.github.com> --- .../java/com/cloud/network/NetworkModel.java | 17 +- .../com/cloud/vm/VirtualMachineManager.java | 3 + .../cloud/vm/VirtualMachineManagerImpl.java | 4 +- .../com/cloud/network/NetworkModelImpl.java | 14 + .../element/CloudZonesNetworkElement.java | 270 ------------------ .../network/router/CommandSetupHelper.java | 21 +- .../ConfigDriveNetworkElementTest.java | 8 + systemvm/debian/var/www/html/latest/.htaccess | 2 + .../integration/component/test_configdrive.py | 42 +++ 9 files changed, 99 insertions(+), 282 deletions(-) delete mode 100644 server/src/main/java/com/cloud/network/element/CloudZonesNetworkElement.java diff --git a/api/src/main/java/com/cloud/network/NetworkModel.java b/api/src/main/java/com/cloud/network/NetworkModel.java index c27290f902d..60f1aff3c62 100644 --- a/api/src/main/java/com/cloud/network/NetworkModel.java +++ b/api/src/main/java/com/cloud/network/NetworkModel.java @@ -70,15 +70,20 @@ public interface NetworkModel { String PUBLIC_KEYS_FILE = "public-keys"; String CLOUD_IDENTIFIER_FILE = "cloud-identifier"; String HYPERVISOR_HOST_NAME_FILE = "hypervisor-host-name"; + String CLOUD_DOMAIN_FILE = "cloud-domain"; + String CLOUD_DOMAIN_ID_FILE = "cloud-domain-id"; int CONFIGDATA_DIR = 0; int CONFIGDATA_FILE = 1; int CONFIGDATA_CONTENT = 2; - ImmutableMap openStackFileMapping = ImmutableMap.of( - AVAILABILITY_ZONE_FILE, "availability_zone", - LOCAL_HOSTNAME_FILE, "hostname", - VM_ID_FILE, "uuid", - PUBLIC_HOSTNAME_FILE, "name" - ); + ImmutableMap openStackFileMapping = ImmutableMap.builder() + .put(AVAILABILITY_ZONE_FILE, "availability_zone") + .put(LOCAL_HOSTNAME_FILE, "hostname") + .put(VM_ID_FILE, "uuid") + .put(PUBLIC_HOSTNAME_FILE, "name") + .put(CLOUD_DOMAIN_FILE, CLOUD_DOMAIN_FILE) + .put(CLOUD_DOMAIN_ID_FILE, CLOUD_DOMAIN_ID_FILE) + .put(HYPERVISOR_HOST_NAME_FILE, HYPERVISOR_HOST_NAME_FILE) + .build(); static final ConfigKey MACIdentifier = new ConfigKey("Advanced",Integer.class, "mac.identifier", "0", "This value will be used while generating the mac addresses for isolated and shared networks. The hexadecimal equivalent value will be present at the 2nd octet of the mac address. Default value is null which means this feature is disabled.Its scope is global.", true, ConfigKey.Scope.Global); diff --git a/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java index 9ee2c2aa7ab..7b8ae5790a1 100644 --- a/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java +++ b/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java @@ -79,6 +79,9 @@ public interface VirtualMachineManager extends Manager { ConfigKey AllowExposeHypervisorHostname = new ConfigKey("Advanced", Boolean.class, "global.allow.expose.host.hostname", "false", "If set to true, it allows the hypervisor host name on which the VM is spawned on to be exposed to the VM", true, ConfigKey.Scope.Global); + ConfigKey AllowExposeDomainInMetadata = new ConfigKey<>("Advanced", Boolean.class, "metadata.allow.expose.domain", + "false", "If set to true, it allows the VM's domain to be seen in metadata.", true, ConfigKey.Scope.Domain); + interface Topics { String VM_POWER_STATE = "vm.powerstate"; } diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index a1831a5cacd..84cc1bab42d 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -4611,7 +4611,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac return new ConfigKey[] { ClusterDeltaSyncInterval, StartRetry, VmDestroyForcestop, VmOpCancelInterval, VmOpCleanupInterval, VmOpCleanupWait, VmOpLockStateRetry, VmOpWaitInterval, ExecuteInSequence, VmJobCheckInterval, VmJobTimeout, VmJobStateReportInterval, VmConfigDriveLabel, VmConfigDriveOnPrimaryPool, VmConfigDriveForceHostCacheUse, VmConfigDriveUseHostCacheOnUnsupportedPool, - HaVmRestartHostUp, ResourceCountRunningVMsonly, AllowExposeHypervisorHostname, AllowExposeHypervisorHostnameAccountLevel, SystemVmRootDiskSize }; + HaVmRestartHostUp, ResourceCountRunningVMsonly, AllowExposeHypervisorHostname, AllowExposeHypervisorHostnameAccountLevel, SystemVmRootDiskSize, + AllowExposeDomainInMetadata + }; } public List getStoragePoolAllocators() { diff --git a/server/src/main/java/com/cloud/network/NetworkModelImpl.java b/server/src/main/java/com/cloud/network/NetworkModelImpl.java index d183ba0dd92..6f242c2a7b8 100644 --- a/server/src/main/java/com/cloud/network/NetworkModelImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkModelImpl.java @@ -34,6 +34,8 @@ import java.util.TreeSet; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.domain.Domain; +import com.cloud.vm.VirtualMachineManager; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; @@ -2555,6 +2557,10 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi final String zoneName = dcVo.getName(); IPAddressVO publicIp = _ipAddressDao.findByAssociatedVmId(vmId); + VirtualMachine vm = _vmDao.findById(vmId); + if (vm == null) { + throw new CloudRuntimeException(String.format("Cannot generate VM instance data, no VM exists by ID: %d", vmId)); + } final List vmData = new ArrayList(); @@ -2623,6 +2629,14 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi vmData.add(new String[]{PASSWORD_DIR, PASSWORD_FILE, password}); } vmData.add(new String[]{METATDATA_DIR, HYPERVISOR_HOST_NAME_FILE, hostname}); + + Domain domain = _domainDao.findById(vm.getDomainId()); + if (domain != null && VirtualMachineManager.AllowExposeDomainInMetadata.valueIn(domain.getId())) { + s_logger.debug("Adding domain info to cloud metadata"); + vmData.add(new String[]{METATDATA_DIR, CLOUD_DOMAIN_FILE, domain.getName()}); + vmData.add(new String[]{METATDATA_DIR, CLOUD_DOMAIN_ID_FILE, domain.getUuid()}); + } + return vmData; } diff --git a/server/src/main/java/com/cloud/network/element/CloudZonesNetworkElement.java b/server/src/main/java/com/cloud/network/element/CloudZonesNetworkElement.java deleted file mode 100644 index 848340b1a24..00000000000 --- a/server/src/main/java/com/cloud/network/element/CloudZonesNetworkElement.java +++ /dev/null @@ -1,270 +0,0 @@ -// 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 com.cloud.network.element; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import javax.inject.Inject; - -import org.apache.log4j.Logger; - -import com.cloud.agent.AgentManager; -import com.cloud.agent.api.Answer; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.routing.SavePasswordCommand; -import com.cloud.agent.api.routing.VmDataCommand; -import com.cloud.agent.manager.Commands; -import com.cloud.configuration.ConfigurationManager; -import com.cloud.configuration.ZoneConfig; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.dao.DataCenterDao; -import com.cloud.deploy.DeployDestination; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.OperationTimedoutException; -import com.cloud.exception.ResourceUnavailableException; -import com.cloud.network.Network; -import com.cloud.network.Network.Capability; -import com.cloud.network.Network.Provider; -import com.cloud.network.Network.Service; -import com.cloud.network.NetworkModel; -import com.cloud.network.Networks.TrafficType; -import com.cloud.network.PhysicalNetworkServiceProvider; -import com.cloud.network.dao.NetworkDao; -import com.cloud.offering.NetworkOffering; -import com.cloud.service.dao.ServiceOfferingDao; -import com.cloud.utils.component.AdapterBase; -import com.cloud.vm.NicProfile; -import com.cloud.vm.ReservationContext; -import com.cloud.vm.UserVmManager; -import com.cloud.vm.UserVmVO; -import com.cloud.vm.VirtualMachine; -import com.cloud.vm.VirtualMachineManager; -import com.cloud.vm.VirtualMachineProfile; -import com.cloud.vm.dao.DomainRouterDao; -import com.cloud.vm.dao.UserVmDao; - -public class CloudZonesNetworkElement extends AdapterBase implements NetworkElement, UserDataServiceProvider { - private static final Logger s_logger = Logger.getLogger(CloudZonesNetworkElement.class); - - private static final Map> capabilities = setCapabilities(); - - @Inject - NetworkDao _networkConfigDao; - @Inject - NetworkModel _networkMgr; - @Inject - UserVmManager _userVmMgr; - @Inject - UserVmDao _userVmDao; - @Inject - DomainRouterDao _routerDao; - @Inject - ConfigurationManager _configMgr; - @Inject - DataCenterDao _dcDao; - @Inject - AgentManager _agentManager; - @Inject - ServiceOfferingDao _serviceOfferingDao; - - private boolean canHandle(DeployDestination dest, TrafficType trafficType) { - DataCenterVO dc = (DataCenterVO)dest.getDataCenter(); - - if (dc.getDhcpProvider().equalsIgnoreCase(Provider.ExternalDhcpServer.getName())) { - _dcDao.loadDetails(dc); - String dhcpStrategy = dc.getDetail(ZoneConfig.DhcpStrategy.key()); - if ("external".equalsIgnoreCase(dhcpStrategy)) { - return true; - } - } - - return false; - } - - @Override - public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException, - ConcurrentOperationException, InsufficientCapacityException { - if (!canHandle(dest, offering.getTrafficType())) { - return false; - } - - return true; - } - - @Override - public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile vmProfile, DeployDestination dest, ReservationContext context) - throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { - return true; - } - - @Override - public boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) { - return true; - } - - @Override - public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { - return false; // assume that the agent will remove userdata etc - } - - @Override - public boolean destroy(Network config, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { - return false; // assume that the agent will remove userdata etc - } - - @Override - public Provider getProvider() { - return Provider.ExternalDhcpServer; - } - - @Override - public Map> getCapabilities() { - return capabilities; - } - - private static Map> setCapabilities() { - Map> capabilities = new HashMap>(); - - capabilities.put(Service.UserData, null); - - return capabilities; - } - - private VmDataCommand generateVmDataCommand(String vmPrivateIpAddress, String userData, String serviceOffering, String zoneName, String guestIpAddress, - String vmName, String vmInstanceName, long vmId, String vmUuid, String publicKey, String hostname) { - VmDataCommand cmd = new VmDataCommand(vmPrivateIpAddress, vmName, _networkMgr.getExecuteInSeqNtwkElmtCmd()); - // if you add new metadata files, also edit systemvm/patches/debian/config/var/www/html/latest/.htaccess - cmd.addVmData("userdata", "user-data", userData); - cmd.addVmData("metadata", "service-offering", serviceOffering); - cmd.addVmData("metadata", "availability-zone", zoneName); - cmd.addVmData("metadata", "local-ipv4", guestIpAddress); - cmd.addVmData("metadata", "local-hostname", vmName); - cmd.addVmData("metadata", "public-ipv4", guestIpAddress); - cmd.addVmData("metadata", "public-hostname", guestIpAddress); - if (vmUuid == null) { - setVmInstanceId(vmInstanceName, vmId, cmd); - } else { - setVmInstanceId(vmUuid, cmd); - } - cmd.addVmData("metadata", "public-keys", publicKey); - cmd.addVmData("metadata", "hypervisor-host-name", hostname); - return cmd; - } - - private void setVmInstanceId(String vmUuid, VmDataCommand cmd) { - cmd.addVmData("metadata", "instance-id", vmUuid); - cmd.addVmData("metadata", "vm-id", vmUuid); - } - - private void setVmInstanceId(String vmInstanceName, long vmId, VmDataCommand cmd) { - cmd.addVmData("metadata", "instance-id", vmInstanceName); - cmd.addVmData("metadata", "vm-id", String.valueOf(vmId)); - } - - @Override - public boolean isReady(PhysicalNetworkServiceProvider provider) { - // TODO Auto-generated method stub - return true; - } - - @Override - public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException, - ResourceUnavailableException { - // TODO Auto-generated method stub - return true; - } - - @Override - public boolean canEnableIndividualServices() { - return false; - } - - @Override - public boolean addPasswordAndUserdata(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) - throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { - if (canHandle(dest, network.getTrafficType())) { - - if (vm.getType() != VirtualMachine.Type.User) { - return false; - } - @SuppressWarnings("unchecked") - UserVmVO uservm = _userVmDao.findById(vm.getId()); - _userVmDao.loadDetails(uservm); - String password = (String)vm.getParameter(VirtualMachineProfile.Param.VmPassword); - String userData = uservm.getUserData(); - String sshPublicKey = uservm.getDetail("SSH.PublicKey"); - - Commands cmds = new Commands(Command.OnError.Continue); - if (password != null && nic.isDefaultNic()) { - SavePasswordCommand cmd = new SavePasswordCommand(password, nic.getIPv4Address(), uservm.getHostName(), _networkMgr.getExecuteInSeqNtwkElmtCmd()); - cmds.addCommand("password", cmd); - } - String serviceOffering = _serviceOfferingDao.findByIdIncludingRemoved(uservm.getServiceOfferingId()).getDisplayText(); - String zoneName = _dcDao.findById(network.getDataCenterId()).getName(); - String destHostname = VirtualMachineManager.getHypervisorHostname(dest.getHost() != null ? dest.getHost().getName() : ""); - cmds.addCommand( - "vmdata", - generateVmDataCommand(nic.getIPv4Address(), userData, serviceOffering, zoneName, nic.getIPv4Address(), uservm.getHostName(), uservm.getInstanceName(), - uservm.getId(), uservm.getUuid(), sshPublicKey, destHostname)); - try { - _agentManager.send(dest.getHost().getId(), cmds); - } catch (OperationTimedoutException e) { - s_logger.debug("Unable to send vm data command to host " + dest.getHost()); - return false; - } - Answer dataAnswer = cmds.getAnswer("vmdata"); - if (dataAnswer != null && dataAnswer.getResult()) { - s_logger.info("Sent vm data successfully to vm " + uservm.getInstanceName()); - return true; - } - s_logger.info("Failed to send vm data to vm " + uservm.getInstanceName()); - return false; - } - return false; - } - - @Override - public boolean savePassword(Network network, NicProfile nic, VirtualMachineProfile vm) throws ResourceUnavailableException { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean saveSSHKey(Network network, NicProfile nic, VirtualMachineProfile vm, String sshPublicKey) throws ResourceUnavailableException { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean saveHypervisorHostname(NicProfile profile, Network network, VirtualMachineProfile vm, DeployDestination dest) throws ResourceUnavailableException { - return true; - } - - @Override - public boolean saveUserData(Network network, NicProfile nic, VirtualMachineProfile vm) throws ResourceUnavailableException { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean verifyServicesCombination(Set services) { - return true; - } -} 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 517b65b83e1..fe0f88c3388 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -26,6 +26,8 @@ import java.util.Map; import javax.inject.Inject; +import com.cloud.domain.Domain; +import com.cloud.domain.dao.DomainDao; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; @@ -149,6 +151,8 @@ public class CommandSetupHelper { @Inject private EntityManager _entityMgr; + @Inject + private DomainDao domainDao; @Inject private NicDao _nicDao; @Inject @@ -210,11 +214,18 @@ public class CommandSetupHelper { Host host = _hostDao.findById(vm.getHostId()); String destHostname = VirtualMachineManager.getHypervisorHostname(host != null ? host.getName() : ""); - cmds.addCommand( - "vmdata", - 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(), destHostname)); + VmDataCommand vmDataCommand = 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(), destHostname); + + Domain domain = domainDao.findById(vm.getDomainId()); + if (domain != null && VirtualMachineManager.AllowExposeDomainInMetadata.valueIn(domain.getId())) { + s_logger.debug("Adding domain info to cloud metadata"); + vmDataCommand.addVmData(NetworkModel.METATDATA_DIR, NetworkModel.CLOUD_DOMAIN_FILE, domain.getName()); + vmDataCommand.addVmData(NetworkModel.METATDATA_DIR, NetworkModel.CLOUD_DOMAIN_ID_FILE, domain.getUuid()); + } + + cmds.addCommand("vmdata", vmDataCommand); } } diff --git a/server/src/test/java/com/cloud/network/element/ConfigDriveNetworkElementTest.java b/server/src/test/java/com/cloud/network/element/ConfigDriveNetworkElementTest.java index ab3489f36b8..06ec0b019b7 100644 --- a/server/src/test/java/com/cloud/network/element/ConfigDriveNetworkElementTest.java +++ b/server/src/test/java/com/cloud/network/element/ConfigDriveNetworkElementTest.java @@ -36,6 +36,8 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; @@ -119,6 +121,7 @@ public class ConfigDriveNetworkElementTest { private final String VMUSERDATA = "H4sIABCvw1oAAystTi1KSSxJ5AIAUPllwQkAAAA="; private final long SOID = 31L; private final long HOSTID = NETWORK_ID; + private final long DOMAINID = 1L; @Mock private DataCenter dataCenter; @Mock private ConfigurationDao _configDao; @@ -134,6 +137,7 @@ public class ConfigDriveNetworkElementTest { @Mock private NetworkDao _networkDao; @Mock private NetworkServiceMapDao _ntwkSrvcDao; @Mock private IPAddressDao _ipAddressDao; + @Mock private DomainDao _domainDao; @Mock private DataCenterVO dataCenterVO; @Mock private DataStore dataStore; @@ -151,6 +155,7 @@ public class ConfigDriveNetworkElementTest { @Mock private IPAddressVO publicIp; @Mock private AgentManager agentManager; @Mock private CallContext callContextMock; + @Mock private DomainVO domainVO; @InjectMocks private final ConfigDriveNetworkElement _configDrivesNetworkElement = new ConfigDriveNetworkElement(); @InjectMocks @Spy private NetworkModelImpl _networkModel = new NetworkModelImpl(); @@ -164,8 +169,10 @@ public class ConfigDriveNetworkElementTest { when(_dataStoreMgr.getImageStoreWithFreeCapacity(DATACENTERID)).thenReturn(dataStore); when(_ep.select(dataStore)).thenReturn(endpoint); when(_vmDao.findById(VMID)).thenReturn(virtualMachine); + when(_vmInstanceDao.findById(VMID)).thenReturn(virtualMachine); when(_dcDao.findById(DATACENTERID)).thenReturn(dataCenterVO); when(_hostDao.findById(HOSTID)).thenReturn(hostVO); + when(_domainDao.findById(DOMAINID)).thenReturn(domainVO); doReturn(nic).when(_networkModel).getDefaultNic(VMID); when(_serviceOfferingDao.findByIdIncludingRemoved(VMID, SOID)).thenReturn(serviceOfferingVO); when(_guestOSDao.findById(anyLong())).thenReturn(guestOSVO); @@ -185,6 +192,7 @@ public class ConfigDriveNetworkElementTest { when(virtualMachine.getInstanceName()).thenReturn(VMINSTANCENAME); when(virtualMachine.getUserData()).thenReturn(VMUSERDATA); when(virtualMachine.getHostName()).thenReturn(VMHOSTNAME); + when(virtualMachine.getDomainId()).thenReturn(DOMAINID); when(dataCenter.getId()).thenReturn(DATACENTERID); when(deployDestination.getHost()).thenReturn(hostVO); when(deployDestination.getDataCenter()).thenReturn(dataCenter); diff --git a/systemvm/debian/var/www/html/latest/.htaccess b/systemvm/debian/var/www/html/latest/.htaccess index 725e7e112a6..ebbed4afb85 100644 --- a/systemvm/debian/var/www/html/latest/.htaccess +++ b/systemvm/debian/var/www/html/latest/.htaccess @@ -21,3 +21,5 @@ RewriteRule ^public-ipv4/?$ ../metadata/%{REMOTE_ADDR}/public-ipv4 [L,NC,QSA] RewriteRule ^public-keys/?$ ../metadata/%{REMOTE_ADDR}/public-keys [L,NC,QSA] RewriteRule ^service-offering/?$ ../metadata/%{REMOTE_ADDR}/service-offering [L,NC,QSA] RewriteRule ^vm-id/?$ ../metadata/%{REMOTE_ADDR}/vm-id [L,NC,QSA] +RewriteRule ^cloud-domain/?$ ../metadata/%{REMOTE_ADDR}/vm-id [L,NC,QSA] +RewriteRule ^cloud-domain-id/?$ ../metadata/%{REMOTE_ADDR}/vm-id [L,NC,QSA] diff --git a/test/integration/component/test_configdrive.py b/test/integration/component/test_configdrive.py index 3df175f672f..b8ce4bdde5b 100644 --- a/test/integration/component/test_configdrive.py +++ b/test/integration/component/test_configdrive.py @@ -552,6 +552,18 @@ class ConfigDriveUtils: if exposeHypevisorHostnameGS == 'true' and exposeHypevisorHostnameAcc == 'true': vm_files.append("hypervisor-host-name.txt") + configs = Configurations.list( + self.api_client, + name="metadata.allow.expose.domain", + listall=True + ) + + exposeDomain = configs[0].value + + if exposeDomain == 'true': + vm_files.append("cloud-domain.txt") + vm_files.append("cloud-domain-id.txt") + def get_name(vm_file): return "{} metadata".format( vm_file.split('.'[-1].replace('-', ' ')) @@ -604,6 +616,18 @@ class ConfigDriveUtils: "on which the VM is spawned" ) + if exposeDomain == 'true': + self.assertEqual( + str(metadata["cloud-domain-id.txt"]), + self.domain.id, + "Domain name in the metadata file does not match expected" + ) + self.assertEqual( + str(metadata["cloud-domain.txt"]), + self.domain.name, + "Domain name in the metadata file does not match expected" + ) + return def _verify_openstack_metadata(self, ssh, mount_path): @@ -2441,6 +2465,12 @@ class TestConfigDrive(cloudstackTestCase, ConfigDriveUtils): value="true" ) + # Enable domain in metadata + Configurations.update(self.api_client, + name="metadata.allow.expose.domain", + value="true" + ) + # Verify that the above mentioned settings are set to true before proceeding if not is_config_suitable( apiclient=self.api_client, @@ -2454,6 +2484,12 @@ class TestConfigDrive(cloudstackTestCase, ConfigDriveUtils): value='true'): self.skipTest('Account level setting account.allow.expose.host.hostname should be true. skipping') + if not is_config_suitable( + apiclient=self.api_client, + name='metadata.allow.expose.domain', + value='true'): + self.skipTest('metadata.allow.expose.domain should be true. skipping') + # ===================================================================== self.debug("+++ Scenario: " "Deploy VM in the Tier 1 with user data") @@ -2513,5 +2549,11 @@ class TestConfigDrive(cloudstackTestCase, ConfigDriveUtils): value="false" ) + # Disable domain in metadata + Configurations.update(self.api_client, + name="metadata.allow.expose.domain", + value="false" + ) + self.delete(vm, expunge=True) self.delete(network1)