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 <mls@apple.com>
Co-authored-by: Marcus Sorensen <mls@apple.com>
Co-authored-by: dahn <daan.hoogland@gmail.com>
Co-authored-by: Daniel Augusto Veronezi Salvador <38945620+GutoVeronezi@users.noreply.github.com>
This commit is contained in:
Marcus Sorensen 2022-09-22 03:44:21 -06:00 committed by GitHub
parent 434f15a9b2
commit 1a0a61fd9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 99 additions and 282 deletions

View File

@ -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<String, String> openStackFileMapping = ImmutableMap.of(
AVAILABILITY_ZONE_FILE, "availability_zone",
LOCAL_HOSTNAME_FILE, "hostname",
VM_ID_FILE, "uuid",
PUBLIC_HOSTNAME_FILE, "name"
);
ImmutableMap<String, String> openStackFileMapping = ImmutableMap.<String, String>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<Integer> MACIdentifier = new ConfigKey<Integer>("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);

View File

@ -79,6 +79,9 @@ public interface VirtualMachineManager extends Manager {
ConfigKey<Boolean> AllowExposeHypervisorHostname = new ConfigKey<Boolean>("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<Boolean> 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";
}

View File

@ -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<StoragePoolAllocator> getStoragePoolAllocators() {

View File

@ -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<String[]> vmData = new ArrayList<String[]>();
@ -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;
}

View File

@ -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<Service, Map<Capability, String>> 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<Service, Map<Capability, String>> getCapabilities() {
return capabilities;
}
private static Map<Service, Map<Capability, String>> setCapabilities() {
Map<Service, Map<Capability, String>> capabilities = new HashMap<Service, Map<Capability, String>>();
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<Service> services) {
return true;
}
}

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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]

View File

@ -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)