This is an automated email from the ASF dual-hosted git repository.
dahn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/main by this push:
new 8c86f24261c enhancement: add instance info as Libvirt metadata (#11061)
8c86f24261c is described below
commit 8c86f24261c5133831d8412aec6067a794a701dd
Author: Phsm Qwerty <[email protected]>
AuthorDate: Fri Nov 7 14:31:34 2025 +0100
enhancement: add instance info as Libvirt metadata (#11061)
---
.../agent/api/to/VirtualMachineMetadataTO.java | 182 ++++++++++++++++++
.../com/cloud/agent/api/to/VirtualMachineTO.java | 9 +
.../kvm/resource/LibvirtComputingResource.java | 12 ++
.../hypervisor/kvm/resource/LibvirtVMDef.java | 209 +++++++++++++++++----
.../com/cloud/hypervisor/HypervisorGuruBase.java | 170 ++++++++++++++++-
.../main/java/com/cloud/hypervisor/KVMGuru.java | 4 +-
6 files changed, 547 insertions(+), 39 deletions(-)
diff --git
a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineMetadataTO.java
b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineMetadataTO.java
new file mode 100644
index 00000000000..5b22afdedd5
--- /dev/null
+++ b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineMetadataTO.java
@@ -0,0 +1,182 @@
+// 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.agent.api.to;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class VirtualMachineMetadataTO {
+ // VM details
+ private final String name;
+ private final String internalName;
+ private final String displayName;
+ private final String instanceUuid;
+ private final Integer cpuCores;
+ private final Integer memory;
+ private final Long created;
+ private final Long started;
+
+ // Owner details
+ private final String ownerDomainUuid;
+ private final String ownerDomainName;
+ private final String ownerAccountUuid;
+ private final String ownerAccountName;
+ private final String ownerProjectUuid;
+ private final String ownerProjectName;
+
+ // Host and service offering
+ private final String serviceOfferingName;
+ private final List<String> serviceOfferingHostTags;
+
+ // zone, pod, and cluster details
+ private final String zoneName;
+ private final String zoneUuid;
+ private final String podName;
+ private final String podUuid;
+ private final String clusterName;
+ private final String clusterUuid;
+
+ // resource tags
+ private final Map<String, String> resourceTags;
+
+ public VirtualMachineMetadataTO(
+ String name, String internalName, String displayName, String
instanceUuid, Integer cpuCores, Integer memory, Long created, Long started,
+ String ownerDomainUuid, String ownerDomainName, String
ownerAccountUuid, String ownerAccountName, String ownerProjectUuid, String
ownerProjectName,
+ String serviceOfferingName, List<String> serviceOfferingHostTags,
+ String zoneName, String zoneUuid, String podName, String podUuid,
String clusterName, String clusterUuid, Map<String, String> resourceTags) {
+ /*
+ * Something failed in the metadata shall not be a fatal error, the VM
can still be started
+ * Thus, the unknown fields just get an explicit "unknown" value so it
can be fixed in case
+ * there are bugs on some execution paths.
+ * */
+
+ this.name = (name != null) ? name : "unknown";
+ this.internalName = (internalName != null) ? internalName : "unknown";
+ this.displayName = (displayName != null) ? displayName : "unknown";
+ this.instanceUuid = (instanceUuid != null) ? instanceUuid : "unknown";
+ this.cpuCores = (cpuCores != null) ? cpuCores : -1;
+ this.memory = (memory != null) ? memory : -1;
+ this.created = (created != null) ? created : 0;
+ this.started = (started != null) ? started : 0;
+ this.ownerDomainUuid = (ownerDomainUuid != null) ? ownerDomainUuid :
"unknown";
+ this.ownerDomainName = (ownerDomainName != null) ? ownerDomainName :
"unknown";
+ this.ownerAccountUuid = (ownerAccountUuid != null) ? ownerAccountUuid
: "unknown";
+ this.ownerAccountName = (ownerAccountName != null) ? ownerAccountName
: "unknown";
+ this.ownerProjectUuid = (ownerProjectUuid != null) ? ownerProjectUuid
: "unknown";
+ this.ownerProjectName = (ownerProjectName != null) ? ownerProjectName
: "unknown";
+ this.serviceOfferingName = (serviceOfferingName != null) ?
serviceOfferingName : "unknown";
+ this.serviceOfferingHostTags = (serviceOfferingHostTags != null) ?
serviceOfferingHostTags : new ArrayList<>();
+ this.zoneName = (zoneName != null) ? zoneName : "unknown";
+ this.zoneUuid = (zoneUuid != null) ? zoneUuid : "unknown";
+ this.podName = (podName != null) ? podName : "unknown";
+ this.podUuid = (podUuid != null) ? podUuid : "unknown";
+ this.clusterName = (clusterName != null) ? clusterName : "unknown";
+ this.clusterUuid = (clusterUuid != null) ? clusterUuid : "unknown";
+
+ this.resourceTags = (resourceTags != null) ? resourceTags : new
HashMap<>();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getInternalName() {
+ return internalName;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public String getInstanceUuid() {
+ return instanceUuid;
+ }
+
+ public Integer getCpuCores() {
+ return cpuCores;
+ }
+
+ public Integer getMemory() {
+ return memory;
+ }
+
+ public Long getCreated() { return created; }
+
+ public Long getStarted() {
+ return started;
+ }
+
+ public String getOwnerDomainUuid() {
+ return ownerDomainUuid;
+ }
+
+ public String getOwnerDomainName() {
+ return ownerDomainName;
+ }
+
+ public String getOwnerAccountUuid() {
+ return ownerAccountUuid;
+ }
+
+ public String getOwnerAccountName() {
+ return ownerAccountName;
+ }
+
+ public String getOwnerProjectUuid() {
+ return ownerProjectUuid;
+ }
+
+ public String getOwnerProjectName() {
+ return ownerProjectName;
+ }
+
+ public String getserviceOfferingName() {
+ return serviceOfferingName;
+ }
+
+ public List<String> getserviceOfferingHostTags() {
+ return serviceOfferingHostTags;
+ }
+
+ public String getZoneName() {
+ return zoneName;
+ }
+
+ public String getZoneUuid() {
+ return zoneUuid;
+ }
+
+ public String getPodName() {
+ return podName;
+ }
+
+ public String getPodUuid() {
+ return podUuid;
+ }
+
+ public String getClusterName() {
+ return clusterName;
+ }
+
+ public String getClusterUuid() {
+ return clusterUuid;
+ }
+
+ public Map<String, String> getResourceTags() { return resourceTags; }
+}
diff --git a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java
b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java
index cffb9874080..e26cc1e9f02 100644
--- a/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java
+++ b/api/src/main/java/com/cloud/agent/api/to/VirtualMachineTO.java
@@ -89,6 +89,7 @@ public class VirtualMachineTO {
private DeployAsIsInfoTO deployAsIsInfo;
private String metadataManufacturer;
private String metadataProductName;
+ private VirtualMachineMetadataTO metadata;
public VirtualMachineTO(long id, String instanceName, VirtualMachine.Type
type, int cpus, Integer speed, long minRam, long maxRam, BootloaderType
bootloader,
String os, boolean enableHA, boolean limitCpuUse, String
vncPassword) {
@@ -494,6 +495,14 @@ public class VirtualMachineTO {
this.metadataProductName = metadataProductName;
}
+ public VirtualMachineMetadataTO getMetadata() {
+ return metadata;
+ }
+
+ public void setMetadata(VirtualMachineMetadataTO metadata) {
+ this.metadata = metadata;
+ }
+
@Override
public String toString() {
return String.format("VM {id: \"%s\", name: \"%s\", uuid: \"%s\",
type: \"%s\"}", id, name, uuid, type);
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 0aa094e56d9..fbfe3ef20eb 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@ -69,6 +69,7 @@ import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
+import com.cloud.agent.api.to.VirtualMachineMetadataTO;
import org.apache.cloudstack.api.ApiConstants.IoDriverPolicy;
import org.apache.cloudstack.command.CommandInfo;
import org.apache.cloudstack.command.ReconcileCommandService;
@@ -199,6 +200,7 @@ import
com.cloud.hypervisor.kvm.resource.LibvirtVMDef.VideoDef;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef;
import
com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef.WatchDogAction;
import
com.cloud.hypervisor.kvm.resource.LibvirtVMDef.WatchDogDef.WatchDogModel;
+import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.MetadataDef;
import
com.cloud.hypervisor.kvm.resource.rolling.maintenance.RollingMaintenanceAgentExecutor;
import
com.cloud.hypervisor.kvm.resource.rolling.maintenance.RollingMaintenanceExecutor;
import
com.cloud.hypervisor.kvm.resource.rolling.maintenance.RollingMaintenanceServiceExecutor;
@@ -3011,9 +3013,19 @@ public class LibvirtComputingResource extends
ServerResourceBase implements Serv
vm.addComp(createClockDef(vmTO));
vm.addComp(createDevicesDef(vmTO, guest, vcpus, isUefiEnabled));
+ MetadataDef metaDef;
+ if ((metaDef = createMetadataDef(vmTO)) != null) {
+ vm.addComp(metaDef);
+ }
+
addExtraConfigsToVM(vmTO, vm, extraConfig);
}
+ protected MetadataDef createMetadataDef(VirtualMachineTO vmTO) {
+ VirtualMachineMetadataTO metadata = vmTO.getMetadata();
+ return (metadata != null) ? new MetadataDef(metadata) : null;
+ }
+
/**
* Adds extra configuration to User VM Domain XML before starting.
*/
diff --git
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
index bf002b37f35..211395513d5 100644
---
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
+++
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
@@ -17,6 +17,10 @@
package com.cloud.hypervisor.kvm.resource;
import java.io.File;
+import java.io.StringWriter;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -29,9 +33,25 @@ import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
+import com.cloud.agent.api.to.VirtualMachineMetadataTO;
+
import com.cloud.agent.properties.AgentProperties;
import com.cloud.agent.properties.AgentPropertiesFileHandler;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+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 static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME;
public class LibvirtVMDef {
protected static Logger LOGGER = LogManager.getLogger(LibvirtVMDef.class);
@@ -46,6 +66,157 @@ public class LibvirtVMDef {
private final Map<String, Object> components = new HashMap<String,
Object>();
private static final int NUMBER_OF_IOTHREADS =
AgentPropertiesFileHandler.getPropertyValue(AgentProperties.IOTHREADS);
+ public static class MetadataDef {
+ private VirtualMachineMetadataTO metaTO;
+
+ public MetadataDef(VirtualMachineMetadataTO data) {
+ metaTO = data;
+ }
+
+ public VirtualMachineMetadataTO getMetadata() {
+ return metaTO;
+ }
+
+ @Override
+ public String toString() {
+ DocumentBuilderFactory docFactory =
DocumentBuilderFactory.newInstance();
+ docFactory.setNamespaceAware(true);
+ Document doc = null;
+ try {
+ doc = docFactory.newDocumentBuilder().newDocument();
+ } catch (ParserConfigurationException e) {
+ LOGGER.warn("Could not create a new DOM XML document. The
metadata will not be included in the libvirt domain XML: {}", e.getMessage());
+ return "";
+ }
+ Element metadata = doc.createElement("metadata"); // <metadata>
+ Element instance =
doc.createElementNS("http://cloudstack.apache.org/instance",
"cloudstack:instance"); // <cloudstack:instance>
+
+ Element zone = doc.createElement("cloudstack:zone");
+ zone.setAttribute("uuid", metaTO.getZoneUuid());
+ zone.setTextContent(metaTO.getZoneName());
+ instance.appendChild(zone);
+
+ Element pod = doc.createElement("cloudstack:pod");
+ pod.setAttribute("uuid", metaTO.getPodUuid());
+ pod.setTextContent(metaTO.getPodName());
+ instance.appendChild(pod);
+
+ Element cluster = doc.createElement("cloudstack:cluster");
+ cluster.setAttribute("uuid", metaTO.getClusterUuid());
+ cluster.setTextContent(metaTO.getClusterName());
+ instance.appendChild(cluster);
+
+ Element instanceName = doc.createElement("cloudstack:name");
+ instanceName.setTextContent(metaTO.getName());
+ instance.appendChild(instanceName);
+
+ Element instanceInternalName =
doc.createElement("cloudstack:internal_name");
+ instanceInternalName.setTextContent(metaTO.getInternalName());
+ instance.appendChild(instanceInternalName);
+
+ Element instanceDisplayName =
doc.createElement("cloudstack:display_name");
+ instanceDisplayName.setTextContent(metaTO.getDisplayName());
+ instance.appendChild(instanceDisplayName);
+
+ Element instanceUuid = doc.createElement("cloudstack:uuid");
+ instanceUuid.setTextContent(metaTO.getInstanceUuid());
+ instance.appendChild(instanceUuid);
+
+ Element serviceOffering =
doc.createElement("cloudstack:service_offering"); // <service_offering>
+
+ Element computeOfferingName = doc.createElement("cloudstack:name");
+
computeOfferingName.setTextContent(metaTO.getserviceOfferingName());
+ serviceOffering.appendChild(computeOfferingName);
+
+ Element cpu = doc.createElement("cloudstack:cpu");
+ cpu.setTextContent(metaTO.getCpuCores().toString());
+ serviceOffering.appendChild(cpu);
+
+ Element memory = doc.createElement("cloudstack:memory");
+ memory.setTextContent(metaTO.getMemory().toString());
+ serviceOffering.appendChild(memory);
+
+ Element hostTags = doc.createElement("cloudstack:host_tags");
+ List<String> tags = metaTO.getserviceOfferingHostTags();
+ if (tags != null) {
+ for (String i : metaTO.getserviceOfferingHostTags()) {
+ Element tag = doc.createElement("cloudstack:tag");
+ tag.setTextContent(i);
+ hostTags.appendChild(tag);
+ }
+ }
+ serviceOffering.appendChild(hostTags);
+
+ instance.appendChild(serviceOffering); // </service_offering>
+
+ Element creationTime = doc.createElement("cloudstack:created_at");
+ creationTime.setTextContent(
+
LocalDateTime.ofInstant(Instant.ofEpochSecond(metaTO.getCreated()),
ZoneOffset.UTC).format(ISO_LOCAL_DATE_TIME)
+ );
+ instance.appendChild(creationTime);
+
+ Element startedTime = doc.createElement("cloudstack:started_at");
+ startedTime.setTextContent(
+
LocalDateTime.ofInstant(Instant.ofEpochSecond(metaTO.getStarted()),
ZoneOffset.UTC).format(ISO_LOCAL_DATE_TIME)
+ );
+ instance.appendChild(startedTime);
+
+ Element owner = doc.createElement("cloudstack:owner"); // <owner>
+
+ Element domain = doc.createElement("cloudstack:domain");
+ domain.setAttribute("uuid", metaTO.getOwnerDomainUuid());
+ domain.setTextContent(metaTO.getOwnerDomainName());
+ owner.appendChild(domain);
+
+ Element account = doc.createElement("cloudstack:account");
+ account.setAttribute("uuid", metaTO.getOwnerAccountUuid());
+ account.setTextContent(metaTO.getOwnerAccountName());
+ owner.appendChild(account);
+
+ Element project = doc.createElement("cloudstack:project");
+ project.setAttribute("uuid", metaTO.getOwnerProjectUuid());
+ project.setTextContent(metaTO.getOwnerProjectName());
+ owner.appendChild(project);
+
+ instance.appendChild(owner); // </owner>
+
+ Element resourceTags =
doc.createElement("cloudstack:resource_tags"); // <resource_tags>
+ for (Map.Entry<String, String> entry :
metaTO.getResourceTags().entrySet()) {
+ Element tag = doc.createElement("cloudstack:resource_tag"); //
<resource_tag>
+ tag.setAttribute("key", entry.getKey());
+ tag.setTextContent(entry.getValue());
+ resourceTags.appendChild(tag); // </resource_tag>
+ }
+ instance.appendChild(resourceTags); // </resource_tags>
+
+ metadata.appendChild(instance); // </cloudstack:instance>
+ doc.appendChild(metadata); // </metadata>
+
+ Transformer transformer = null;
+ try {
+ transformer =
TransformerFactory.newInstance().newTransformer();
+ } catch (TransformerConfigurationException e) {
+ LOGGER.warn("Could not create an XML transformer. The metadata
will not be included in the libvirt domain XML: {}", e.getMessage());
+ return "";
+ }
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,
"yes");
+ transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+
+ DOMSource domSource = new DOMSource(doc);
+ StringWriter writer = new StringWriter();
+ StreamResult result = new StreamResult(writer);
+ try {
+ transformer.transform(domSource, result);
+ } catch (TransformerException e) {
+ LOGGER.warn("Could not generate metadata XML. The metadata
will not be included in the libvirt domain XML: {}", e.getMessage());
+ return "";
+ }
+
+ return writer.toString();
+ }
+ }
+
public static class GuestDef {
enum GuestType {
KVM, XEN, EXE, LXC
@@ -2163,34 +2334,6 @@ public class LibvirtVMDef {
}
}
- public class MetadataDef {
- Map<String, Object> customNodes = new HashMap<>();
-
- public <T> T getMetadataNode(Class<T> fieldClass) {
- T field = (T) customNodes.get(fieldClass.getName());
- if (field == null) {
- try {
- field = fieldClass.newInstance();
- customNodes.put(field.getClass().getName(), field);
- } catch (InstantiationException | IllegalAccessException e) {
- LOGGER.debug("No default constructor available in class "
+ fieldClass.getName() + ", ignoring exception", e);
- }
- }
- return field;
- }
-
- @Override
- public String toString() {
- StringBuilder fsBuilder = new StringBuilder();
- fsBuilder.append("<metadata>\n");
- for (Object field : customNodes.values()) {
- fsBuilder.append(field.toString());
- }
- fsBuilder.append("</metadata>\n");
- return fsBuilder.toString();
- }
- }
-
public static class RngDef {
enum RngModel {
VIRTIO("virtio");
@@ -2493,15 +2636,6 @@ public class LibvirtVMDef {
return null;
}
- public MetadataDef getMetaData() {
- MetadataDef o = (MetadataDef)
components.get(MetadataDef.class.toString());
- if (o == null) {
- o = new MetadataDef();
- addComp(o);
- }
- return o;
- }
-
@Override
public String toString() {
StringBuilder vmBuilder = new StringBuilder();
@@ -2513,6 +2647,7 @@ public class LibvirtVMDef {
if (_desc != null) {
vmBuilder.append("<description>" + _desc + "</description>\n");
}
+
for (Object o : components.values()) {
vmBuilder.append(o.toString());
}
diff --git a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
index d40b5b22698..928107be9ce 100644
--- a/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
+++ b/server/src/main/java/com/cloud/hypervisor/HypervisorGuruBase.java
@@ -16,6 +16,9 @@
// under the License.
package com.cloud.hypervisor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -24,18 +27,31 @@ import java.util.UUID;
import javax.inject.Inject;
import com.cloud.agent.api.to.GPUDeviceTO;
+import com.cloud.agent.api.to.VirtualMachineMetadataTO;
import com.cloud.cpu.CPU;
+import com.cloud.dc.ClusterVO;
import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.HostPodVO;
+import com.cloud.dc.dao.ClusterDao;
import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.HostPodDao;
import com.cloud.domain.Domain;
+import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.gpu.VgpuProfileVO;
import com.cloud.gpu.dao.VgpuProfileDao;
import com.cloud.network.vpc.VpcVO;
import com.cloud.network.vpc.dao.VpcDao;
+import com.cloud.projects.ProjectVO;
+import com.cloud.projects.dao.ProjectDao;
+import com.cloud.server.ResourceTag;
+import com.cloud.tags.dao.ResourceTagDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.dao.UserVmDao;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.backup.Backup;
import
org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
@@ -97,7 +113,7 @@ public abstract class HypervisorGuruBase extends AdapterBase
implements Hypervis
@Inject
protected AccountManager accountManager;
@Inject
- private DomainDao domainDao;
+ protected DomainDao domainDao;
@Inject
private DataCenterDao dcDao;
@Inject
@@ -125,7 +141,19 @@ public abstract class HypervisorGuruBase extends
AdapterBase implements Hypervis
@Inject
private UserVmManager userVmManager;
@Inject
+ protected UserVmDao userVmDao;
+ @Inject
+ protected ProjectDao projectDao;
+ @Inject
+ protected ClusterDao clusterDao;
+ @Inject
+ protected DataCenterDao dataCenterDao;
+ @Inject
+ protected HostPodDao hostPodDao;
+ @Inject
private ConfigurationManager configurationManager;
+ @Inject
+ ResourceTagDao tagsDao;
public static ConfigKey<Boolean>
VmMinMemoryEqualsMemoryDividedByMemOverprovisioningFactor = new
ConfigKey<Boolean>("Advanced", Boolean.class,
"vm.min.memory.equals.memory.divided.by.mem.overprovisioning.factor", "true",
"If we set this to 'true', a minimum memory (memory/
mem.overprovisioning.factor) will be set to the VM, independent of using a
scalable service offering or not.", true, ConfigKey.Scope.Cluster);
@@ -470,4 +498,144 @@ public abstract class HypervisorGuruBase extends
AdapterBase implements Hypervis
logger.error("Unsupported operation: cannot remove template file");
return false;
}
+
+ /**
+ * Generates VirtualMachineMetadataTO object from VirtualMachineProfile
+ * It is a helper function to be used in the inherited classes to avoid
repetition
+ * while generating metadata for multiple Guru implementations
+ *
+ * @param vmProfile virtual machine profile object
+ * @return A VirtualMachineMetadataTO ready to be appended to
VirtualMachineTO object
+ * @see KVMGuru
+ */
+ protected VirtualMachineMetadataTO
makeVirtualMachineMetadata(VirtualMachineProfile vmProfile) {
+ String vmName = "unknown",
+ instanceName = "unknown",
+ displayName = "unknown",
+ instanceUuid = "unknown",
+ clusterName = "unknown",
+ clusterUuid = "unknown",
+ zoneUuid = "unknown",
+ zoneName = "unknown",
+ podUuid = "unknown",
+ podName = "unknown",
+ domainUuid = "unknown",
+ domainName = "unknown",
+ accountUuid = "unknown",
+ accountName = "unknown",
+ projectName = "", // the project can be empty
+ projectUuid = "", // the project can be empty
+ serviceOfferingName = "unknown";
+ long created = 0L;
+ Integer cpuCores = -1, memory = -1;
+ List<String> serviceOfferingTags = new ArrayList<>();
+ HashMap<String, String> resourceTags = new HashMap<>();
+
+ UserVmVO vmVO =
userVmDao.findById(vmProfile.getVirtualMachine().getId());
+ if (vmVO != null) {
+ instanceUuid = vmVO.getUuid();
+ vmName = vmVO.getHostName(); // this returns the VM name field
+ instanceName = vmVO.getInstanceName();
+ displayName = vmVO.getDisplayName();
+ created = vmVO.getCreated().getTime() / 1000L;
+
+ HostVO host = hostDao.findById(vmVO.getHostId());
+ if (host != null) {
+ // Find zone and cluster
+ Long clusterId = host.getClusterId();
+ ClusterVO cluster = clusterDao.findById(clusterId);
+
+ if (cluster != null) {
+ clusterName = cluster.getName();
+ clusterUuid = cluster.getUuid();
+
+ DataCenterVO zone =
dataCenterDao.findById(cluster.getDataCenterId());
+ if (zone != null) {
+ zoneUuid = zone.getUuid();
+ zoneName = zone.getName();
+ }
+
+ HostPodVO pod = hostPodDao.findById(cluster.getPodId());
+ if (pod != null) {
+ podUuid = pod.getUuid();
+ podName = pod.getName();
+ }
+ }
+ } else {
+ logger.warn("Could not find the Host object for the virtual
machine (null value returned). Libvirt metadata for cluster, pod, zone will not
be populated.");
+ }
+
+ DomainVO domain = domainDao.findById(vmVO.getDomainId());
+ if (domain != null) {
+ domainUuid = domain.getUuid();
+ domainName = domain.getName();
+ } else {
+ logger.warn("Could not find the Domain object for the virtual
machine (null value returned). Libvirt metadata for domain will not be
populated.");
+ }
+
+ Account account = accountManager.getAccount(vmVO.getAccountId());
+ if (account != null) {
+ accountUuid = account.getUuid();
+ accountName = account.getName();
+
+ ProjectVO project =
projectDao.findByProjectAccountId(account.getId());
+ if (project != null) {
+ projectName = project.getName();
+ projectUuid = project.getUuid();
+ }
+ } else {
+ logger.warn("Could not find the Account object for the virtual
machine (null value returned). Libvirt metadata for account and project will
not be populated.");
+ }
+
+ List<? extends ResourceTag> resourceTagsList =
tagsDao.listBy(vmVO.getId(), ResourceTag.ResourceObjectType.UserVm);
+ if (resourceTagsList != null) {
+ for (ResourceTag tag : resourceTagsList) {
+ resourceTags.put(tag.getKey(), tag.getValue());
+ }
+ }
+ } else {
+ logger.warn("Could not find the VirtualMachine object by its
profile (null value returned). Libvirt metadata will not be populated.");
+ }
+
+ ServiceOffering serviceOffering = vmProfile.getServiceOffering();
+ if (serviceOffering != null) {
+ serviceOfferingName = serviceOffering.getName();
+ cpuCores = serviceOffering.getCpu();
+ memory = serviceOffering.getRamSize();
+
+ String hostTagsCommaSeparated = serviceOffering.getHostTag();
+ if (hostTagsCommaSeparated != null) { // when service offering has
no host tags, this value is null
+ serviceOfferingTags =
Arrays.asList(hostTagsCommaSeparated.split(","));
+ }
+ } else {
+ logger.warn("Could not find the ServiceOffering object by its
profile (null value returned). Libvirt metadata for service offering will not
be populated.");
+ }
+
+
+ return new VirtualMachineMetadataTO(
+ vmName, // name
+ instanceName, // internalName
+ displayName, // displayName
+ instanceUuid , // instanceUUID
+ cpuCores, // cpuCores
+ memory, // memory
+ created, // created, unix epoch in seconds
+ System.currentTimeMillis() / 1000L, // started, unix epoch in
seconds
+ domainUuid, // ownerDomainUUID
+ domainName, // ownerDomainName
+ accountUuid, // ownerAccountUUID
+ accountName, // ownerAccountName
+ projectUuid,
+ projectName,
+ serviceOfferingName,
+ serviceOfferingTags, // serviceOfferingTags
+ zoneName,
+ zoneUuid,
+ podName,
+ podUuid,
+ clusterName,
+ clusterUuid,
+ resourceTags
+ );
+ }
}
diff --git a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java
b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java
index 64881df4c82..d907e726b20 100644
--- a/server/src/main/java/com/cloud/hypervisor/KVMGuru.java
+++ b/server/src/main/java/com/cloud/hypervisor/KVMGuru.java
@@ -155,7 +155,6 @@ public class KVMGuru extends HypervisorGuruBase implements
HypervisorGuru {
}
@Override
-
public VirtualMachineTO implement(VirtualMachineProfile vm) {
VirtualMachineTO to = toVirtualMachineTO(vm);
setVmQuotaPercentage(to, vm);
@@ -170,6 +169,9 @@ public class KVMGuru extends HypervisorGuruBase implements
HypervisorGuru {
configureVmOsDescription(virtualMachine, to, host);
configureVmMemoryAndCpuCores(to, host, virtualMachine, vm);
+
+ to.setMetadata(makeVirtualMachineMetadata(vm));
+
return to;
}