Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ public VolumeFormat getFormat() {
return this._volFormat;
}

public Long getVolSize() {
return _volSize;
}

@Override
public String toString() {
StringBuilder storageVolBuilder = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;

import com.cloud.utils.StringUtils;
import org.apache.cloudstack.utils.security.ParserUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
Expand All @@ -35,6 +36,35 @@
public class LibvirtStorageVolumeXMLParser {
protected Logger logger = LogManager.getLogger(getClass());

public String getBackingFileNameIfExists(String volXML) {
try {
DocumentBuilder builder = ParserUtils.getSaferDocumentBuilderFactory().newDocumentBuilder();

InputSource is = new InputSource();
is.setCharacterStream(new StringReader(volXML));
Document doc = builder.parse(is);

Element rootElement = doc.getDocumentElement();
NodeList backingStores = rootElement.getElementsByTagName("backingStore");
if (backingStores.getLength() > 0) {
Element backingStore = (Element) backingStores.item(0);
NodeList pathNodes = backingStore.getElementsByTagName("path");
if (pathNodes.getLength() > 0) {
String path = pathNodes.item(0).getTextContent();
if (StringUtils.isBlank(path)) {
return null;
}
path = path.trim();
int lastSlash = path.lastIndexOf('/');
return lastSlash >= 0 ? path.substring(lastSlash + 1) : path;
}
}
} catch (ParserConfigurationException | SAXException | IOException e) {
logger.error(e.toString(), e);
}
return null;
}

public LibvirtStorageVolumeDef parseStorageVolumeXML(String volXML) {
DocumentBuilder builder;
try {
Expand All @@ -50,6 +80,7 @@ public LibvirtStorageVolumeDef parseStorageVolumeXML(String volXML) {
Element target = (Element)rootElement.getElementsByTagName("target").item(0);
String format = getAttrValue("type", "format", target);
Long capacity = Long.parseLong(getTagValue("capacity", rootElement));

return new LibvirtStorageVolumeDef(VolName, capacity, LibvirtStorageVolumeDef.VolumeFormat.getFormat(format), null, null);
} catch (ParserConfigurationException e) {
logger.debug(e.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -505,6 +506,12 @@ public LibvirtStoragePoolDef getStoragePoolDef(Connect conn, StoragePool pool) t
return parser.parseStoragePoolXML(poolDefXML);
}

private String getBackingFileOfVolumeIfExists(StorageVol vol) throws LibvirtException {
String volDefXML = vol.getXMLDesc(0);
LibvirtStorageVolumeXMLParser parser = new LibvirtStorageVolumeXMLParser();
return parser.getBackingFileNameIfExists(volDefXML);
}

public LibvirtStorageVolumeDef getStorageVolumeDef(Connect conn, StorageVol vol) throws LibvirtException {
String volDefXML = vol.getXMLDesc(0);
LibvirtStorageVolumeXMLParser parser = new LibvirtStorageVolumeXMLParser();
Expand Down Expand Up @@ -655,6 +662,28 @@ public KVMStoragePool getStoragePool(String uuid, boolean refreshInfo) {
}
}

private Long getBackingFileSizes(StoragePool pool, StorageVol vol) throws LibvirtException {
long total = 0L;
Set<String> visited = new HashSet<>();
StorageVol current = vol;

while (current != null) {
total += current.getInfo().allocation;
String backingName = getBackingFileOfVolumeIfExists(current);
if (StringUtils.isBlank(backingName) || !visited.add(backingName)) {
break;
}
try {
current = getVolume(pool, backingName);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens when the backing file isnt found in this pool? looks like each miss refreshes the whole pool, and this runs for every volume on each stats pass

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the backing file is not on the pool. Then the VM is inconsistent and likely corrupt. This should never happen currently.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, so the refresh only runs on a broken volume. that covers it

} catch (CloudRuntimeException e) {
logger.error("Unable to resolve backing volume {} in pool {}: {}", backingName, pool.getName(), e.getMessage());
break;
}
}

return total;
}

@Override
public KVMPhysicalDisk getPhysicalDisk(String volumeUuid, KVMStoragePool pool) {
LibvirtStoragePool libvirtPool = (LibvirtStoragePool)pool;
Expand All @@ -663,8 +692,9 @@ public KVMPhysicalDisk getPhysicalDisk(String volumeUuid, KVMStoragePool pool) {
StorageVol vol = getVolume(libvirtPool.getPool(), volumeUuid);
KVMPhysicalDisk disk;
LibvirtStorageVolumeDef voldef = getStorageVolumeDef(libvirtPool.getPool().getConnect(), vol);
Long allSizes = getBackingFileSizes(libvirtPool.getPool(), vol);
disk = new KVMPhysicalDisk(vol.getPath(), vol.getName(), pool);
disk.setSize(vol.getInfo().allocation);
disk.setSize(allSizes);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wont every volume made from the same template now count the whole template too? adding up the volumes on a pool would count it many times

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understood your question. But yes, volumes with linked clone templates will also account for the template size in the volume size. Which is congruent with what would be seen from inside the VM.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense if its meant to match what the vm sees. that covers it

disk.setVirtualSize(vol.getInfo().capacity);

/**
Expand Down
Loading