Exemple #1
0
    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")
Exemple #2
0
 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"))
Exemple #3
0
    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")
Exemple #4
0
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"]
        )
Exemple #5
0
    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))
Exemple #6
0
    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))
Exemple #7
0
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")
Exemple #8
0
    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
Exemple #9
0
    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()
Exemple #10
0
 def setUp(self):
     """Test case setup function called automatically prior to each test."""
     self.xml = XML(self.input_ovf)
     super(TestXMLInstance, self).setUp()
Exemple #11
0
 def setUp(self):
     """Test case setup function called automatically prior to each test."""
     self.xml = XML(self.input_ovf)
     super(TestXMLInstance, self).setUp()
Exemple #12
0
 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()
Exemple #13
0
    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
Exemple #14
0
    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()