From ejcasler@us.ibm.com Thu Aug 14 17:06:18 2008 Date: Thu, 14 Aug 2008 14:05:38 -0700 From: Eric Casler To: ssmoser@linux.vnet.ibm.com Subject: [PATCH] Added filter & renamed getSections. Modified callers, OvfLibvirt, rmovf Now uses 'criteria', a variable length argument list, to filter results returned from getElementsByTagName. Searched project for calls to getSections, and modified to use getElements. Usually just changing name, but in some instances modifying call to utilize new method. Signed-off-by: Eric Casler --- py/ovf/Ovf.py | 133 ++++++++++++++++++++++--------------------------- py/ovf/OvfLibvirt.py | 13 +++-- py/scripts/rmovf | 8 ++-- 3 files changed, 71 insertions(+), 83 deletions(-) diff --git a/py/ovf/Ovf.py b/py/ovf/Ovf.py index 3da3c71..73038b6 100644 --- a/py/ovf/Ovf.py +++ b/py/ovf/Ovf.py @@ -65,69 +65,68 @@ def rmNodeAttributes(node,attributeList=[],strict=False): def getDefaultConfiguration(ovfDoc): """ - Returns identifier for the default configuration - """ - deploySection = getNodes(ovfDoc, 'DeploymentOptions') - if deploySection != []: - deployDict = getDict(deploySection[0]) - if deployDict['children'] != []: - return deployDict['children'][0]['ovf:id'] - - return None - -def getNodes(ovfNode, tagName, attrList = { }): + Returns identifier for the default configuration. + + @param ovfDoc: OVF Document + @type ovfDoc: DOM Document + + @return: default configuration identifier + @rtype: String """ - Returns a list of nodes from an OVF whose tagname is tagName - and that have attributes matching attrList. + default = getElements(ovfDoc, 'Configuration', + ('ovf:default', 'true')) + if len(default) == 0: + default = ovfDoc.getElementsByTagName('Configuration') + if len(default) == 0: + return None + else: + return default[0].getAttribute('ovf:id') + else: + return default[0].getAttribute('ovf:id') + +def getElements(ovfNode, tagName, *criteria): + """ + Returns a list of elements from an XML DOM Document, with the specified + tagName, filtered by optional search criteria. + + @note: For 'criteria', the user has two cases: + + B{Case 1}: key:value pairs. Limits results to elements with attribute names + equal to 'key' with values equal to 'value'. + + B{Case 2}: function:value pairs. 'function' takes a single argument, a DOM + Node, and returns a String. The String is tested for equality to the + 'value' element of the tuple. + + B{example}: ('ovf:class','org.redhat') - @param ovfNode: document or element to search + @param ovfNode: OVF document or element @type ovfNode: DOM Node - @param tagName: tag name of a node + @param tagName: tag name of section @type tagName: String - @param attrList: dictionary of attributes that returned list must contain - @type attrList: dictionary - - @return: list of nodes + @param criteria: filters for limiting results, processed in order + @type criteria: variable length list of tuples + + @return: list of elements @rtype: list of DOM nodes """ - matches = [ ] - for element in ovfNode.getElementsByTagName(tagName): - matches.append(element) - for key, val in attrList.items(): - if element.getAttribute(key) != val: - matches.pop() - break - return(matches) - -def getNodesWithId(ovfNode, tagName, id = None): - """ - return a list of nodes that have attribute - ( ovf:id | ovf:msgid | ovf:diskId ) == id - if id is 'None', all nodes matching tagName will be returned - - @param ovfNode: document or element to search - @type ovfNode: DOM Node - - @param tagName: tag name of a node - @type tagName: String - - @param id: id - @type id: String - - @return: list of nodes - @rtype: list of DOM nodes - """ - if(id == None): - return(getNodes(ovfNode, tagName)) - else: - t = getNodes(ovfNode,tagName) - return([ x for x in getNodes(ovfNode,tagName) - if x.getAttribute('ovf:id') == id or - x.getAttribute('ovf:msgid') == id or - x.getAttribute('ovf:diskId') == id - ]) + elements = ovfNode.getElementsByTagName(tagName) + + if criteria != None: + # Filter sections + for pair in criteria: + value = pair[1] + if isinstance(pair[0], type('')): + function = lambda elem: elem.getAttribute(pair[0]) + else: + function = pair[0] + + elements = [elem for elem in elements + if function(elem) == value] + + return elements def getContentEntities(ovfNode, ovfId=None): """ @@ -155,8 +154,8 @@ def getDict(ovfSection, configId=None): """ Returns a dictionary, with keys representing the attributes and the children, for an ovf section. Optionally, limits to given configuration. - L{getNodes} can be used to get a list of sections, each of which - could be passed in for the argument ovfSectionNode. + L{getElements} can be used to get a list of sections, each of which could + be passed in for the argument ovfSectionNode. @param ovfSection: OVF section @type ovfSection: DOM Node @@ -297,7 +296,8 @@ def isVirtualSystem(ovfDoc, ovfId): @return: True or False @rtype: boolean """ - return(getNodes(ovfDoc,'VirtualSystem', { 'ovf:id':ovfId }) != []) + systems = getElements(ovfDoc, 'VirtualSystem', ('ovf:id', ovfId)) + return (systems != []) def isVirtualSystemCollection(ovfDoc, ovfId): """ @@ -313,8 +313,8 @@ def isVirtualSystemCollection(ovfDoc, ovfId): @return: True or False @rtype: boolean """ - return(getNodes(ovfDoc,'VirtualSystemCollection', - { 'ovf:id':ovfId }) != []) + systems = getElements(ovfDoc, 'VirtualSystemCollection', ('ovf:id', ovfId)) + return (systems != []) def isConfiguration(ovfDoc, configId): """ @@ -328,22 +328,9 @@ def isConfiguration(ovfDoc, configId): @return: tests if configuration exists @rtype: boolean - - @raise ValueError: ConfigId doesn't match any in DeploymentOptions - @raise NotImplementedError: DeploymentOptions not defined """ - deploy = getNodes(ovfDoc, 'DeploymentOptions') - if deploy != []: - configList = getDict(deploy[0])['children'] - while configList != []: - config = configList.pop(0) - if config['ovf:id'] == configId: - return True - - return False - else: - # may want to throw different error if doesn't exist - raise NotImplementedError("Ovf.isConfiguration: No configurations found.") + configs = getElements(ovfDoc, 'Configuration', ('ovf:id', configId)) + return (configs != []) def sha1sumFile(path): """ diff --git a/py/ovf/OvfLibvirt.py b/py/ovf/OvfLibvirt.py index b47f6e0..1ba348a 100644 --- a/py/ovf/OvfLibvirt.py +++ b/py/ovf/OvfLibvirt.py @@ -937,7 +937,7 @@ def getOvfDisks(ovf, virtualHardware, configId=None): hostResource = ovfDisk['rasd:HostResource'] resourceId = hostResource.rsplit('/', 1).pop() if hostResource.startswith('ovf://disk/'): - diskList = Ovf.getDict(Ovf.getNodes(ovf, 'DiskSection')[0], + diskList = Ovf.getDict(Ovf.getElements(ovf, 'DiskSection')[0], configId)['children'] for child in diskList: @@ -946,7 +946,7 @@ def getOvfDisks(ovf, virtualHardware, configId=None): resourceId = hostResource.rsplit('/', 1).pop() if hostResource.startswith('ovf://file/'): - refList = Ovf.getDict(Ovf.getNodes(ovf, 'References')[0], + refList = Ovf.getDict(Ovf.getElements(ovf, 'References')[0], configId)['children'] for child in refList: @@ -1023,7 +1023,8 @@ def getOvfDomain(ovf, virtualSys, ovfId, configId=None): @todo: needs work, very basic, assumes hypervisor type """ # Get VirtualHardwareSection - virtualHardwareSection = Ovf.getNodes(virtualSys, 'VirtualHardwareSection') + virtualHardwareSection = Ovf.getElements(virtualSys, + 'VirtualHardwareSection') if virtualHardwareSection == []: raise NotImplementedError("OvfLibvirt.getOvfDomain: No " + \ @@ -1103,7 +1104,7 @@ def getOvfLibvirt(ovf, configId=None): configId = Ovf.getDefaultConfiguration(ovf) # For each system, create libvirt domain description - for system in Ovf.getNodes(ovf, 'VirtualSystem'): + for system in Ovf.getElements(ovf, 'VirtualSystem'): ovfId = system.getAttribute('ovf:id') domains[ovfId] = getOvfDomain(ovf, system, ovfId, configId) @@ -1126,7 +1127,7 @@ def getOvfStartup(ovf): systems = startupDict['entities'] # Create a list of all startup sections - startupSections = Ovf.getNodes(ovf, 'StartupSection') + startupSections = Ovf.getElements(ovf, 'StartupSection') # Create an entry in startup dictionary for each entry in Startup sections for section in startupSections: @@ -1153,7 +1154,7 @@ def getOvfStartup(ovf): systems[sysId] = virtualSys # Create a default entry for each system not in a startup section - for each in Ovf.getNodes(ovf, 'VirtualSystem'): + for each in Ovf.getElements(ovf, 'VirtualSystem'): sysId = each.getAttribute('ovf:id') # If parentNode is Envelope, set as root system diff --git a/py/scripts/rmovf b/py/scripts/rmovf index 693fba9..f20cb41 100755 --- a/py/scripts/rmovf +++ b/py/scripts/rmovf @@ -34,7 +34,7 @@ def rmReferences(ovfFile, options): @param options: The options from the optparser. @type options: Optparser object. """ - node = Ovf.getNodes(ovfFile.envelope, 'References') + node = Ovf.getElements(ovfFile.envelope, 'References') child = None for child in node[0].childNodes: if child.nodeName == "File": @@ -63,7 +63,7 @@ def rmDiskSection(ovfFile, options): @param options: The options from the optparser. @type options: Optparser object. """ - node = Ovf.getNodes(ovfFile.envelope, 'DiskSection') + node = Ovf.getElements(ovfFile.envelope, 'DiskSection') if options.section: ovfFile.envelope.removeChild(node[0]) else: @@ -103,7 +103,7 @@ def rmNetworkSection(ovfFile, options): @param options: The options from the optparser. @type options: Optparser object. """ - node = Ovf.getNodes(ovfFile.envelope, "NetworkSection") + node = Ovf.getElements(ovfFile.envelope, "NetworkSection") #need to get Network which is a child of node[0] if options.section: ovfFile.removeChild(node[0]) @@ -142,7 +142,7 @@ def rmDeploymentOptions(ovfFile, options): @type options: Optparser object. """ - node = Ovf.getNodes(ovfFile.envelope, 'DeploymentOptionSection') + node = Ovf.getElements(ovfFile.envelope, 'DeploymentOptionSection') if options.section: ovfFile.envelope.removeChild(node[0]) for child in node[0].childNodes: -- 1.5.4.3