server: Enable sending hypervior host name via metadata - VR and Config Drive (#3976)

Enable sending hypervisor host details via metadata for VR and Config Drive providers

Co-authored-by: Pearl Dsilva <pearl.dsilva@shapeblue.com>
This commit is contained in:
Pearl Dsilva 2020-07-01 08:44:11 +05:30 committed by GitHub
parent 8c1d749360
commit a73712ec4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1005 additions and 82 deletions

View File

@ -66,6 +66,7 @@ public interface NetworkModel {
String VM_ID_FILE = "vm-id";
String PUBLIC_KEYS_FILE = "public-keys";
String CLOUD_IDENTIFIER_FILE = "cloud-identifier";
String HYPERVISOR_HOST_NAME_FILE = "hypervisor-host-name";
int CONFIGDATA_DIR = 0;
int CONFIGDATA_FILE = 1;
int CONFIGDATA_CONTENT = 2;
@ -313,7 +314,7 @@ public interface NetworkModel {
boolean getNetworkEgressDefaultPolicy(Long networkId);
List<String[]> generateVmData(String userData, String serviceOffering, long datacenterId,
String vmName, String vmHostName, long vmId, String vmUuid, String guestIpAddress, String publicKey, String password, Boolean isWindows);
String vmName, String vmHostName, long vmId, String vmUuid, String guestIpAddress, String publicKey, String password, Boolean isWindows, String hostname);
String getValidNetworkCidr(Network guestNetwork);

View File

@ -34,4 +34,15 @@ public interface UserDataServiceProvider extends NetworkElement {
boolean saveUserData(Network network, NicProfile nic, VirtualMachineProfile vm) throws ResourceUnavailableException;
boolean saveSSHKey(Network network, NicProfile nic, VirtualMachineProfile vm, String sshPublicKey) throws ResourceUnavailableException;
/**
* Saves the hypervisor hostname in configdrive ISO or in the virtual router
* @param profile
* @param network
* @param vm
* @param dest
* @return
* @throws ResourceUnavailableException
*/
boolean saveHypervisorHostname(NicProfile profile, Network network, VirtualMachineProfile vm, DeployDestination dest) throws ResourceUnavailableException;
}

View File

@ -38,6 +38,10 @@ public interface VirtualMachineProfile {
void setVmData(List<String[]> vmData);
void setDisks(List<DiskTO> disks);
void setNics(List<NicProfile> nics);
String getConfigDriveLabel();
void setConfigDriveLabel(String configDriveLabel);

View File

@ -72,5 +72,4 @@ public class VmDataCommand extends NetworkElementCommand {
public void addVmData(String folder, String file, String contents) {
vmData.add(new String[] {folder, file, contents});
}
}

View File

@ -21,6 +21,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.ConfigKey;
import com.cloud.agent.api.to.NicTO;
@ -41,6 +42,7 @@ import com.cloud.offering.DiskOfferingInfo;
import com.cloud.offering.ServiceOffering;
import com.cloud.storage.StoragePool;
import com.cloud.template.VirtualMachineTemplate;
import com.cloud.user.Account;
import com.cloud.utils.component.Manager;
import com.cloud.utils.fsm.NoTransitionException;
@ -61,6 +63,12 @@ public interface VirtualMachineManager extends Manager {
ConfigKey<Boolean> ResoureCountRunningVMsonly = new ConfigKey<Boolean>("Advanced", Boolean.class, "resource.count.running.vms.only", "false",
"Count the resources of only running VMs in resource limitation.", true);
ConfigKey<Boolean> AllowExposeHypervisorHostnameAccountLevel = new ConfigKey<Boolean>("Advanced", Boolean.class, "account.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.Account);
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);
interface Topics {
String VM_POWER_STATE = "vm.powerstate";
}
@ -214,6 +222,12 @@ public interface VirtualMachineManager extends Manager {
boolean getExecuteInSequence(HypervisorType hypervisorType);
static String getHypervisorHostname(String name) {
final Account caller = CallContext.current().getCallingAccount();
String destHostname = (AllowExposeHypervisorHostname.value() && AllowExposeHypervisorHostnameAccountLevel.valueIn(caller.getId())) ? name : null;
return destHostname;
}
/**
* Unmanage a VM from CloudStack:
* - Remove the references of the VM and its volumes, nics, IPs from database

View File

@ -294,6 +294,16 @@ public interface NetworkOrchestrationService {
void finalizeUpdateInSequence(Network network, boolean success);
/**
* Adds hypervisor hostname to a file - hypervisor-host-name if the userdata
* service provider is ConfigDrive or VirtualRouter
* @param vm holds the details of the Virtual Machine
* @param dest holds information of the destination
* @param migrationSuccessful
* @throws ResourceUnavailableException in case Datastore or agent to which a command is to be sent is unavailable
*/
void setHypervisorHostname(VirtualMachineProfile vm, DeployDestination dest, boolean migrationSuccessful) throws ResourceUnavailableException;
List<NetworkGuru> getNetworkGurus();
/**

View File

@ -2432,7 +2432,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
protected void migrate(final VMInstanceVO vm, final long srcHostId, final DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException {
s_logger.info("Migrating " + vm + " to " + dest);
final UserVmVO userVm = _userVmDao.findById(vm.getId());
final long dstHostId = dest.getHost().getId();
final Host fromHost = _hostDao.findById(srcHostId);
if (fromHost == null) {
@ -2582,7 +2582,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
} catch (final OperationTimedoutException e) {
s_logger.debug("Error while checking the vm " + vm + " on host " + dstHostId, e);
}
migrated = true;
} finally {
if (!migrated) {
@ -2597,7 +2596,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
} catch (final AgentUnavailableException ae) {
s_logger.info("Looks like the destination Host is unavailable for cleanup");
}
_networkMgr.setHypervisorHostname(profile, dest, false);
try {
stateTransitTo(vm, Event.OperationFailed, srcHostId);
} catch (final NoTransitionException e) {
@ -2605,6 +2604,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
}
} else {
_networkMgr.commitNicForMigration(vmSrc, profile);
_networkMgr.setHypervisorHostname(profile, dest, true);
}
work.setStep(Step.Done);
@ -2906,6 +2906,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
vm.setLastHostId(srcHostId);
vm.setPodIdToDeployIn(destHost.getPodId());
moveVmToMigratingState(vm, destHostId, work);
List<String[]> vmData = null;
boolean migrated = false;
try {
@ -2916,7 +2917,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
Nic defaultNic = _networkModel.getDefaultNic(vm.getId());
List<String[]> vmData = null;
if (defaultNic != null) {
UserVmVO userVm = _userVmDao.findById(vm.getId());
Map<String, String> details = userVmDetailsDao.listDetailsKeyPairs(vm.getId());
@ -2926,9 +2926,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
if (_networkModel.isSharedNetworkWithoutServices(network.getId())) {
final String serviceOffering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId()).getDisplayText();
boolean isWindows = _guestOSCategoryDao.findById(_guestOSDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
vmData = _networkModel.generateVmData(userVm.getUserData(), serviceOffering, vm.getDataCenterId(), vm.getInstanceName(), vm.getHostName(), vm.getId(),
vm.getUuid(), defaultNic.getMacAddress(), userVm.getDetail("SSH.PublicKey"), (String) profile.getParameter(VirtualMachineProfile.Param.VmPassword), isWindows);
vm.getUuid(), defaultNic.getMacAddress(), userVm.getDetail("SSH.PublicKey"), (String) profile.getParameter(VirtualMachineProfile.Param.VmPassword), isWindows, VirtualMachineManager.getHypervisorHostname(destination.getHost().getName()));
String vmName = vm.getInstanceName();
String configDriveIsoRootFolder = "/tmp";
String isoFile = configDriveIsoRootFolder + "/" + vmName + "/configDrive/" + vmName + ".iso";
@ -2946,7 +2945,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
s_logger.debug("TIme out occured while exeuting command AttachOrDettachConfigDrive " + e.getMessage());
}
}
}
@ -2970,7 +2968,6 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
} catch (final OperationTimedoutException e) {
s_logger.warn("Error while checking the vm " + vm + " is on host " + destHost, e);
}
migrated = true;
} finally {
if (!migrated) {
@ -2987,6 +2984,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
} catch (final NoTransitionException e) {
s_logger.error("Error while transitioning vm from migrating to running state.", e);
}
_networkMgr.setHypervisorHostname(profile, destination, false);
} else {
_networkMgr.setHypervisorHostname(profile, destination, true);
}
work.setStep(Step.Done);
@ -4201,12 +4201,14 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
} catch (final AgentUnavailableException ae) {
s_logger.info("Looks like the destination Host is unavailable for cleanup");
}
_networkMgr.setHypervisorHostname(profile, dest, false);
try {
stateTransitTo(vm, Event.OperationFailed, srcHostId);
} catch (final NoTransitionException e) {
s_logger.warn(e.getMessage());
}
} else {
_networkMgr.setHypervisorHostname(profile, dest, true);
}
work.setStep(Step.Done);
@ -4464,7 +4466,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
return new ConfigKey<?>[] {ClusterDeltaSyncInterval, StartRetry, VmDestroyForcestop, VmOpCancelInterval, VmOpCleanupInterval, VmOpCleanupWait,
VmOpLockStateRetry,
VmOpWaitInterval, ExecuteInSequence, VmJobCheckInterval, VmJobTimeout, VmJobStateReportInterval, VmConfigDriveLabel, VmConfigDriveOnPrimaryPool, HaVmRestartHostUp,
ResoureCountRunningVMsonly };
ResoureCountRunningVMsonly, AllowExposeHypervisorHostname, AllowExposeHypervisorHostnameAccountLevel };
}
public List<StoragePoolAllocator> getStoragePoolAllocators() {

View File

@ -143,6 +143,7 @@ import com.cloud.network.dao.PhysicalNetworkVO;
import com.cloud.network.dao.RemoteAccessVpnDao;
import com.cloud.network.dao.RemoteAccessVpnVO;
import com.cloud.network.element.AggregatedCommandExecutor;
import com.cloud.network.element.ConfigDriveNetworkElement;
import com.cloud.network.element.DhcpServiceProvider;
import com.cloud.network.element.DnsServiceProvider;
import com.cloud.network.element.IpDeployer;
@ -151,6 +152,7 @@ import com.cloud.network.element.NetworkElement;
import com.cloud.network.element.RedundantResource;
import com.cloud.network.element.StaticNatServiceProvider;
import com.cloud.network.element.UserDataServiceProvider;
import com.cloud.network.element.VirtualRouterElement;
import com.cloud.network.guru.NetworkGuru;
import com.cloud.network.guru.NetworkGuruAdditionalFunctions;
import com.cloud.network.lb.LoadBalancingRulesManager;
@ -1614,6 +1616,26 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
}
}
@Override
public void setHypervisorHostname(VirtualMachineProfile vm, DeployDestination dest, boolean migrationSuccessful) throws ResourceUnavailableException {
final List<NicVO> nics = _nicDao.listByVmId(vm.getId());
for (final NicVO nic : nics) {
final NetworkVO network = _networksDao.findById(nic.getNetworkId());
final Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId());
final NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network),
_networkModel.getNetworkTag(vm.getHypervisorType(), network));
for (final NetworkElement element : networkElements) {
if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.UserData) && element instanceof UserDataServiceProvider) {
if (element instanceof ConfigDriveNetworkElement && !migrationSuccessful || element instanceof VirtualRouterElement && migrationSuccessful) {
final UserDataServiceProvider sp = (UserDataServiceProvider) element;
if (!sp.saveHypervisorHostname(profile, network, vm, dest)) {
throw new CloudRuntimeException("Failed to Add hypervisor hostname");
}
}
}
}
}
}
@DB
protected void updateNic(final NicVO nic, final long networkId, final int count) {
@ -1749,7 +1771,6 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
.collect(Collectors.toMap(NicExtraDhcpOptionVO::getCode, NicExtraDhcpOptionVO::getValue));
}
@Override
public void prepareNicForMigration(final VirtualMachineProfile vm, final DeployDestination dest) {
if(vm.getType().equals(VirtualMachine.Type.DomainRouter) && (vm.getHypervisorType().equals(HypervisorType.KVM) || vm.getHypervisorType().equals(HypervisorType.VMware))) {

View File

@ -365,8 +365,10 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
@Override
public void loadDetails(UserVmVO vm) {
Map<String, String> details = _detailsDao.listDetailsKeyPairs(vm.getId());
vm.setDetails(details);
if (vm != null ) {
Map<String, String> details = _detailsDao.listDetailsKeyPairs(vm.getId());
vm.setDetails(details);
}
}
@Override

View File

@ -88,6 +88,11 @@ public class BaremetalUserdataElement extends AdapterBase implements NetworkElem
return false;
}
@Override
public boolean saveHypervisorHostname(NicProfile profile, Network network, VirtualMachineProfile vm, DeployDestination dest) throws ResourceUnavailableException {
return true;
}
@Override
public Map<Service, Map<Capability, String>> getCapabilities() {
return capabilities;

View File

@ -22,6 +22,7 @@ package com.cloud.hypervisor.kvm.resource.wrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -37,12 +38,12 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import com.cloud.agent.api.to.DiskTO;
import com.cloud.agent.api.to.DpdkTO;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.IOUtils;
@ -64,6 +65,7 @@ import com.cloud.agent.api.Answer;
import com.cloud.agent.api.MigrateAnswer;
import com.cloud.agent.api.MigrateCommand;
import com.cloud.agent.api.MigrateCommand.MigrateDiskInfo;
import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
import com.cloud.hypervisor.kvm.resource.LibvirtConnection;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
@ -115,6 +117,9 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
conn = libvirtUtilitiesHelper.getConnectionByVmName(vmName);
ifaces = libvirtComputingResource.getInterfaces(conn, vmName);
disks = libvirtComputingResource.getDisks(conn, vmName);
VirtualMachineTO to = command.getVirtualMachine();
dm = conn.domainLookupByName(vmName);
/*
We replace the private IP address with the address of the destination host.
@ -141,6 +146,12 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
xmlDesc = dm.getXMLDesc(xmlFlag);
xmlDesc = replaceIpForVNCInDescFile(xmlDesc, target);
String oldIsoVolumePath = getOldVolumePath(disks, vmName);
String newIsoVolumePath = getNewVolumePathIfDatastoreHasChanged(libvirtComputingResource, conn, to);
if (newIsoVolumePath != null && !newIsoVolumePath.equals(oldIsoVolumePath)) {
s_logger.debug("Editing mount path");
xmlDesc = replaceDiskSourceFile(xmlDesc, newIsoVolumePath, vmName);
}
// delete the metadata of vm snapshots before migration
vmsnapshots = libvirtComputingResource.cleanVMSnapshotMetadata(dm);
@ -226,30 +237,16 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
if (result.startsWith("unable to connect to server") && result.endsWith("refused")) {
result = String.format("Migration was refused connection to destination: %s. Please check libvirt configuration compatibility and firewall rules on the source and destination hosts.", destinationUri);
}
} catch (final InterruptedException e) {
s_logger.debug("Interrupted while migrating domain: " + e.getMessage());
result = e.getMessage();
} catch (final ExecutionException e) {
s_logger.debug("Failed to execute while migrating domain: " + e.getMessage());
result = e.getMessage();
} catch (final TimeoutException e) {
s_logger.debug("Timed out while migrating domain: " + e.getMessage());
result = e.getMessage();
} catch (final IOException e) {
s_logger.debug("IOException: " + e.getMessage());
result = e.getMessage();
} catch (final ParserConfigurationException e) {
s_logger.debug("ParserConfigurationException: " + e.getMessage());
result = e.getMessage();
} catch (final SAXException e) {
s_logger.debug("SAXException: " + e.getMessage());
result = e.getMessage();
} catch (final TransformerConfigurationException e) {
s_logger.debug("TransformerConfigurationException: " + e.getMessage());
result = e.getMessage();
} catch (final TransformerException e) {
s_logger.debug("TransformerException: " + e.getMessage());
result = e.getMessage();
} catch (final InterruptedException
| ExecutionException
| TimeoutException
| IOException
| ParserConfigurationException
| SAXException
| TransformerException
| URISyntaxException e) {
s_logger.debug(String.format("%s : %s", e.getClass().getSimpleName(), e.getMessage()));
result = "Exception during migrate: " + e.getMessage();
} finally {
try {
if (dm != null && result != null) {
@ -507,6 +504,33 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
return getXml(doc);
}
private String getOldVolumePath(List<DiskDef> disks, String vmName) {
String oldIsoVolumePath = null;
for (DiskDef disk : disks) {
if (disk.getDiskPath() != null && disk.getDiskPath().contains(vmName)) {
oldIsoVolumePath = disk.getDiskPath();
break;
}
}
return oldIsoVolumePath;
}
private String getNewVolumePathIfDatastoreHasChanged(LibvirtComputingResource libvirtComputingResource, Connect conn, VirtualMachineTO to) throws LibvirtException, URISyntaxException {
DiskTO newDisk = null;
for (DiskTO disk : to.getDisks()) {
if (disk.getPath() != null && disk.getPath().contains("configdrive")) {
newDisk = disk;
break;
}
}
String newIsoVolumePath = null;
if (newDisk != null) {
newIsoVolumePath = libvirtComputingResource.getVolumePath(conn, newDisk);
}
return newIsoVolumePath;
}
private String getPathFromSourceText(Set<String> paths, String sourceText) {
if (paths != null && !StringUtils.isBlank(sourceText)) {
for (String path : paths) {
@ -572,4 +596,62 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper<MigrateCo
return byteArrayOutputStream.toString();
}
private String replaceDiskSourceFile(String xmlDesc, String isoPath, String vmName) throws IOException, SAXException, ParserConfigurationException, TransformerException {
InputStream in = IOUtils.toInputStream(xmlDesc);
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(in);
// Get the root element
Node domainNode = doc.getFirstChild();
NodeList domainChildNodes = domainNode.getChildNodes();
for (int i = 0; i < domainChildNodes.getLength(); i++) {
Node domainChildNode = domainChildNodes.item(i);
if ("devices".equals(domainChildNode.getNodeName())) {
NodeList devicesChildNodes = domainChildNode.getChildNodes();
if (findDiskNode(doc, devicesChildNodes, vmName, isoPath)) {
break;
}
}
}
return getXml(doc);
}
private boolean findDiskNode(Document doc, NodeList devicesChildNodes, String vmName, String isoPath) {
for (int x = 0; x < devicesChildNodes.getLength(); x++) {
Node deviceChildNode = devicesChildNodes.item(x);
if ("disk".equals(deviceChildNode.getNodeName())) {
Node diskNode = deviceChildNode;
if (findSourceNode(doc, diskNode, vmName, isoPath)) {
return true;
}
}
}
return false;
}
private boolean findSourceNode(Document doc, Node diskNode, String vmName, String isoPath) {
NodeList diskChildNodes = diskNode.getChildNodes();
for (int z = 0; z < diskChildNodes.getLength(); z++) {
Node diskChildNode = diskChildNodes.item(z);
if ("source".equals(diskChildNode.getNodeName())) {
Node sourceNode = diskChildNode;
NamedNodeMap sourceNodeAttributes = sourceNode.getAttributes();
Node sourceNodeAttribute = sourceNodeAttributes.getNamedItem("file");
if ( sourceNodeAttribute.getNodeValue().contains(vmName)) {
diskNode.removeChild(diskChildNode);
Element newChildSourceNode = doc.createElement("source");
newChildSourceNode.setAttribute("file", isoPath);
diskNode.appendChild(newChildSourceNode);
return true;
}
}
}
return false;
}
}

View File

@ -1289,10 +1289,11 @@ public class LibvirtComputingResourceTest {
final boolean isWindows = false;
final VirtualMachineTO vmTO = Mockito.mock(VirtualMachineTO.class);
final boolean executeInSequence = false;
DiskTO[] diskTOS = new DiskTO[]{};
final MigrateCommand command = new MigrateCommand(vmName, destIp, isWindows, vmTO, executeInSequence );
when(libvirtComputingResource.getLibvirtUtilitiesHelper()).thenReturn(libvirtUtilitiesHelper);
when(vmTO.getDisks()).thenReturn(diskTOS);
try {
when(libvirtUtilitiesHelper.getConnectionByVmName(vmName)).thenReturn(conn);
when(libvirtUtilitiesHelper.retrieveQemuConnection("qemu+tcp://" + command.getDestinationIp() + "/system")).thenReturn(dconn);

View File

@ -2389,7 +2389,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi
@Override
public List<String[]> generateVmData(String userData, String serviceOffering, long datacenterId,
String vmName, String vmHostName, long vmId, String vmUuid,
String guestIpAddress, String publicKey, String password, Boolean isWindows) {
String guestIpAddress, String publicKey, String password, Boolean isWindows, String hostname) {
DataCenterVO dcVo = _dcDao.findById(datacenterId);
final String zoneName = dcVo.getName();
@ -2462,7 +2462,7 @@ 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});
return vmData;
}

View File

@ -55,6 +55,7 @@ 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;
@ -147,7 +148,7 @@ public class CloudZonesNetworkElement extends AdapterBase implements NetworkElem
}
private VmDataCommand generateVmDataCommand(String vmPrivateIpAddress, String userData, String serviceOffering, String zoneName, String guestIpAddress,
String vmName, String vmInstanceName, long vmId, String vmUuid, String publicKey) {
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);
@ -163,7 +164,7 @@ public class CloudZonesNetworkElement extends AdapterBase implements NetworkElem
setVmInstanceId(vmUuid, cmd);
}
cmd.addVmData("metadata", "public-keys", publicKey);
cmd.addVmData("metadata", "hypervisor-host-name", hostname);
return cmd;
}
@ -217,11 +218,11 @@ public class CloudZonesNetworkElement extends AdapterBase implements NetworkElem
}
String serviceOffering = _serviceOfferingDao.findByIdIncludingRemoved(uservm.getServiceOfferingId()).getDisplayText();
String zoneName = _dcDao.findById(network.getDataCenterId()).getName();
String destHostname = VirtualMachineManager.getHypervisorHostname(dest.getHost().getName());
cmds.addCommand(
"vmdata",
generateVmDataCommand(nic.getIPv4Address(), userData, serviceOffering, zoneName, nic.getIPv4Address(), uservm.getHostName(), uservm.getInstanceName(),
uservm.getId(), uservm.getUuid(), sshPublicKey));
uservm.getId(), uservm.getUuid(), sshPublicKey, destHostname));
try {
_agentManager.send(dest.getHost().getId(), cmds);
} catch (OperationTimedoutException e) {
@ -251,6 +252,11 @@ public class CloudZonesNetworkElement extends AdapterBase implements NetworkElem
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
@ -261,5 +267,4 @@ public class CloudZonesNetworkElement extends AdapterBase implements NetworkElem
public boolean verifyServicesCombination(Set<Service> services) {
return true;
}
}

View File

@ -29,6 +29,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
import org.apache.cloudstack.storage.configdrive.ConfigDrive;
import org.apache.cloudstack.storage.configdrive.ConfigDriveBuilder;
import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
import org.apache.cloudstack.storage.to.TemplateObjectTO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
@ -39,13 +40,16 @@ import com.cloud.agent.api.Answer;
import com.cloud.agent.api.HandleConfigDriveIsoCommand;
import com.cloud.agent.api.to.DiskTO;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.HostPodDao;
import com.cloud.deploy.DeployDestination;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.UnsupportedServiceException;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.HypervisorGuruManager;
import com.cloud.network.Network;
import com.cloud.network.Network.Capability;
import com.cloud.network.Network.Provider;
@ -66,6 +70,7 @@ import com.cloud.storage.dao.GuestOSDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.crypt.DBEncryptionUtil;
import com.cloud.utils.db.EntityManager;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.StateListener;
import com.cloud.utils.fsm.StateMachine2;
@ -110,11 +115,23 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
@Inject
HostDao _hostDao;
@Inject
HostPodDao _podDao;
@Inject
ClusterDao _clusterDao;
@Inject
AgentManager agentManager;
@Inject
DataStoreManager _dataStoreMgr;
@Inject
EndPointSelector _ep;
@Inject
EntityManager _entityMgr;
@Inject
ServiceOfferingDao _offeringDao;
@Inject
ImageStoreDao imgstore;
@Inject
private HypervisorGuruManager _hvGuruMgr;
private final static Integer CONFIGDRIVEDISKSEQ = 4;
@ -204,8 +221,8 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
public boolean addPasswordAndUserdata(Network network, NicProfile nic, VirtualMachineProfile profile, DeployDestination dest, ReservationContext context)
throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
return (canHandle(network.getTrafficType())
&& configureConfigDriveData(profile, nic))
&& createConfigDriveIso(profile, dest);
&& configureConfigDriveData(profile, nic, dest))
&& createConfigDriveIso(profile, dest, null);
}
@Override
@ -244,6 +261,19 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
return canHandle;
}
@Override
public boolean saveHypervisorHostname(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest) throws ResourceUnavailableException {
if (vm.getVirtualMachine().getType() == VirtualMachine.Type.User) {
try {
recreateConfigDriveIso(nic, network, vm, dest);
} catch (ResourceUnavailableException e) {
LOG.error("Failed to add config disk drive due to: ", e);
return false;
}
}
return true;
}
@Override
public boolean saveUserData(final Network network, final NicProfile nic, final VirtualMachineProfile vm) throws ResourceUnavailableException {
// saveUserData is called by updateVirtualMachine API which requires VM to be shutdown
@ -325,6 +355,32 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
public void commitMigration(NicProfile nic, Network network, VirtualMachineProfile vm, ReservationContext src, ReservationContext dst) {
}
private void recreateConfigDriveIso(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest) throws ResourceUnavailableException {
if (nic.isDefaultNic() && _networkModel.getUserDataUpdateProvider(network).getProvider().equals(Provider.ConfigDrive)) {
DiskTO diskToUse = null;
for (DiskTO disk : vm.getDisks()) {
if (disk.getType() == Volume.Type.ISO && disk.getPath() != null && disk.getPath().contains("configdrive")) {
diskToUse = disk;
break;
}
}
final UserVmVO userVm = _userVmDao.findById(vm.getId());
if (userVm != null) {
final boolean isWindows = isWindows(userVm.getGuestOSId());
List<String[]> vmData = _networkModel.generateVmData(userVm.getUserData(), _serviceOfferingDao.findById(userVm.getServiceOfferingId()).getName(), userVm.getDataCenterId(), userVm.getInstanceName(), vm.getHostName(), vm.getId(),
vm.getUuid(), nic.getMacAddress(), userVm.getDetail("SSH.PublicKey"), (String) vm.getParameter(VirtualMachineProfile.Param.VmPassword), isWindows, VirtualMachineManager.getHypervisorHostname(dest.getHost().getName()));
vm.setVmData(vmData);
vm.setConfigDriveLabel(VirtualMachineManager.VmConfigDriveLabel.value());
createConfigDriveIso(vm, dest, diskToUse);
}
}
}
private boolean isWindows(long guestOSId) {
return _guestOSCategoryDao.findById(_guestOSDao.findById(guestOSId).getCategoryId()).getName().equalsIgnoreCase("Windows");
}
private DataStore findDataStore(VirtualMachineProfile profile, DeployDestination dest) {
DataStore dataStore = null;
if (VirtualMachineManager.VmConfigDriveOnPrimaryPool.value()) {
@ -422,8 +478,9 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
return agentId;
}
private boolean createConfigDriveIso(VirtualMachineProfile profile, DeployDestination dest) throws ResourceUnavailableException {
final DataStore dataStore = findDataStore(profile, dest);
private boolean createConfigDriveIso(VirtualMachineProfile profile, DeployDestination dest, DiskTO disk) throws ResourceUnavailableException {
DataStore dataStore = getDatastoreForConfigDriveIso(disk, profile, dest);
final Long agentId = findAgentId(profile, dest, dataStore);
if (agentId == null || dataStore == null) {
throw new ResourceUnavailableException("Config drive iso creation failed, agent or datastore not available",
@ -446,6 +503,28 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
return true;
}
private DataStore getDatastoreForConfigDriveIso(DiskTO disk, VirtualMachineProfile profile, DeployDestination dest) {
DataStore dataStore = null;
if (disk != null) {
String dId = disk.getData().getDataStore().getUuid();
if (VirtualMachineManager.VmConfigDriveOnPrimaryPool.value()) {
dataStore = _dataStoreMgr.getDataStore(dId, DataStoreRole.Primary);
} else {
List<DataStore> dataStores = _dataStoreMgr.listImageStores();
String url = disk.getData().getDataStore().getUrl();
for(DataStore ds : dataStores) {
if (url.equals(ds.getUri()) && DataStoreRole.Image.equals(ds.getRole())) {
dataStore = ds;
break;
}
}
}
} else {
dataStore = findDataStore(profile, dest);
}
return dataStore;
}
private boolean deleteConfigDriveIso(final VirtualMachine vm) throws ResourceUnavailableException {
DataStore dataStore = _dataStoreMgr.getImageStoreWithFreeCapacity(vm.getDataCenterId());
Long agentId = findAgentIdForImageStore(dataStore);
@ -502,7 +581,7 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
}
}
private boolean configureConfigDriveData(final VirtualMachineProfile profile, final NicProfile nic) {
private boolean configureConfigDriveData(final VirtualMachineProfile profile, final NicProfile nic, final DeployDestination dest) {
final UserVmVO vm = _userVmDao.findById(profile.getId());
if (vm.getType() != VirtualMachine.Type.User) {
return false;
@ -512,9 +591,15 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
final String sshPublicKey = getSshKey(profile);
final String serviceOffering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId()).getDisplayText();
boolean isWindows = _guestOSCategoryDao.findById(_guestOSDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
String hostname = _hostDao.findById(vm.getHostId()).getName();
String destHostname = null;
if (dest.getHost() == null ) {
destHostname = VirtualMachineManager.getHypervisorHostname(hostname);
} else {
destHostname = VirtualMachineManager.getHypervisorHostname(dest.getHost().getName());
}
final List<String[]> vmData = _networkModel.generateVmData(vm.getUserData(), serviceOffering, vm.getDataCenterId(), vm.getInstanceName(), vm.getHostName(), vm.getId(),
vm.getUuid(), nic.getIPv4Address(), sshPublicKey, (String) profile.getParameter(VirtualMachineProfile.Param.VmPassword), isWindows);
vm.getUuid(), nic.getIPv4Address(), sshPublicKey, (String) profile.getParameter(VirtualMachineProfile.Param.VmPassword), isWindows, destHostname);
profile.setVmData(vmData);
profile.setConfigDriveLabel(VirtualMachineManager.VmConfigDriveLabel.value());
}

View File

@ -31,7 +31,10 @@ import org.cloud.network.router.deployment.RouterDeploymentDefinitionBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.vm.VirtualMachineProfileImpl;
import com.cloud.vm.VmDetailConstants;
import com.cloud.vm.dao.NicDao;
import com.google.gson.Gson;
import org.apache.cloudstack.api.command.admin.router.ConfigureOvsElementCmd;
@ -117,7 +120,7 @@ import com.cloud.vm.dao.UserVmDao;
public class VirtualRouterElement extends AdapterBase implements VirtualRouterElementService, DhcpServiceProvider, UserDataServiceProvider, SourceNatServiceProvider,
StaticNatServiceProvider, FirewallServiceProvider, LoadBalancingServiceProvider, PortForwardingServiceProvider, RemoteAccessVPNServiceProvider, IpDeployer,
NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServiceProvider {
NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServiceProvider{
private static final Logger s_logger = Logger.getLogger(VirtualRouterElement.class);
public static final AutoScaleCounterType AutoScaleCounterCpu = new AutoScaleCounterType("cpu");
public static final AutoScaleCounterType AutoScaleCounterMemory = new AutoScaleCounterType("memory");
@ -163,6 +166,10 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
DataCenterDao _dcDao;
@Inject
NetworkModel _networkModel;
@Inject
NicDao _nicDao;
@Inject
VMTemplateDao _templateDao;
@Inject
NetworkTopologyContext networkTopologyContext;
@ -765,6 +772,33 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
return result;
}
@Override
public boolean saveHypervisorHostname(NicProfile nicProfile, Network network, VirtualMachineProfile vm, DeployDestination dest) throws ResourceUnavailableException {
if (_networkModel.getUserDataUpdateProvider(network).getProvider().equals(Provider.VirtualRouter) && vm.getVirtualMachine().getType() == VirtualMachine.Type.User) {
VirtualMachine uvm = vm.getVirtualMachine();
UserVmVO destVm = _userVmDao.findById(uvm.getId());
VirtualMachineProfile profile = null;
if (destVm != null) {
destVm.setHostId(dest.getHost().getId());
_userVmDao.update(uvm.getId(), destVm);
profile = new VirtualMachineProfileImpl(destVm);
profile.setDisks(vm.getDisks());
profile.setNics(vm.getNics());
profile.setVmData(vm.getVmData());
} else {
profile = vm;
}
updateUserVmData(nicProfile, network, profile);
if (destVm != null) {
destVm.setHostId(uvm.getHostId());
_userVmDao.update(uvm.getId(), destVm);
}
}
return true;
}
@Override
public boolean saveUserData(final Network network, final NicProfile nic, final VirtualMachineProfile vm) throws ResourceUnavailableException {
if (!canHandle(network, null)) {
@ -1066,6 +1100,8 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
}
final VirtualMachineProfile uservm = vm;
List<java.lang.String[]> vmData = uservm.getVmData();
uservm.setVmData(vmData);
final List<DomainRouterVO> routers = getRouters(network, dest);
@ -1204,6 +1240,19 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
return true;
}
private void updateUserVmData(final NicProfile nic, final Network network, final VirtualMachineProfile vm) throws ResourceUnavailableException {
if (_networkModel.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Service.UserData)) {
boolean result = saveUserData(network, nic, vm);
if (!result) {
s_logger.warn("Failed to update userdata for vm " + vm + " and nic " + nic);
} else {
s_logger.debug("Successfully saved user data to router");
}
} else {
s_logger.debug("Not applying userdata for nic id=" + nic.getId() + " in vm id=" + vm.getId() + " because it is not supported in network id=" + network.getId());
}
}
@Override
public boolean prepareMigration(final NicProfile nic, final Network network, final VirtualMachineProfile vm, final DeployDestination dest, final ReservationContext context) {
if (nic.getBroadcastType() != Networks.BroadcastDomainType.Pvlan) {
@ -1351,5 +1400,4 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
_routerDao.persist(router);
}
}
}

View File

@ -68,6 +68,8 @@ import com.cloud.dc.DataCenter.NetworkType;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.VlanDao;
import com.cloud.host.Host;
import com.cloud.host.dao.HostDao;
import com.cloud.network.IpAddress;
import com.cloud.network.Network;
import com.cloud.network.Network.Provider;
@ -177,23 +179,29 @@ public class CommandSetupHelper {
private VlanDao _vlanDao;
@Inject
private IPAddressDao _ipAddressDao;
@Inject
private RouterControlHelper _routerControlHelper;
@Inject
private HostDao _hostDao;
@Autowired
@Qualifier("networkHelper")
protected NetworkHelper _networkHelper;
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,
staticNatIp == null || staticNatIp.getState() != IpAddress.State.Allocated ? null : staticNatIp.getAddress().addr(), vm.getHostName(), vm.getInstanceName(),
vm.getId(), vm.getUuid(), publicKey, nic.getNetworkId()));
if (vm != null && router != null && nic != null) {
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());
Host host = _hostDao.findById(vm.getHostId());
String destHostname = VirtualMachineManager.getHypervisorHostname(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));
}
}
public void createApplyVpnUsersCommand(final List<? extends VpnUser> users, final VirtualRouter router, final Commands cmds) {
@ -1038,7 +1046,7 @@ public class CommandSetupHelper {
private VmDataCommand generateVmDataCommand(final VirtualRouter router, final String vmPrivateIpAddress, final String userData, final String serviceOffering,
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, String hostname) {
final VmDataCommand cmd = new VmDataCommand(vmPrivateIpAddress, vmName, _networkModel.getExecuteInSeqNtwkElmtCmd());
cmd.setAccessDetail(NetworkElementCommand.ROUTER_IP, _routerControlHelper.getRouterControlIp(router.getId()));
@ -1084,6 +1092,7 @@ public class CommandSetupHelper {
}
cmd.addVmData("metadata", "cloud-identifier", cloudIdentifier);
cmd.addVmData("metadata", "hypervisor-host-name", hostname);
return cmd;
}

View File

@ -4341,9 +4341,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
if (_networkModel.isSharedNetworkWithoutServices(network.getId())) {
final String serviceOffering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId()).getDisplayText();
boolean isWindows = _guestOSCategoryDao.findById(_guestOSDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
String destHostname = VirtualMachineManager.getHypervisorHostname(dest.getHost().getName());
List<String[]> vmData = _networkModel.generateVmData(vm.getUserData(), serviceOffering, vm.getDataCenterId(), vm.getInstanceName(), vm.getHostName(), vm.getId(),
vm.getUuid(), defaultNic.getIPv4Address(), vm.getDetail(VmDetailConstants.SSH_PUBLIC_KEY), (String) profile.getParameter(VirtualMachineProfile.Param.VmPassword), isWindows);
vm.getUuid(), defaultNic.getIPv4Address(), vm.getDetail(VmDetailConstants.SSH_PUBLIC_KEY), (String) profile.getParameter(VirtualMachineProfile.Param.VmPassword), isWindows, destHostname);
String vmName = vm.getInstanceName();
String configDriveIsoRootFolder = "/tmp";
String isoFile = configDriveIsoRootFolder + "/" + vmName + "/configDrive/" + vmName + ".iso";

View File

@ -349,7 +349,6 @@ public class BasicNetworkTopology implements NetworkTopology {
final Long podId = null;
final UserdataToRouterRules userdataToRouterRules = new UserdataToRouterRules(network, nic, profile);
return applyRules(network, router, typeString, isPodLevelException, podId, failWhenDisconnect, new RuleApplierWrapper<RuleApplier>(userdataToRouterRules));
}

View File

@ -898,7 +898,7 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel {
}
@Override
public List<String[]> generateVmData(String userData, String serviceOffering, long datacenterId, String vmName, String vmHostName, long vmId, String vmUuid, String guestIpAddress, String publicKey, String password, Boolean isWindows) {
public List<String[]> generateVmData(String userData, String serviceOffering, long datacenterId, String vmName, String vmHostName, long vmId, String vmUuid, String guestIpAddress, String publicKey, String password, Boolean isWindows, String hostname) {
return null;
}

View File

@ -36,6 +36,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
@ -83,6 +84,7 @@ import com.cloud.storage.GuestOSCategoryVO;
import com.cloud.storage.GuestOSVO;
import com.cloud.storage.dao.GuestOSCategoryDao;
import com.cloud.storage.dao.GuestOSDao;
import com.cloud.user.Account;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.utils.fsm.StateListener;
import com.cloud.utils.fsm.StateMachine2;
@ -100,6 +102,7 @@ import com.cloud.vm.dao.VMInstanceDao;
import com.google.common.collect.Maps;
@RunWith(PowerMockRunner.class)
@PrepareForTest(CallContext.class)
public class ConfigDriveNetworkElementTest {
public static final String CLOUD_ID = "xx";
@ -146,6 +149,7 @@ public class ConfigDriveNetworkElementTest {
@Mock private UserVmVO virtualMachine;
@Mock private IPAddressVO publicIp;
@Mock private AgentManager agentManager;
@Mock private CallContext callContextMock;
@InjectMocks private final ConfigDriveNetworkElement _configDrivesNetworkElement = new ConfigDriveNetworkElement();
@InjectMocks @Spy private NetworkModelImpl _networkModel = new NetworkModelImpl();
@ -157,7 +161,6 @@ public class ConfigDriveNetworkElementTest {
_configDrivesNetworkElement._networkModel = _networkModel;
when(_dataStoreMgr.getImageStoreWithFreeCapacity(DATACENTERID)).thenReturn(dataStore);
when(_ep.select(dataStore)).thenReturn(endpoint);
when(_vmDao.findById(VMID)).thenReturn(virtualMachine);
when(_dcDao.findById(DATACENTERID)).thenReturn(dataCenterVO);
@ -173,6 +176,7 @@ public class ConfigDriveNetworkElementTest {
when(serviceOfferingVO.getDisplayText()).thenReturn(VMOFFERING);
when(guestOSVO.getCategoryId()).thenReturn(0L);
when(virtualMachine.getGuestOSId()).thenReturn(0L);
when(virtualMachine.getHostId()).thenReturn(0L);
when(virtualMachine.getType()).thenReturn(VirtualMachine.Type.User);
when(virtualMachine.getId()).thenReturn(VMID);
when(virtualMachine.getServiceOfferingId()).thenReturn(SOID);
@ -254,10 +258,12 @@ public class ConfigDriveNetworkElementTest {
@Test
@SuppressWarnings("unchecked")
@PrepareForTest({ConfigDriveBuilder.class})
@PrepareForTest({ConfigDriveBuilder.class, CallContext.class})
public void testAddPasswordAndUserData() throws Exception {
PowerMockito.mockStatic(ConfigDriveBuilder.class);
PowerMockito.mockStatic(CallContext.class);
PowerMockito.when(CallContext.current()).thenReturn(callContextMock);
Mockito.doReturn(Mockito.mock(Account.class)).when(callContextMock).getCallingAccount();
Method method = ReflectionUtils.getMethods(ConfigDriveBuilder.class, ReflectionUtils.withName("buildConfigDrive")).iterator().next();
PowerMockito.when(ConfigDriveBuilder.class, method).withArguments(Mockito.anyListOf(String[].class), Mockito.anyString(), Mockito.anyString()).thenReturn("content");
@ -273,11 +279,14 @@ public class ConfigDriveNetworkElementTest {
when(_userVmDetailsDao.findDetail(anyLong(), anyString())).thenReturn(userVmDetailVO);
when(_ipAddressDao.findByAssociatedVmId(VMID)).thenReturn(publicIp);
when(publicIp.getAddress()).thenReturn(new Ip("7.7.7.7"));
when(_hostDao.findById(virtualMachine.getHostId())).thenReturn(hostVO);
when(_hostDao.findById(virtualMachine.getHostId()).getName()).thenReturn("dest-hyp-host-name");
Map<VirtualMachineProfile.Param, Object> parms = Maps.newHashMap();
parms.put(VirtualMachineProfile.Param.VmPassword, PASSWORD);
parms.put(VirtualMachineProfile.Param.VmSshPubKey, PUBLIC_KEY);
VirtualMachineProfile profile = new VirtualMachineProfileImpl(virtualMachine, null, serviceOfferingVO, null, parms);
profile.setConfigDriveLabel("testlabel");
assertTrue(_configDrivesNetworkElement.addPasswordAndUserdata(
network, nicp, profile, deployDestination, null));

View File

@ -940,6 +940,11 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches
return;
}
@Override
public void setHypervisorHostname(VirtualMachineProfile vm, DeployDestination dest, boolean migrationSuccessful) {
return;
}
@Override
public void prepareNicForMigration(VirtualMachineProfile vm, DeployDestination dest) {
// TODO Auto-generated method stub

View File

@ -913,7 +913,7 @@ public class MockNetworkModelImpl extends ManagerBase implements NetworkModel {
}
@Override
public List<String[]> generateVmData(String userData, String serviceOffering, long datacenterId, String vmName, String vmHostName, long vmId, String vmUuid, String guestIpAddress, String publicKey, String password, Boolean isWindows) {
public List<String[]> generateVmData(String userData, String serviceOffering, long datacenterId, String vmName, String vmHostName, long vmId, String vmUuid, String guestIpAddress, String publicKey, String password, Boolean isWindows, String hostname) {
return null;
}

View File

@ -32,6 +32,7 @@ from marvin.cloudstackAPI import (restartVPC)
from marvin.cloudstackTestCase import cloudstackTestCase
from marvin.lib.base import (Account,
createVlanIpRange,
Configurations,
FireWallRule,
Host,
listVlanIpRanges,
@ -52,7 +53,8 @@ from marvin.lib.base import (Account,
Hypervisor, Template)
from marvin.lib.common import (get_domain,
get_template,
get_zone, get_test_template)
get_zone, get_test_template,
is_config_suitable)
from marvin.lib.utils import random_gen
# Import System Modules
from nose.plugins.attrib import attr
@ -530,6 +532,24 @@ class ConfigDriveUtils:
"local-hostname.txt",
"local-ipv4.txt",
"public-ipv4.txt"]
# Verify hostname if the appropriate settings are true
configs = Configurations.list(
self.api_client,
name="global.allow.expose.host.hostname",
listall=True
)
exposeHypevisorHostnameGS = configs[0].value
configs = Configurations.list(
self.api_client,
name="account.allow.expose.host.hostname",
listall=True
)
exposeHypevisorHostnameAcc = configs[0].value
if exposeHypevisorHostnameGS == 'true' and exposeHypevisorHostnameAcc == 'true':
vm_files.append("hypervisor-host-name.txt")
def get_name(vm_file):
return "{} metadata".format(
@ -537,9 +557,9 @@ class ConfigDriveUtils:
)
metadata = {vm_file:
self._get_config_drive_data(ssh,
metadata_dir + vm_file,
get_name(vm_file))
self._get_config_drive_data(ssh,
metadata_dir + vm_file,
get_name(vm_file))
for vm_file in vm_files}
self.assertEqual(
@ -571,6 +591,18 @@ class ConfigDriveUtils:
"Service offering inside metadata does not match "
"with the instance offering"
)
if exposeHypevisorHostnameGS == 'true' and exposeHypevisorHostnameAcc == 'true':
hostname = vm.hostname
self.debug("Verifying hypervisor hostname of the VM: %s" % vm.name)
self.assertEqual(
str(metadata["hypervisor-host-name.txt"]),
hostname,
"Hostname in the metadata file does not match the host "
"on which the VM is spawned"
)
return
def _verify_openstack_metadata(self, ssh, mount_path):
@ -753,7 +785,8 @@ class ConfigDriveUtils:
self.create_StaticNatRule_For_VM(vm, public_ip, network)
# Verification
self.validate_StaticNat_rule_For_VM(public_ip, network, vm)
# self.validate_StaticNat_rule_For_VM(public_ip, network, vm)
if not self.vpc:
fw_rule = self.create_FirewallRule(public_ip,
@ -1090,12 +1123,12 @@ class ConfigDriveUtils:
self.fail("Failed to decrypt new password")
except ImportError:
# No pycrypto, fallback to openssl
cmd = ["echo " + password_ +
cmd = ["echo " + password_ +
" | base64 -d"
" | openssl rsautl -decrypt -inkey "
+ self.keypair.private_key_file
+ " 2> /dev/null"
]
]
new_password = subprocess.check_output(cmd, shell=True)
self.debug("Decrypted password %s" % new_password)
@ -1314,6 +1347,7 @@ class TestConfigDrive(cloudstackTestCase, ConfigDriveUtils):
isstaticnat=static_nat,
listall=True
)
self.debug("PUBLIC IP = " + public_ips[0])
self.assertEqual(isinstance(public_ips, list), True,
"List public IP for network should return a "
"valid list"
@ -1675,6 +1709,7 @@ class TestConfigDrive(cloudstackTestCase, ConfigDriveUtils):
else:
self.debug("No host available for migration. "
"Test requires at-least 2 hosts")
return host
# create_NetworkAclList - Creates network ACL list in the given VPC
def create_NetworkAclList(self, name, description, vpc):
@ -2258,3 +2293,242 @@ class TestConfigDrive(cloudstackTestCase, ConfigDriveUtils):
keypair=self.keypair.name)
self.delete(vm1, expunge=True)
self.delete(shared_network.network)
@attr(tags=["advanced", "isonw"], required_hardware="true")
def test_configdrive_isolated_network_hypervisor_hostname_exposed(self):
"""Test Configdrive as provider for isolated Networks
to provide userdata and password reset functionality
"""
# 1. Given a ConfigDrive provider and a network offering
# which has userdata provided ConfigDrive, create
# an Isolated network using that network offering.
# Verify network is successfully created and in the Allocated state
# Set the "global.allow.expose.host.hostname" and "account.allow.expose.host.hostname" flags to true
# to enable viewing hypevisor host name in the metadata file
# Deploy VM in the network created, verify metadata in the configdrive
# my mounting the configdrive ISO and verify the respective files
#
# 2. Create another Isolated network and plug NIC of the VM to this network
# make it the default NIC, verify the metadata file contents.
#
# 3. Remove the default NIC, reboot the VM and verify the metadata file contents
#
# 4. Restart network without cleanup and verify the metadata file contents
#
# 5. Restart the network with cleanup and verify the metadata file contents
# 6. Migrate the VM to another host and verify the metadata file contents
# 10. Delete all the created objects (cleanup).
self.debug("+++ Preparation Scenario: "
"creating an Isolated networks with "
"config drive when config drive provider is "
"enabled.")
self.given_config_drive_provider_is("Enabled")
self.given_a_network_offering_with_configdrive()
create_network1 = self.when_I_create_a_network_with_that_offering()
self.then_the_network_is_successfully_created(create_network1)
self.then_the_network_has(create_network1, state="Allocated")
network1 = create_network1.network
# Update global setting for "allow.expose.host.hostname"
Configurations.update(self.api_client,
name="global.allow.expose.host.hostname",
value="true"
)
# Update Account level setting
Configurations.update(self.api_client,
name="account.allow.expose.host.hostname",
value="true"
)
# Verify that the above mentioned settings are set to true before proceeding
if not is_config_suitable(
apiclient=self.api_client,
name='global.allow.expose.host.hostname',
value='true'):
self.skipTest('global.allow.expose.host.hostname should be true. skipping')
if not is_config_suitable(
apiclient=self.api_client,
name='account.allow.expose.host.hostname',
value='true'):
self.skipTest('Account level setting account.allow.expose.host.hostname should be true. skipping')
self.debug("+++Deploy VM in the created Isolated network "
"with user data provider as configdrive")
vm1 = self.when_I_deploy_a_vm(network1)
public_ip_1 = self.when_I_create_a_static_nat_ip_to(vm1, network1)
self.then_vr_is_as_expected(network1)
self.then_config_drive_is_as_expected(
vm1, public_ip_1,
metadata=True)
# =====================================================================
# Network restart tests
# =====================================================================
self.debug("+++ Scenario: "
"verify config drive after restart Isolated network without"
" cleanup...")
self.when_I_restart_the_network_with(network1, cleanup=False)
self.then_config_drive_is_as_expected(vm1, public_ip_1, metadata=True)
# =====================================================================
self.debug("+++ Scenario: "
"verify config drive after restart Isolated network with"
" cleanup...")
self.when_I_restart_the_network_with(network1, cleanup=True)
self.then_config_drive_is_as_expected(vm1, public_ip_1, metadata=True)
# =====================================================================
self.debug("+++ Scenario: "
"verify vm metadata after migrate")
host = self.migrate_VM(vm1)
vm1.hostname = host.name
self.then_config_drive_is_as_expected(vm1, public_ip_1, metadata=True)
# Reset configuration values to default values i.e., false
Configurations.update(self.api_client,
name="global.allow.expose.host.hostname",
value="false"
)
# Update Account level setting
Configurations.update(self.api_client,
name="account.allow.expose.host.hostname",
value="false"
)
self.delete(vm1, expunge=True)
self.delete(network1)
@attr(tags=["advanced", "vpc"], required_hardware="true")
def test_configdrive_vpc_network_verify_metadata(self):
"""Test Configdrive for VPC Networks
choose user data with configDrive as service provider
and test vmdata functionality using ConfigDrive
"""
# 1. Given ConfigDrive provider is enabled in zone
# And a network offering for VPC which has
# user data provided by ConfigDrive
# And a VPC
# When I create an VPC Tier in the VPC using that network offering
# Then the network is successfully created,
# And is in the "Allocated" state.
# 2. When I deploy a VM in the created VPC tier with user data,
# Then the network state is changed to "Implemented"
# And the VM is successfully deployed and is in the "Running" state
# 3. And the user data in the ConfigDrive device is as expected
# 4. Verify various scenarios and check the data in configdriveIso
# 5. Delete all the created objects (cleanup).
self.debug("+++ Preparation Scenario: "
"Create a tier with config drive "
"when config drive provider is enabled.")
self.given_a_vpc()
self.given_config_drive_provider_is("Enabled")
self.given_a_network_offering_for_vpc_with_configdrive()
create_network1 = self.when_I_create_a_vpc_tier_with_that_offering(
gateway='10.1.1.1')
self.then_the_network_is_successfully_created(create_network1)
self.then_the_network_has(create_network1, state="Implemented")
network1 = create_network1.network
# Update global setting for "allow.expose.host.hostname"
Configurations.update(self.api_client,
name="global.allow.expose.host.hostname",
value="true"
)
# Update Account level setting
Configurations.update(self.api_client,
name="account.allow.expose.host.hostname",
value="true"
)
# Verify that the above mentioned settings are set to true before proceeding
if not is_config_suitable(
apiclient=self.api_client,
name='global.allow.expose.host.hostname',
value='true'):
self.skipTest('global.allow.expose.host.hostname should be true. skipping')
if not is_config_suitable(
apiclient=self.api_client,
name='account.allow.expose.host.hostname',
value='true'):
self.skipTest('Account level setting account.allow.expose.host.hostname should be true. skipping')
# =====================================================================
self.debug("+++ Scenario: "
"Deploy VM in the Tier 1 with user data")
vm = self.when_I_deploy_a_vm(network1)
public_ip_1 = self.when_I_create_a_static_nat_ip_to(vm, network1)
self.then_config_drive_is_as_expected(vm, public_ip_1, metadata=True)
# =====================================================================
# Network restart tests
# =====================================================================
self.debug("+++ Scenario: "
"verify config drive after Restart VPC with cleanup...")
self.when_I_restart_the_vpc_with(cleanup=True)
self.then_config_drive_is_as_expected(vm, public_ip_1,
metadata=True, reconnect=False)
# =====================================================================
self.debug("+++ Scenario: "
"verify config drive after Restart VPC without cleanup...")
self.when_I_restart_the_network_with(network1, cleanup=False)
self.then_config_drive_is_as_expected(vm, public_ip_1,
metadata=True, reconnect=False)
# =====================================================================
self.debug("+++ Scenario: "
"verify config drive after restart tier with cleanup...")
self.when_I_restart_the_network_with(network1, cleanup=True)
self.then_config_drive_is_as_expected(vm, public_ip_1,
metadata=True, reconnect=False)
# =====================================================================
self.debug("+++ Scenario: "
"validate vm metadata after reboot")
vm.reboot(self.api_client)
self.then_config_drive_is_as_expected(vm, public_ip_1, metadata=True)
# =====================================================================
self.debug("+++ Scenario: "
"validate updated userdata after migrate")
host = self.migrate_VM(vm)
vm.hostname = host.name
self.then_config_drive_is_as_expected(vm, public_ip_1, metadata=True)
# Reset configuration values to default values i.e., false
Configurations.update(self.api_client,
name="global.allow.expose.host.hostname",
value="false"
)
# Update Account level setting
Configurations.update(self.api_client,
name="account.allow.expose.host.hostname",
value="false"
)
self.delete(vm, expunge=True)
self.delete(network1)

View File

@ -0,0 +1,337 @@
# 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.
# this script will cover VMdeployment with Userdata tests
from marvin.cloudstackTestCase import cloudstackTestCase
from marvin.lib.base import *
from marvin.lib.utils import (validateList, cleanup_resources)
from marvin.lib.common import *
from nose.plugins.attrib import attr
from marvin.codes import PASS,FAIL
_multiprocess_shared_ = True
class Services:
def __init__(self):
self.services = {
"virtual_machine": {
"displayname": "TesVM1",
"username": "root",
"password": "password",
"ssh_port": 22,
"hypervisor": 'XenServer',
"privateport": 22,
"publicport": 22,
"protocol": 'TCP',
},
"ostype": 'CentOS 5.5 (64-bit)',
"service_offering": {
"name": "Tiny Instance",
"displaytext": "Tiny Instance",
"cpunumber": 1,
"cpuspeed": 100,
"memory": 256,
},
}
class TestDeployVmWithMetaData(cloudstackTestCase):
@classmethod
def setUpClass(cls):
cls.testclient = super(TestDeployVmWithMetaData, cls).getClsTestClient()
cls.apiclient = cls.testclient.getApiClient()
cls._cleanup = []
#cls.services = Services().services
cls.services = cls.testclient.getParsedTestDataConfig()
cls.zone = get_zone(cls.apiclient, cls.testclient.getZoneForTests())
cls.service_offering = ServiceOffering.create(
cls.apiclient,
cls.services["service_offering"]
)
cls.template = get_template(
cls.apiclient,
cls.zone.id,
cls.services["ostype"]
)
@classmethod
def tearDownClass(cls):
try:
cls._cleanup = cls._cleanup[::-1]
cleanup_resources(cls.apiclient, cls._cleanup)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
def setUp(self):
self.apiclient = self.testClient.getApiClient()
self.cleanup = []
def tearDown(self):
try:
self.cleanup = self.cleanup[::-1]
cleanup_resources(self.apiclient, self.cleanup)
except Exception as e:
raise Exception("Warning: Exception during cleanup : %s" % e)
return
def migrate_VM(self, vm):
"""Migrates VM to another host, if available"""
self.debug("+++ Migrating one of the VMs in the created "
"VPC Tier network to another host, if available...")
self.debug("Checking if a host is available for migration...")
hosts = Host.listForMigration(self.apiclient, virtualmachineid=vm.id)
if hosts:
self.assertEqual(isinstance(hosts, list), True,
"List hosts should return a valid list"
)
host = hosts[0]
self.debug("Migrating VM with ID: "
"%s to Host: %s" % (vm.id, host.id))
try:
vm.migrate(self.apiclient, hostid=host.id)
except Exception as e:
self.fail("Failed to migrate instance, %s" % e)
self.debug("Migrated VM with ID: "
"%s to Host: %s" % (vm.id, host.id))
else:
self.debug("No host available for migration. "
"Test requires at-least 2 hosts")
return host
def list_nics(self, vm_id):
list_vm_res = VirtualMachine.list(self.apiclient, id=vm_id)
self.assertEqual(validateList(list_vm_res)[0], PASS, "List vms returned invalid response")
nics = list_vm_res[0].nic
for nic in nics:
if nic.type == "Shared":
nic_res = NIC.list(
self.apiclient,
virtualmachineid=vm_id,
nicid=nic.id
)
nic_ip = nic_res[0].ipaddress
self.assertIsNotNone(nic_ip, "listNics API response does not have the ip address")
else:
continue
return
@attr(tags=["advanced"], required_hardware='True')
def test_deployVM_verify_metadata_in_VR(self):
"""
1. Create a network (VR as a provider)
2. Deploy a VM in the network
3. Verify VM deployment
4. From the VM, curl the gateway of the VR to verify the corresponding metadata - hypervisor host name
if the respective Global level and account level flags are set to true
"""
# Update global setting for "global.allow.expose.host.hostname"
Configurations.update(self.apiclient,
name="global.allow.expose.host.hostname",
value="true"
)
# Update Account level setting
Configurations.update(self.apiclient,
name="account.allow.expose.host.hostname",
value="true"
)
# Verify that the above mentioned settings are set to true before proceeding
if not is_config_suitable(
apiclient=self.apiclient,
name='global.allow.expose.host.hostname',
value='true'):
self.skipTest('global.allow.expose.host.hostname should be true. skipping')
if not is_config_suitable(
apiclient=self.apiclient,
name='account.allow.expose.host.hostname',
value='true'):
self.skipTest('account.allow.expose.host.hostname should be true. skipping')
self.no_isolate = NetworkOffering.create(
self.apiclient,
self.services["isolated_network_offering"]
)
self.no_isolate.update(self.apiclient, state='Enabled')
self.isolated_network = Network.create(
self.apiclient,
self.services["network"],
networkofferingid=self.no_isolate.id,
zoneid=self.zone.id,
accountid="admin",
domainid=1
)
self.cleanup.append(self.isolated_network)
self.vm = VirtualMachine.create(
self.apiclient,
self.services["virtual_machine"],
templateid=self.template.id,
accountid="admin",
domainid=1,
serviceofferingid=self.service_offering.id,
zoneid=self.zone.id,
networkids=[self.isolated_network.id],
)
self.assertIsNotNone(
self.vm,
"VM creation failed in the isolated network"
)
self.cleanup.append(self.vm)
ip_addr = self.vm.ipaddress
self.debug("VM ip address = %s" % ip_addr)
# Verify the retrieved ip address in listNICs API response
self.list_nics(self.vm.id)
vr_res = Router.list(
self.apiclient,
networkid=self.isolated_network.id,
listAll=True
)
self.assertEqual(validateList(vr_res)[0], PASS, "List Routers returned invalid response")
vr_ip = vr_res[0].guestipaddress
ssh = self.vm.get_ssh_client(ipaddress=ip_addr)
cmd = "curl http://%s/latest/hypervisor-host-name" % vr_ip
res = ssh.execute(cmd)
self.debug("Verifying hypervisor hostname details in the VR")
self.assertEqual(
str(res),
self.vm.hostname,
"Failed to get the hypervisor host name from VR in isolated network"
)
# Reset configuration values to default values i.e., false
Configurations.update(self.apiclient,
name="global.allow.expose.host.hostname",
value="false"
)
# Update Account level setting
Configurations.update(self.apiclient,
name="account.allow.expose.host.hostname",
value="false"
)
return
@attr(tags=["advanced"], required_hardware='True')
def test_deployVM_verify_metadata_in_VR_after_migration(self):
"""
1. Create a network (VR as a provider)
2. Deploy a VM in the network
3. Verify VM deployment
4. Migrate VM to another host
4. After migration, from the VM, curl the gateway to verify the corresponding metadata - hypervisor host name
if the respective Global level and account level flags are set to true
"""
# Update global setting for "global.allow.expose.host.hostname"
Configurations.update(self.apiclient,
name="global.allow.expose.host.hostname",
value="true"
)
# Update Account level setting
Configurations.update(self.apiclient,
name="account.allow.expose.host.hostname",
value="true"
)
# Verify that the above mentioned settings are set to true before proceeding
if not is_config_suitable(
apiclient=self.apiclient,
name='global.allow.expose.host.hostname',
value='true'):
self.skipTest('global.allow.expose.host.hostname should be true. skipping')
if not is_config_suitable(
apiclient=self.apiclient,
name='account.allow.expose.host.hostname',
value='true'):
self.skipTest('Account level account.allow.expose.host.hostname should be true. skipping')
self.no_isolate = NetworkOffering.create(
self.apiclient,
self.services["isolated_network_offering"]
)
self.no_isolate.update(self.apiclient, state='Enabled')
self.isolated_network = Network.create(
self.apiclient,
self.services["network"],
networkofferingid=self.no_isolate.id,
zoneid=self.zone.id,
accountid="admin",
domainid=1
)
self.cleanup.append(self.isolated_network)
self.vm = VirtualMachine.create(
self.apiclient,
self.services["virtual_machine"],
templateid=self.template.id,
accountid="admin",
domainid=1,
serviceofferingid=self.service_offering.id,
zoneid=self.zone.id,
networkids=[self.isolated_network.id],
)
self.assertIsNotNone(
self.vm,
"VM creation failed in the isolated network"
)
host = self.migrate_VM(self.vm)
self.cleanup.append(self.vm)
ip_addr = self.vm.ipaddress
self.debug("VM ip address = %s" % ip_addr)
# Verify the retrieved ip address in listNICs API response
self.list_nics(self.vm.id)
vr_res = Router.list(
self.apiclient,
networkid=self.isolated_network.id,
listAll=True
)
self.assertEqual(validateList(vr_res)[0], PASS, "List Routers returned invalid response")
vr_ip = vr_res[0].guestipaddress
ssh = self.vm.get_ssh_client(ipaddress=ip_addr)
cmd = "curl http://%s/latest/hypervisor-host-name" % vr_ip
res = ssh.execute(cmd)
self.debug("Verifying hypervisor hostname details in the VR")
self.assertEqual(
str(res),
host.name,
"Failed to get the hypervisor host name from VR in isolated network"
)
# Reset configuration values to default values i.e., false
Configurations.update(self.apiclient,
name="global.allow.expose.host.hostname",
value="false"
)
# Update Account level setting
Configurations.update(self.apiclient,
name="account.allow.expose.host.hostname",
value="false"
)
return