7004864 Read profile to be parsed from DOC if not specified via arguments
authorMatt Keenan <matt.keenan@oracle.com>
Fri, 17 Dec 2010 17:40:48 +0000
changeset 962 bc73134b4101
parent 961 1db352e5e4c9
child 965 4286ab2a4249
7004864 Read profile to be parsed from DOC if not specified via arguments
usr/src/lib/install_manifest/parser/parser.py
usr/src/lib/install_manifest/test/test_mp_invalid_params.py
usr/src/lib/install_manifest/test/test_mp_with_engine.py
--- a/usr/src/lib/install_manifest/parser/parser.py	Thu Dec 16 17:37:28 2010 -0700
+++ b/usr/src/lib/install_manifest/parser/parser.py	Fri Dec 17 17:40:48 2010 +0000
@@ -32,17 +32,17 @@
 import os
 import re
 
-from solaris_install.data_object import ParsingError
+from solaris_install.data_object import ParsingError, DataObject
 from solaris_install.engine import InstallEngine
 from solaris_install.engine.checkpoint import AbstractCheckpoint
 from solaris_install.manifest import ManifestError, validate_manifest
 
+MANIFEST_PARSER_DATA = "manifest_parser_data"
 
 class ManifestParser(AbstractCheckpoint):
     '''
         ManifestParser - parse, validate and import an XML manifest.
 
-
         Summary:
         This class implements the AbstractCheckpoint abstract base class
         which allows it to be executed from within the InstallEngine.
@@ -90,14 +90,20 @@
         overridden in ManifestParser.
     '''
 
-    def __init__(self, name, manifest, validate_from_docinfo=None,
+    def __init__(self, name, manifest=None, validate_from_docinfo=None,
         dtd_file=None, load_defaults=True, call_xinclude=False):
         '''
             Class initializer method.
 
             Parameters:
             - name arg is required by AbstractCheckpoint.  Not used.
-            - manifest must be the path to a readable XML file
+            - manifest, if passed,  must be the path to a readable XML file.
+              The manifest value can be set when the object is instantiated
+              by passing in a value for this param, or setting can be deferred
+              until later by not passing in any value here. In this case,
+              before the 1st attempt to access the manifest, there must
+              be a valid manifest value stored in the DataObjectCache at the 
+              location specified by MANIFEST_PARSER_DATA.
             - validate_from_docinfo controls whether the manifest is
               validated against the DTD in the file's XML headers, if any.
               The default value is None.  This parameter can have 3 values:
@@ -154,10 +160,9 @@
 
         # Check params
 
-        if manifest is None:
-            raise ManifestError("No manifest specified")
-        if not os.path.isfile(manifest):
-            raise ManifestError("Manifest [%s] is not a file" % manifest)
+        # Set self._manifest from argument passed in.
+        # All subsequent access to manifest will be done via  the
+        # @property self.manifest.
         self._manifest = manifest
 
         self._validate_from_docinfo = validate_from_docinfo
@@ -172,6 +177,25 @@
         self._call_xinclude = call_xinclude
 
 
+    def get_manifest_from_doc(self):
+        '''
+            Read the location of the manifest to be parsed from Data Object
+            Cache from the element MANIFEST_PARSER_DATA.
+        '''
+        ret_manifest = None
+
+        # Attempt to read from DOC under MANIFEST_PARSER_DATA
+        doc = InstallEngine.get_instance().data_object_cache
+
+        if doc is not None:
+            pm = doc.volatile.get_first_child(name=MANIFEST_PARSER_DATA)
+
+        if pm is not None:
+            ret_manifest = pm.manifest
+
+        return ret_manifest
+
+
     def get_progress_estimate(self):
         '''
             The parent class requires that this method be implemented
@@ -284,7 +308,7 @@
 
     def _load_manifest(self, dtd_validation=False, attribute_defaults=True):
         '''
-            Loads the manifest contained in self._manifest.
+            Loads the manifest contained in property self.manifest.
 
             Parameters:
             - dtd_validation must be True or False.  Default is False.  If
@@ -310,15 +334,15 @@
             attribute_defaults=attribute_defaults)
 
         try:
-            tree = etree.parse(self._manifest, parser)
+            tree = etree.parse(self.manifest, parser)
         except IOError, error:
-            msg = "Cannot access Manifest file [%s]" % (self._manifest)
+            msg = "Cannot access Manifest file [%s]" % (self.manifest)
             self.logger.exception(msg)
             self.logger.exception(error)
             raise ManifestError(msg, orig_exception=error)
         except etree.XMLSyntaxError, error:
             msg = "XML syntax error in manifest [%s]" % \
-                (self._manifest)
+                (self.manifest)
             self.logger.exception(msg)
             self.logger.exception(error)
             raise ManifestError(msg, orig_exception=error)
@@ -343,3 +367,68 @@
                 etree.tostring(tree, pretty_print=True, method="xml"))
 
         return tree
+
+    @property
+    def manifest(self):
+        '''
+            Instance accessor for the manifest to be parsed
+
+            The use of a property here is to ensure _manifest has a valid
+            value, either passed in as an argument to __init__() or via
+            reading the DOC where the location to the manifest to be parsed
+            is stored by another consumer. 
+
+            If manifest to be parsed is passed in as an __init__() argument
+            then self._manifest will already be set, and there's not need
+            to read the DOC. Constructor argument takes precedence over DOC.
+
+            Raise ManifestError exception if manifest is not available or
+            manifest file does not exist.
+        '''
+        if self._manifest is None:
+            self._manifest = self.get_manifest_from_doc()
+
+        if self._manifest is None:
+            raise ManifestError("No manifest specified")
+
+        if not os.path.isfile(self._manifest):
+            raise ManifestError("Manifest [%s] is not a file" % \
+                (self._manifest))
+
+        return self._manifest
+
+
+class ManifestParserData(DataObject):
+    '''
+        Parser Manifest DataObject class for storage of manifest to be parsed in
+        Data Object Cache.
+    '''
+    def __init__(self, name, manifest=None):
+        """
+            Class constructor
+        """
+        super(ManifestParserData, self).__init__(name)
+        self.manifest = manifest
+
+    def to_xml(self):
+        """
+            Convert DataObject DOM to XML
+        """
+        # NO-OP method as ManifestParserData is Never stored in XML manifest
+        return None
+
+    @classmethod
+    def can_handle(cls, element):
+        """
+            can_handle notification method for ai_instance tags
+        """
+        # NO-OP method as ManifestParserData is Never stored in XML manifest
+        return False
+
+    @classmethod
+    def from_xml(cls, element):
+        """
+            Convert from xml for DOM for DataObject storage 
+        """
+        # NO-OP method as ManifestParserData is Never stored in XML manifest
+        return None
--- a/usr/src/lib/install_manifest/test/test_mp_invalid_params.py	Thu Dec 16 17:37:28 2010 -0700
+++ b/usr/src/lib/install_manifest/test/test_mp_invalid_params.py	Fri Dec 17 17:40:48 2010 +0000
@@ -44,14 +44,6 @@
         logging.setLoggerClass(InstallLogger)
 
 
-    def test_invalid_params_manifest(self):
-        '''
-            test_invalid_params_manifest - set manifest param to None
-        '''
-        self.assertRaises(ManifestError, ManifestParser, "manifest-parser",
-            None)
-
-
     def test_invalid_params_dtd_file(self):
         '''
             test_invalid_params_dtd_file - set dtd_file param to directory name "/tmp"
--- a/usr/src/lib/install_manifest/test/test_mp_with_engine.py	Thu Dec 16 17:37:28 2010 -0700
+++ b/usr/src/lib/install_manifest/test/test_mp_with_engine.py	Fri Dec 17 17:40:48 2010 +0000
@@ -34,6 +34,8 @@
 from solaris_install.engine import InstallEngine
 from solaris_install.engine.test.engine_test_utils import reset_engine, \
     get_new_engine_instance
+from solaris_install.manifest.parser import ManifestParserData, \
+    MANIFEST_PARSER_DATA
 
 ####################################################################
 # importing these classes causes them to be registered with the DOC
@@ -146,5 +148,55 @@
             "ManifestParser checkpoint should have failed")
 
 
+    def test_mp_engine_load_fail(self):
+        '''
+            test_mp_engine_load_fail - test manifest_parser failure as no manifest to parse either via __init__() or in DOC
+        '''
+        my_args = None
+
+        my_kwargs = {}
+        my_kwargs["validate_from_docinfo"] = False
+
+        self.engine.register_checkpoint("manifest_parser",
+            "solaris_install/manifest/parser",
+            "ManifestParser",
+            args=my_args,
+            kwargs=my_kwargs)
+
+        status = self.engine.execute_checkpoints()[0]
+
+        self.assertEqual(status, InstallEngine.EXEC_FAILED,
+            "ManifestParser checkpoint should have failed")
+
+
+    def test_mp_engine_load_good(self):
+        '''
+            test_mp_engine_load_good - test manifest_parser succeeds parsing manifest stored in DOC
+        '''
+        # Store manifest in DOC
+        doc = InstallEngine.get_instance().data_object_cache
+        if doc is not None:
+            mp_data = doc.volatile.get_first_child(name=MANIFEST_PARSER_DATA)
+            if mp_data is None:
+                mp_data = ManifestParserData(MANIFEST_PARSER_DATA)
+                doc.volatile.insert_children(mp_data)
+            mp_data.manifest = common.MANIFEST_DC
+
+        my_args = None
+        my_kwargs = {}
+        my_kwargs["validate_from_docinfo"] = False
+
+        self.engine.register_checkpoint("manifest_parser",
+            "solaris_install/manifest/parser",
+            "ManifestParser",
+            args=my_args,
+            kwargs=my_kwargs)
+
+        status = self.engine.execute_checkpoints()[0]
+
+        self.assertEqual(status, InstallEngine.EXEC_SUCCESS,
+            "ManifestParser checkpoint should have succeeded")
+
+
 if __name__ == '__main__':
     unittest.main()