Package virtualization :: Module domain_config
[hide private]
[frames] | no frames]

Source Code for Module virtualization.domain_config

  1  # 
  2  # Copyright (c) 2008--2013 Red Hat, Inc. 
  3  # 
  4  # This software is licensed to you under the GNU General Public License, 
  5  # version 2 (GPLv2). There is NO WARRANTY for this software, express or 
  6  # implied, including the implied warranties of MERCHANTABILITY or FITNESS 
  7  # FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 
  8  # along with this software; if not, see 
  9  # http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 
 10  # 
 11  # Red Hat trademarks are not licensed under GPLv2. No permission is 
 12  # granted to use or replicate Red Hat trademarks that are incorporated 
 13  # in this software or its documentation. 
 14  # 
 15   
 16  from xml.dom.minidom import parse 
 17  import os 
 18  import sys 
 19   
 20  from spacewalk.common.usix import raise_with_tb 
 21   
 22   
 23  ############################################################################### 
 24  # Exceptions 
 25  ############################################################################### 
 26   
27 -class DomainConfigError(Exception): pass
28 29 ############################################################################### 30 # Classes 31 ############################################################################### 32
33 -class DataType:
34 ATTRIBUTE = "attribute" 35 VALUE = "value"
36
37 -class DomainConfigItem:
38 - def __init__(self, path, data_type):
39 self.path = path 40 self.data_type = data_type
41
42 -class DomainConfig:
43 44 ########################################################################### 45 # Constants 46 ########################################################################### 47 48 NAME = DomainConfigItem("domain/name", DataType.VALUE) 49 UUID = DomainConfigItem("domain/uuid", DataType.VALUE) 50 BOOTLOADER = DomainConfigItem("domain/bootloader", DataType.VALUE) 51 MEMORY = DomainConfigItem("domain/memory", DataType.VALUE) 52 VCPU = DomainConfigItem("domain/vcpu", DataType.VALUE) 53 OS = DomainConfigItem("domain/os", DataType.VALUE) 54 OS_TYPE = DomainConfigItem("domain/os/type", DataType.VALUE) 55 ROOT_DEVICE = DomainConfigItem("domain/os/root", DataType.VALUE) 56 COMMAND_LINE = DomainConfigItem("domain/os/cmdline", DataType.VALUE) 57 KERNEL_PATH = DomainConfigItem("domain/os/kernel", DataType.VALUE) 58 RAMDISK_PATH = DomainConfigItem("domain/os/initrd", DataType.VALUE) 59 DISK_IMAGE_PATH = DomainConfigItem("domain/devices/disk/source/file", 60 DataType.ATTRIBUTE) 61 DOMAIN_ID = DomainConfigItem("domain/id", DataType.ATTRIBUTE) 62 63 ########################################################################### 64 # Public Interface 65 ########################################################################### 66
67 - def __init__(self, config_path, uuid):
68 # Prepare the file name and parse the XML file. 69 if uuid.find(".xml") > 1 and os.path.exists(uuid): 70 self.__file_name = uuid 71 else: 72 self.__file_name = "%s/%s.xml" % (config_path, uuid) 73 74 self.__dom_tree = None 75 try: 76 self.__dom_tree = parse(self.__file_name).documentElement 77 except Exception: 78 e = sys.exc_info()[1] 79 raise_with_tb(DomainConfigError("Error reading config file '%s': %s" % (self.__file_name, str(e))), 80 sys.exc_info()[2])
81 82
83 - def save(self):
84 """Saves any changes made to this configuration.""" 85 file = None 86 try: 87 try: 88 file = open(self.__file_name, "w") 89 file.write(self.__dom_tree.toxml()) 90 except IOError: 91 ioe = sys.exc_info()[1] 92 raise_with_tb(DomainConfigError("Error saving config file '%s': %s" % (self.__file_name, str(ioe))), 93 sys.exc_info()[2]) 94 95 finally: 96 if file is not None: 97 file.close()
98
99 - def getFileName(self):
100 """ 101 Returns the path to the configuration file represented by this 102 object. 103 """ 104 return self.__file_name
105
106 - def toXML(self):
107 """Returns the XML representation of this configuration.""" 108 return self.__dom_tree.toxml()
109
110 - def getConfigItem(self, config_item):
111 if config_item.data_type == DataType.ATTRIBUTE: 112 return self.__getElementAttribute( 113 self.__dom_tree, 114 *config_item.path.split("/")) 115 elif config_item.data_type == DataType.VALUE: 116 return self.__getElementValue( 117 self.__dom_tree, 118 *config_item.path.split("/")) 119 120 raise DomainConfigError("Unknown config item data type '%s'" % \ 121 str(config_item.data_type))
122
123 - def hasConfigItem(self, config_item):
124 try: 125 self.getConfigItem(config_item) 126 except DomainConfigError: 127 return 0 128 return 1
129
130 - def removeConfigItem(self, config_item):
131 if config_item.data_type == DataType.ATTRIBUTE: 132 return self.__removeElementAttribute( 133 self.__dom_tree, 134 *config_item.path.split("/")) 135 elif config_item.data_type == DataType.VALUE: 136 return self.__removeElementValue( 137 self.__dom_tree, 138 *config_item.path.split("/")) 139 140 raise DomainConfigError("Unknown config item data type '%s'" % \ 141 str(config_item.data_type))
142
143 - def setConfigItem(self, config_item, value):
144 """ 145 Sets the value of an item in the tree. If the item does not yet exist, 146 it will be created. 147 """ 148 if config_item.data_type == DataType.ATTRIBUTE: 149 return self.__setElementAttribute( 150 self.__dom_tree, 151 value, 152 *config_item.path.split("/")) 153 elif config_item.data_type == DataType.VALUE: 154 return self.__setElementValue( 155 self.__dom_tree, 156 value, 157 *config_item.path.split("/")) 158 159 raise DomainConfigError("Unknown config item data type '%s'" % \ 160 str(config_item.data_type))
161
162 - def isInstallerConfig(self):
163 """ 164 Returns true if this configuration indicates that the domain was 165 started in a method that would put it into the installer. 166 """ 167 result = 0 168 if self.hasConfigItem(DomainConfig.COMMAND_LINE): 169 # Convert the command line to a dict for easy parsability. 170 command_line = self.getConfigItem(DomainConfig.COMMAND_LINE) 171 command_line_parts = command_line.strip().split(" ") 172 command_line_dict = {} 173 for part in command_line_parts: 174 command_line_args = part.split("=") 175 key = command_line_args[0] 176 command_line_dict[key] = None 177 if len(command_line_args) >= 2: 178 command_line_dict[key] = '='.join(command_line_args[1:]) 179 180 # Look for the "method" argument. This is a good indication that 181 # the instance is in the installer. 182 if "method" in command_line_dict or "ks" in command_line_dict or "autoyast" in command_line_dict: 183 result = 1 184 185 return result
186 187 ########################################################################### 188 # Helpers 189 ########################################################################### 190
191 - def __getElementValue(self, start_tree, *tag_path):
192 found = self.__extractElement(start_tree, *tag_path) 193 194 if len(found.childNodes) == 0: 195 raise DomainConfigError("Unable to find config value: " + "/".join(tag_path)) 196 197 return found.childNodes[0].data
198
199 - def __getElementAttribute(self, start_tree, *tag_path):
200 """ 201 Returns the value of the requested XML attribute. The attribute name 202 is the last value in the tag_path. 203 """ 204 attribute_name = tag_path[-1] 205 found = self.__extractElement(start_tree, *tag_path[:-1]) 206 207 # Dig out the value of the requested attribute. 208 if not found.hasAttribute(attribute_name): 209 raise DomainConfigError("Unable to find config attribute: " + "/".join(tag_path)) 210 211 return found.getAttribute(attribute_name)
212
213 - def __removeElementValue(self, start_tree, *tag_path):
214 found = self.__extractElement(start_tree, *tag_path) 215 216 if len(found.childNodes) == 0: 217 raise DomainConfigError("Unable to find config value: " + "/".join(tag_path)) 218 219 found.parentNode.removeChild(found)
220
221 - def __removeElementAttribute(self, start_tree, *tag_path):
222 attribute_name = tag_path[-1] 223 found = self.__extractElement(start_tree, *tag_path[:-1]) 224 225 if not found.hasAttribute(attribute_name): 226 raise DomainConfigError("Unable to find config attribute: " + "/".join(tag_path)) 227 228 found.removeAttribute(attribute_name)
229
230 - def __setElementValue(self, start_tree, value, *tag_path):
231 try: 232 found = self.__extractElement(start_tree, *tag_path) 233 except DomainConfigError: 234 # If an exception was thrown, the element did not exist. We'll 235 # add it. 236 found = self.__makeElement(start_tree, *tag_path) 237 238 if len(found.childNodes) == 0: 239 document = self.__dom_tree.parentNode 240 element_text = document.createTextNode('') 241 found.appendChild(element_text) 242 243 try: 244 found.childNodes[0].data = str(value) 245 except IndexError: 246 raise_with_tb(DomainConfigError("Error writing %s tag in '%s'." % ('/'.join(tag_path), self.__file_name)), 247 sys.exc_info()[2])
248
249 - def __setElementAttribute(self, start_tree, value, *tag_path):
250 attribute_name = tag_path[-1] 251 found = self.__extractElement(start_tree, *tag_path[:-1]) 252 found.setAttribute(attribute_name, str(value))
253
254 - def __makeElement(self, start_tree, *tag_path):
255 # If there are no more tags left in the path, there's nothing more to 256 # add. 257 if len(tag_path) == 0: 258 return start_tree 259 260 # Look for the first part of the tag. 261 tag = tag_path[0] 262 try: 263 element = self.__extractElement(start_tree, tag) 264 except DomainConfigError: 265 # No matching tag found. Create one. 266 document = self.__dom_tree.parentNode 267 element = document.createElement(tag) 268 start_tree.appendChild(element) 269 270 tag_path = tag_path[1:] 271 return self.__makeElement(element, *tag_path)
272
273 - def __extractElement(self, start_tree, *tag_path):
274 # If there are no more tags left in the path, we're done. 275 if len(tag_path) == 0: 276 return start_tree 277 278 # Extract the first matching child from this tree. 279 tag = tag_path[0] 280 281 if start_tree == self.__dom_tree: 282 # If this is the root node, ensure that the first part of the path 283 # matches. This is a special case because the getElementsByTagName 284 # only applies to elements below the root node. 285 if start_tree.nodeName != tag: 286 # First part of the tag path didn't match. Raise exception. 287 raise DomainConfigError("Could not locate tag <%s>." % tag) 288 else: 289 # First part matched; adjust the tag pointer, if there's any 290 # thing left. 291 tag_path = tag_path[1:] 292 if len(tag_path) == 0: 293 return start_tree 294 else: 295 tag = tag_path[0] 296 297 node_list = start_tree.getElementsByTagName(tag) 298 299 if node_list is not None and len(node_list) > 0: 300 tag_node = node_list[0] 301 return self.__extractElement(tag_node, *tag_path[1:]) 302 303 # If we got here, we couldn't find the tag in question. Raise an 304 # exception 305 raise DomainConfigError("Could not locate tag " + str(tag))
306 307 ############################################################################### 308 # Test Method 309 ############################################################################### 310 311 if __name__ == "__main__": 312 import sys 313 uuid = sys.argv[1] 314 f = DomainConfig("/etc/sysconfig/rhn/virt", uuid) 315 print("name=", f.getConfigItem(DomainConfig.NAME)) 316 print("memory=", f.getConfigItem(DomainConfig.MEMORY)) 317 print("domain_id=", f.getConfigItem(DomainConfig.DOMAIN_ID)) 318 f.setConfigItem(DomainConfig.DOMAIN_ID, 22322) 319 f.setConfigItem(DomainConfigItem("domain/argh", DataType.ATTRIBUTE), 22322) 320 f.setConfigItem(DomainConfigItem("domain/pete", DataType.VALUE), "hello") 321 f.setConfigItem(DomainConfigItem("domain/vcpu", DataType.VALUE), "22") 322 f.setConfigItem(DomainConfig.BOOTLOADER, "/usr/pete/bin/pygrub") 323 f.removeConfigItem(DomainConfigItem("domain/os", DataType.VALUE)) 324 print(f.toXML()) 325