usr/src/cmd/install-tools/ManifestServ.py
author Sue Sohn <Susan.Sohn@Oracle.COM>
Fri, 20 Aug 2010 11:31:18 -0600
changeset 862 e9f31f2f2f2d
parent 649 ba353c37b287
permissions -rw-r--r--
16423 Updates to AI schema should be made 15449 installadm add validates combined manifest against image-specific schema as well as schema in /usr/share/auto_install/ 6975043 separate criteria and ai manifest 6975686 installadm list shows value rather than range if lower bound is 0

#!/usr/bin/python2.6

#
# 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) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
#

# =============================================================================
# =============================================================================
"""
ManifestServ.py - ManifestServ XML data access interface module
                  commandline interface

"""
# =============================================================================
# =============================================================================

import errno
import sys

import atexit
import getopt
from osol_install.ManifestServ import ManifestServ

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def query_local(mfest_obj):
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    """ Process local (non-socket) queries from the commandline.

    Accepts queries from the commandline, and prints results to the
    screen.  Uses mfest_obj.get_values() to get the data.

    Loops until user types ^D.

    Args:
      mfest_obj: object to which queries are made for data.

    Returns: None

    Raises: None.

    """
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    key_mode = False
    print ""
    while (True):

        if (key_mode):
            print "Please enter a key or "
            print ("\"-key\" to search an element or " +
                   "attribute path:")
        else:
            print ("Please enter an element or attribute path")
            print "or \"+key\" to search for keys:"

        try:
            path = sys.stdin.readline()
            if not path:
                break
        except KeyboardInterrupt:
            break
        path = path.strip()

        if (path == "+key"):
            key_mode = True
            print "key mode set to " + str(key_mode)
            continue
        elif (path == "-key"):
            key_mode = False
            print "key mode set to " + str(key_mode)
            continue

        try:
            results = mfest_obj.get_values(path, key_mode)
        except StandardError, err:
            print >> sys.stderr, ("Exception caught when retrieving values")
            print >> sys.stderr, "    request: " + path
            print >> sys.stderr, "    " + str(err)
            continue
			
        for result in results:
            if (result.strip() == ""):
                print "(empty string / no value)"
            else:
                print result


# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def usage(msg_fd):
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    """ Display commandline options and arguments.

    Args: file descriptor to write message to.

    Returns: None

    Raises: None

    """
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    print >> msg_fd, ("Usage: %s [-d] [-h|-?] [-s] [-t] [-v] " +
                      "[-f <validation_file_base> ]") % sys.argv[0]
    print >> msg_fd, ("    [-o <out_manifest.xml file> ] <manifest.xml file>")
    print >> msg_fd, "where:"
    print >> msg_fd, ("  -d: turn on socket debug output (valid when " +
                      "-s also specified)")
    print >> msg_fd, ("  -f <validation_file_base>: give basename " +
                      "for schema and defval files")
    print >> msg_fd, ("      Defaults to basename of manifest " +
                      "(name less .xml suffix) when not provided")
    print >> msg_fd, "  -h or -?: print this message"
    print >> msg_fd, ("  -o <out_manifest.xml file>: write resulting " +
                      "XML after defaults and")
    print >> msg_fd, "      validation processing"
    print >> msg_fd, "  -t: save temporary file"
    print >> msg_fd, ("      Temp file is \"/tmp/" +
                      "<manifest_basename>_temp_<pid>")
    print >> msg_fd, "  -v: verbose defaults/validation output"
    print >> msg_fd, ("  -s: start socket server for use by ManifestRead")
    print >> msg_fd, ("  --dtd: use DTD validation (default is RelaxNG)")


# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def exit_handler(mfest_obj):
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    """ Called at exit time to stop the socket server.

    Args:
      mfest_obj: ManifestServ object to stop the socket server on.

    Returns: None

    Raises: None

    """
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    mfest_obj.stop_socket_server()


# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def main():
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    """ Main

    Args: None.  (Use sys.argv[] to get args)

    Returns: N/A

    Raises: None

    """
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    # Initialize option flags.
    d_flag = s_flag = t_flag = v_flag = dtd_flag = False

    mfest_obj = None
    err = None
    ret = 0

    # Options come first in the commandline.
    # See usage method for option explanations.
    try:
        (opt_pairs, other_args) = getopt.getopt(sys.argv[1:], "df:ho:stv?", "dtd")
    except getopt.GetoptError, err:
        print >> sys.stderr, "ManifestServ: " + str(err)
    except IndexError, err:
        print >> sys.stderr, "ManifestServ: Insufficient arguments"
    if (err):
        usage(sys.stderr)
        sys.exit (errno.EINVAL)

    valfile_root = None
    out_manifest = None
    for (opt, optarg) in opt_pairs:
        if (opt == "-d"):
            d_flag = True
        if (opt == "-f"):
            valfile_root = optarg
        if ((opt == "-h") or (opt == "-?")):
            usage(sys.stdout)
            sys.exit (0)
        if (opt == "-o"):
            out_manifest = optarg
        if (opt == "-s"):
            s_flag = True
        elif (opt == "-t"):
            t_flag = True
        elif (opt == "-v"):
            v_flag = True
        elif (opt == "--dtd"):
            dtd_flag = True

    # Must have the project data manifest.
    # Also check for mismatching options.
    if ((len(other_args) != 1) or (d_flag and not s_flag)):
        usage(sys.stderr)
        sys.exit (errno.EINVAL)

    try:
        # Create the object used to extract the data.
        mfest_obj = ManifestServ(other_args[0], valfile_root,
                                 out_manifest, v_flag, t_flag, dtd_schema=dtd_flag)

        # Start the socket server if requested.
        if (s_flag):
            mfest_obj.start_socket_server(d_flag)
            print "Connect to socket with name " + mfest_obj.get_sockname()

            # Set up to shut down the socket server at exit.
            atexit.register(exit_handler, mfest_obj)

        # Enable querying from this process as well.  This method will
        # block to hold the socket server open for remote queries as
        # well (if enabled).
        query_local(mfest_obj)
    except (SystemExit, KeyboardInterrupt):
        print >> sys.stderr, "Caught SystemExit exception"
    except Exception, err:
        print >> sys.stderr, "Error running Manifest Server"

    if (err is not None):
        ret = err.args[0]
        sys.exit(ret)

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Main
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if __name__ == "__main__":
    main()