def test_strip_ns(self): """Test the strip_ns() function.""" self.assertEqual( "required", XML.strip_ns("{http://schemas.dmtf.org/ovf/envelope/1}required")) self.assertEqual("required", XML.strip_ns("required")) self.assertLogged(levelname="ERROR", msg="no associated namespace")
def test_strip_ns(self): """Test the strip_ns() function.""" self.assertEqual( "required", XML.strip_ns("{http://schemas.dmtf.org/ovf/envelope/1}required")) self.assertEqual( "required", XML.strip_ns("required"))
def test_strip_ns(self): """Test the strip_ns() function.""" self.assertEqual( "required", XML.strip_ns("{http://schemas.dmtf.org/ovf/envelope/1}required")) self.assertEqual( "required", XML.strip_ns("required")) self.assertLogged(levelname="ERROR", msg="no associated namespace")
class TestXMLInstance(unittest.TestCase): """Test cases for XML instance methods.""" OVF = "{http://schemas.dmtf.org/ovf/envelope/1}" def setUp(self): """Test case setup function called automatically prior to each test.""" self.xml = XML() self.xml.read_xml(resource_filename(__name__, "input.ovf")) super(TestXMLInstance, self).setUp() def test_find_child(self): """Test corner cases of the find_child() method.""" match = self.xml.find_child(self.xml.root, self.OVF + "References") self.assertEqual(match.tag, self.OVF + "References") # multiple children -> LookupError self.assertRaises(LookupError, self.xml.find_child, match, self.OVF + "File") # no such child -> None unless required match = self.xml.find_child(self.xml.root, self.OVF + "Foobar") self.assertEqual(None, match) # no such child -> KeyError if required self.assertRaises(KeyError, self.xml.find_child, self.xml.root, self.OVF + "Foobar", required=True) def test_set_or_make_child(self): """Call set_or_make_child() in some slightly incorrect ways.""" # Trigger the warning in add_child() logged when # creating a new child that's in a known namespace # but the child isn't in the expected ordering self.xml.set_or_make_child( self.xml.root, self.OVF + "foo", ordering=[self.OVF + "References"], known_namespaces=["http://schemas.dmtf.org/ovf/envelope/1"] ) # Trigger the warning in add_child() logged when # creating a new child in a known namespace # with an expected ordering that includes the child, # but other children in this namespace are left out. self.xml.set_or_make_child( self.xml.root, self.OVF + "bar", ordering=[self.OVF + "DiskSection", self.OVF + "bar"], known_namespaces=["http://schemas.dmtf.org/ovf/envelope/1"] )
def update_xml(self): """Regenerate all Items under the VirtualHardwareSection, if needed. Will do nothing if no Items have been changed. """ modified = False if len(self.item_dict) != len( XML.find_all_children( self.ovf.virtual_hw_section, set([ self.ovf.ITEM, self.ovf.STORAGE_ITEM, self.ovf.ETHERNET_PORT_ITEM ]))): modified = True else: for ovfitem in self.item_dict.values(): if ovfitem.modified: modified = True break if not modified: logger.verbose("No changes to hardware definition, " "so no XML update is required") return # Delete the existing Items: delete_count = 0 for item in list(self.ovf.virtual_hw_section): if (item.tag == self.ovf.ITEM or item.tag == self.ovf.STORAGE_ITEM or item.tag == self.ovf.ETHERNET_PORT_ITEM): self.ovf.virtual_hw_section.remove(item) delete_count += 1 logger.debug("Cleared %d existing items from VirtualHWSection", delete_count) # Generate the new XML Items, in appropriately sorted order by Instance ordering = [self.ovf.INFO, self.ovf.SYSTEM, self.ovf.ITEM] for instance in natural_sort(self.item_dict): logger.debug("Writing Item(s) with InstanceID %s", instance) ovfitem = self.item_dict[instance] new_items = ovfitem.generate_items() logger.spam("Generated %d items", len(new_items)) for item in new_items: XML.add_child(self.ovf.virtual_hw_section, item, ordering) logger.verbose( "Updated XML VirtualHardwareSection, now contains %d " "Items representing %d devices", len(self.ovf.virtual_hw_section.findall(self.ovf.ITEM)), len(self.item_dict))
def update_xml(self): """Regenerate all Items under the VirtualHardwareSection, if needed. Will do nothing if no Items have been changed. """ modified = False if len(self.item_dict) != len(XML.find_all_children( self.ovf.virtual_hw_section, set([self.ovf.ITEM, self.ovf.STORAGE_ITEM, self.ovf.ETHERNET_PORT_ITEM]))): modified = True else: for ovfitem in self.item_dict.values(): if ovfitem.modified: modified = True break if not modified: logger.verbose("No changes to hardware definition, " "so no XML update is required") return # Delete the existing Items: delete_count = 0 for item in list(self.ovf.virtual_hw_section): if (item.tag == self.ovf.ITEM or item.tag == self.ovf.STORAGE_ITEM or item.tag == self.ovf.ETHERNET_PORT_ITEM): self.ovf.virtual_hw_section.remove(item) delete_count += 1 logger.debug("Cleared %d existing items from VirtualHWSection", delete_count) # Generate the new XML Items, in appropriately sorted order by Instance ordering = [self.ovf.INFO, self.ovf.SYSTEM, self.ovf.ITEM] for instance in natural_sort(self.item_dict): logger.debug("Writing Item(s) with InstanceID %s", instance) ovfitem = self.item_dict[instance] new_items = ovfitem.generate_items() logger.spam("Generated %d items", len(new_items)) for item in new_items: XML.add_child(self.ovf.virtual_hw_section, item, ordering) logger.verbose("Updated XML VirtualHardwareSection, now contains %d " "Items representing %d devices", len(self.ovf.virtual_hw_section.findall(self.ovf.ITEM)), len(self.item_dict))
class TestXMLInstance(COTTestCase): """Test cases for XML instance methods.""" OVF = "{http://schemas.dmtf.org/ovf/envelope/1}" def setUp(self): """Test case setup function called automatically prior to each test.""" self.xml = XML(self.input_ovf) super(TestXMLInstance, self).setUp() def test_find_child(self): """Test corner cases of the find_child() method.""" match = self.xml.find_child(self.xml.root, self.OVF + "References") self.assertEqual(match.tag, self.OVF + "References") # multiple children -> LookupError self.assertRaises(LookupError, self.xml.find_child, match, self.OVF + "File") # no such child -> None unless required match = self.xml.find_child(self.xml.root, self.OVF + "Foobar") self.assertEqual(None, match) # no such child -> KeyError if required self.assertRaises(KeyError, self.xml.find_child, self.xml.root, self.OVF + "Foobar", required=True) def test_set_or_make_child(self): """Call set_or_make_child() in some slightly incorrect ways.""" # Trigger the warning in add_child() logged when # creating a new child that's in a known namespace # but the child isn't in the expected ordering self.xml.set_or_make_child( self.xml.root, self.OVF + "foo", ordering=[self.OVF + "References"], known_namespaces=["http://schemas.dmtf.org/ovf/envelope/1"]) self.assertLogged(levelname="WARNING", msg="in a known namespace.*not in the list") # Trigger the warning in add_child() logged when # creating a new child in a known namespace # with an expected ordering that includes the child, # but other children in this namespace are left out. self.xml.set_or_make_child( self.xml.root, self.OVF + "bar", ordering=[self.OVF + "DiskSection", self.OVF + "bar"], known_namespaces=["http://schemas.dmtf.org/ovf/envelope/1"]) self.assertLogged(levelname="WARNING", msg="Found unexpected child element")
def generate_items(self): """Get a list of Item XML elements derived from this object's data. Returns: list: Generated list of XML Item elements """ set_string_list = self.get_nonintersecting_set_list() # Now, construct the Items item_tag = self.item_tag_for_namespace(self.namespace) child_ordering = [self.namespace + i for i in self.ITEM_CHILDREN] item_list = [] for set_string in set_string_list: if not set_string: # no config profile item = ET.Element(item_tag) final_set = set([None]) set_string = '<generic>' else: item = ET.Element(item_tag, {self.ITEM_CONFIG: set_string}) final_set = set(set_string.split()) logger.spam("set string: %s; final_set: %s", set_string, final_set) for name in sorted(self.property_names): val = self.get_value(name, final_set) if not val: logger.debug( "No value defined for attribute '%s' " "under profile set '%s' for instance %s", name, set_string, self.get_value(self.INSTANCE_ID)) continue # Convert list of ResourceSubType values to a space-separated # list for output if name == self.RESOURCE_SUB_TYPE: val = " ".join(val) if val else None # Is this an attribute, a child, or a custom element? attrib_match = re.match(r"(.*)" + self.ATTRIB_KEY_SUFFIX, name) if attrib_match: attrib_string = attrib_match.group(1) child_attrib = re.match(r"(.*)_attrib_(.*)", name) custom_elem = re.match(r"(.*)" + self.ELEMENT_KEY_SUFFIX, name) if attrib_match: item.set(attrib_string, val) elif child_attrib: child = XML.set_or_make_child( item, child_attrib.group(1), None, ordering=child_ordering, known_namespaces=self.NSM.values()) child.set(child_attrib.group(2), val) elif custom_elem: # Recreate the element in question and append it item.append(ET.fromstring(val)) else: # Children of Item must be in sorted order XML.set_or_make_child(item, self.namespace + name, val, ordering=child_ordering, known_namespaces=self.NSM.values()) logger.spam("Item is:\n%s", ET.tostring(item)) item_list.append(item) return item_list
def add_item(self, item): """Add the given ``Item`` element to this OVFItem. Args: item (xml.etree.ElementTree.Element): XML ``Item`` element Raises: ValueUnsupportedError: if the ``item`` is not a recognized Item variant. OVFItemDataError: if the new Item conflicts with existing data already in the OVFItem. """ logger.spam("Adding new %s", item.tag) self.namespace = self.namespace_for_item_tag(item.tag) if not self.namespace: raise ValueUnsupportedError("item", item.tag, "Item, StorageItem, EthernetPortItem") profiles = set(item.get(self.ITEM_CONFIG, "").split()) # Store any attributes of the Item itself: for (attrib, value) in item.attrib.items(): if attrib == self.ITEM_CONFIG: continue attrib_string = attrib + self.ATTRIB_KEY_SUFFIX self.set_property(attrib_string, value, profiles, overwrite=False) # Store any child elements of the Item. # We save the ElementName and Description elements for last because # they may include references to the VirtualQuantity, ResourceSubType, # and/or Connection entries, which we won't know until we process them. children = list(item) name_child = next((child for child in children if XML.strip_ns(child.tag) == self.ELEMENT_NAME), None) desc_child = next( (child for child in children if XML.strip_ns(child.tag) == self.ITEM_DESCRIPTION), None) if name_child is not None: children.remove(name_child) children.append(name_child) # Description is *after* name because it may reference name if desc_child is not None: children.remove(desc_child) children.append(desc_child) for child in children: tag = XML.strip_ns(child.tag) if tag not in self.ITEM_CHILDREN: # Non-standard elements may not follow the standard rules - # for example, VMware OVF extensions may have multiple # vmw:Config elements, each distinguished by its vmw:key attr. # Rather than try to guess how these items do or do not match, # we simply store the whole item self.set_property((ET.tostring(child).decode().strip() + self.ELEMENT_KEY_SUFFIX), ET.tostring(child).decode(), profiles, overwrite=False) continue # Store the value of this element: self.set_property(tag, child.text, profiles, overwrite=False) # Store any attributes of this element for (attrib, value) in child.attrib.items(): attrib_string = tag + "_attrib_" + attrib self.set_property(attrib_string, value, profiles, overwrite=False) self.modified = True logger.spam("Added %s - new status:\n%s", item.tag, str(self)) self.validate()
def setUp(self): """Test case setup function called automatically prior to each test.""" self.xml = XML(self.input_ovf) super(TestXMLInstance, self).setUp()
def setUp(self): """Test case setup function called automatically prior to each test.""" self.xml = XML() self.xml.read_xml(resource_filename(__name__, "input.ovf")) super(TestXMLInstance, self).setUp()
def generate_items(self): """Get a list of Item XML elements derived from this object's data. Returns: list: Generated list of XML Item elements """ set_string_list = self.get_nonintersecting_set_list() # Now, construct the Items item_tag = self.item_tag_for_namespace(self.namespace) child_ordering = [self.namespace + i for i in self.ITEM_CHILDREN] item_list = [] for set_string in set_string_list: if not set_string: # no config profile item = ET.Element(item_tag) final_set = set([None]) set_string = '<generic>' else: item = ET.Element(item_tag, {self.ITEM_CONFIG: set_string}) final_set = set(set_string.split()) logger.spam("set string: %s; final_set: %s", set_string, final_set) for name in sorted(self.property_names): val = self.get_value(name, final_set) if not val: logger.debug("No value defined for attribute '%s' " "under profile set '%s' for instance %s", name, set_string, self.get_value(self.INSTANCE_ID)) continue # Convert list of ResourceSubType values to a space-separated # list for output if name == self.RESOURCE_SUB_TYPE: val = " ".join(val) if val else None # Is this an attribute, a child, or a custom element? attrib_match = re.match(r"(.*)" + self.ATTRIB_KEY_SUFFIX, name) if attrib_match: attrib_string = attrib_match.group(1) child_attrib = re.match(r"(.*)_attrib_(.*)", name) custom_elem = re.match(r"(.*)" + self.ELEMENT_KEY_SUFFIX, name) if attrib_match: item.set(attrib_string, val) elif child_attrib: child = XML.set_or_make_child( item, child_attrib.group(1), None, ordering=child_ordering, known_namespaces=self.NSM.values()) child.set(child_attrib.group(2), val) elif custom_elem: # Recreate the element in question and append it item.append(ET.fromstring(val)) else: # Children of Item must be in sorted order XML.set_or_make_child(item, self.namespace + name, val, ordering=child_ordering, known_namespaces=self.NSM.values()) logger.spam("Item is:\n%s", ET.tostring(item)) item_list.append(item) return item_list
def add_item(self, item): """Add the given ``Item`` element to this OVFItem. Args: item (xml.etree.ElementTree.Element): XML ``Item`` element Raises: ValueUnsupportedError: if the ``item`` is not a recognized Item variant. OVFItemDataError: if the new Item conflicts with existing data already in the OVFItem. """ logger.spam("Adding new %s", item.tag) self.namespace = self.namespace_for_item_tag(item.tag) if not self.namespace: raise ValueUnsupportedError("item", item.tag, "Item, StorageItem, EthernetPortItem") profiles = set(item.get(self.ITEM_CONFIG, "").split()) # Store any attributes of the Item itself: for (attrib, value) in item.attrib.items(): if attrib == self.ITEM_CONFIG: continue attrib_string = attrib + self.ATTRIB_KEY_SUFFIX self.set_property(attrib_string, value, profiles, overwrite=False) # Store any child elements of the Item. # We save the ElementName and Description elements for last because # they may include references to the VirtualQuantity, ResourceSubType, # and/or Connection entries, which we won't know until we process them. children = list(item) name_child = next( (child for child in children if XML.strip_ns(child.tag) == self.ELEMENT_NAME), None) desc_child = next( (child for child in children if XML.strip_ns(child.tag) == self.ITEM_DESCRIPTION), None) if name_child is not None: children.remove(name_child) children.append(name_child) # Description is *after* name because it may reference name if desc_child is not None: children.remove(desc_child) children.append(desc_child) for child in children: tag = XML.strip_ns(child.tag) if tag not in self.ITEM_CHILDREN: # Non-standard elements may not follow the standard rules - # for example, VMware OVF extensions may have multiple # vmw:Config elements, each distinguished by its vmw:key attr. # Rather than try to guess how these items do or do not match, # we simply store the whole item self.set_property((ET.tostring(child).decode().strip() + self.ELEMENT_KEY_SUFFIX), ET.tostring(child).decode(), profiles, overwrite=False) continue # Store the value of this element: self.set_property(tag, child.text, profiles, overwrite=False) # Store any attributes of this element for (attrib, value) in child.attrib.items(): attrib_string = tag + "_attrib_" + attrib self.set_property(attrib_string, value, profiles, overwrite=False) self.modified = True logger.spam("Added %s - new status:\n%s", item.tag, str(self)) self.validate()