--- a/usr/src/Makefile.master Thu Oct 28 15:10:27 2010 -0700
+++ b/usr/src/Makefile.master Fri Oct 29 13:35:45 2010 +0000
@@ -105,6 +105,7 @@
ROOTPYTHONVENDORSOLINSTALLENGINE = $(ROOTPYTHONVENDORSOLINSTALL)/engine
ROOTPYTHONVENDORSOLINSTALLENGINETEST = $(ROOTPYTHONVENDORSOLINSTALLENGINE)/test
ROOTPYTHONVENDORSOLINSTALLTARGET = $(ROOTPYTHONVENDORSOLINSTALL)/target
+ROOTPYTHONVENDORSOLINSTALLMANIFEST= $(ROOTPYTHONVENDORSOLINSTALL)/manifest
ROOTAUTOINST= $(ROOT)/usr/share/auto_install
ROOTAUTOINSTSCPROFILES= $(ROOTAUTOINST)/sc_profiles
ROOTSBIN= $(ROOT)/sbin
--- a/usr/src/Targetdirs Thu Oct 28 15:10:27 2010 -0700
+++ b/usr/src/Targetdirs Fri Oct 29 13:35:45 2010 +0000
@@ -72,6 +72,7 @@
/usr/lib/python2.6/vendor-packages/solaris_install/engine \
/usr/lib/python2.6/vendor-packages/solaris_install/engine/test \
/usr/lib/python2.6/vendor-packages/solaris_install/target \
+ /usr/lib/python2.6/vendor-packages/solaris_install/manifest \
/usr/sbin \
/usr/share/auto_install \
/usr/share/auto_install/sc_profiles \
--- a/usr/src/lib/Makefile Thu Oct 28 15:10:27 2010 -0700
+++ b/usr/src/lib/Makefile Fri Oct 29 13:35:45 2010 +0000
@@ -51,7 +51,8 @@
install_engine \
install_logging \
install_logging_pymod \
- install_target
+ install_target \
+ install_manifest
ADMINLIBRARIES= libadmldb.so libadmutil.so
ROOTADMINLIBLINKS= $(ADMINLIBRARIES:%=$(ROOTADMINLIB)/%)
--- a/usr/src/lib/Makefile.targ Thu Oct 28 15:10:27 2010 -0700
+++ b/usr/src/lib/Makefile.targ Fri Oct 29 13:35:45 2010 +0000
@@ -124,6 +124,9 @@
$(ROOTPYTHONVENDORSOLINSTALLTARGET):
$(INS.dir)
+$(ROOTPYTHONVENDORSOLINSTALLMANIFEST):
+ $(INS.dir)
+
#
# Python .py and .pyc files need to be installed with the original
# timestamp of the file preserved. Otherwise, .pyc files will
@@ -149,6 +152,9 @@
$(ROOTPYTHONVENDORSOLINSTALLTARGET)/%: %
$(CP_P.file)
+$(ROOTPYTHONVENDORSOLINSTALLMANIFEST)/%: %
+ $(CP_P.file)
+
$(ROOTRNGSCHEMA)/%: %
$(INS.file)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/Makefile Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,55 @@
+#
+##
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+
+include $(SRC)/Makefile.master
+
+SUBDIRS= common parser writer
+
+.PARALLEL: $(SUBDIRS)
+
+all:= TARGET= all
+check:= TARGET= check
+clean:= TARGET= clean
+clobber:= TARGET= clobber
+install:= TARGET= install
+install_h:= TARGET= install_h
+lint:= TARGET= lint
+
+.KEEP_STATE:
+
+all check clean clobber lint: $(SUBDIRS)
+
+install: $(SUBDIRS)
+
+headers:
+
+install_h: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/common/Makefile Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,63 @@
+#
+##
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+
+PYMODS = __init__.py
+
+PYCMODS = $(PYMODS:%.py=%.pyc)
+
+ROOTPYMODS= $(PYMODS:%=$(ROOTPYTHONVENDORSOLINSTALLMANIFEST)/%)
+
+ROOTPYCMODS= $(PYCMODS:%=$(ROOTPYTHONVENDORSOLINSTALLMANIFEST)/%)
+
+
+CLOBBERFILES = $(PYCMODS)
+CLEANFILES = $(CLOBBERFILES)
+
+include ../../Makefile.lib
+
+static:
+
+dynamic:
+
+python:
+ $(PYTHON) -m compileall -l $(@D)
+
+all: python
+
+install_h:
+
+install: all .WAIT \
+ $(ROOTPYTHONVENDOR) \
+ $(ROOTPYTHONVENDORSOLINSTALL) \
+ $(ROOTPYTHONVENDORSOLINSTALLMANIFEST) \
+ $(ROOTPYMODS) $(ROOTPYCMODS)
+
+lint: lint_SRCS
+
+FRC:
+
+include ../../Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/common/__init__.py Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,104 @@
+#
+##
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+"""init module for ManifestParser and ManifestWriter"""
+
+import sys
+
+from lxml import etree
+
+
+class ManifestError(Exception):
+ '''
+ Raised if an error occurs during ManifestParser or ManifestWriter.
+
+ Instances of this class have the following attributes:
+ - msg (mandatory), a text string
+ - orig_exception (optional), another Exception object
+ This attribute is used to encapsulate another exception
+ '''
+
+ def __init__(self, msg, orig_exception=None):
+ Exception.__init__(self)
+ self.msg = msg
+ self.orig_exception = orig_exception
+ self.orig_traceback = sys.exc_info()[2]
+
+ def __str__(self):
+ msg = self.msg
+
+ if self.orig_exception is not None:
+ # Return a useful message that includes the original msg,
+ # the name of the encapsulated exception's class (eg
+ # "IOError" or "XMLSyntaxError") and the the msg from
+ # the encapsulated exception.
+ msg = "%s : %s - %s" % (msg,
+ self.orig_exception.__class__.__name__,
+ self.orig_exception)
+
+ return msg
+
+
+def validate_manifest(tree, dtd_file, logger):
+ '''
+ Validates the given XML tree against the given DTD.
+
+ This is a common function used by ManifestParser and ManifestWriter.
+
+ Parameters:
+ - tree, an etree.ElementTree
+ - dtd_file, the path to a DTD file
+ - logger, where to log errors to
+
+ Returns:
+ - Nothing
+ On success, this method returns; on error it raises an exception.
+
+ Raises:
+ - ManifestError is raised if the DTD file cannot be loaded,
+ or if validation fails.
+ '''
+
+ try:
+ dtd = etree.DTD(dtd_file)
+ except etree.DTDParseError, error:
+ msg = "Unable to parse DTD file [%s]:" % (dtd_file)
+ logger.exception(msg)
+ logger.exception(str(error))
+ raise ManifestError(msg, orig_exception=error)
+
+ if not dtd.validate(tree.getroot()):
+ msg = "Validation against DTD [%s] failed" % (dtd_file)
+ logger.error(msg)
+
+ for error in dtd.error_log.filter_from_errors():
+ logger.error(str(error))
+ msg = msg + " : " + str(error)
+
+ raise ManifestError(msg)
+
+
+__all__ = ["parser", "writer"]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/parser/Makefile Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,63 @@
+#
+##
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+
+PYMODS = parser.py
+
+PYCMODS = $(PYMODS:%.py=%.pyc)
+
+ROOTPYMODS= $(PYMODS:%=$(ROOTPYTHONVENDORSOLINSTALLMANIFEST)/%)
+
+ROOTPYCMODS= $(PYCMODS:%=$(ROOTPYTHONVENDORSOLINSTALLMANIFEST)/%)
+
+
+CLOBBERFILES = $(PYCMODS)
+CLEANFILES = $(CLOBBERFILES)
+
+include ../../Makefile.lib
+
+static:
+
+dynamic:
+
+python:
+ $(PYTHON) -m compileall -l $(@D)
+
+all: python
+
+install_h:
+
+install: all .WAIT \
+ $(ROOTPYTHONVENDOR) \
+ $(ROOTPYTHONVENDORSOLINSTALL) \
+ $(ROOTPYTHONVENDORSOLINSTALLMANIFEST) \
+ $(ROOTPYMODS) $(ROOTPYCMODS)
+
+lint: lint_SRCS
+
+FRC:
+
+include ../../Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/parser/parser.py Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,331 @@
+#
+##
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''ManifestParser Checkpoint'''
+
+import logging
+from lxml import etree
+import os
+
+from solaris_install.data_object import ParsingError
+from solaris_install.engine import InstallEngine
+from solaris_install.engine.checkpoint import AbstractCheckpoint
+from solaris_install.manifest import ManifestError, validate_manifest
+
+
+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.
+ It also provides an additional API that allow it to be run
+ outside of the InstallEngine context.
+
+
+ Initializer method:
+ The parameters of the initializer method give the location
+ of the XML manifest to be parsed and define what validation and
+ other optional operations will be performed.
+
+
+ execute() and parse() methods:
+ When running in an InstallEngine context the execute() method
+ performs the main tasks of parsing and, optionally, validating
+ the manifest.
+
+ When run outside the InstallEngine context, the parse() method
+ performs these same functions.
+
+ The main difference between execute() and parse() is whether or
+ not the manifest data is imported into a DataObjectCache (DOC)
+ instance and from where the reference to the DOC is obtained.
+ execute() assumes an InstallEngine singleton exists and gets
+ the DOC reference from it. With parse(), importing to the DOC
+ is optional and if required, a reference to an existing DOC
+ instance must be passed in.
+
+ If an error occurs during the execute() or parse() methods,
+ including XML syntax errors or failure to validate the
+ manifest, a ManifestError exception is raised.
+
+ If no errors occur, the methods simply return, with no return
+ value. If importing to a DOC has been requested, the data
+ will be available in the DOC for retrieval by other system
+ components.
+
+
+ Other public methods:
+ The get_progress_estimate() method is required by the parent
+ AbstractCheckpoint class.
+
+ The cancel() method defined in AbstractCheckpoint is not
+ overridden in ManifestParser.
+ '''
+
+ def __init__(self, name, manifest, 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
+ - 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:
+ None: validate against the DTD, if present; if DTD URI is not
+ present, no error is raised
+ True: attempt to validate against the DTD on-the-fly as it is
+ loaded. If DTD is not specified, raise an error
+ False: whether or not a DTD is specified, do not attempt to
+ validate against it
+ If validation is attempted and fails, an error is raised.
+ - dtd_file specifes the path to a DTD against which the manifest
+ will be validated. This validation may be performed instead
+ of, or as well as, the validation controlled by
+ validate_from_docinfo, or it may be skipped by leaving dtd_file
+ as None (the default). If validation is attempted and fails,
+ an error is raised.
+ Note: default attribute values (see below) cannot be loaded
+ during this form of validation - they can only be loaded if
+ the manifest directly references a DTD in its headers.
+ - load_defaults must be either True or False. The default value
+ is True. load_defaults is only relevant when the manifest
+ references a DTD. If True, default attribute values from the
+ DTD are loaded when the manifest is parsed. If the manifest
+ does not reference a DTD, no defaults are loaded and no error
+ is raised. (Note: Defaults can be loaded even if
+ validate_from_docinfo is False.)
+ - call_xinclude must be either True or False and controls
+ whether XInclude statements in the manifest will be processed
+ or not. It defaults to False
+ Note: Currently, the on-the-fly validation performed if
+ validate_from_docinfo=True occurs *before* XInclude statements
+ are processed and validation triggered when
+ validate_from_docinfo=None or when dtd_file is specified occurs
+ *after* XInclude processing. XInclude processing may affect
+ whether validation succeeds or not, so this ordering may need
+ to be considered.
+
+ Returns:
+ - Nothing
+
+ Raises:
+ - ManifestError is raised if invalid values are specified
+ for any paramaters or if manifest and/or dtd_file are
+ specified but are not actual files
+ '''
+
+ super(ManifestParser, self).__init__(name)
+
+ self.logger.debug("Initializing ManifestParser " \
+ "(manifest=%s, validate_from_docinfo=%s, dtd_file=%s, " \
+ "load_defaults=%s, call_xinclude=%s)",
+ manifest, validate_from_docinfo, dtd_file,
+ load_defaults, call_xinclude)
+
+ # 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)
+ self._manifest = manifest
+
+ self._validate_from_docinfo = validate_from_docinfo
+
+ if ((dtd_file is not None) and
+ (not os.path.isfile(dtd_file))):
+ raise ManifestError("DTD [%s] is not a file" % dtd_file)
+ self._dtd_file = dtd_file
+
+ self._load_defaults = load_defaults
+
+ self._call_xinclude = call_xinclude
+
+
+ def get_progress_estimate(self):
+ '''
+ The parent class requires that this method be implemented
+ in sub-classes.
+
+ This returns an estimate of how long the execute() method
+ will take to run.
+ '''
+
+ return 1
+
+
+ def parse(self, doc=None):
+ '''
+ This API method is not part of the AbstractCheckpoint spec.
+ It can be used to access the ManifestParser functionality outside
+ the InstallEngine context.
+
+ This method is also used as a convenience function within this
+ class to do most of the work of the execute() method.
+
+ Parameters:
+ - doc, a reference to the DataObjectCache in which to store
+ the manifest data. If None, the manifest data will not be
+ stored anywhere, in which case this method only serves to
+ confirm whether the manifest can be parsed and, optionally,
+ validated.
+
+ Returns:
+ - Nothing
+ On success, this method returns; on error it raises an exception.
+
+ Raises:
+ - ManifestError is raised if an error occurs in _load_manifest()
+ or validate_manifest() or if
+ DataObjectCache.import_from_manifest_xml() raises a ParsingError
+ exception.
+ '''
+
+ self.logger.debug("ManifestParser.parse(doc=%s) called", doc)
+
+ if self._cancel_requested.is_set():
+ self.logger.debug("Cancel requested, returning.")
+ return
+
+ self.logger.debug("loading manifest (dtd_validation=%s)",
+ self._validate_from_docinfo)
+ tree = self._load_manifest(dtd_validation=self._validate_from_docinfo,
+ attribute_defaults=self._load_defaults)
+
+ if self._cancel_requested.is_set():
+ self.logger.debug("Cancel requested, returning.")
+ return
+
+ if self._validate_from_docinfo is None:
+ if ((tree.docinfo is not None) and
+ (tree.docinfo.system_url is not None)):
+ validate_manifest(tree, tree.docinfo.system_url, self.logger)
+
+ if self._dtd_file is not None:
+ validate_manifest(tree, self._dtd_file, self.logger)
+
+ if self._cancel_requested.is_set():
+ self.logger.debug("Cancel requested, returning.")
+ return
+
+ if doc is not None:
+ # import the Manifest data into the Volatile sub-tree
+ # of the DataObjectCache
+
+ try:
+ doc.import_from_manifest_xml(tree.getroot(), volatile=True)
+ except ParsingError, error:
+ msg = "Unable to import manifest into data_object_cache"
+ self.logger.exception(msg)
+ self.logger.exception(error)
+ raise ManifestError(msg, orig_exception=error)
+
+
+ def execute(self, dry_run=False):
+ '''
+ Abstract method defined in AbstractCheckpoint class.
+
+ Loads the specified Manifest and does the requested validation.
+ Imports resulting data into DOC.
+
+ Parameters:
+ - the dry_run keyword paramater, specified in AbstractCheckpoint,
+ is ignored in this method.
+
+ Returns:
+ - Nothing
+ On success, this method returns; on error it raises an exception.
+
+ Raises:
+ - ManifestError is raised if unable to fetch DOC reference or
+ if an error occurs in parse().
+ '''
+
+ self.logger.debug("ManifestParser.execute(dry_run=%s) called", dry_run)
+
+ engine = InstallEngine.get_instance()
+
+ doc = engine.data_object_cache
+ if doc is None:
+ raise ManifestError("Cannot get DOC reference from InstallEngine")
+
+ self.parse(doc=doc)
+
+
+ def _load_manifest(self, dtd_validation=False, attribute_defaults=True):
+ '''
+ Loads the manifest contained in self._manifest.
+
+ Parameters:
+ - dtd_validation must be True or False. Default is False. If
+ True, then the document will also be validated on-the-fly as
+ it is loaded.
+ - attribute_defaults must be True or False. Default is True.
+ Only relevant if the manifest references a DTD. If True, then
+ default values for XML attributes given in the DTD will be
+ loaded as the document is parsed.
+
+ Returns:
+ - an etree.ElementTree object
+
+ Raises:
+ - ManifestError is raised if the manifest file cannot be
+ accessed or if XMLSyntaxError is raised while parsing
+ and, optionally, validating it.
+ '''
+
+ # Create the XML parser to be used when processing the manifest.
+ parser = etree.XMLParser(remove_blank_text=True,
+ dtd_validation=dtd_validation,
+ attribute_defaults=attribute_defaults)
+
+ try:
+ tree = etree.parse(self._manifest, parser)
+ except IOError, error:
+ 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.logger.exception(msg)
+ self.logger.exception(error)
+ raise ManifestError(msg, orig_exception=error)
+
+ if self._call_xinclude:
+ tree.xinclude()
+
+ if self.logger.isEnabledFor(logging.DEBUG):
+ self.logger.debug("Parsed XML document:\n%s",
+ etree.tostring(tree, pretty_print=True, method="xml"))
+
+ return tree
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/common.py Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,87 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''ManifestParser/ManifestWriter test common module'''
+
+import os
+
+TEST_BASE_DIR = os.path.dirname(os.path.abspath(__file__))
+
+MANIFEST_DC = "%s/manifests/manifest_simple.xml" % TEST_BASE_DIR
+MANIFEST_DC_DTD_PATH = "%s/manifests/manifest_simple_dtd_path.xml" % TEST_BASE_DIR
+MANIFEST_NO_DTD_REF = "%s/manifests/manifest_no_dtd_ref.xml" % TEST_BASE_DIR
+MANIFEST_XINCLUDE = "%s/manifests/manifest_xinclude_main.xml" % TEST_BASE_DIR
+MANIFEST_INVALID = "%s/manifests/manifest_invalid.xml" % TEST_BASE_DIR
+MANIFEST_PARSE_ERROR = "%s/manifests/manifest_parse_error.xml" % TEST_BASE_DIR
+MANIFEST_SYNTAX_ERROR = "%s/manifests/manifest_syntax_error.xml" % TEST_BASE_DIR
+MANIFEST_NON_EXISTENT = "non/existent/dir/manifest.dtd"
+
+MANIFEST_OUT_OK = "/tmp/test_manifest_writer_01.xml"
+MANIFEST_OUT_NON_EXISTENT = "non/existent/dir/test_manifest_writer_01.xml"
+
+DTD_DC = "%s/manifests/manifest.dtd" % TEST_BASE_DIR
+DTD_INVALID = "/etc/release"
+DTD_INVALID_2 = "/tmp"
+DTD_NON_EXISTENT = "non/existent/dir/manifest.dtd"
+
+XSLT_DOC_TO_DC = "%s/manifests/doc-to-manifest.xslt" % TEST_BASE_DIR
+XSLT_INVALID = "/etc/release"
+XSLT_NON_EXISTENT = "non/existent/dir/file.xslt"
+
+
+def file_line_matches(filename, lineno, string):
+ '''
+ Returns True if line number 'lineno' of file 'filename'
+ matches the string 'string'. Returns False if file
+ cannot be read, does not contain enough lines or if
+ the text doesn't match.
+
+ lineno is the line number within the file, starting at 0.
+ If lineno is a negative number it is taken to indicate a
+ number of lines from the end of the file, where -1 indicates
+ the last line of the file, -2 indicates the second last
+ line, etc.
+
+ Examples:
+ file_line_matches(filename, 0, string) # match first line of file
+ file_line_matches(filename, -1, string) # match last line of file
+
+ '''
+
+ try:
+ file_obj = open(filename)
+ # read in entire file
+ lines = file_obj.readlines()
+ except IOError:
+ return False
+ finally:
+ file_obj.close()
+
+ try:
+ line = lines[lineno].strip()
+ except IndexError:
+ return False
+
+ return (line == string)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/manifests/configuration.dtd Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,44 @@
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+-->
+
+<!ELEMENT configuration (validation?)>
+<!ATTLIST configuration source CDATA #REQUIRED>
+<!ATTLIST configuration dest CDATA #IMPLIED>
+
+<!--
+ Default to user configuration if type is not set.
+-->
+<!ATTLIST configuration type (network|sysconf|zone|user) #IMPLIED>
+
+<!--
+ Configuration name should match the name of the checkpoint consuming
+ the configuration data.
+-->
+<!ATTLIST configuration name CDATA #REQUIRED>
+
+<!ELEMENT validation EMPTY>
+<!ATTLIST validation path CDATA #IMPLIED>
+<!ATTLIST validation args CDATA #IMPLIED>
+<!ATTLIST validation on_error CDATA "stop">
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/manifests/doc-to-manifest.xslt Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+-->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+ <xsl:output method="xml" indent="yes" encoding="UTF-8" doctype-system="file:///tmp/manifest.dtd"/>
+
+ <!-- Restructure the contents of the DataObjectCache to -->
+ <!-- resemble a DC Manifest. -->
+ <!-- For now, we are only doing a high-level restructuring. -->
+ <!-- That is, we create the top-level <dc> element, the -->
+ <!-- second-level <distro> element (with any relevant attributes -->
+ <!-- from the DOC) and the 5 sub-elements of <distro>: -->
+ <!-- <distro_spec>, <target>, <software>, <execution> and -->
+ <!-- <configuration>, copied unmodified and in their -->
+ <!-- entirety from the DOC, as many times as they occur. -->
+
+ <xsl:template match="/">
+ <dc>
+ <distro>
+ <xsl:choose>
+ <xsl:when test="//distro">
+ <!-- Copy all <distro>'s attributes. -->
+ <xsl:copy-of select="//distro/@*"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- If there was no <distro> in source document, -->
+ <!-- then provide the compulsory name attribute. -->
+ <xsl:attribute name="name">
+ <xsl:text>generated manifest</xsl:text>
+ </xsl:attribute>
+ </xsl:otherwise>
+ </xsl:choose>
+
+ <!-- Place these other elements (and their sub-elements) -->
+ <!-- directly under distro, regardless of where they -->
+ <!-- were found in the source document. If they are not -->
+ <!-- found, they will just be skipped. -->
+ <xsl:copy-of select="//distro_spec"/>
+ <xsl:copy-of select="//target"/>
+ <xsl:copy-of select="//software"/>
+ <xsl:copy-of select="//execution"/>
+ <xsl:copy-of select="//configuration"/>
+ </distro>
+ </dc>
+ </xsl:template>
+</xsl:stylesheet>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/manifests/execution.dtd Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,34 @@
+<!ELEMENT execution (checkpoint+)>
+
+<!--
+ The stop_on_error attribute is for the whole execution sequence.
+ Not per checkpoint.
+-->
+<!ATTLIST execution stop_on_error (true|false) "true">
+
+<!--
+ The name of a checkpoint is a unique to the registration instance.
+ The mod_path is relative to the PYTHONPATH. The checkpoint_class
+ is required so we can associate a checkpoint class with the
+ mod_path which is a file that contains the checkpoint class. There
+ may not necessarily be a 1-1 relationship.
+-->
+<!ELEMENT checkpoint (args?, kwargs?)>
+<!ATTLIST checkpoint name CDATA #REQUIRED>
+<!ATTLIST checkpoint desc CDATA #IMPLIED>
+<!ATTLIST checkpoint mod_path CDATA #REQUIRED>
+<!ATTLIST checkpoint log_level CDATA #IMPLIED>
+<!ATTLIST checkpoint checkpoint_class CDATA #REQUIRED>
+
+<!--
+ Args are non keyword arguments, which can be parsed by the parser
+ if required. kwargs are keyword arguments which must conform to
+ the published format. Each checkpoint will provide the format
+ if kwargs are enabled.
+-->
+
+<!ELEMENT args (#PCDATA)>
+<!ELEMENT kwargs (arg+)>
+
+<!ELEMENT arg (#PCDATA)>
+<!ATTLIST arg name CDATA #REQUIRED>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/manifests/manifest.dtd Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,53 @@
+<!ELEMENT dc (distro)>
+
+<!ENTITY % target SYSTEM "target.dtd">
+%target;
+
+<!ENTITY % execution SYSTEM "execution.dtd">
+%execution;
+
+<!ENTITY % configuration SYSTEM "configuration.dtd">
+%configuration;
+
+<!ENTITY % software SYSTEM "software.dtd">
+%software;
+
+<!--
+ If no special distro args, then we don't have to have a
+ distro_spec element. We do require target, execution. Software
+ and configuration are optional, although without software
+ we cannot create a media image. The optional software elements
+ are due to the VM image not requiring a software specification.
+ Compression settings are specified as an argument to the
+ associated execution checkpoint element.
+-->
+
+<!ELEMENT distro (distro_spec?, target+, software*, execution+, configuration*)>
+<!ATTLIST distro name CDATA #REQUIRED>
+<!ATTLIST distro incremental_media_name (true|false) "false">
+<!ATTLIST distro http_proxy CDATA #IMPLIED>
+
+<!ELEMENT distro_spec (img_params*)>
+
+<!ELEMENT img_params (media_im|vm_im)>
+
+<!ELEMENT media_im (grub_mods*, max_size?)>
+<!ELEMENT grub_mods (grub_entry*)>
+<!ATTLIST grub_mods min_mem CDATA #IMPLIED>
+<!ATTLIST grub_mods title CDATA #IMPLIED>
+<!ATTLIST grub_mods default_entry CDATA #IMPLIED>
+<!ATTLIST grub_mods timeout CDATA #IMPLIED>
+
+<!ELEMENT grub_entry (title_suffix, line+)>
+<!ATTLIST grub_entry position CDATA #IMPLIED>
+<!ELEMENT title_suffix (#PCDATA)>
+<!ELEMENT line (#PCDATA)>
+
+<!--
+ max_size refers to the maximum size an image area can get,
+ if the user wants to define this.
+-->
+
+<!ELEMENT max_size (size)>
+
+<!ELEMENT vm_im EMPTY>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/manifests/manifest_invalid.xml Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dc SYSTEM "manifest.dtd">
+<dc>
+<distro name="OpenSolaris_X86.iso"
+ http_proxy="http://example.com">
+<distro_spec>
+ <img_params>
+ <media_im>
+ <grub_mods min_mem="0" title="myentry" default_entry="0"
+ timeout="5">
+ <grub_entry position="1">
+ <title_suffix>Enable SSH</title_suffix>
+ <line>kernel$ /platform/i86pc/kernel/$ISADIR/unix -B
+ livessh=enable</line>
+ <line>module$ /platform/i86pc/$ISADIR/boot_archive</line>
+ </grub_entry>
+ </grub_mods>
+ </media_im>
+ </img_params>
+</distro_spec>
+
+<!--
+ Software section.
+-->
+<software name="transfer-ips-install">
+ <destination>
+ <image img_root="/rpool/new_dc_test/build_data/pkg_image" action="create"></image>
+ </destination>
+ <source>
+ <publisher name="opensolaris.org">
+ <origin name="http://ipkg.sfbay/dev"></origin>
+ </publisher>
+ </source>
+ <software_data action="install" type="IPS">
+ <name>SUNWcs</name>
+ <name>SUNWcsd</name>
+ <name>entire</name>
+ </software_data>
+ <software_data action="install" type="IPS">
+ <name>slim_install</name>
+ <name>system/install/media/internal</name>
+ </software_data>
+</software>
+<!--
+ Execution section.
+-->
+<execution stop_on_error="true">
+ <checkpoint name="transfer-ips-install"
+ mod_path="solaris_install/transfer/transfer_ips"
+ checkpoint_class="TransferIPS">
+ <kwargs>
+ <arg name="dist_iso_sort">path</arg>
+ </kwargs>
+ </checkpoint>
+</execution>
+
+<!--
+ Image SMF configuration. Applied to boot archive in the order they
+ are specified. Image files are always used.
+-->
+
+</distro>
+</dc>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/manifests/manifest_no_dtd_ref.xml Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<dc>
+<distro name="OpenSolaris_X86.iso"
+ http_proxy="http://example.com">
+<distro_spec>
+ <img_params>
+ <media_im>
+ <grub_mods min_mem="0" title="myentry" default_entry="0"
+ timeout="5">
+ <grub_entry position="1">
+ <title_suffix>Enable SSH</title_suffix>
+ <line>kernel$ /platform/i86pc/kernel/$ISADIR/unix -B
+ livessh=enable</line>
+ <line>module$ /platform/i86pc/$ISADIR/boot_archive</line>
+ </grub_entry>
+ </grub_mods>
+ </media_im>
+ </img_params>
+</distro_spec>
+
+<target>
+ <target_device>
+ <swap>
+ <zvol name="swap">
+ <size val="0"/>
+ </zvol>
+ </swap>
+ </target_device>
+</target>
+
+<!--
+ Software section.
+-->
+<software name="transfer-ips-install">
+ <destination>
+ <image img_root="/rpool/new_dc_test/build_data/pkg_image" action="create"></image>
+ </destination>
+ <source>
+ <publisher name="opensolaris.org">
+ <origin name="http://ipkg.sfbay/dev"></origin>
+ </publisher>
+ </source>
+ <software_data action="install" type="IPS">
+ <name>SUNWcs</name>
+ <name>SUNWcsd</name>
+ <name>entire</name>
+ </software_data>
+ <software_data action="install" type="IPS">
+ <name>slim_install</name>
+ <name>system/install/media/internal</name>
+ </software_data>
+</software>
+<!--
+ Execution section.
+-->
+<execution stop_on_error="true">
+ <checkpoint name="transfer-ips-install"
+ mod_path="solaris_install/transfer/transfer_ips"
+ checkpoint_class="TransferIPS">
+ <kwargs>
+ <arg name="dist_iso_sort">path</arg>
+ </kwargs>
+ </checkpoint>
+</execution>
+
+<!--
+ Image SMF configuration. Applied to boot archive in the order they
+ are specified. Image files are always used.
+-->
+
+</distro>
+</dc>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/manifests/manifest_parse_error.xml Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dc SYSTEM "manifest.dtd">
+<dc>
+<distro name="OpenSolaris_X86.iso"
+ http_proxy="http://example.com">
+<distro_spec>
+ <img_params>
+ <media_im>
+ <grub_mods min_mem="0" title="myentry" default_entry="0"
+ timeout="5">
+ <grub_entry position="1">
+ <title_suffix>Enable SSH</title_suffix>
+ <line>kernel$ /platform/i86pc/kernel/$ISADIR/unix -B
+ livessh=enable</line>
+ <line>module$ /platform/i86pc/$ISADIR/boot_archive</line>
+ </grub_entry>
+ </grub_mods>
+ </media_im>
+ </img_params>
+</distro_spec>
+
+<target>
+ <target_device>
+ <swap>
+ <zvol name="swap">
+ <size val="0"/>
+ </zvol>
+ </swap>
+ </target_device>
+</target>
+
+<!--
+ Software section.
+-->
+<software name="transfer-ips-install">
+ <destination>
+ <image img_root="/rpool/new_dc_test/build_data/pkg_image" action="create"></image>
+ </destination>
+ <source>
+ <publisher name="opensolaris.org">
+ <origin name="http://ipkg.sfbay/dev"></origin>
+ </publisher>
+ </source>
+ <software_data action="install" type="IPS">
+ <name>SUNWcs</name>
+ <name>SUNWcsd</name>
+ <name>entire</name>
+ </software_data>
+ <software_data action="install" type="IPS">
+ <name>slim_install</name>
+ <name>system/install/media/internal</name>
+ </software_data>
+</software>
+<!--
+ Execution section.
+-->
+<execution stop_on_error="true">
+ <checkpoint name="transfer-ips-install"
+ mod_path="solaris_install/transfer/transfer_ips"
+ checkpoint_class="TransferIPS">
+ <kwargs>
+ <argX name="dist_iso_sort">path</argX>
+ </kwargs>
+ </checkpoint>
+</execution>
+
+<!--
+ Image SMF configuration. Applied to boot archive in the order they
+ are specified. Image files are always used.
+-->
+
+</distro>
+</dc>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/manifests/manifest_simple.xml Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dc SYSTEM "manifest.dtd">
+<dc>
+<distro name="OpenSolaris_X86.iso"
+ http_proxy="http://example.com">
+<distro_spec>
+ <img_params>
+ <media_im>
+ <grub_mods min_mem="0" title="myentry" default_entry="0"
+ timeout="5">
+ <grub_entry position="1">
+ <title_suffix>Enable SSH</title_suffix>
+ <line>kernel$ /platform/i86pc/kernel/$ISADIR/unix -B
+ livessh=enable</line>
+ <line>module$ /platform/i86pc/$ISADIR/boot_archive</line>
+ </grub_entry>
+ </grub_mods>
+ </media_im>
+ </img_params>
+</distro_spec>
+
+<target>
+ <target_device>
+ <swap>
+ <zvol name="swap">
+ <size val="0"/>
+ </zvol>
+ </swap>
+ </target_device>
+</target>
+
+<!--
+ Software section.
+-->
+<software name="transfer-ips-install">
+ <destination>
+ <image img_root="/rpool/new_dc_test/build_data/pkg_image" action="create"></image>
+ </destination>
+ <source>
+ <publisher name="opensolaris.org">
+ <origin name="http://ipkg.sfbay/dev"></origin>
+ </publisher>
+ </source>
+ <software_data action="install" type="IPS">
+ <name>SUNWcs</name>
+ <name>SUNWcsd</name>
+ <name>entire</name>
+ </software_data>
+ <software_data action="install" type="IPS">
+ <name>slim_install</name>
+ <name>system/install/media/internal</name>
+ </software_data>
+</software>
+<!--
+ Execution section.
+-->
+<execution stop_on_error="true">
+ <checkpoint name="transfer-ips-install"
+ mod_path="solaris_install/transfer/transfer_ips"
+ checkpoint_class="TransferIPS">
+ <kwargs>
+ <arg name="dist_iso_sort">path</arg>
+ </kwargs>
+ </checkpoint>
+</execution>
+
+<!--
+ Image SMF configuration. Applied to boot archive in the order they
+ are specified. Image files are always used.
+-->
+
+</distro>
+</dc>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/manifests/manifest_simple_dtd_path.xml Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dc SYSTEM "lib/install_manifest/test/manifests/manifest.dtd">
+<dc>
+<distro name="OpenSolaris_X86.iso"
+ http_proxy="http://example.com">
+<distro_spec>
+ <img_params>
+ <media_im>
+ <grub_mods min_mem="0" title="myentry" default_entry="0"
+ timeout="5">
+ <grub_entry position="1">
+ <title_suffix>Enable SSH</title_suffix>
+ <line>kernel$ /platform/i86pc/kernel/$ISADIR/unix -B
+ livessh=enable</line>
+ <line>module$ /platform/i86pc/$ISADIR/boot_archive</line>
+ </grub_entry>
+ </grub_mods>
+ </media_im>
+ </img_params>
+</distro_spec>
+
+<target>
+ <target_device>
+ <swap>
+ <zvol name="swap">
+ <size val="0"/>
+ </zvol>
+ </swap>
+ </target_device>
+</target>
+
+<!--
+ Software section.
+-->
+<software name="transfer-ips-install">
+ <destination>
+ <image img_root="/rpool/new_dc_test/build_data/pkg_image" action="create"></image>
+ </destination>
+ <source>
+ <publisher name="opensolaris.org">
+ <origin name="http://ipkg.sfbay/dev"></origin>
+ </publisher>
+ </source>
+ <software_data action="install" type="IPS">
+ <name>SUNWcs</name>
+ <name>SUNWcsd</name>
+ <name>entire</name>
+ </software_data>
+ <software_data action="install" type="IPS">
+ <name>slim_install</name>
+ <name>system/install/media/internal</name>
+ </software_data>
+</software>
+<!--
+ Execution section.
+-->
+<execution stop_on_error="true">
+ <checkpoint name="transfer-ips-install"
+ mod_path="solaris_install/transfer/transfer_ips"
+ checkpoint_class="TransferIPS">
+ <kwargs>
+ <arg name="dist_iso_sort">path</arg>
+ </kwargs>
+ </checkpoint>
+</execution>
+
+<!--
+ Image SMF configuration. Applied to boot archive in the order they
+ are specified. Image files are always used.
+-->
+
+</distro>
+</dc>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/manifests/manifest_syntax_error.xml Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dc SYSTEM "manifest.dtd">
+<dc>
+distro name="OpenSolaris_X86.iso"
+ http_proxy="http://example.com">
+<distro_spec>
+ <img_params>
+ <media_im>
+ <grub_mods min_mem="0" title="myentry" default_entry="0"
+ timeout="5">
+ <grub_entry position="1">
+ <title_suffix>Enable SSH</title_suffix>
+ <line>kernel$ /platform/i86pc/kernel/$ISADIR/unix -B
+ livessh=enable</line>
+ <line>module$ /platform/i86pc/$ISADIR/boot_archive</line>
+ </grub_entry>
+ </grub_mods>
+ </media_im>
+ </img_params>
+</distro_spec>
+
+<target>
+ <target_device>
+ <swap>
+ <zvol name="swap">
+ <size val="0"/>
+ </zvol>
+ </swap>
+ </target_device>
+</target>
+
+<!--
+ Software section.
+-->
+<software name="transfer-ips-install">
+ <destination>
+ <image img_root="/rpool/new_dc_test/build_data/pkg_image" action="create"></image>
+ </destination>
+ <source>
+ <publisher name="opensolaris.org">
+ <origin name="http://ipkg.sfbay/dev"></origin>
+ </publisher>
+ </source>
+ <software_data action="install" type="IPS">
+ <name>SUNWcs</name>
+ <name>SUNWcsd</name>
+ <name>entire</name>
+ </software_data>
+ <software_data action="install" type="IPS">
+ <name>slim_install</name>
+ <name>system/install/media/internal</name>
+ </software_data>
+</software>
+<!--
+ Execution section.
+-->
+<execution stop_on_error="true">
+ <checkpoint name="transfer-ips-install"
+ mod_path="solaris_install/transfer/transfer_ips"
+ checkpoint_class="TransferIPS">
+ <kwargs>
+ <arg name="dist_iso_sort">path</arg>
+ </kwargs>
+ </checkpoint>
+</execution>
+
+<!--
+ Image SMF configuration. Applied to boot archive in the order they
+ are specified. Image files are always used.
+-->
+
+</distro>
+</dc>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/manifests/manifest_xinclude_main.xml Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE dc SYSTEM "manifest.dtd">
+<dc>
+<distro name="OpenSolaris_X86.iso"
+ http_proxy="http://example.com">
+<distro_spec>
+ <img_params>
+ <media_im>
+ <grub_mods min_mem="0" title="myentry" default_entry="0"
+ timeout="5">
+ <grub_entry position="1">
+ <title_suffix>Enable SSH</title_suffix>
+ <line>kernel$ /platform/i86pc/kernel/$ISADIR/unix -B
+ livessh=enable</line>
+ <line>module$ /platform/i86pc/$ISADIR/boot_archive</line>
+ </grub_entry>
+ </grub_mods>
+ </media_im>
+ </img_params>
+</distro_spec>
+
+<include href="manifest_xinclude_target.xml" xmlns="http://www.w3.org/2001/XInclude"/>
+
+<!--
+ Software section.
+-->
+<software name="transfer-ips-install">
+ <destination>
+ <image img_root="/rpool/new_dc_test/build_data/pkg_image" action="create"></image>
+ </destination>
+ <source>
+ <publisher name="opensolaris.org">
+ <origin name="http://ipkg.sfbay/dev"></origin>
+ </publisher>
+ </source>
+ <software_data action="install" type="IPS">
+ <name>SUNWcs</name>
+ <name>SUNWcsd</name>
+ <name>entire</name>
+ </software_data>
+ <software_data action="install" type="IPS">
+ <name>slim_install</name>
+ <name>system/install/media/internal</name>
+ </software_data>
+</software>
+<!--
+ Execution section.
+-->
+<execution stop_on_error="true">
+ <checkpoint name="transfer-ips-install"
+ mod_path="solaris_install/transfer/transfer_ips"
+ checkpoint_class="TransferIPS">
+ <kwargs>
+ <arg name="dist_iso_sort">path</arg>
+ </kwargs>
+ </checkpoint>
+</execution>
+
+<!--
+ Image SMF configuration. Applied to boot archive in the order they
+ are specified. Image files are always used.
+-->
+
+</distro>
+</dc>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/manifests/manifest_xinclude_target.xml Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,11 @@
+
+<target>
+ <target_device>
+ <swap>
+ <zvol name="swap">
+ <size val="0"/>
+ </zvol>
+ </swap>
+ </target_device>
+</target>
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/manifests/software.dtd Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,107 @@
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+-->
+
+<!ELEMENT software (destination?, source*, software_data*)>
+
+<!--
+ The software name is utilized to allow users to associate
+ a specific software instance with a specific checkpoint.
+ For example, we could have multiple transfer types during the
+ course of an installation process. If a software is
+ to be associated with a specific checkpoint the software inst
+ name must be utilized and must be the same as the associated
+ checkpoint. If no name provided the software elements
+ will be used in order based on the type provided.
+-->
+
+<!ATTLIST software name CDATA #IMPLIED>
+
+<!ELEMENT software_data (name*)>
+<!ATTLIST software_data action (install|uninstall|unpack|noinstall) "install">
+<!ATTLIST software_data type (IPS|SVR4|ARCHIVE|IMAGE|P5I|DU|P5P|FILE|DIR) "IPS">
+
+<!ELEMENT name (#PCDATA)>
+
+<!--
+ Destination element is not required. If specified there can only
+ be one destination per software element. If not specified,
+ the destination is assumed to be an ipkg image and will be
+ discovered automatically.
+-->
+
+<!ELEMENT destination (image|dir)>
+
+<!ELEMENT image (facet*, img_type?, property*)>
+<!ATTLIST image action (create|use_existing) "create">
+<!ATTLIST image index (true|false) "false">
+<!ATTLIST image ssl_key CDATA #IMPLIED>
+<!ATTLIST image ssl_cert CDATA #IMPLIED>
+<!ATTLIST image img_root CDATA #IMPLIED>
+
+<!ELEMENT img_type EMPTY>
+<!ATTLIST img_type completeness (full|partial) #REQUIRED>
+<!ATTLIST img_type zone (true|false) "false">
+
+<!--
+ A property on an image is set via pkg set-property <propname>.
+ So, for use in this schema an example would be:
+ <image>
+ <img_type completeness="partial" zone="true"/>
+ <property val="true">send-uuid</property>
+ <property val="false">flush-content-cache-on-success
+ </property>
+ </image>
+ A property can also require a string value, rather than just true
+ or false.
+-->
+<!ELEMENT property (#PCDATA)>
+<!ATTLIST property val CDATA #REQUIRED>
+
+<!--
+ A facet is an option that may be selected or not selected,
+ such as various locales, documentation, etc. This is per
+ image.
+-->
+
+<!ELEMENT facet (#PCDATA)>
+<!ATTLIST facet set (true|false) "true">
+
+<!ELEMENT source (publisher+|dir)>
+
+<!--
+ If name is not specified, and this is an ips install,
+ then publishers known by the specified repository will be added to
+ the image. Origin can be an uri, path to a file, archive, directory.
+-->
+<!ELEMENT publisher (origin+, mirror*)>
+<!ATTLIST publisher name CDATA #IMPLIED>
+
+<!ELEMENT origin EMPTY>
+<!ATTLIST origin name CDATA #REQUIRED>
+
+<!ELEMENT mirror EMPTY>
+<!ATTLIST mirror name CDATA #REQUIRED>
+
+<!ELEMENT dir EMPTY>
+<!ATTLIST dir path CDATA #REQUIRED>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/manifests/target.dtd Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,196 @@
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+-->
+
+<!ELEMENT target (target_device+)>
+
+<!--
+ A partition and slice element must be specified within a
+ containing element, such as a disk, zpool or vdev. There must
+ be one element, if disk or pool are specified, that is
+ tagged as the root device. If no target_devices are specified
+ the the application must choose the device based on its
+ specific criteria and assume this is the root device.
+-->
+
+<!ELEMENT target_device (disk|zpool+|swap|dump)>
+
+<!--
+ If a disk is specified at the top level, that is not contained
+ within a zpool specification, this disk will be assumed
+ to be the root device. If a disk target is specified
+ at the top level, and then a zpool with the is_root attribute
+ set this is an error. The user can specify a specific
+ slice within the disk to be used as the root slice. If
+ no slice specified then root slice will be 0.
+-->
+
+<!ELEMENT disk ((disk_name|disk_prop|disk_keyword|iscsi), partition*, slice*)>
+<!--
+ Disk name can be one of ctd, volid, devpath or devid name.
+ Default is "ctd".
+-->
+<!ELEMENT disk_name EMPTY>
+<!ATTLIST disk_name name CDATA #REQUIRED>
+<!ATTLIST disk_name name_type (ctd|volid|devpath|devid) "ctd">
+
+<!ELEMENT disk_prop EMPTY>
+<!ATTLIST disk_prop dev_type CDATA #IMPLIED>
+<!ATTLIST disk_prop dev_vendor CDATA #IMPLIED>
+<!ATTLIST disk_prop dev_size CDATA #IMPLIED>
+
+<!ELEMENT disk_keyword EMPTY>
+<!ATTLIST disk_keyword key (boot_disk) #REQUIRED>
+
+<!--
+ A vdev must start with a disk element. The slice and partition
+ elements use numerical names, such as 0 or 1. A disk must
+ be named for a vdev, using the disk element notation.
+-->
+
+<!ELEMENT vdev (disk+, partition*, slice*)>
+<!ATTLIST vdev redundancy (mirror|raidz|raidz1|raidz2|raidz3|none) "mirror">
+
+<!ELEMENT dataset (zvol|filesystem)>
+
+<!--
+ No size specification means we create the slice the whole size of
+ the disk. If multiple slices specified for one disk, with
+ no sizes, this is an error. The attribute is_root is only
+ valid when a slice is part of a disk definition, outside of
+ a zpool definition. The user can request to format the disk
+ with multiple slices but specify one that they want to
+ be included in the root pool.
+
+-->
+
+
+<!ELEMENT slice (size?)>
+<!ATTLIST slice action (create|delete|preserve) "create">
+<!ATTLIST slice name CDATA #REQUIRED>
+<!ATTLIST slice is_root (true|false) #IMPLIED>
+
+<!--
+ The use of the 'force' attribute on slice specifies that on
+ a 'create' of a slice that already exists we overwrite the
+ slice if force==true. Otherwise the application errors.
+-->
+
+<!ATTLIST slice force (true|false) "false">
+
+<!--
+ If partition size is not provided the partition will be the
+ remaining free size left on the disk.
+-->
+
+<!ELEMENT partition (slice*, size?)>
+<!ATTLIST partition action (create|delete|use_existing) "create">
+
+<!--
+ A partition name is a numeric value, e.g. 1, will be
+ interpreted as partition 1. If a name is not provided
+ the user must specify the use_existing action, otherwise
+ this will be an invalid specification.
+-->
+<!ATTLIST partition name CDATA #IMPLIED>
+<!ATTLIST partition part_type CDATA "191">
+
+<!--
+ Size must be suffixed with a size unit. i.e 100gb, 2secs, 2tb.
+-->
+<!ELEMENT size EMPTY>
+<!ATTLIST size val CDATA #REQUIRED>
+<!ATTLIST size start_sector CDATA #IMPLIED>
+
+
+<!ELEMENT options (#PCDATA)>
+
+<!--
+ Option elements allow any string type, and this string is parsable
+ character data, should the application require it.
+-->
+
+<!--
+ Filesystem options are for zfs filesystems. The format of these
+ is this: "-o property=value". Any editable ZFS filesystem property
+ can be set at creation time. Multiple -o options can be
+ specified. An error will occur if a propert is specified in
+ multiple -o options.
+-->
+
+<!ELEMENT filesystem (options?)>
+<!ATTLIST filesystem name CDATA #REQUIRED>
+<!ATTLIST filesystem action (create|delete|preserve) "create">
+<!ATTLIST filesystem mountpoint CDATA #IMPLIED>
+
+<!--
+ Redundancy needs to be part of the vdev grouping,
+ not a property on zpool itself. There can be multiple
+ vdev groupings within one pool configuration.
+-->
+
+<!ELEMENT zpool (vdev*, dataset*, pool_options?, dataset_options?)>
+<!ATTLIST zpool action (create|delete|preserve|use_existing) "create">
+<!ATTLIST zpool name CDATA #REQUIRED>
+<!ATTLIST zpool is_root (true|false) "false">
+
+<!--
+ The pool option string, which is also a parsable string,
+ can include both pool options and filesystem options.
+ For pool options the format is: "-o property=value". For
+ filesystem properties the format is: "-O file-system-property=value"
+ Both of these typs of properties can be set in the option string.
+ An example of combining these in the option string:
+
+"-o altroot=/a -o autoexpand=off -o delegation=off -O atime=on -O compression=lzbj"
+-->
+
+<!ELEMENT pool_options (options)>
+<!ELEMENT dataset_options (options)>
+
+
+<!ELEMENT zvol (options?, size) >
+<!ATTLIST zvol action (create|delete|preserve|use_existing) "create">
+<!ATTLIST zvol name CDATA #REQUIRED>
+
+<!--
+ ISCSI does not have an action attribute. We use iscsi devices but
+ we do not operate directly on them.
+-->
+<!ELEMENT iscsi (ip)>
+<!ATTLIST iscsi name CDATA #REQUIRED>
+<!ATTLIST iscsi source CDATA #IMPLIED>
+<!ATTLIST iscsi target_lun CDATA #IMPLIED>
+<!ATTLIST iscsi target_port CDATA #IMPLIED>
+
+<!ELEMENT ip (#PCDATA)>
+
+<!--
+ Swap and dump are optional with Solaris install.
+-->
+
+<!ELEMENT swap (zvol)>
+<!ATTLIST swap no_swap (true|false) "false">
+
+<!ELEMENT dump (zvol)>
+<!ATTLIST dump no_dump (true|false) "false">
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/test_mp_invalid_params.py Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,63 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''ManifestParser invalid params test module'''
+
+
+import logging
+import unittest
+
+import common
+from solaris_install.logger import InstallLogger
+from solaris_install.manifest import ManifestError
+from solaris_install.manifest.parser import ManifestParser
+
+
+class InvalidParams(unittest.TestCase):
+ '''ManifestParser invalid params tests'''
+
+ def setUp(self):
+ '''Set up logging'''
+ 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"
+ '''
+ self.assertRaises(ManifestError, ManifestParser, "manifest-parser",
+ common.MANIFEST_DC, dtd_file=common.DTD_INVALID_2)
+
+
+if __name__ == '__main__':
+ unittest.main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/test_mp_load_manifest.py Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,173 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''ManifestParser tests for _load_manifest method'''
+
+
+import logging
+import unittest
+
+from lxml import etree
+
+import common
+from solaris_install.logger import InstallLogger
+from solaris_install.manifest import ManifestError
+from solaris_install.manifest.parser import ManifestParser
+
+
+class ManifestParserLoadManifest(unittest.TestCase):
+ '''ManifestParser tests for _load_manifest method'''
+
+ def setUp(self):
+ '''Set up logging'''
+ logging.setLoggerClass(InstallLogger)
+
+
+ def test_mp_load_manifest_valid(self):
+ '''
+ test_mp_load_manifest_valid - load and validate standard manifest
+ '''
+
+ validate_from_docinfo = True
+ load_defaults = False
+ call_xinclude = False
+ path = "/dc/distro"
+ attribute = "http_proxy"
+ attribute_value = "http://example.com"
+
+ try:
+ mp_cp = ManifestParser("manifest-parser",
+ common.MANIFEST_DC,
+ validate_from_docinfo=validate_from_docinfo,
+ load_defaults=load_defaults,
+ call_xinclude=call_xinclude)
+ except ManifestError, err:
+ self.fail(str(err))
+
+ try:
+ tree = mp_cp._load_manifest(dtd_validation=validate_from_docinfo,
+ attribute_defaults=load_defaults)
+ except ManifestError, err:
+ self.fail(str(err))
+
+ # confirm some expected value from the XML tree
+ elements = tree.xpath(path)
+ self.assertEqual(len(elements), 1)
+ self.assertTrue(elements[0].attrib.has_key(attribute))
+ self.assertEqual(elements[0].get(attribute), attribute_value)
+
+
+ def test_mp_load_manifest_defaults(self):
+ '''
+ test_mp_load_manifest_defaults - load a standard manifest with attribute defaults
+ '''
+
+ validate_from_docinfo = False
+ load_defaults = True
+ call_xinclude = False
+
+ try:
+ mp_cp = ManifestParser("manifest-parser",
+ common.MANIFEST_DC,
+ validate_from_docinfo=validate_from_docinfo,
+ load_defaults=load_defaults,
+ call_xinclude=call_xinclude)
+ except ManifestError, err:
+ self.fail(str(err))
+
+ try:
+ tree = mp_cp._load_manifest(dtd_validation=validate_from_docinfo,
+ attribute_defaults=load_defaults)
+ except ManifestError, err:
+ self.fail(str(err))
+
+ # confirm some expected value from the XML tree
+ # (this needs to wait until some more DataObject classes are written)
+
+
+ def test_mp_load_manifest_xinclude(self):
+ '''
+ test_mp_load_manifest_xinclude - load a manifest with XInclude statements
+ '''
+
+ validate_from_docinfo = False
+ load_defaults = False
+ call_xinclude = True
+ path = "/dc/distro/target/target_device/swap/zvol"
+ attribute = "name"
+ attribute_value = "swap"
+
+ try:
+ mp_cp = ManifestParser("manifest-parser",
+ common.MANIFEST_XINCLUDE,
+ validate_from_docinfo=validate_from_docinfo,
+ load_defaults=load_defaults,
+ call_xinclude=call_xinclude)
+ except ManifestError, err:
+ self.fail(str(err))
+
+ try:
+ tree = mp_cp._load_manifest(dtd_validation=validate_from_docinfo,
+ attribute_defaults=load_defaults)
+ except ManifestError, err:
+ self.fail(str(err))
+
+ # confirm some expected value from the XInclude'd portion of the XML tree
+ elements = tree.xpath(path)
+ self.assertEqual(len(elements), 1)
+ self.assertTrue(elements[0].attrib.has_key(attribute))
+ self.assertEqual(elements[0].get(attribute), attribute_value)
+
+
+ def test_mp_load_manifest_syntax(self):
+ '''
+ test_mp_load_manifest_syntax - ensure XMLSyntaxError raised for bad manifest
+ '''
+
+ validate_from_docinfo = False
+ load_defaults = False
+ call_xinclude = False
+
+ try:
+ mp_cp = ManifestParser("manifest-parser",
+ common.MANIFEST_SYNTAX_ERROR,
+ validate_from_docinfo=validate_from_docinfo,
+ load_defaults=load_defaults,
+ call_xinclude=call_xinclude)
+ except ManifestError, err:
+ self.fail(str(err))
+
+ try:
+ tree = mp_cp._load_manifest(dtd_validation=validate_from_docinfo,
+ attribute_defaults=load_defaults)
+ except ManifestError, err:
+ # confirm the reason for faiing was an XMLSyntaxError
+ self.assertTrue(isinstance(err.orig_exception, etree.XMLSyntaxError))
+ else:
+ self.fail("_load_manifest should have failed.")
+
+
+if __name__ == '__main__':
+ unittest.main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/test_mp_with_engine.py Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,150 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''ManifestParser Tests using InstallEngine'''
+
+
+import logging
+import unittest
+
+import common
+from solaris_install.engine import InstallEngine
+from solaris_install.engine.test.engine_test_utils import reset_engine, \
+ get_new_engine_instance
+
+####################################################################
+# importing these classes causes them to be registered with the DOC
+####################################################################
+# pylint: disable-msg=W0614
+#from solaris_install.distro_const.configuration import *
+#from solaris_install.distro_const.distro_spec import *
+#from solaris_install.distro_const.execution_checkpoint import *
+from solaris_install.target.target_spec import *
+#from solaris_install.transfer.transfer_info import *
+
+
+class ManifestParserWithEngine(unittest.TestCase):
+ '''ManifestParser Tests using InstallEngine'''
+
+ def setUp(self):
+ '''instantiate the Engine so that the DOC is created'''
+ self.engine = get_new_engine_instance()
+
+ def tearDown(self):
+ '''Force all content of the DOC to be cleared.'''
+ reset_engine()
+
+
+ ### COMMENTED OUT UNTIL DC code is pushed
+ #def test_mp_engine_simple(self):
+ # '''
+ # test_mp_engine_simple - import and validate a standard manifest
+ # '''
+ # my_args = [common.MANIFEST_DC]
+ # my_kwargs = {}
+ # my_kwargs["validate_from_docinfo"] = True
+ # my_kwargs["load_defaults"] = 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 failed [%s]" % status)
+
+ # # Check some expected value from the cache
+ # distro_list = \
+ # self.engine.data_object_cache.get_descendants(class_type=Distro)
+ # self.assertEqual(len(distro_list), 1)
+ # self.assertTrue(distro_list[0].name == "OpenSolaris_X86.iso")
+
+ def test_mp_engine_validate(self):
+ '''
+ test_mp_engine_validate - use validate_from_docinfo=None to validate if DTD specified
+ '''
+ my_args = [common.MANIFEST_DC_DTD_PATH]
+ my_kwargs = {}
+ my_kwargs["validate_from_docinfo"] = None
+ my_kwargs["load_defaults"] = 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 failed")
+
+
+ def test_mp_engine_doesnt_validate(self):
+ '''
+ test_mp_engine_doesnt_validate - execution fails if validation requested and fails
+ '''
+ my_args = [common.MANIFEST_INVALID]
+ my_kwargs = {}
+ my_kwargs["validate_from_docinfo"] = None
+ my_kwargs["load_defaults"] = 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_no_dtd_ref(self):
+ '''
+ test_mp_engine_no_dtd_ref - confirm error if validate_...=True and DTD not specified
+ '''
+ my_args = [common.MANIFEST_NO_DTD_REF]
+ my_kwargs = {}
+ my_kwargs["validate_from_docinfo"] = True
+
+ 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")
+
+
+if __name__ == '__main__':
+ unittest.main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/test_mp_without_engine.py Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,151 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''ManifestParser tests without InstallEngine'''
+
+
+import logging
+import unittest
+
+from lxml import etree
+
+import common
+from solaris_install.manifest import ManifestError
+from solaris_install.manifest.parser import ManifestParser
+from solaris_install.data_object import ParsingError
+from solaris_install.data_object.cache import DataObjectCache
+
+####################################################################
+# importing these classes causes them to be registered with the DOC
+####################################################################
+# pylint: disable-msg=W0614
+#from solaris_install.distro_const.configuration import *
+#from solaris_install.distro_const.distro_spec import *
+#from solaris_install.distro_const.execution_checkpoint import *
+from solaris_install.target.target_spec import *
+#from solaris_install.transfer.transfer_info import *
+
+
+class ManifestParserWithoutEngine(unittest.TestCase):
+ '''ManifestParser tests without InstallEngine'''
+
+ def setUp(self):
+ '''instantiate the DOC'''
+ self.doc = DataObjectCache()
+
+ def tearDown(self):
+ '''Clear the DOC'''
+ self.doc = None
+
+
+ def test_mp_no_engine_no_doc(self):
+ '''
+ test_mp_no_engine_no_doc - parse standard manifest without importing to DOC
+ '''
+ try:
+ mp_cp = ManifestParser("manifest-parser",
+ common.MANIFEST_DC,
+ validate_from_docinfo=True)
+ except ManifestError, err:
+ self.fail(str(err))
+
+ try:
+ mp_cp.parse()
+ except ManifestError, err:
+ self.fail(str(err))
+
+
+ ### COMMENTED OUT UNTIL DC code is pushed
+ #def test_mp_no_engine_doc(self):
+ # '''
+ # test_mp_no_engine_doc - parse standard manifest and import to DOC
+ # '''
+ # try:
+ # mp_cp = ManifestParser("manifest-parser",
+ # common.MANIFEST_DC,
+ # validate_from_docinfo=True)
+ # except ManifestError, err:
+ # self.fail(str(err))
+
+ # try:
+ # mp_cp.parse(doc=self.doc)
+ # except ManifestError, err:
+ # self.fail(str(err))
+
+ # # Check some expected values from the cache
+ # distro_list = self.doc.get_descendants(class_type=Distro)
+ # self.assertTrue(len(distro_list) == 1)
+ # self.assertTrue(distro_list[0].name == "OpenSolaris_X86.iso")
+
+
+ def test_mp_no_engine_dtd_error(self):
+ '''
+ test_mp_no_engine_dtd_error - DTDParseError raised if DTD contains invalid syntax
+ '''
+
+ try:
+ mp_cp = ManifestParser("manifest-parser",
+ common.MANIFEST_DC,
+ dtd_file=common.DTD_INVALID)
+ except ManifestError, err:
+ self.fail(str(err))
+
+ try:
+ mp_cp.parse(doc=self.doc)
+ except ManifestError, err:
+ # Ensure exception wrapped inside ManifestError is a DTDParseError
+ self.assertTrue(isinstance(err.orig_exception, etree.DTDParseError))
+ # Check the string representation while we're at it
+ self.assertTrue(str(err).count("DTDParseError") > 0)
+ else:
+ self.fail("ManifestError should have been raised")
+
+
+ ### COMMENTED OUT UNTIL DC code is pushed
+ #def test_mp_no_engine_parse_error(self):
+ # '''
+ # test_mp_no_engine_parse_error - ParsingError raised when import to DOC fails
+ # '''
+
+ # try:
+ # mp_cp = ManifestParser("manifest-parser",
+ # common.MANIFEST_PARSE_ERROR,
+ # validate_from_docinfo=False)
+ # except ManifestError, err:
+ # self.fail(str(err))
+
+ # try:
+ # mp_cp.parse(doc=self.doc)
+ # except ManifestError, err:
+ # # Ensure exception wrapped inside ManifestError is a ParsingError
+ # self.assertTrue(isinstance(err.orig_exception, ParsingError))
+ # # Check the string representation while we're at it
+ # self.assertTrue(str(err).count("ParsingError") > 0)
+ # else:
+ # self.fail("ManifestError should have been raised")
+
+
+if __name__ == '__main__':
+ unittest.main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/test_mw_dry_run.py Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,105 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''ManifestWriter dry_run tests'''
+
+
+import logging
+import unittest
+
+import common
+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 import ManifestError
+from solaris_install.manifest.writer import ManifestWriter
+
+####################################################################
+# importing these classes causes them to be registered with the DOC
+####################################################################
+# pylint: disable-msg=W0614
+#from solaris_install.distro_const.configuration import *
+#from solaris_install.distro_const.distro_spec import *
+#from solaris_install.distro_const.execution_checkpoint import *
+from solaris_install.target.target_spec import *
+#from solaris_install.transfer.transfer_info import *
+
+
+class ManifestParserWithEngine(unittest.TestCase):
+ '''ManifestWriter dry_run tests'''
+
+ def setUp(self):
+ '''instantiate the Engine so that the DOC is created'''
+ self.engine = get_new_engine_instance()
+
+ def tearDown(self):
+ '''Force all content of the DOC to be cleared.'''
+ reset_engine()
+
+
+ def test_mw_dry_run(self):
+ '''
+ test_mw_dry_run - confirm output file is changed if dry_run=True
+ '''
+ my_args = [common.MANIFEST_DC]
+ my_kwargs = {}
+ my_kwargs["validate_from_docinfo"] = True
+ my_kwargs["load_defaults"] = False
+
+ self.engine.register_checkpoint("manifest_parser",
+ "solaris_install/manifest/parser",
+ "ManifestParser",
+ args=my_args,
+ kwargs=my_kwargs)
+
+ status = self.engine.execute_checkpoints()[0]
+
+ if status != InstallEngine.EXEC_SUCCESS:
+ self.fail("ManifestParser checkpoint failed")
+
+ # By-pass the engine for running ManifestWriter, so we
+ # can verify the object's attributes
+
+ try:
+ mw_cp = ManifestWriter("manifest-writer", common.MANIFEST_OUT_OK)
+ mw_cp.execute()
+ except ManifestError, err:
+ self.fail(str(err))
+
+ self.assertTrue(mw_cp._manifest == common.MANIFEST_OUT_OK)
+
+ # Run it again so we can be sure outfile already exists,
+ # and therefore must be changed
+ try:
+ mw_cp.execute(dry_run=True)
+ except ManifestError, err:
+ self.fail(str(err))
+
+ self.assertTrue(mw_cp._manifest != common.MANIFEST_OUT_OK)
+
+
+
+if __name__ == '__main__':
+ unittest.main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/test_mw_invalid_params.py Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,62 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''ManifestWriter invalid params tests'''
+
+import logging
+import unittest
+
+import common
+from solaris_install.logger import InstallLogger
+from solaris_install.manifest import ManifestError
+from solaris_install.manifest.writer import ManifestWriter
+
+
+class InvalidParams(unittest.TestCase):
+ '''ManifestWriter invalid params tests'''
+
+ def setUp(self):
+ '''Set up logging'''
+ logging.setLoggerClass(InstallLogger)
+
+
+ def test_mw_invalid_params_xslt(self):
+ '''
+ test_mw_invalid_params_xslt - confirm error if xslt_file doesn't exist
+ '''
+ self.assertRaises(ManifestError, ManifestWriter, "manifest-writer",
+ common.MANIFEST_OUT_OK, xslt_file=common.XSLT_NON_EXISTENT)
+
+
+ def test_mw_invalid_params_dtd_file(self):
+ '''
+ test_mw_invalid_params_dtd_file - confirm error if dtd_file doesn't exist
+ '''
+ self.assertRaises(ManifestError, ManifestWriter, "manifest-writer",
+ common.MANIFEST_OUT_OK, dtd_file=common.DTD_NON_EXISTENT)
+
+
+if __name__ == '__main__':
+ unittest.main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/test_mw_with_engine.py Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,234 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''ManifestWriter tests using InstallEngine'''
+
+
+import logging
+import os.path
+import unittest
+
+import common
+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 import ManifestError
+
+####################################################################
+# importing these classes causes them to be registered with the DOC
+####################################################################
+# pylint: disable-msg=W0614
+#from solaris_install.distro_const.configuration import *
+#from solaris_install.distro_const.distro_spec import *
+#from solaris_install.distro_const.execution_checkpoint import *
+from solaris_install.target.target_spec import *
+#from solaris_install.transfer.transfer_info import *
+
+
+class ManifestParserWithEngine(unittest.TestCase):
+ '''ManifestWriter tests using InstallEngine'''
+
+ def setUp(self):
+ '''instantiate the Engine so that the DOC is created'''
+ self.engine = get_new_engine_instance()
+
+ def tearDown(self):
+ '''Force all content of the DOC to be cleared.'''
+ reset_engine()
+
+
+ def test_mw_engine_simple(self):
+ '''
+ test_mw_engine_simple - read in and then write out a standard manifest
+ '''
+ my_args = [common.MANIFEST_DC]
+ my_kwargs = {}
+ my_kwargs["validate_from_docinfo"] = True
+ my_kwargs["load_defaults"] = 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 failed")
+
+ my_args = [common.MANIFEST_OUT_OK]
+ my_kwargs = {}
+ my_kwargs["xslt_file"] = common.XSLT_DOC_TO_DC
+ my_kwargs["validate_from_docinfo"] = False
+ my_kwargs["dtd_file"] = None
+
+ self.engine.register_checkpoint("manifest_writer",
+ "solaris_install/manifest/writer",
+ "ManifestWriter",
+ args=my_args,
+ kwargs=my_kwargs)
+
+ status = self.engine.execute_checkpoints()[0]
+
+ self.assertEqual(status, InstallEngine.EXEC_SUCCESS,
+ "ManifestWriter checkpoint failed")
+
+ # Confirm the output manifest looks as expected
+ self.assertTrue(common.file_line_matches(common.MANIFEST_OUT_OK,
+ 1, '<dc>') == True)
+ self.assertTrue(common.file_line_matches(common.MANIFEST_OUT_OK,
+ -1, '</dc>') == True)
+
+
+ def test_mw_engine_invalid_file(self):
+ '''
+ test_mw_engine_invalid_file - try to write to file in non-existent dir
+ '''
+
+ # Repeat of test_mw_with_engine_simple, but change output file
+ # and ensure test fails
+ my_args = [common.MANIFEST_DC]
+ my_kwargs = {}
+ my_kwargs["validate_from_docinfo"] = True
+ my_kwargs["load_defaults"] = 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 failed")
+
+ my_args = [common.MANIFEST_OUT_NON_EXISTENT]
+ my_kwargs = {}
+ my_kwargs["xslt_file"] = common.XSLT_DOC_TO_DC
+ my_kwargs["validate_from_docinfo"] = False
+ my_kwargs["dtd_file"] = None
+
+ self.engine.register_checkpoint("manifest_writer",
+ "solaris_install/manifest/writer",
+ "ManifestWriter",
+ args=my_args,
+ kwargs=my_kwargs)
+
+ status = self.engine.execute_checkpoints()[0]
+
+ self.assertEqual(status, InstallEngine.EXEC_FAILED,
+ "ManifestWriter checkpoint should have failed")
+
+ # Confirm the output manifest wasn't created
+ self.assertTrue(os.path.exists(common.MANIFEST_OUT_NON_EXISTENT)
+ == False)
+
+
+ ### COMMENTED OUT UNTIL DC code is pushed
+ #def test_mw_engine_nonexistent_xslt(self):
+ # '''
+ # test_mw_engine_nonexistent_xslt - try to transform using non-existing XSLT file
+ # '''
+
+ # # Repeat of test_mw_with_engine_simple, but change xslt file
+ # # and ensure test fails
+ # my_args = [common.MANIFEST_DC]
+ # my_kwargs = {}
+ # my_kwargs["validate_from_docinfo"] = True
+ # my_kwargs["load_defaults"] = 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 failed")
+
+ # my_args = [common.MANIFEST_OUT_OK]
+ # my_kwargs = {}
+ # my_kwargs["xslt_file"] = common.XSLT_NON_EXISTENT
+ # my_kwargs["validate_from_docinfo"] = False
+ # my_kwargs["dtd_file"] = None
+
+ # self.engine.register_checkpoint("manifest_writer",
+ # "solaris_install/manifest/writer",
+ # "ManifestWriter",
+ # args=my_args,
+ # kwargs=my_kwargs)
+
+ # try:
+ # status = self.engine.execute_checkpoints()[0]
+ # except ManifestError:
+ # pass
+ # else:
+ # self.fail("ManifestWriter __init__() should have failed")
+
+
+ def test_mw_engine_invalid_xslt(self):
+ '''
+ test_mw_engine_invalid_xslt - use XSLT file with invalid syntax
+ '''
+ my_args = [common.MANIFEST_DC]
+ my_kwargs = {}
+ my_kwargs["validate_from_docinfo"] = True
+ my_kwargs["load_defaults"] = 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 failed")
+
+ my_args = [common.MANIFEST_OUT_OK]
+ my_kwargs = {}
+ my_kwargs["xslt_file"] = common.XSLT_INVALID
+ my_kwargs["validate_from_docinfo"] = False
+ my_kwargs["dtd_file"] = None
+
+ self.engine.register_checkpoint("manifest_writer",
+ "solaris_install/manifest/writer",
+ "ManifestWriter",
+ args=my_args,
+ kwargs=my_kwargs)
+
+ status = self.engine.execute_checkpoints()[0]
+
+ self.assertEqual(status, InstallEngine.EXEC_FAILED,
+ "ManifestWriter checkpoint should have failed")
+
+
+if __name__ == '__main__':
+ unittest.main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/test/test_mw_without_engine.py Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,132 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''ManifestWriter tests without InstallEngine'''
+
+import logging
+import unittest
+
+import common
+from solaris_install.data_object.cache import DataObjectCache
+from solaris_install.manifest import ManifestError
+from solaris_install.manifest.parser import ManifestParser
+from solaris_install.manifest.writer import ManifestWriter
+
+####################################################################
+# importing these classes causes them to be registered with the DOC
+####################################################################
+# pylint: disable-msg=W0614
+#from solaris_install.distro_const.configuration import *
+#from solaris_install.distro_const.distro_spec import *
+#from solaris_install.distro_const.execution_checkpoint import *
+from solaris_install.target.target_spec import *
+#from solaris_install.transfer.transfer_info import *
+
+
+class ManifestParserWithoutEngine(unittest.TestCase):
+ '''ManifestWriter tests without InstallEngine'''
+
+ def setUp(self):
+ '''instantiate the Engine so that the DOC is created'''
+ self.doc = DataObjectCache()
+
+ def tearDown(self):
+ '''Force all content of the DOC to be cleared.'''
+ self.doc = None
+
+
+ def test_mw_no_engine_empty_doc(self):
+ '''
+ test_mw_no_engine_empty_doc - write manifest from empty DOC
+ '''
+
+ try:
+ manifest_writer = ManifestWriter("manifest-writer",
+ common.MANIFEST_OUT_OK)
+ manifest_writer.write(self.doc)
+ except ManifestError, err:
+ self.fail(str(err))
+
+ # Confirm the output manifest looks as expected
+ self.assertTrue(common.file_line_matches(common.MANIFEST_OUT_OK,
+ 0, '<root/>') == True)
+
+
+ ### COMMENTED OUT UNTIL DC code is pushed
+ #def test_mw_no_engine_dc_simple(self):
+ # '''
+ # test_mw_no_engine_dc_simple - read in and write out a standard manifest
+ # '''
+
+ # try:
+ # manifest_parser = ManifestParser("manifest-parser",
+ # common.MANIFEST_DC,
+ # validate_from_docinfo=True)
+ # manifest_parser.parse(doc=self.doc)
+ # manifest_writer = ManifestWriter("manifest-writer",
+ # common.MANIFEST_OUT_OK)
+ # manifest_writer.write(self.doc)
+ # except ManifestError, err:
+ # self.fail(str(err))
+
+ # # Confirm the output manifest looks as expected
+ # self.assertTrue(common.file_line_matches(common.MANIFEST_OUT_OK,
+ # 0, '<root>') == True)
+ # self.assertTrue(common.file_line_matches(common.MANIFEST_OUT_OK,
+ # -1, '</root>') == True)
+
+
+ def test_mw_no_engine_with_xslt(self):
+ '''
+ test_mw_no_engine_with_xslt - read a manifest, then transform it and write it out
+ '''
+
+ try:
+ manifest_parser = ManifestParser("manifest-parser",
+ common.MANIFEST_DC,
+ validate_from_docinfo=True)
+ manifest_parser.parse(doc=self.doc)
+
+ # We cannot test validate_from_docinfo=True on the output
+ # until the to_xml() methods of the relevant classes in
+ # other modules return XML that conforms to the schema
+
+ manifest_writer = ManifestWriter("manifest-writer",
+ common.MANIFEST_OUT_OK,
+ xslt_file=common.XSLT_DOC_TO_DC,
+ validate_from_docinfo=False)
+ manifest_writer.write(self.doc)
+ except ManifestError, err:
+ self.fail(str(err))
+
+ # Confirm the output manifest looks as expected
+ self.assertTrue(common.file_line_matches(common.MANIFEST_OUT_OK,
+ 1, '<dc>') == True)
+ self.assertTrue(common.file_line_matches(common.MANIFEST_OUT_OK,
+ -1, '</dc>') == True)
+
+
+if __name__ == '__main__':
+ unittest.main()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/writer/Makefile Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,63 @@
+#
+##
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+
+PYMODS = writer.py
+
+PYCMODS = $(PYMODS:%.py=%.pyc)
+
+ROOTPYMODS= $(PYMODS:%=$(ROOTPYTHONVENDORSOLINSTALLMANIFEST)/%)
+
+ROOTPYCMODS= $(PYCMODS:%=$(ROOTPYTHONVENDORSOLINSTALLMANIFEST)/%)
+
+
+CLOBBERFILES = $(PYCMODS)
+CLEANFILES = $(CLOBBERFILES)
+
+include ../../Makefile.lib
+
+static:
+
+dynamic:
+
+python:
+ $(PYTHON) -m compileall -l $(@D)
+
+all: python
+
+install_h:
+
+install: all .WAIT \
+ $(ROOTPYTHONVENDOR) \
+ $(ROOTPYTHONVENDORSOLINSTALL) \
+ $(ROOTPYTHONVENDORSOLINSTALLMANIFEST) \
+ $(ROOTPYMODS) $(ROOTPYCMODS)
+
+lint: lint_SRCS
+
+FRC:
+
+include ../../Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/install_manifest/writer/writer.py Fri Oct 29 13:35:45 2010 +0000
@@ -0,0 +1,311 @@
+#
+##
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+'''ManifestWriter Checkpoint'''
+
+import logging
+from lxml import etree
+import os
+import tempfile
+
+from solaris_install.engine import InstallEngine
+from solaris_install.engine.checkpoint import AbstractCheckpoint
+from solaris_install.manifest import ManifestError, validate_manifest
+
+
+class ManifestWriter(AbstractCheckpoint):
+ '''
+ ManifestWriter - export, transform and validate an XML manifest.
+
+
+ Summary:
+ This class implements the AbstractCheckpoint abstract base class
+ which allows it to be executed from within the InstallEngine.
+ It also provides an additional API that allow it to be run
+ outside of the InstallEngine context.
+
+
+ Initializer method:
+ The parameters of the initializer method give the location
+ of the XML manifest to be created and define what transformation
+ and validation will be performed.
+
+
+ execute() and parse() methods:
+ When running in an InstallEngine context the execute() method
+ performs the main tasks of exporting and, optionally, transforming
+ and validating the manifest.
+
+ When run outside the InstallEngine context, the write() method
+ performs these same functions.
+
+ The main difference between execute() and write() is from where
+ the DataObjectCache (DOC) reference is obtained. execute()
+ assumes an InstallEngine singleton exists and gets the DOC
+ reference from it. With write(), a reference to an existing DOC
+ instance must be passed in.
+
+ If an error occurs during the execute() or write() methods,
+ including XML syntax errors or failure to validate the
+ manifest, a ManifestError exception is raised.
+
+ If no errors occur, the methods simply return, with no return
+ value. The output manifest file will be created as requested.
+
+
+ Other public methods:
+ The get_progress_estimate() method is required by the parent
+ AbstractCheckpoint class.
+
+ The cancel() method defined in AbstractCheckpoint is not
+ overridden in ManifestParser.
+ '''
+
+ def __init__(self, name, manifest, xslt_file=None,
+ validate_from_docinfo=False, dtd_file=None):
+ '''
+ Class initializer method.
+
+ Parameters:
+ - name arg is required by AbstractCheckpoint. Not used.
+ - manifest must be the path to a writable XML file
+ - xslt_file defaults to None. Otherwise, it must be the
+ path to a readable XSLT file which will be applied to
+ the manifest XML data to transform it into the required
+ format. Typically, this is used to structure the data
+ according to the AI or DC schema.
+ - validate_from_docinfo defaults to False. It is only
+ relevant if, following XSL Transformation, the XML document
+ contains a reference to a DTD. This will typically have
+ been added by the XSLT file. If validate_from_docinfo is
+ True, the XML document will be validated against its
+ referenced DTD, if present. If validation fails, an
+ error is raised. If validate_from_docinfo is False or
+ no DTD is referenced, this validation is skipped.
+ - dtd_file defaults to None. Otherwise, it must be the
+ path to a DTD file against which the manifest XML will be
+ validated before it is written out. If validation is
+ attempted and fails, an error is raised. This validation
+ is separate from that controlled by validate_from_docinfo.
+
+ Returns:
+ - Nothing
+
+ Raises:
+ - ManifestError is raised if invalid values are specified
+ for any paramaters or if xslt_file or dtd_file are specified
+ but do not exist.
+ '''
+
+ super(ManifestWriter, self).__init__(name)
+
+ self.logger.debug("Initializing ManifestWriter " \
+ "(manifest=%s, xslt_file=%s, " \
+ "validate_from_docinfo=%s, dtd_file=%s)",
+ manifest, xslt_file,
+ validate_from_docinfo, dtd_file)
+
+ # Check and store params
+
+ self._manifest = manifest
+
+ if ((xslt_file is not None) and
+ (not os.path.isfile(xslt_file))):
+ raise ManifestError("XSLT file [%s] is not a file" % xslt_file)
+ self._xslt_file = xslt_file
+
+ self._validate_from_docinfo = validate_from_docinfo
+
+ if ((dtd_file is not None) and
+ (not os.path.isfile(dtd_file))):
+ raise ManifestError("DTD [%s] is not a file" % dtd_file)
+ self._dtd_file = dtd_file
+
+
+ def get_progress_estimate(self):
+ '''
+ The parent class requires that this method be implemented
+ in sub-classes.
+
+ This returns an estimate of how long the execute() method
+ will take to run.
+ '''
+
+ return 1
+
+
+ def write(self, doc):
+ '''
+ This API method is not part of the AbstractCheckpoint spec.
+ It can be used to access the ManifestParser functionality outside
+ the InstallEngine context.
+
+ This method is also used as a convenience function within this
+ class to do most of the work of the execute() method.
+
+ Parameters:
+ - doc, a reference to the DataObjectCache instance from which to
+ export the manifest data.
+
+ Returns:
+ - Nothing
+ On success, this method returns; on error it raises an exception.
+
+ Raises:
+ ManifestError is raised if:
+ - xslt_file cannot be read or is not a valid XSLT file
+ - output file cannot be created or written to
+ or if validate_manifest raises an error.
+ '''
+
+ self.logger.debug("ManifestWriter.write(doc=%s) called", doc)
+
+ if self._cancel_requested.is_set():
+ self.logger.debug("Cancel requested, returning.")
+ return
+
+ # Get XML data from DOC. This always returns something
+ xml = doc.generate_xml_manifest()
+
+ tree = etree.ElementTree(xml)
+ if self.logger.isEnabledFor(logging.DEBUG):
+ self.logger.debug("XML returned from DOC:\n%s\n",
+ etree.tostring(tree, pretty_print=True))
+
+ if self._xslt_file is not None:
+ # Perform the requested XSL Transform on the XML data
+ try:
+ xslt_doc = etree.parse(self._xslt_file)
+ except IOError, error:
+ msg = "Cannot access XSLT file [%s]" % (self._xslt_file)
+ self.logger.exception(msg)
+ self.logger.exception(error)
+ raise ManifestError(msg, orig_exception=error)
+ except etree.XMLSyntaxError, error:
+ msg = "XML syntax error in XSLT file [%s]" % \
+ (self._xslt_file)
+ self.logger.exception(msg)
+ self.logger.exception(error)
+ raise ManifestError(msg, orig_exception=error)
+
+ transform = etree.XSLT(xslt_doc)
+
+ tree = transform(tree)
+
+ if self._cancel_requested.is_set():
+ self.logger.debug("Cancel requested, returning.")
+ return
+
+ if self._validate_from_docinfo:
+ # Validate against the DTD referenced in the headers, if any
+ if ((tree.docinfo is not None) and
+ (tree.docinfo.system_url is not None)):
+ validate_manifest(tree, tree.docinfo.system_url, self.logger)
+
+ if self._dtd_file is not None:
+ # Validate against the DTD file passed into the constructor
+ validate_manifest(tree, self._dtd_file, self.logger)
+
+ text = etree.tostring(tree, pretty_print=True)
+
+ if self._cancel_requested.is_set():
+ self.logger.debug("Cancel requested, returning.")
+ return
+
+ self.logger.debug("About to write out:\n%s\n", text)
+
+ # Write to output file
+ manifest_file = None
+ try:
+ manifest_file = open(self._manifest, mode='w')
+ manifest_file.write(text)
+ except IOError, error:
+ msg = "Cannot write to output Manifest [%s]" % (self._manifest)
+ self.logger.exception(msg)
+ self.logger.exception(error)
+ raise ManifestError(msg, orig_exception=error)
+ finally:
+ if manifest_file is not None:
+ manifest_file.close()
+
+
+ def execute(self, dry_run=False):
+ '''
+ Abstract method defined in AbstractCheckpoint class.
+
+ Exports data from InstallEngine's DataObjectCache to the
+ file named in self._manifest.
+
+ Parameters:
+ - dry_run is used to control what actions are taken if
+ self._manifest already exists. If dry_run is False, the
+ file will be overwritten if it exists. if dry_run is
+ True, the output will be written to a similarly-named,
+ but non-existing file.
+
+ Returns:
+ - Nothing
+ On success, this method returns; on error it raises an exception.
+
+ Raises:
+ - ManifestError is raised if unable to fetch DOC reference or
+ if an error occurs in write().
+ '''
+
+ self.logger.debug("ManifestWriter.execute(dry_run=%s) called", dry_run)
+
+ engine = InstallEngine.get_instance()
+
+ doc = engine.data_object_cache
+ if doc is None:
+ raise ManifestError("Cannot get DOC reference from InstallEngine")
+
+ if dry_run and os.path.exists(self._manifest):
+ self._manifest = _create_unique_variant(self._manifest)
+
+ self.write(doc)
+
+
+def _create_unique_variant(orig_filename):
+ '''
+ Create a variant of the passed-in filename, which does not already
+ exist. This uses the tempfile module to create a file whose name
+ is based on orig_filename but with some random letters and numbers
+ inserted.
+ '''
+
+ dirname, filename = os.path.split(orig_filename)
+ prefix, suffix = os.path.splitext(filename)
+
+ file_desc, new_filename = \
+ tempfile.mkstemp(suffix=suffix, prefix=prefix+"_", dir=dirname)
+
+ try:
+ os.close(file_desc)
+ except IOError:
+ raise ManifestError("Could not close temp file [%s]" % new_filename)
+
+ return new_filename
--- a/usr/src/pkg/manifests/system-library-install.mf Thu Oct 28 15:10:27 2010 -0700
+++ b/usr/src/pkg/manifests/system-library-install.mf Fri Oct 29 13:35:45 2010 +0000
@@ -37,6 +37,7 @@
dir path=usr/lib/python2.6/vendor-packages/solaris_install/data_object
dir path=usr/lib/python2.6/vendor-packages/solaris_install/engine
dir path=usr/lib/python2.6/vendor-packages/solaris_install/target
+dir path=usr/lib/python2.6/vendor-packages/solaris_install/manifest
dir path=usr/snadm
dir path=usr/snadm/lib
file path=usr/lib/libaiscf.so.1
@@ -76,6 +77,12 @@
file path=usr/lib/python2.6/vendor-packages/solaris_install/target/zfs.pyc
file path=usr/lib/python2.6/vendor-packages/solaris_install/target/zpool.py
file path=usr/lib/python2.6/vendor-packages/solaris_install/target/zpool.pyc
+file path=usr/lib/python2.6/vendor-packages/solaris_install/manifest/__init__.py
+file path=usr/lib/python2.6/vendor-packages/solaris_install/manifest/__init__.pyc
+file path=usr/lib/python2.6/vendor-packages/solaris_install/manifest/parser.py
+file path=usr/lib/python2.6/vendor-packages/solaris_install/manifest/parser.pyc
+file path=usr/lib/python2.6/vendor-packages/solaris_install/manifest/writer.py
+file path=usr/lib/python2.6/vendor-packages/solaris_install/manifest/writer.pyc
file path=usr/snadm/lib/libspmicommon.so.1
license cr_Sun license=cr_Sun
link path=usr/lib/libaiscf.so target=libaiscf.so.1
--- a/usr/src/tools/tests/tests.nose Thu Oct 28 15:10:27 2010 -0700
+++ b/usr/src/tools/tests/tests.nose Fri Oct 29 13:35:45 2010 +0000
@@ -30,4 +30,4 @@
# the files in that directory should begine with "test_". Files
# containing in-line doc-tests should be added explicitly.
-tests=lib/liberrsvc_pymod/test/,cmd/ai-webserver/test/,cmd/text-install/osol_install/text_install/test/,cmd/installadm/test/,cmd/installadm/installadm_common.py,lib/install_utils/test/,lib/libict_pymod/test/,lib/install_logging_pymod/test,lib/install_doc/test,lib/install_engine/test
+tests=lib/liberrsvc_pymod/test/,cmd/ai-webserver/test/,cmd/text-install/osol_install/text_install/test/,cmd/installadm/test/,cmd/installadm/installadm_common.py,lib/install_utils/test/,lib/libict_pymod/test/,lib/install_logging_pymod/test,lib/install_doc/test,lib/install_engine/test,lib/install_manifest/test/