1919
2020package com .cloud .hypervisor .kvm .resource .wrapper ;
2121
22+ import java .io .IOException ;
23+ import java .io .InputStream ;
24+ import java .io .StringWriter ;
2225import java .net .URISyntaxException ;
26+ import java .nio .charset .StandardCharsets ;
2327
28+ import javax .xml .parsers .DocumentBuilder ;
29+ import javax .xml .parsers .DocumentBuilderFactory ;
30+ import javax .xml .parsers .ParserConfigurationException ;
31+ import javax .xml .transform .Transformer ;
32+ import javax .xml .transform .TransformerException ;
33+ import javax .xml .transform .TransformerFactory ;
34+ import javax .xml .transform .dom .DOMSource ;
35+ import javax .xml .transform .stream .StreamResult ;
36+ import javax .xml .xpath .XPath ;
37+ import javax .xml .xpath .XPathConstants ;
38+ import javax .xml .xpath .XPathExpressionException ;
39+ import javax .xml .xpath .XPathFactory ;
40+
41+ import org .apache .cloudstack .utils .security .ParserUtils ;
42+ import org .apache .commons .io .IOUtils ;
2443import org .libvirt .Connect ;
2544import org .libvirt .Domain ;
2645import org .libvirt .LibvirtException ;
46+ import org .w3c .dom .Document ;
47+ import org .w3c .dom .Node ;
48+ import org .w3c .dom .NodeList ;
49+ import org .xml .sax .SAXException ;
2750
2851import com .cloud .agent .api .Answer ;
2952import com .cloud .agent .api .UnmanageInstanceAnswer ;
@@ -48,29 +71,39 @@ public Answer execute(final UnmanageInstanceCommand command, final LibvirtComput
4871 logger .debug ("Attempting to unmanage KVM instance: {}" , instanceName );
4972 Domain dom = null ;
5073 Connect conn = null ;
74+ String vmFinalSpecification ;
5175 try {
5276 if (vmSpec == null ) {
5377 conn = libvirtUtilitiesHelper .getConnectionByVmName (instanceName );
5478 dom = conn .domainLookupByName (instanceName );
55- String domainXML = dom .getXMLDesc (1 );
56- conn .domainDefineXML (domainXML ).free ();
79+ vmFinalSpecification = dom .getXMLDesc (1 );
80+ if (command .isConfigDriveAttached ()) {
81+ vmFinalSpecification = cleanupConfigDrive (vmFinalSpecification , instanceName );
82+ }
5783 } else {
5884 // define domain using reconstructed vmSpec
5985 logger .debug ("Unmanaging Stopped KVM instance: {}" , instanceName );
6086 LibvirtVMDef vm = libvirtComputingResource .createVMFromSpec (vmSpec );
6187 libvirtComputingResource .createVbd (conn , vmSpec , instanceName , vm );
6288 conn = libvirtUtilitiesHelper .getConnectionByType (vm .getHvsType ());
6389 String vmInitialSpecification = vm .toString ();
64- String vmFinalSpecification = performXmlTransformHook (vmInitialSpecification , libvirtComputingResource );
65- conn .domainDefineXML (vmFinalSpecification ).free ();
90+ vmFinalSpecification = performXmlTransformHook (vmInitialSpecification , libvirtComputingResource );
6691 }
67- logger .debug ("Successfully unmanaged KVM instance: {}" , instanceName );
92+ conn .domainDefineXML (vmFinalSpecification ).free ();
93+ logger .debug ("Successfully unmanaged KVM instance: {} with domain XML: {}" , instanceName , vmFinalSpecification );
6894 return new UnmanageInstanceAnswer (command , true , "Successfully unmanaged" );
6995 } catch (final LibvirtException e ) {
70- logger .warn ("LibvirtException occurred during unmanaging instance: {} " , instanceName , e );
96+ logger .error ("LibvirtException occurred during unmanaging instance: {} " , instanceName , e );
7197 return new UnmanageInstanceAnswer (command , false , e .getMessage ());
72- } catch (final URISyntaxException | InternalErrorException e ) {
73- logger .warn ("URISyntaxException " , e );
98+ } catch (final IOException
99+ | ParserConfigurationException
100+ | SAXException
101+ | TransformerException
102+ | XPathExpressionException
103+ | InternalErrorException
104+ | URISyntaxException e ) {
105+
106+ logger .error ("Failed to unmanage Instance: {}." , instanceName , e );
74107 return new UnmanageInstanceAnswer (command , false , e .getMessage ());
75108 } finally {
76109 if (dom != null ) {
@@ -83,6 +116,45 @@ public Answer execute(final UnmanageInstanceCommand command, final LibvirtComput
83116 }
84117 }
85118
119+ String cleanupConfigDrive (String domainXML , String instanceName ) throws ParserConfigurationException , IOException , SAXException , XPathExpressionException , TransformerException {
120+ String isoName = "/" + instanceName + ".iso" ;
121+ DocumentBuilderFactory docFactory = ParserUtils .getSaferDocumentBuilderFactory ();
122+ DocumentBuilder docBuilder = docFactory .newDocumentBuilder ();
123+ Document document ;
124+ try (InputStream inputStream = IOUtils .toInputStream (domainXML , StandardCharsets .UTF_8 )) {
125+ document = docBuilder .parse (inputStream );
126+ }
127+ XPathFactory xPathFactory = XPathFactory .newInstance ();
128+ XPath xpath = xPathFactory .newXPath ();
129+
130+ // Find all <disk device='cdrom'> elements with source file containing instanceName.iso
131+ String expression = String .format ("//disk[@device='cdrom'][source/@file[contains(., '%s')]]" , isoName );
132+ NodeList cdromDisks = (NodeList ) xpath .evaluate (expression , document , XPathConstants .NODESET );
133+
134+ // If nothing matched, return original XML
135+ if (cdromDisks == null || cdromDisks .getLength () == 0 ) {
136+ logger .debug ("No config drive found in domain XML for Instance: {}" , instanceName );
137+ return domainXML ;
138+ }
139+
140+ // Remove all matched config drive disks
141+ for (int i = 0 ; i < cdromDisks .getLength (); i ++) {
142+ Node diskNode = cdromDisks .item (i );
143+ if (diskNode != null && diskNode .getParentNode () != null ) {
144+ diskNode .getParentNode ().removeChild (diskNode );
145+ }
146+ }
147+ logger .debug ("Removed {} config drive ISO CD-ROM entries for instance: {}" , cdromDisks .getLength (), instanceName );
148+
149+ TransformerFactory transformerFactory = ParserUtils .getSaferTransformerFactory ();
150+ Transformer transformer = transformerFactory .newTransformer ();
151+ DOMSource source = new DOMSource (document );
152+ StringWriter output = new StringWriter ();
153+ StreamResult result = new StreamResult (output );
154+ transformer .transform (source , result );
155+ return output .toString ();
156+ }
157+
86158 private String performXmlTransformHook (String vmInitialSpecification , final LibvirtComputingResource libvirtComputingResource ) {
87159 String vmFinalSpecification ;
88160 try {
0 commit comments