# Checker Context File
# vim: set filetype=python:

# This file must be self contained.  It must not import any Isilon modules
# and must be compatible with all versions of Python used by OneFS 
# 5.5(Scotch Bonnet) on.  This means this file must work with Python 2.3.

# Consumers of this file are the script isi_version_checker, and the 
# isi.sys.update modules.    


# For all these functions cluster_info should be a dictionary whose 
# ["Node"] entry is a list of dictionaries and
# possibly strings (if there was an error on the gather_cluster_info and
# allow_down_nodes was true, then the error string is put in place of the 
# dictionary for the node that failed the gather.  The dictionaries are those 
# gathered by isi.sys.version.Gatherer class, with possibly a shim.  The version
# is a string of the form given by kern_osrelease() (possibly without the 
# initial v) All these functions return true if all checks pass, and a string if
# there is a failed check.

# Execing this file may put additional helper functions in to the current 
# context, but any such should start with _checker.  

# _checker_cluster_info_delver is a helper method to do tests on cluster_info.
# It takes function and runs it on all available nodes, and does a logical
# 'or' of the results.  

# Store the results of a check for later retrieval. We are providing
# a separate results object (Rather than returning results with check.)
# for backwards compatibility. check_upgrade returns boolean on success
# or a string on error. In either case, this list will be populated
# with the result objects from the various checks.
# REMEMBER TO CLEAR THIS LIST BETWEEN CHECKS
_checker_extended_results = []

def checker_get_extended_results():
    """Returns a list of the _checker_CheckResult objects"""
    return _checker_extended_results


# CHECKER_CAN_USE_INT is a flag indicating that various check functions 
# can take an integer as a target_version.
CHECKER_CAN_USE_INT = True

def _checker_vercomp(v1, v2):
    """
    Compare two version objects (lists)
    Each version should be in the form of a list like: [ 6, 5, 1 ]

    @see: _checker_ver_to_list() - a string conversion util.
    """

    # XXX:TODO support branch styles and dot releases correctly until we
    # can to it right, silently stop at 3 if we have more than three
    # elements.
    for i in range(min(len(v1), len(v2), 3)):
        if v1[i] == v2[i]:
            continue
        if v1[i] == "HEAD":
            return 1
        if v2[i] == "HEAD":
            return -1
        if int(v1[i]) == int(v2[i]):
            continue
        if int(v1[i]) > int(v2[i]):
            return 1
        if int(v1[i]) < int(v2[i]):
            return -1
    return 0

def _checker_ver_to_list(version):
    """Given a version string, like: 'v5.5.1', returns a list like:
        [ '5', '5', '1' ] (The input style required for _checker_vercomp)
        or, given a number, will parse it into a list of
        [major, minor, sub, dot, reserved, style, build], according to
        http://wiki/index.php?title=OneFS_Version_Integer
    """
    if isinstance(version, str):
        # XXX: handle branch style tags in the version if we go above
        # checking 3 places.
        ret_list = (version[0] == 'v' and version[1:] or version).split('.')
    else:
        # It should be an int or a long
        # XXX:everything below Sub is untrustworthy for old (<6.5.5?)
        # version integer formats.
        ret_list = [(version>>56) & (2**8-1), # Major 
                    (version>>48) & (2**8-1), # Minor
                    (version>>40) & (2**8-1), # Sub
                    (version>>20) & (2**8-1), # Dot
                    (version>>28) & (2**8-1), # Reserved
                    (version>>36) & (2**4-1), # Branch Style
                    (version>>0) & (2**20-1), # Build
                    ]
    return ret_list

def _checker_cluster_info_delver(function, cluster_info):
    for info in cluster_info["nodes"]:
        if not info["available"]:
            continue
        if function(info):
            return True
    return False

def _checker_node_validate_dictionary_version(node_info):
    return node_info["dictionary version"]["number"] == 1

def _checker_cluster_validate_dictionary_version(cluster_info):
    return _checker_cluster_info_delver(
            _checker_node_validate_dictionary_version, cluster_info)

def check_join(cluster_info, node_info):

    if not _checker_cluster_validate_dictionary_version(cluster_info):
        return "Cannot validate join: Wrong cluster dictionary version"

    if not _checker_node_validate_dictionary_version(node_info):
        return "Cannot validate join: Wrong node dictionary version"

    if "compliance" not in node_info:
        node_info["compliance"] = False
    if "compliance" not in cluster_info:
        cluster_info["compliance"] = False

    node_worm_type = ["Enterprise", "Compliance"][node_info["compliance"]]
    cluster_worm_type = ["Enterprise", "Compliance"][cluster_info["compliance"]]
    if node_info["compliance"] != cluster_info["compliance"]:
        return ("Cannot join a SmartLock %s node to a SmartLock %s cluster." %
            (node_worm_type, cluster_worm_type))

    cluster_supports_seds = cluster_info.get("self encrypting drives", False)
    if (node_info.get("supported num self encrypting drives", 0) == 0 and
        node_info.get("is accelerator", 0) == 0 and cluster_supports_seds is True):
        return "Cannot join unencrypted node to a cluster with encrypted nodes."

    first_build = ''
    for node in cluster_info["nodes"]:
        if not node["available"]:
            continue
        if not first_build:
            first_build = node["OneFS build"]
        if first_build != node["OneFS build"]:
            return ("Cannot add nodes to clusters of mixed builds: " +
                    "found both %s and %s on cluster." %
                    (first_build, node["OneFS build"]))
    return True

def check_cto_reimage(node_info, target_version):
    v_parts = _checker_ver_to_list(target_version)

    # We care about the main chassis and the type of NVRAM card. Expansion
    # chassis are not supported within CTO.
    chassis_name = node_info["chasses"][0]["name"]
    nvram_name = node_info["nvram"]["name"]

    # Self-encrypting drive support was added in OneFS 7.1
    supported_num_seds = node_info.get(
        "supported num self encrypting drives", 0)
    if int(supported_num_seds) > 0:
        if _checker_vercomp(v_parts, [7,1,0]) < 0:
            return "Support for self encrypting drives begins in 7.1.0"

    # For CTO nodes, a base chassis defines the following:
    #  - boot drives
    #  - front panel
    #  - 3/4 chassis, comprised of:
    #      - drive midplanes
    #      - power supplies
    #      - batteries
    #      - fans
    #      - motherboard
    #      - disk controller
    #      - infiniband HBA
    #      - journal (nvram) card
    #
    if chassis_name == "ISI36V2" and nvram_name == "MT25208":
        if _checker_vercomp(v_parts, [6,5,5]) < 0:
            return "Support for this hardware begins in 6.5.5"
        else:
            return True
    elif chassis_name == "ISI36V2" and nvram_name == "RF6487":
        if _checker_vercomp(v_parts, [7,0,2]) < 0:
            return "Support for this hardware begins in 7.0.2"
        else:
            return True
    elif chassis_name in ['EMC8']:
        if _checker_vercomp(v_parts, [7,0,2]) < 0:
            return "Support for this hardware begins in 7.0.2"
        else:
            return True
    else:
        return "Node is an unknown hardware version."

def check_maunaloa_reimage(node_info, target_version):
    v_parts = _checker_ver_to_list(target_version)

    # There are a couple of Mauna Loa spin-offs that came
    # later and the only way to differentiate is to check
    # the product name. 
    product_name = node_info["chasses"][0]["product name"]

    if product_name == "IQ 108NL":
        if _checker_vercomp(v_parts, [6,5,1]) < 0:
            return "Support for this hardware begins in 6.5.1"
        else:
            return True
    elif product_name == "IQ 108000x":
        if _checker_vercomp(v_parts, [6,5,4]) < 0:
            return "Support for this hardware begins in 6.5.4"
        else:
            return True
    # IQ 32000x-ssd not correctly supported in 7.0.0 (bug 97400)
    elif product_name == "IQ 32000x-ssd":
        if _checker_vercomp(v_parts, [7,0,0]) == 0:
            return "Support for this hardware begins in 7.0.1"

    if _checker_vercomp(v_parts, [5,0,3]) <= 0:
        return "Support for this hardware begins in 5.0.4"
    else:
        return True

def check_reimage(node_info, target_version):
    # Likely will need updating for new version version
    if not _checker_node_validate_dictionary_version(node_info):
        return "Cannot validate reimage: Wrong node dictionary version"

    if target_version == "vHEAD":
        return True

    v_parts = _checker_ver_to_list(target_version)
    hwgen_name = node_info["hwgen"]["name"]
    nvram_name = node_info["nvram"]["name"]
    if _checker_vercomp(v_parts, [4, 6]) == 0:
        if hwgen_name in ["VMware"]:
            return True
        else:
            return "4.6 can only be run by VMware"
    elif len(node_info["chasses"]) > 1:
        if _checker_vercomp(v_parts, [3]) <= 0:
            return "Support for expander nodes begins in 4.0"
    if hwgen_name in ["K2"]:
        if _checker_vercomp(v_parts, [6, 0]) >= 0:
            return "IQ 200 has been end-of-lifed past 6.0"
        else:
            return True
    if hwgen_name in ["Chedder", "Mozz"]:
        if _checker_vercomp(v_parts, [5, 0]) >= 0:
            return "IQ Classic, IQ 1440, and IQ 2250 have been end-of-lifed " \
                    "past 5.0"
        else:
            return True
    elif hwgen_name == "Rainier":
        if _checker_vercomp(v_parts, [6, 0]) >= 0 and \
                 not node_info["netiface"]["has IB"]:
            return "IQ 1920, IQ 3000, IQ 4800 and IQ 6000 have been " \
                   "end-of-lifed past 6.0"
        if _checker_vercomp(v_parts, [7, 0]) >= 0:
            return "IQ 1920i, IQ 3000i, IQ 4800i, IQ 6000i, IQ 9000i, and " \
                   "IQ 12000i have been end-of-lifed past 7.0"
        if _checker_vercomp(v_parts, [3, 4]) <= 0 and \
                 node_info["diskctl family"]["name"] == "TWE":
            return "Support for this hardware begins in 3.5"
        if node_info["diskctl family"]["name"] == "LSI" and \
                _checker_vercomp(v_parts, [3]) <= 0:
            return "Support for this hardware begins in 4.0"
        else:
            return True
    elif hwgen_name == "Ullr":
        if _checker_vercomp(v_parts, [3]) <= 0:
            return "Support for this hardware begins in 4.0"
        else:
            return True
    elif hwgen_name == "Graham":
        # First check if it is an S series node
        if _checker_vercomp(v_parts, [5,0,3]) <= 0 and node_info["is sasnode"]:
            return "Support for this hardware begins in 5.0.4"
        elif _checker_vercomp(v_parts, [4,7,1]) <= 0:
            return "Support for this hardware begins in 4.7.2"
        else:
            return True
    elif hwgen_name == "RacerX":
        if _checker_vercomp(v_parts, [5,0,3]) <= 0:
            return "Support for this hardware begins in 5.0.4"
        else:
            return True
    elif hwgen_name == "Annapurna":
        # First check if it is a Backup Accelerator
        if _checker_vercomp(v_parts, [5,0,3]) <= 0 and node_info["is bua"]:
            return "Support for this hardware begins in 5.0.4"
        elif _checker_vercomp(v_parts, [4]) <= 0:
            return "Support for this hardware begins in 5.0"
        else:
            return True
    elif hwgen_name == "VMware":
        # Don't block VMware from reimaging ever.
        return True
    elif hwgen_name == "MaunaLoa":
        return check_maunaloa_reimage(node_info, target_version)
    elif hwgen_name in [ "Wingfoot", "Blue Flame" ]:
        # Self-encrypting drive support was added in OneFS 7.1
        # This check also exists in check_cto_reimage, but the one here covers
        # the legacy Wingfoot/Blue Flame cases
        supported_num_seds = node_info.get(
            "supported num self encrypting drives", 0)
        if int(supported_num_seds) > 0:
            if _checker_vercomp(v_parts, [7,1,0]) < 0:
                return "Support for self encrypting drives begins in 7.1.0"
        if nvram_name == "MT25208":
            if _checker_vercomp(v_parts, [6,5,1]) < 0:
                return "Support for this hardware begins in 6.5.1"
            else:
                return True
        if nvram_name == "RF6487":
            if _checker_vercomp(v_parts, [7,0,2]) < 0:
                return "Support for this hardware begins in 7.0.2"
            else:
                return True
    elif hwgen_name == "CTO":
        return check_cto_reimage(node_info, target_version)
    else:
        return "Node is an unknown hardware version."

def check_upgrade(cluster_info, target_version, filter_out=None):
    """
    Performs basic and extended checks.

    On error, results are returned as a string for interfaces that require it,
    and also stored as an object list so that more advanced interfaces may
    inspect the results for more detailed error output.

    @return True if no error, otherwise string.
    """
    global _checker_extended_results
    # Must reset _before_ any return statements might be triggered.
    _checker_extended_results = []

    if not _checker_cluster_validate_dictionary_version(cluster_info):
        return "Cannot validate upgrade: Wrong cluster dictionary version"

    # XXX FS_FMT_VERSION should match the value in isilon/lib/python/fs/lib.py
    # and the value in sys/ifs/lbm/lbm_super.h. NOTE When updating this number
    # also update the PROHIBITED_UNSTABLE_VERSIONS below.  Uncomment the 
    # on-deck version, and then place the next UPGRADE_IN_PROGRESS version
    # on-deck and commented out.
    FS_FMT_VERSION = 16 #FS_FMT_MAV

    PROHIBITED_UNSTABLE_VERSIONS = [9, # FS_FMT_CPIN_UPGRADE_IN_PROGRESS
                                    11, # FS_FMT_SB_UPGRADE_IN_PROGRESS
                                    13, # FS_FMT_HAB_UPGRADE_IN_PROGRESS
    # XXX ON DECK Currently allowed 15, # FS_FMT_MAV_UPGRADE_IN_PROGRESS
                                   ]
    # XXX FS_FMT_EARLIEST_READABLE should match the value in 
    # sys/ifs/lbm/lbm_super.h
    FS_FMT_EARLIEST_READABLE = 14 #FS_FMT_HAB

    if (cluster_info["FS version"] < FS_FMT_VERSION and
            _checker_cluster_info_delver(lambda info: info["read only"],
            cluster_info)):
        return "Cannot upgrade as the cluster contains read only nodes and " \
                "this upgrade would upgrade the file system format."

    # Generally a given version only knows how to complete a FS upgrade
    # from the most recent IN_PROGRESS version.  Prohibit others.
    if (cluster_info["FS version"] in PROHIBITED_UNSTABLE_VERSIONS):
        return "Cannot upgrade as the cluster has not finished the file "\
                "system upgrade from a previous OneFS upgrade, and the "\
                "target version would not be able "\
                "to complete this file system upgrade."

    # A given version cannot complete an in progress FS upgrade if it cannot
    # read the version the FS upgrade is coming from.
    # If cluster_info has no "previous FS version", the node is running an 
    # earlier version which has a stricter check then this one.
    if ("previous FS version" in cluster_info and
            cluster_info["previous FS version"] < FS_FMT_EARLIEST_READABLE):
        return "Cannot upgrade as the target OneFS version would not be able "\
                "to read the current file system format."

    # Currently we consider preview and beta branches 'dead ends' for
    # upgrades, which means that we block an upgrade if any of the nodes
    # would be transitioning off of that branch style.  This check is only
    # valid starting with Mavericks = [7]
    # XXX: pull these out of somehwere?
    BRANCH_STYLE_PREVIEW = 2
    BRANCH_STYLE_BETA = 3
    DEAD_END_BRANCH_STYLES = [BRANCH_STYLE_PREVIEW,
                              BRANCH_STYLE_BETA
                             ]

    # XXX: if target_version is a string, we can't currently
    # realistically expect to get the branch style (this only happens
    # if CHECKER_CAN_USE_INT is unset), so just ignore these tests

    if not isinstance(target_version, str):
        v_parts = _checker_ver_to_list(target_version)
        if _checker_vercomp(v_parts, [7]) >= 0:
            target_branch_style = v_parts[5]

            # this is a helper method for the call below
            def invalid_branch_transition(node):
                """Returns true if the node would be upgrading from a branch
                style in DEAD_END_BRANCH_STYLES and the target version branch
                style is not the same"""
                node_ver_list = _checker_ver_to_list(
                        node['OneFS version']['number'])

                # check this is a Mavericks build or better, so we can rely
                # on the branch style bits being in the right place
                if (_checker_vercomp(node_ver_list, [7]) >= 0) and \
                        (node_ver_list[5] in DEAD_END_BRANCH_STYLES) and \
                        (node_ver_list[5] != target_branch_style):
                    return True
                # And, since we released a Mavericks beta before the beta
                # branch bits existed, we have to special-case check for and
                # block non-beta upgrades from that particular build.
                if (node['OneFS build'].find('B_7_0_BETA_4') != -1) and \
                        (target_branch_style != BRANCH_STYLE_BETA):
                    return True 
                return False

            if _checker_cluster_info_delver(invalid_branch_transition,
                    cluster_info):
                return "Cannot upgrade as one or more nodes is running a "\
                        "pre-release version of OneFS which is ineligible "\
                        "for upgrade to the requested revision."

    output_required = False

    # These checks are defined in the modules in 
    # isilon/lib/python/upgrade/preupgradechecks
    # The checker classes are obtained with the get_checks() function in
    # each module
    for checkfile in all_checks:

        checkdict = {}
        exec checkfile in checkdict
        checks = checkdict['get_checks']()
        for check in checks:
            if filter_out != None and check.name() in filter_out:
                continue

            # This method belongs to the call below it
            def in_range(node):
                """Returns true if the version of the node is within one of the
                "supported" version ranges for the check (got from the outer
                for loop)"""
                # This "check" is the one in the outer for loop.
                ranges = check.supported_version_ranges()
                if ranges == None:
                    return True
                node_ver_list = _checker_ver_to_list(
                    node['OneFS version']['number'])
                # TODO : write a BVT to test ranges (ensure lower < higher, and that
                # there are two of each "range") -- aaron.hachez
                for (low_version,high_version) in ranges:
                    lv =  _checker_vercomp(node_ver_list, low_version)
                    hv = _checker_vercomp(high_version , node_ver_list)
                    if lv >= 0 and hv >= 0:
                        return True
                    return False

            # Make sure that the check applies to this version
            if not _checker_cluster_info_delver(in_range, cluster_info):
                continue

            result = _checker_CheckResult(check.name())
            result.errors, result.warnings, result.others = \
                    check.do_check(cluster_info)

            _checker_extended_results.append(result) # Append for later

            # Note that we're in error, but continue processing
            if result.has_errors() or result.has_warnings():
                output_required = True

    # There was an error or warning in one of the checks.
    if output_required:
        ret_str = ""
        for r in _checker_extended_results:
            prefix_str = None
            if r.has_errors():
                prefix_str = "%s check failed:\n%s"
            elif r.has_warnings():
                prefix_str = "%s check had warnings:\n%s"

            # Right now, if a result only has "others" (advisory) ignore it
            if prefix_str != None:
                ret_str += prefix_str \
                        % (r.check_name, r.to_string(indent="    "))

        return ret_str

    return True

def rolling_upgrade_capable(cluster_info, target_build):
    def validate_node(node):
        build = node['OneFS build']
        if build == target_build:
            return False
        fbuild = build.split('(')[0]
        return "+%s" % (fbuild) not in ["+B_7_1_0_12","+B_7_1_0_34","+B_7_1_0_1_120821_39","+B_7_1_0_47","+B_7_1_0_91","+B_7_1_0_148","+B_7_1_0_154",]

    if _checker_cluster_info_delver(validate_node, cluster_info):
        return "Cluster is not rolling upgrade capable to %s " \
                "as the builds on the cluster are not all compatible with %s" %\
                (target_build, target_build)
    else:
        return True

#################################################
## extended check related functions/structures ##
#################################################

class _checker_CheckResult:
    """This is a custom result class for the extended checks to utilize

        An instance should have the form:
            result.check_name   : "<check name>"
            result.errors       : [str1, str2, etc...]
            result.warnings     : [str1, str2, etc...]
            result.others       : [str1, str2, etc...]

        Each string should be a human readable string with _no_ trailing
        white space. (Formatting to be done by the UI)

        If there are no results for a particular category, the list should be
        empty (Default) not None.
    """

    def __init__(self, check_name):
        """check_name should be the name of the check that produced this
        particular instance of ResultSet"""

        self.check_name = check_name
        self.errors = []
        self.warnings = []
        self.others = []

    def has_errors(self):
        return (0 < len(self.errors))

    def has_warnings(self):
        return (0 < len(self.warnings))

    def has_others(self):
        return (0 < len(self.others))

    def errors_to_string(self, indent=''):
        """For output to users only! The format is not guaranteed to stay
        consistent from version to version."""
        ret_str = ""
        for error in self.errors:
            ret_str += indent + error + "\n"
        return ret_str

    def warnings_to_string(self, indent=''):
        """For output to users only! The format is not guaranteed to stay
        consistent from version to version."""
        ret_str = ""
        for warning in self.warnings:
            ret_str += indent + warning + "\n"
        return ret_str

    def others_to_string(self, indent=''):
        """For output to users only! The format is not guaranteed to stay
        consistent from version to version."""
        ret_str = ""
        for other in self.others:
            ret_str += indent + other + "\n"
        return ret_str

    def to_string(self, indent=''):
        """For output to user only! The format is not guaranteed to stay
        consistent from version to version."""

        ret_str = '='*len(self.check_name)+'\n'
        ret_str += '%s\n' % self.check_name
        ret_str += '='*len(self.check_name)+'\n'
        ret_str += self.errors_to_string(indent)
        ret_str += self.warnings_to_string(indent)
        ret_str += self.others_to_string(indent)
        if not (self.has_warnings() or self.has_errors()):
            ret_str += 'All checks passed\n'


        return ret_str

####################################
# extended checks below this point #
####################################

all_checks = ['#!/usr/bin/env python\n\n# Copyright C 2009 by Isilon Systems, Inc. All rights not expressly\n# granted herein are reserved.\n# Created in the United States of America.\n#\n# This digital media is protected by U.S. and international copyright and\n# intellectual property laws. Unless otherwise specified, all information\n# and screens appearing as part of this digital medium, including\n# software, services, documents, text, images, icons, and logos design;\n# the selection, assembly, arrangement, and design thereof; and the code\n# that enables its presentation, are the sole property of Isilon Systems,\n# Inc.\n#\n# Except as otherwise required by applicable law, no part of any\n# copyrighted material may be reproduced, modified, translated,\n# distributed, published, or transmitted by any means, electronic or\n# mechanical, for any purpose, without the prior written consent of Isilon\n# Systems.\n#\n# Isilon and Isilon Systems are registered trademarks of Isilon Systems,\n# Inc.  Legion is a trademark of Isilon Systems, Inc.  All other\n# trademarks and registered trademarks are the property of their\n# respective holders.\n\n#\n# XXX: This module is meant to be installed on older builds for\n# verification purposes and therefore must only import standard python\n# modules.\n#\n\nimport logging\nimport xml.dom.minidom as xml\n\nREVISION = "$Revision: 239415 $"\n\ndef get_version():\n    import re\n\n    v = re.sub("[^0-9]+", "", REVISION)\n    if v:\n        return "r%s" % v\n    else:\n        return "UNKNOWN"\n\n#  ____  _   _ ____  ____   ___  ____ _____\n# / ___|| | | |  _ \\|  _ \\ / _ \\|  _ \\_   _|\n# \\___ \\| | | | |_) | |_) | | | | |_) || |\n#  ___) | |_| |  __/|  __/| |_| |  _ < | |\n# |____/ \\___/|_|   |_|    \\___/|_| \\_\\|_|\n#       _____  _    ____  _     _____\n#      |_   _|/ \\  | __ )| |   | ____|\n#        | | / _ \\ |  _ \\| |   |  _|\n#        | |/ ___ \\| |_) | |___| |___\n#        |_/_/   \\_\\____/|_____|_____|\n\n# Parameter scope\nGLOBAL = \'global\'\nSHARE =  \'share\'\nEITHER = \'global or share\'\n\nOVERRIDE_PATH = "/etc/mcp/override"\nSMBD_XML = "smbd.xml"\nSMBD_SHARES_XML = "smbd_shares.xml"\n\nSHARE_NAME_CONFLICT = \'__share_name_conflict\'\n\n# Error type\nSUPPORTED =  \'supported\'  # Parameter is supported\nWARNING =    \'warning\'    # Parameter is unsupported, but doesn\'t do anything on OneFS\nDEPRECATED = \'deprecated\' # Parameter is supported, but will be removed\nERROR =      \'error\'      # Parameter is unsupported\n\nSEVERITIES = [ERROR, DEPRECATED, WARNING, SUPPORTED]\n\nVOLD = [0,0,0]\nV5_0 = [5,0,0]\nV5_5 = [5,5,0]\nV6_0 = [6,0,0]\nV6_5 = [6,5,0]\nV6_5_0 = V6_5\nV6_5_1 = [6,5,1]\nV6_5_3 = [6,5,3]\nV6_5_4 = [6,5,4]\nV6_5_5 = [6,5,5]\n\n# It is CRITICAL to update the CURRENT_VERSION here as the three\n# places it is checked, will then also use this version:\n# 1. isi_pre_upgrade_check (installed with a patch for the customer to pro-actively run)\n# 2. checker.m4 (during the pre-upgrade check)\n# 3. smb.py (after the os upgrade, when the config is being upgraded).\nCURRENT_VERSION = V6_5_5\n\ndef version_to_string(v):\n    s = ""\n    for n in v:\n        s += "%s." % n\n    return s[:-1]\n\n# Common upgrade reasons\nSHAREDB = \'share permissions are now maintained in a separate database\'\nUSE_X = \'use "%s" instead\'\nOBSOLETE = \'obsolete in this version, parameter has no effect\'\nSYSTEM = \'parameter is under OneFS control and should not be overridden\'\nAUTHPARAM = \'auth configuration must be changed manually\'\nAUDITPARAM = \'audit configuration must be upgraded manually\'\n\n# Generic functions if all parameter values are supported equally:\ndef _supported():\n    return lambda val, pfunc : (SUPPORTED,)\n\ndef _deprecated(v):\n    return lambda val, pfunc : (DEPRECATED,\n        \'parameter is deprecated and will be obsolete in %s\'\n          % version_to_string(v))\n\ndef _warning(text = None):\n    return lambda val, pfunc : (WARNING, text or \'parameter has no effect\')\n\ndef _error(text = None):\n    return lambda val, pfunc : (ERROR, text or \'parameter is unsupported\')\n\ndef _error_if(b):\n    return lambda val, pfunc : _error_if_internal(val, pfunc, b)\n\ndef _error_if_internal(val, pfunc, b):\n    if val != b:\n        return (SUPPORTED,)\n    else:\n        return (ERROR, "parameter is unsupported when %s" % b)\n\ndef _handle_passdb_backend_V50(value, pfunc):\n    # The default changed. Rather than add versioned defaults,\n    # handle the check here explicitly.\n    if value == \'smbpasswd\':\n        return (SUPPORTED,)\n    else:\n        return _deprecated(V5_5)(value, pfunc)\n\ndef _handle_password_server(value, pfunc):\n    sec = pfunc(\'security\')\n    if sec in [\'domain\', \'ads\']:\n        return (SUPPORTED,)\n    elif sec in [\'share\', \'user\']:\n        return _warning()(value, pfunc)\n\ndef _handle_security(value, pfunc):\n    if value in [\'ads\', \'share\', \'user\']:\n        return (SUPPORTED,)\n    elif value == \'domain\':\n        return (DEPRECATED,\n            \'security = domain is deprecated and will be obsolete in 5.5.0\')\n    else:\n        return _error()(value, pfunc)\n\ndef _list_contains_invalid(list, valid, sev, text):\n    diff = filter(lambda x: x not in valid, list)\n    if diff:\n        return (sev, text % diff)\n    else:\n        return (SUPPORTED,)\n\ndef _handle_vfs_objects(valid):\n    return lambda list, pfunc : \\\n           _list_contains_invalid(list, valid,\n                                  ERROR, \'unsupported vfs objects: %s\')\n\ndef _if_joined_internal(value, pfunc, required):\n    sec = pfunc(\'security\')\n    if sec != \'ads\':\n        return _warning()(value, pfunc)\n\n    if value == required:\n        return _supported()(value, pfunc)\n    else:\n        return _error("value required to be \'%s\' when joined" %\n                      required)(value, pfunc)\n\ndef _if_joined(required):\n    return lambda value, pfunc: _if_joined_internal(value, pfunc, required)\n\ndef _warn_without_audit(value, pfunc):\n    vo = pfunc(\'vfs objects\')\n    if \'full_audit\' in vo:\n        return _supported()(value, pfunc)\n    else:\n        return _warning(\'audit parameters, but full_audit not in use\')(value, pfunc)\n\nglobal_support_table = {}\n\ndef _gst(type, name_in, version, support_func):\n    name = name_in.lower()\n    def _gst_inner(scope):\n        if not global_support_table.has_key((scope, name)):\n            global_support_table[(scope, name)] = []\n        global_support_table[(scope, name)].append((version, support_func))\n    if type == EITHER:\n        _gst_inner(GLOBAL)\n        _gst_inner(SHARE)\n    else:\n        _gst_inner(type)\n\n# _gst maps a parameter name and version to:\n#   lamba (param value, context) : (support, text)\n#\n# In other words, each of these entries is actually a support function\n# that will determine if the given value is supported.\n#\n# For the same parameter, the _gst should be done in chronological\n# order if the support changes. So, for example, if there\'s a support\n# function for V5_0 and then a support function for V6_5, all versions\n# starting at 5.0 before 6.5 will use the first function and at 6.5\n# and greater will use the latter.\n\n# Supported parameters\n_gst(EITHER, \'access based share enum\', V5_0, _supported())\n_gst(EITHER, \'access based share enum\', V6_5, _error_if(True))\n_gst(EITHER, \'access based share enum\', V6_5_4, _supported())\n_gst(EITHER, \'accessible child dotsnap\', V5_0, _supported())\n_gst(EITHER, \'accessible child dotsnap\', V5_5, _warning(USE_X % \'onefs: dot snap child accessible\'))\n_gst(EITHER, \'onefs: dot snap child accessible\', V5_5, _supported())\n_gst(EITHER, \'accessible root dotsnap\', V5_0, _supported())\n_gst(EITHER, \'accessible root dotsnap\', V5_5, _warning(USE_X % \'onefs: dot snap root accessible\'))\n_gst(EITHER, \'onefs: dot snap root accessible\', V5_5, _supported())\n_gst(EITHER, \'acl modify list\', V5_0, _supported())\n_gst(EITHER, \'acl modify list\', V5_5, _warning(SHAREDB))\n_gst(EITHER, \'admin users\', V5_0, _supported())\n_gst(GLOBAL, \'allow trusted domains\', V5_0, _supported())\n_gst(EITHER, \'onefs: allow execute always\', V5_5, _supported())\n_gst(SHARE,  \'available\', V5_0, _supported())\n_gst(SHARE,  \'available\', V6_5, _error_if(False))\n_gst(EITHER, \'use atomic sendfile\', V5_0, _supported())\n_gst(EITHER, \'use atomic sendfile\', V6_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'auth methods\', V5_0, _supported())\n_gst(GLOBAL, \'auth methods\', V5_5, _warning(SYSTEM))\n_gst(GLOBAL, \'blacklisted servers\', V5_0, _supported())\n_gst(GLOBAL, \'blacklisted servers\', V5_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'browse list\', V5_0, _supported())\n_gst(GLOBAL, \'browse list\', V6_5, _warning(OBSOLETE))\n_gst(EITHER, \'browseable\', V5_0, _supported())\n_gst(EITHER, \'browseable\', V6_5, _error_if(False))\n_gst(EITHER, \'browseable\', V6_5_4, _supported())\n_gst(EITHER, \'no notify change\', V5_0, _supported())\n_gst(EITHER, \'no notify change\', V5_5, _warning(USE_X % \'change notify\'))\n_gst(EITHER, \'onefs: case insensitive lookup\', V6_5, _warning(OBSOLETE))\n_gst(EITHER, \'catia:mappings\', V5_0, _supported())\n_gst(EITHER, \'change notify\', V5_5, _supported())\n_gst(EITHER, \'change notify restrict recursive\', V5_5, _supported())\n_gst(EITHER, \'change notify timeout\', V5_0, _supported())\n_gst(EITHER, \'change notify timeout\', V5_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'client signing\', V5_0, _supported())\n_gst(GLOBAL, \'client signing\', V5_5, _warning(OBSOLETE))\n_gst(EITHER, \'comment\', V5_0, _supported())\n_gst(EITHER, \'create mask\', V5_0, _supported())\n_gst(EITHER, \'creator owner gets full control\', V5_0, _supported())\n_gst(EITHER, \'creator owner gets full control\', V5_5,\n     _warning(USE_X % \'onefs: creator owner gets full control\'))\n_gst(EITHER, \'onefs: creator owner gets full control\', V5_5, _supported())\n_gst(EITHER, \'onefs: creator owner gets full control\', V6_5, _error_if(True))\n_gst(EITHER, \'csc policy\', V5_0, _supported())\n_gst(GLOBAL, \'deadtime\', V5_0, _supported())\n_gst(GLOBAL, \'debug hires timestamp\', V5_0, _supported())\n_gst(GLOBAL, \'debug hires timestamp\', V6_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'dedicated keytab file\', V5_5, _if_joined(\'/etc/krb5.keytab\'))\n_gst(EITHER, \'delete readonly\', V5_0, _supported())\n_gst(EITHER, \'delete veto files\', V5_0, _supported())\n_gst(EITHER, \'delete veto files\', V6_5, _error())\n_gst(EITHER, \'directory mask\', V5_0, _supported())\n_gst(EITHER, \'disable netbios\', V5_0, _supported())\n_gst(GLOBAL, \'encrypt passwords\', V5_0, _warning())\n_gst(GLOBAL, \'encrypt passwords\', V6_5, _error_if(False))\n_gst(EITHER, \'follow symlinks\', V5_0, _supported())\n_gst(EITHER, \'follow symlinks\', V6_5, _error_if(False))\n_gst(EITHER, \'force create mode\', V5_0, _supported())\n_gst(EITHER, \'force directory mode\', V5_0, _supported())\n_gst(EITHER, \'force group\', V5_0, _supported())\n_gst(EITHER, \'force group\', V6_5, _warning(OBSOLETE))\n_gst(EITHER, \'force unknown acl user\', V5_0, _supported())\n_gst(EITHER, \'force unknown acl user\', V6_5, _warning(OBSOLETE))\n_gst(EITHER, \'force user\', V5_0, _supported())\n_gst(GLOBAL, \'force username map\', V5_0, _supported())\n_gst(GLOBAL, \'force username map\', V6_5, _error(AUTHPARAM))\n_gst(EITHER, \'full_audit:success\', V5_0, _warn_without_audit)\n_gst(EITHER, \'full_audit:success\', V6_5, _error(AUDITPARAM))\n_gst(EITHER, \'full_audit:failure\', V5_0, _warn_without_audit)\n_gst(EITHER, \'full_audit:failure\', V6_5, _error(AUDITPARAM))\n_gst(EITHER, \'full_audit:prefix\', V5_0, _warn_without_audit)\n_gst(EITHER, \'full_audit:prefix\', V6_5, _error(AUDITPARAM))\n_gst(GLOBAL, \'getwd cache\', V5_0, _supported())\n_gst(GLOBAL, \'getwd cache\', V6_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'guest account\', V5_0, _supported())\n_gst(SHARE,  \'guest ok\', V5_0, _supported())\n_gst(SHARE,  \'guest only\', V5_0, _supported())\n_gst(EITHER, \'hide dot files\', V5_0, _supported())\n_gst(EITHER, \'hide files\', V5_0, _supported())\n_gst(EITHER, \'hide files\', V6_5, _error())\n_gst(EITHER, \'hide special files\', V5_0, _supported())\n_gst(EITHER, \'hide special files\', V6_5, _error())\n_gst(EITHER, \'hide unreadable\', V5_0, _supported())\n_gst(EITHER, \'hide unreadable\', V6_5, _error_if(True))\n_gst(EITHER, \'hide unreadable\', V6_5_3, _supported())\n_gst(EITHER, \'hide unaccessible root only\', V6_5_5, _supported())\n_gst(EITHER, \'hosts allow\', V5_0, _supported())\n_gst(EITHER, \'hosts allow\', V6_5, _error())\n_gst(EITHER, \'hosts allow\', V6_5_5, _supported())\n_gst(EITHER, \'hosts deny\', V5_0, _supported())\n_gst(EITHER, \'hosts deny\', V6_5, _error())\n_gst(EITHER, \'hosts deny\', V6_5_5, _supported())\n_gst(GLOBAL, \'idmap backend\', V5_0, _deprecated(V5_5))\n_gst(GLOBAL, \'idmap backend\', V5_5, _error())\n_gst(GLOBAL, \'idmap gid\', V5_0, _supported())\n_gst(GLOBAL, \'idmap gid\', V5_5, _warning(AUTHPARAM))\n_gst(GLOBAL, \'idmap uid\', V5_0, _supported())\n_gst(GLOBAL, \'idmap uid\', V5_5, _warning(AUTHPARAM))\n_gst(EITHER, \'ifs allow execute\', V5_0, _supported())\n_gst(EITHER, \'ifs allow execute\', V5_5, _warning(USE_X % \'onefs: allow execute always\'))\n_gst(EITHER, \'ifs brl\', V5_0, _supported())\n_gst(EITHER, \'ifs brl\', V5_5, _warning(OBSOLETE))\n_gst(EITHER, \'ifs virtual names\', V5_0, _supported())\n_gst(EITHER, \'ifs virtual names\', V5_5, _warning(USE_X % \'configure with WebUI/"isi auth" instead\'))\n_gst(EITHER, \'ifs virtual settings\', V5_0, _supported())\n_gst(EITHER, \'ifs virtual settings\', V5_5, _warning(USE_X % \'configure with WebUI/"isi auth" instead\'))\n_gst(EITHER, \'ignore extended attributes\', V5_0, _supported())\n_gst(EITHER, \'ignore extended attributes\', V5_5, _warning(USE_X % \'ea support\'))\n_gst(EITHER, \'ea support\', V5_5, _supported())\n_gst(EITHER, \'ea support\', V6_5_5, _supported())\n_gst(EITHER, \'ignore named streams\', V5_0, _supported())\n_gst(EITHER, \'ignore named streams\', V5_5, _warning(USE_X % \'onefs: ignore streams\'))\n_gst(EITHER, \'onefs: ignore streams\', V5_5, _supported())\n_gst(EITHER, \'onefs: ignore streams\', V6_5, _error_if(True))\n_gst(EITHER, \'ignore sacls\', V5_0, _supported())\n_gst(EITHER, \'ignore sacls\', V5_5, _warning(USE_X % "onefs: ignore sacls"))\n_gst(EITHER, \'onefs: ignore sacls\', V5_5, _supported())\n_gst(EITHER, \'onefs: ignore sacls\', V6_5, _error_if(True))\n_gst(EITHER, \'ignore unmappable sids\', V5_0, _supported())\n_gst(EITHER, \'ignore unmappable sids\', V5_5, _warning(USE_X % \'onefs: ignore unmappable sids\'))\n_gst(EITHER, \'onefs: ignore unmappable sids\', V5_5, _supported())\n_gst(EITHER, \'onefs: ignore unmappable sids\', V6_5, _warning(OBSOLETE))\n_gst(EITHER, \'inherit permissions\', V5_0, _supported())\n_gst(EITHER, \'interfaces\', V5_0, _supported())\n_gst(EITHER, \'invalid users\', V5_0, _supported())\n_gst(EITHER, \'invalid users\', V5_5, _warning(SHAREDB))\n_gst(EITHER, \'level2 oplocks\', V5_0, _supported())\n_gst(EITHER, \'level2 oplocks\', V6_5, _error_if(False))\n_gst(GLOBAL, \'kerberos method\', V5_5, _if_joined(\'dedicated keytab\'))\n_gst(GLOBAL, \'ldap admin dn\', V5_0, _supported())\n_gst(GLOBAL, \'ldap admin dn\', V5_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'ldap group suffix\', V5_0, _supported())\n_gst(GLOBAL, \'ldap group suffix\', V5_0, _warning(OBSOLETE))\n_gst(GLOBAL, \'ldap passwd sync\', V5_0, _supported())\n_gst(GLOBAL, \'ldap passwd sync\', V5_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'ldap ssl\', V5_0, _supported())\n_gst(GLOBAL, \'ldap ssl\', V5_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'ldap suffix\', V5_0, _supported())\n_gst(GLOBAL, \'ldap suffix\', V5_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'ldap user suffix\', V5_0, _supported())\n_gst(GLOBAL, \'ldap user suffix\', V5_0, _warning(OBSOLETE))\n_gst(GLOBAL, \'ldap timeout\', V5_0, _supported())\n_gst(GLOBAL, \'ldap timeout\', V5_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'local master\', V5_0, _supported())\n_gst(GLOBAL, \'local master\', V6_5, _error_if(True))\n_gst(GLOBAL, \'log level\', V5_0, _supported())\n_gst(GLOBAL, \'log level\', V6_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'mac extensions\', V6_5, _error_if(True))\n_gst(EITHER, \'mangled names\', V5_0, _supported())\n_gst(EITHER, \'mangled names\', V6_5, _warning(OBSOLETE))\n_gst(EITHER, \'mangle prefix\', V5_0, _supported())\n_gst(GLOBAL, \'mangle prefix\', V6_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'map to guest\', V5_0, _supported())\n_gst(GLOBAL, \'map untrusted to domain\', V5_5, _supported())\n_gst(SHARE,  \'max connections\', V5_0, _supported())\n_gst(SHARE,  \'max connections\', V6_5, _warning(OBSOLETE))\n_gst(EITHER, \'max disk size\', V5_0, _supported())\n_gst(EITHER, \'max disk size\', V6_5, _error())\n_gst(GLOBAL, \'max log size\', V5_0, _supported())\n_gst(GLOBAL, \'max log size\', V6_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'max mux\', V5_0, _supported())\n_gst(GLOBAL, \'max mux\', V6_5, _error())\n_gst(GLOBAL, \'name resolve order\', V5_0, _supported())\n_gst(GLOBAL, \'name resolve order\', V5_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'netbios aliases\', V5_0, _supported())\n_gst(GLOBAL, \'netbios name\', V5_0, _supported())\n_gst(EITHER, \'nt acl support\', V5_0, _supported())\n_gst(EITHER, \'oplocks\', V5_0, _supported())\n_gst(EITHER, \'oplocks\', V6_5, _supported())\n_gst(GLOBAL, \'passdb backend\', V5_0, _handle_passdb_backend_V50)\n_gst(GLOBAL, \'passdb backend\', V5_5, _error())\n_gst(GLOBAL, \'passdb backend\', V6_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'password server\', V5_0, _handle_password_server)\n_gst(GLOBAL, \'password server\', V5_5, _warning(OBSOLETE))\n_gst(SHARE,  \'path\', V5_0, _supported())\n_gst(SHARE,  \'path\', V6_5_5, _supported())\n_gst(EITHER, \'posix locking\', V5_0, _supported())\n_gst(EITHER, \'posix locking\', V5_5, _warning(OBSOLETE))\n_gst(EITHER, \'preexec\', V5_0, _supported())\n_gst(EITHER, \'preexec\', V6_5, _error())\n_gst(EITHER, \'read list\', V5_0, _supported())\n_gst(EITHER, \'read list\', V5_5, _warning(SHAREDB))\n_gst(EITHER, \'read only\', V5_0, _supported())\n_gst(EITHER, \'read only\', V6_5, _error_if(True))\n_gst(GLOBAL, \'realm\', V5_0, _supported())\n_gst(EITHER, \'root preexec\', V5_0, _supported())\n_gst(EITHER, \'root preexec\', V6_5, _error())\n_gst(GLOBAL, \'security\', V5_0, _handle_security)\n_gst(GLOBAL, \'server signing\', V5_0, _supported())\n_gst(EITHER, \'onefs: sendfile large reads\', V5_5, _supported())\n_gst(EITHER, \'onefs: sendfile large reads\', V6_5, _warning(OBSOLETE))\n_gst(EITHER, \'onefs: sendfile safe\', V5_5, _supported())\n_gst(EITHER, \'onefs: sendfile safe\', V6_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'server string\', V5_0, _supported())\n_gst(EITHER, \'simple file sharing compatibility mode\', V5_0, _supported())\n_gst(EITHER, \'simple file sharing compatibility mode\', V5_5,\n     _warning(USE_X % \'onefs: simple file sharing compatibility mode\'))\n_gst(EITHER, \'onefs: simple file sharing compatibility mode\', V5_5, _supported())\n_gst(EITHER, \'onefs: simple file sharing compatibility mode\', V6_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'smb passwd file\', V5_0, _deprecated(V5_5))\n_gst(GLOBAL, \'smb passwd file\', V5_5, _error())\n_gst(EITHER, \'strict locking\', V5_5, _supported())\n_gst(EITHER, \'strict sync\', V5_0, _supported())\n_gst(GLOBAL, \'template homedir\', V5_0, _supported())\n_gst(SHARE,  \'template homedir\', V5_0, _warning())\n_gst(GLOBAL, \'template homedir\', V5_5, _warning(AUTHPARAM))\n_gst(GLOBAL, \'template shell\', V5_0, _supported())\n_gst(GLOBAL, \'template shell\', V5_5, _warning(AUTHPARAM))\n_gst(EITHER, \'onefs: unmappable sids ignore list\', V5_5, _supported())\n_gst(EITHER, \'onefs: unmappable sids ignore list\', V6_5, _warning(OBSOLETE))\n_gst(EITHER, \'unmappable sids deny everyone\', V5_0, _supported())\n_gst(EITHER, \'unmappable sids deny everyone\', V5_5,\n     _warning(USE_X % \'onefs: unmappable sids deny everyone\'))\n_gst(EITHER, \'onefs: unmappable sids deny everyone\', V5_5, _supported())\n_gst(EITHER, \'onefs: unmappable sids deny everyone\', V6_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'username map\', V5_0, _supported())\n_gst(GLOBAL, \'username map\', V6_5, _error(AUTHPARAM))\n_gst(GLOBAL, \'use localgrp\', V5_0, _supported())\n_gst(GLOBAL, \'use localgrp\', V5_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'use readdirplus\', V5_0, _supported())\n_gst(GLOBAL, \'use readdirplus\', V5_5,\n     _warning(USE_X % \'onefs: use readdirplus\'))\n_gst(GLOBAL, \'onefs: use readdirplus\', V5_5, _supported())\n_gst(GLOBAL, \'onefs: use readdirplus\', V6_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'use sendfile\', V5_0, _supported())\n_gst(GLOBAL, \'use sendfile\', V6_5, _warning(OBSOLETE))\n_gst(EITHER, \'valid users\', V5_0, _supported())\n_gst(EITHER, \'valid users\', V5_5, _warning(SHAREDB))\n_gst(EITHER, \'veto files\', V5_0, _supported())\n_gst(EITHER, \'veto files\', V6_5, _error())\n_gst(EITHER, \'veto oplock files\', V5_0, _supported())\n_gst(EITHER, \'veto oplock files\', V6_5, _error())\n_gst(EITHER, \'visible child dotsnap\', V5_0, _supported())\n_gst(EITHER, \'visible child dotsnap\', V5_5, _warning(USE_X % \'onefs: dot snap child visible\'))\n_gst(EITHER, \'onefs: dot snap child visible\', V5_5, _supported())\n_gst(EITHER, \'visible root dotsnap\', V5_0, _supported())\n_gst(EITHER, \'visible root dotsnap\', V5_5, _warning(USE_X % \'dot snap root visible\'))\n_gst(EITHER, \'onefs: dot snap root visible\', V5_5, _supported())\n_gst(GLOBAL, \'vfs objects\', V5_0,\n     _handle_vfs_objects([\'shadow_copy\', \'stream\', \'full_audit\', \'catia\']))\n_gst(GLOBAL, \'vfs objects\', V5_5,\n     _handle_vfs_objects([\'onefs\', \'onefs_shadow_copy\', \'full_audit\', \'catia\']))\n_gst(EITHER, \'wide links\', V5_0, _supported())\n_gst(EITHER, \'wide links\', V6_5, _error_if(True))\n_gst(GLOBAL, \'winbind cache time\', V5_0, _supported())\n_gst(GLOBAL, \'winbind cache time\', V5_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'winbind enum groups\', V5_0, _supported())\n_gst(GLOBAL, \'winbind enum groups\', V5_5, _warning(AUTHPARAM))\n_gst(GLOBAL, \'winbind enum users\', V5_0, _supported())\n_gst(GLOBAL, \'winbind enum users\', V5_5, _warning(AUTHPARAM))\n_gst(GLOBAL, \'winbind map domains\', V5_0, _supported())\n_gst(GLOBAL, \'winbind map domains\', V5_5, _warning(AUTHPARAM))\n_gst(GLOBAL, \'winbind max clients\', V5_0, _supported())\n_gst(GLOBAL, \'winbind max clients\', V5_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'winbind strict trusted domains only\', V5_0, _supported())\n_gst(GLOBAL, \'winbind strict trusted domains only\', V5_5, _warning(AUTHPARAM))\n_gst(GLOBAL, \'winbind use default domain\', V5_0, _supported())\n_gst(GLOBAL, \'winbind use default domain\', V5_5, _warning(AUTHPARAM))\n_gst(GLOBAL, \'winbind ignore domains\', V5_0, _supported())\n_gst(GLOBAL, \'winbind ignore domains\', V5_5, _warning(AUTHPARAM))\n_gst(GLOBAL, \'winbind trusted domains only\', V5_0, _supported())\n_gst(GLOBAL, \'winbind trusted domains only\', V5_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'wins server\', V5_0, _supported())\n_gst(GLOBAL, \'wins server\', V5_5, _warning(OBSOLETE))\n_gst(GLOBAL, \'workgroup\', V5_0, _supported())\n_gst(EITHER, \'write list\', V5_0, _supported())\n_gst(EITHER, \'write list\', V5_5, _warning(SHAREDB))\n\n# Harmless but unsupported parameters\n_gst(GLOBAL, \'algorithmic rid base\', V5_0, _warning())\n_gst(GLOBAL, \'client lanman auth\', V5_0, _warning())\n_gst(GLOBAL, \'client ldap sasl wrapping\', V5_0, _warning())\n_gst(GLOBAL, \'client NTLMv2 auth\', V5_0, _warning())\n_gst(GLOBAL, \'client plaintext auth\', V5_0, _warning())\n_gst(GLOBAL, \'client schannel\', V5_0, _warning())\n_gst(GLOBAL, \'client use spnego\', V5_0, _warning())\n_gst(GLOBAL, \'cups connection timeout\', V5_0, _warning())\n_gst(GLOBAL, \'cups options\', V5_0, _warning())\n_gst(EITHER, \'directory security mask\', V5_0, _warning())\n_gst(GLOBAL, \'disable spoolss\', V5_0, _warning())\n_gst(EITHER, \'force directory security mode\', V5_0, _warning())\n_gst(EITHER, \'force security mode\', V5_0, _warning())\n_gst(EITHER, \'security mask\', V5_0, _warning())\n_gst(GLOBAL, \'winbind separator\', V5_0, _warning())\n_gst(GLOBAL, \'preload\', V5_0, _warning())\n\n#             _  ___   _  _____        ___   _\n#            | |/ / \\ | |/ _ \\ \\      / / \\ | |\n#            | \' /|  \\| | | | \\ \\ /\\ / /|  \\| |\n#            | . \\| |\\  | |_| |\\ V  V / | |\\  |\n#            |_|\\_\\_| \\_|\\___/  \\_/\\_/  |_| \\_|\n#  ____   _    ____      _    __  __ _____ _____ _____ ____  ____\n# |  _ \\ / \\  |  _ \\    / \\  |  \\/  | ____|_   _| ____|  _ \\/ ___|\n# | |_) / _ \\ | |_) |  / _ \\ | |\\/| |  _|   | | |  _| | |_) \\___ \\\n# |  __/ ___ \\|  _ <  / ___ \\| |  | | |___  | | | |___|  _ < ___) |\n# |_| /_/   \\_\\_| \\_\\/_/   \\_\\_|  |_|_____| |_| |_____|_| \\_\\____/\n#\n# This is all known parameters in the 5.0.0->5.5.2 range with defaults\n# from the latest release to support the parameter.\n\nglobal_param_table = {}\nglobal_alias_table = {}\n\ndef _addalias(name, altname):\n    global_alias_table[altname] = name\n\ndef _addparam(name, type, default):\n    if type[0] == \'ENUM\':\n        type = (\'ENUM\', map(lambda x : x.lower(), type[1]))\n    global_param_table[name.lower()] = { \'type\' : type, \'default\' : default }\n    _addalias(name, name)\n\n# Known parameters\n_addparam(\'-valid\', (\'BOOL\'), \'Yes\')\n_addparam(\'NIS homedir\', (\'BOOL\'), \'No\')\n_addparam(\'abort shutdown script\', (\'STRING\'), None)\n_addparam(\'access based share enum\', (\'BOOL\'), \'No\')\n_addparam(\'accessible child dotsnap\', (\'BOOL\'), \'Yes\')\n_addparam(\'accessible root dotsnap\', (\'BOOL\'), \'Yes\')\n_addparam(\'acl check permissions\', (\'BOOL\'), \'Yes\')\n_addparam(\'acl compatibility\', (\'ENUM\', [\'auto\', \'winnt\', \'win2k\']), None)\n_addparam(\'acl group control\', (\'BOOL\'), \'No\')\n_addparam(\'acl map full control\', (\'BOOL\'), \'Yes\')\n_addparam(\'acl modify list\', (\'LIST\'), \'\')\n_addparam(\'acl wire format\', (\'ENUM\', [\'No Format\', \'Format Windows SD\', \'Always Format SD\']), \'ACL_FORMAT_WINDOWS_SD\')\n_addparam(\'add group script\', (\'STRING\'), None)\n_addparam(\'add machine script\', (\'STRING\'), None)\n_addparam(\'add share command\', (\'STRING\'), None)\n_addparam(\'add user script\', (\'STRING\'), None)\n_addparam(\'add user to group script\', (\'STRING\'), None)\n_addparam(\'addport command\', (\'STRING\'), None)\n_addparam(\'addprinter command\', (\'STRING\'), None)\n_addparam(\'admin users\', (\'LIST\'), \'\')\n_addparam(\'administrative share\', (\'BOOL\'), \'No\')\n_addparam(\'afs share\', (\'BOOL\'), \'No\')\n_addparam(\'afs token lifetime\', (\'INTEGER\'), \'604800\')\n_addparam(\'afs username map\', (\'STRING\'), None)\n_addparam(\'aio read size\', (\'INTEGER\'), \'0\')\n_addparam(\'aio write behind\', (\'STRING\'), \'\')\n_addparam(\'aio write size\', (\'INTEGER\'), \'0\')\n_addparam(\'algorithmic rid base\', (\'INTEGER\'), \'BASE_RID\')\n_addparam(\'allocation roundup size\', (\'INTEGER\'), \'SMB_ROUNDUP_ALLOCATION_SIZE\')\n_addparam(\'allow short dns domain name\', (\'BOOL\'), \'No\')\n_addparam(\'allow trusted domains\', (\'BOOL\'), \'Yes\')\n_addparam(\'announce as\', (\'ENUM\', [\'NT\', \'NT Server\', \'NT Workstation\', \'win95\', \'WfW\']), \'NT Server\')\n_addparam(\'announce version\', (\'STRING\'), \'5.0.x\')\n_addparam(\'atime now files\', (\'STRING\'), \'\')\n_addparam(\'atime now slop\', (\'INTEGER\'), None)\n_addparam(\'atime static files\', (\'STRING\'), \'\')\n_addparam(\'auth methods\', (\'LIST\'), \'guest wbc\')\n_addparam(\'available\', (\'BOOL\'), \'Yes\')\n_addparam(\'bind interfaces only\', (\'BOOL\'), \'No\')\n_addparam(\'blacklisted servers\', (\'LIST\'), None)\n_addparam(\'block size\', (\'INTEGER\'), \'1024\')\n_addparam(\'blocking locks\', (\'BOOL\'), \'Yes\')\n_addparam(\'brl kos\', (\'BOOL\'), \'Yes\')\n_addparam(\'browse list\', (\'BOOL\'), \'Yes\')\n_addparam(\'browseable\', (\'BOOL\'), \'Yes\')\n_addparam(\'cache directory\', (\'STRING\'), \'get_dyn_CACHEDIR()\')\n_addparam(\'case sensitive\', (\'ENUM\', [\'No\', \'False\', \'0\', \'Yes\', \'True\', \'1\', \'Auto\']), None)\n_addparam(\'casesignames\', (\'ENUM\', [\'No\', \'False\', \'0\', \'Yes\', \'True\', \'1\', \'Auto\']), None)\n_addparam(\'catia:mappings\', (\'STRING\'), \'\')\n_addparam(\'change notify\', (\'BOOL\'), \'Yes\')\n_addparam(\'change notify restrict recursive\', (\'BOOL\'), \'No\')\n_addparam(\'change notify timeout\', (\'INTEGER\'), None)\n_addparam(\'change share command\', (\'STRING\'), None)\n_addparam(\'check password script\', (\'STRING\'), None)\n_addparam(\'client NTLMv2 auth\', (\'BOOL\'), \'No\')\n_addparam(\'client lanman auth\', (\'BOOL\'), \'No\')\n_addparam(\'client ldap sasl wrapping\', (\'ENUM\', [\'plain\', \'sign\', \'seal\']), None)\n_addparam(\'client plaintext auth\', (\'BOOL\'), \'No\')\n_addparam(\'client schannel\', (\'ENUM\', [\'No\', \'False\', \'0\', \'Yes\', \'True\', \'1\', \'Auto\']), \'Auto\')\n_addparam(\'client signing\', (\'ENUM\', [\'No\', \'False\', \'0\', \'Off\', \'disabled\', \'Yes\', \'True\', \'1\', \'On\', \'enabled\', \'auto\', \'required\', \'mandatory\', \'force\', \'forced\', \'enforced\']), \'auto\')\n_addparam(\'client use spnego\', (\'BOOL\'), \'Yes\')\n_addparam(\'cluster addresses\', (\'LIST\'), \'NULL\')\n_addparam(\'cluster directory\', (\'STRING\'), \'dyn_CLUSTERDIR\')\n_addparam(\'clustering\', (\'BOOL\'), \'No\')\n_addparam(\'comment\', (\'STRING\'), \'\')\n_addparam(\'config backend\', (\'ENUM\', [\'file\', \'registry\']), \'config_backend\')\n_addparam(\'config file\', (\'STRING\'), None)\n_addparam(\'copy\', (\'STRING\'), \'\')\n_addparam(\'create mask\', (\'OCTAL\'), \'700\')\n_addparam(\'creator owner gets full control\', (\'BOOL\'), \'Yes\')\n_addparam(\'csc policy\', (\'ENUM\', [\'manual\', \'documents\', \'programs\', \'disable\']), \'0\')\n_addparam(\'ctdbd socket\', (\'STRING\'), \'\')\n_addparam(\'ctime now files\', (\'STRING\'), \'\')\n_addparam(\'ctime now slop\', (\'INTEGER\'), None)\n_addparam(\'cups connection timeout\', (\'INTEGER\'), \'CUPS_DEFAULT_CONNECTION_TIMEOUT\')\n_addparam(\'cups options\', (\'STRING\'), \'\')\n_addparam(\'cups server\', (\'STRING\'), \'\')\n_addparam(\'deadtime\', (\'INTEGER\'), \'0\')\n_addparam(\'debug class\', (\'BOOL\'), \'No\')\n_addparam(\'debug hires timestamp\', (\'BOOL\'), \'Yes\')\n_addparam(\'debug pid\', (\'BOOL\'), \'No\')\n_addparam(\'debug prefix timestamp\', (\'BOOL\'), \'No\')\n_addparam(\'debug timestamp\', (\'BOOL\'), \'Yes\')\n_addparam(\'debug uid\', (\'BOOL\'), \'Yes\')\n_addparam(\'dedicated keytab file\', (\'STRING\'), None)\n_addparam(\'default case\', (\'ENUM\', [\'lower\', \'upper\']), \'lower\')\n_addparam(\'default devmode\', (\'BOOL\'), \'Yes\')\n_addparam(\'default service\', (\'STRING\'), None)\n_addparam(\'defer sharing violations\', (\'BOOL\'), \'Yes\')\n_addparam(\'delete group script\', (\'STRING\'), None)\n_addparam(\'delete readonly\', (\'BOOL\'), \'Yes\')\n_addparam(\'delete share command\', (\'STRING\'), None)\n_addparam(\'delete user from group script\', (\'STRING\'), None)\n_addparam(\'delete user script\', (\'STRING\'), None)\n_addparam(\'delete veto files\', (\'BOOL\'), \'No\')\n_addparam(\'deleteprinter command\', (\'STRING\'), None)\n_addparam(\'dfree cache time\', (\'INTEGER\'), \'0\')\n_addparam(\'dfree command\', (\'STRING\'), \'\')\n_addparam(\'directory mask\', (\'OCTAL\'), \'700\')\n_addparam(\'directory name cache size\', (\'INTEGER\'), \'100\')\n_addparam(\'directory security mask\', (\'OCTAL\'), \'0777\')\n_addparam(\'disable netbios\', (\'BOOL\'), None)\n_addparam(\'disable samba\', (\'BOOL\'), \'No\')\n_addparam(\'disable spoolss\', (\'BOOL\'), \'No\')\n_addparam(\'display charset\', (\'STRING\'), \'ASCII\')\n_addparam(\'dmapi support\', (\'BOOL\'), \'No\')\n_addparam(\'dns proxy\', (\'BOOL\'), \'No\')\n_addparam(\'domain admin password\', (\'STRING\'), \'\')\n_addparam(\'domain administrator\', (\'STRING\'), \'\')\n_addparam(\'domain logons\', (\'BOOL\'), \'No\')\n_addparam(\'domain master\', (\'ENUM\', [\'No\', \'False\', \'0\', \'Yes\', \'True\', \'1\', \'Auto\']), \'Auto\')\n_addparam(\'dont descend\', (\'STRING\'), \'\')\n_addparam(\'dos charset\', (\'STRING\'), \'ascii\')\n_addparam(\'dos filemode\', (\'BOOL\'), \'No\')\n_addparam(\'dos filetime resolution\', (\'BOOL\'), \'No\')\n_addparam(\'dos filetimes\', (\'BOOL\'), \'Yes\')\n_addparam(\'ea support\', (\'BOOL\'), \'No\')\n_addparam(\'enable asu support\', (\'BOOL\'), \'No\')\n_addparam(\'enable core files\', (\'BOOL\'), \'Yes\')\n_addparam(\'enable privileges\', (\'BOOL\'), \'No\')\n_addparam(\'encrypt passwords\', (\'BOOL\'), \'Yes\')\n_addparam(\'enhanced browsing\', (\'BOOL\'), \'true\')\n_addparam(\'enumports command\', (\'STRING\'), None)\n_addparam(\'eventlog list\', (\'LIST\'), None)\n_addparam(\'failed conn cache timeout\', (\'INTEGER\'), \'30\')\n_addparam(\'fake directory create times\', (\'BOOL\'), \'No\')\n_addparam(\'fake oplocks\', (\'BOOL\'), \'No\')\n_addparam(\'fam change notify\', (\'BOOL\'), \'Yes\')\n_addparam(\'follow symlinks\', (\'BOOL\'), \'Yes\')\n_addparam(\'force create mode\', (\'OCTAL\'), \'100\')\n_addparam(\'force directory mode\', (\'OCTAL\'), \'0000\')\n_addparam(\'force directory security mode\', (\'OCTAL\'), \'0\')\n_addparam(\'force group\', (\'STRING\'), None)\n_addparam(\'force printername\', (\'BOOL\'), \'No\')\n_addparam(\'force security mode\', (\'OCTAL\'), \'0\')\n_addparam(\'force unknown acl user\', (\'BOOL\'), \'Yes\')\n_addparam(\'force user\', (\'STRING\'), None)\n_addparam(\'force username map\', (\'BOOL\'), None)\n_addparam(\'fqdn lookups\', (\'BOOL\'), \'No\')\n_addparam(\'fstype\', (\'STRING\'), \'\')\n_addparam(\'full_audit:failure\', (\'STRING\'), \'\')\n_addparam(\'full_audit:prefix\', (\'STRING\'), \'\')\n_addparam(\'full_audit:success\', (\'STRING\'), \'\')\n_addparam(\'get quota command\', (\'STRING\'), None)\n_addparam(\'getwd cache\', (\'BOOL\'), \'true\')\n_addparam(\'guest account\', (\'STRING\'), \'nobody\')\n_addparam(\'guest ok\', (\'BOOL\'), \'No\')\n_addparam(\'guest only\', (\'BOOL\'), \'No\')\n_addparam(\'hide dot files\', (\'BOOL\'), \'No\')\n_addparam(\'hide files\', (\'STRING\'), \'\')\n_addparam(\'hide special files\', (\'BOOL\'), \'No\')\n_addparam(\'hide unaccessible root only\', (\'BOOL\'), \'No\')\n_addparam(\'hide unreadable\', (\'BOOL\'), \'No\')\n_addparam(\'hide unwriteable files\', (\'BOOL\'), \'No\')\n_addparam(\'homedir map\', (\'STRING\'), \'auto.home\')\n_addparam(\'host msdfs\', (\'BOOL\'), \'No\')\n_addparam(\'hostname lookups\', (\'BOOL\'), \'No\')\n_addparam(\'hosts allow\', (\'LIST\'), \'\')\n_addparam(\'hosts deny\', (\'LIST\'), \'\')\n_addparam(\'idmap alloc backend\', (\'STRING\'), None)\n_addparam(\'idmap backend\', (\'STRING\'), \'tdb\')\n_addparam(\'idmap cache time\', (\'INTEGER\'), \'604800\')\n_addparam(\'idmap gid\', (\'STRING\'), \'10000 - 20000\')\n_addparam(\'idmap gid system threshold\', (\'INTEGER\'), \'80\')\n_addparam(\'idmap negative cache time\', (\'INTEGER\'), \'120\')\n_addparam(\'idmap uid\', (\'STRING\'), \'10000 - 20000\')\n_addparam(\'idmap uid system threshold\', (\'INTEGER\'), \'80\')\n_addparam(\'ifs allow execute\', (\'BOOL\'), \'No\')\n_addparam(\'ifs brl\', (\'BOOL\'), \'Yes\')\n_addparam(\'ifs brl gc\', (\'BOOL\'), \'Yes\')\n_addparam(\'ifs brl gc rate\', (\'INTEGER\'), \'3600\')\n_addparam(\'ifs brl lock dirs\', (\'INTEGER\'), \'10\')\n_addparam(\'ifs debug oplock callback records\', (\'BOOL\'), \'No\')\n_addparam(\'ifs event change notify\', (\'BOOL\'), \'Yes\')\n_addparam(\'ifs event match windows coalescing\', (\'BOOL\'), \'Yes\')\n_addparam(\'ifs event max backlog\', (\'INTEGER\'), \'0\')\n_addparam(\'ifs event send success enum dir\', (\'BOOL\'), \'Yes\')\n_addparam(\'ifs smlock delete on close\', (\'BOOL\'), \'No\')\n_addparam(\'ifs virtual names\', (\'LIST\'), None)\n_addparam(\'ifs virtual settings\', (\'ENUM\', [\'NONE\', \'VIRTUAL\', \'VIRTUAL HIGH PERF\']), \'VIRTUAL_NONE\')\n_addparam(\'ignore extended attributes\', (\'BOOL\'), \'No\')\n_addparam(\'ignore named streams\', (\'BOOL\'), None)\n_addparam(\'ignore sacls\', (\'BOOL\'), \'No\')\n_addparam(\'ignore sids list\', (\'LIST\'), \'\')\n_addparam(\'ignore unmappable sids\', (\'BOOL\'), \'No\')\n_addparam(\'include\', (\'STRING\'), \'\')\n_addparam(\'inherit acls\', (\'BOOL\'), \'No\')\n_addparam(\'inherit owner\', (\'BOOL\'), \'No\')\n_addparam(\'inherit permissions\', (\'BOOL\'), \'No\')\n_addparam(\'init logon delay\', (\'INTEGER\'), \'100\')\n_addparam(\'init logon delayed hosts\', (\'LIST\'), None)\n_addparam(\'interfaces\', (\'LIST\'), None)\n_addparam(\'invalid users\', (\'LIST\'), \'\')\n_addparam(\'iprint server\', (\'STRING\'), \'\')\n_addparam(\'keepalive\', (\'INTEGER\'), \'DEFAULT_KEEPALIVE\')\n_addparam(\'kerberos method\', (\'ENUM\', [\'default\', \'secrets only\', \'system keytab\', \'dedicated keytab\', \'secrets and keytab\']), None)\n_addparam(\'kernel change notify\', (\'BOOL\'), \'Yes\')\n_addparam(\'kernel oplocks\', (\'BOOL\'), \'Yes\')\n_addparam(\'lanman auth\', (\'BOOL\'), \'No\')\n_addparam(\'large readwrite\', (\'BOOL\'), \'Yes\')\n_addparam(\'ldap admin dn\', (\'STRING\'), \'\')\n_addparam(\'ldap connection timeout\', (\'INTEGER\'), \'LDAP_CONNECTION_DEFAULT_TIMEOUT\')\n_addparam(\'ldap debug level\', (\'INTEGER\'), \'0\')\n_addparam(\'ldap debug threshold\', (\'INTEGER\'), \'10\')\n_addparam(\'ldap delete dn\', (\'BOOL\'), \'No\')\n_addparam(\'ldap group suffix\', (\'STRING\'), \'\')\n_addparam(\'ldap idmap suffix\', (\'STRING\'), \'\')\n_addparam(\'ldap machine suffix\', (\'STRING\'), \'\')\n_addparam(\'ldap page size\', (\'INTEGER\'), \'LDAP_PAGE_SIZE\')\n_addparam(\'ldap passwd sync\', (\'ENUM\', [\'no\', \'off\', \'yes\', \'on\', \'only\']), \'LDAP_PASSWD_SYNC_OFF\')\n_addparam(\'ldap replication sleep\', (\'INTEGER\'), \'1000\')\n_addparam(\'ldap ssl\', (\'ENUM\', [\'no\', \'off\', \'start tls\', \'start_tls\']), \'LDAP_SSL_START_TLS\')\n_addparam(\'ldap ssl ads\', (\'BOOL\'), \'No\')\n_addparam(\'ldap suffix\', (\'STRING\'), \'\')\n_addparam(\'ldap timeout\', (\'INTEGER\'), \'LDAP_DEFAULT_TIMEOUT\')\n_addparam(\'ldap user suffix\', (\'STRING\'), \'\')\n_addparam(\'level2 oplocks\', (\'BOOL\'), \'Yes\')\n_addparam(\'lm announce\', (\'ENUM\', [\'No\', \'False\', \'0\', \'Yes\', \'True\', \'1\', \'Auto\']), \'2\')\n_addparam(\'lm interval\', (\'INTEGER\'), \'60\')\n_addparam(\'load printers\', (\'BOOL\'), \'Yes\')\n_addparam(\'local master\', (\'BOOL\'), \'No\')\n_addparam(\'lock directory\', (\'STRING\'), \'get_dyn_LOCKDIR()\')\n_addparam(\'lock spin count\', (\'INTEGER\'), \'3\')\n_addparam(\'lock spin time\', (\'INTEGER\'), \'WINDOWS_MINIMUM_LOCK_TIMEOUT_MS\')\n_addparam(\'locking\', (\'BOOL\'), \'Yes\')\n_addparam(\'log file\', (\'STRING\'), \'NULL\')\n_addparam(\'log level\', (\'STRING\'), \'0\')\n_addparam(\'log nt token command\', (\'STRING\'), None)\n_addparam(\'logon drive\', (\'STRING\'), \'\')\n_addparam(\'logon home\', (\'STRING\'), \'\\\\\\\\%N\\\\%U\')\n_addparam(\'logon path\', (\'STRING\'), \'\\\\\\\\%N\\\\%U\\\\profile\')\n_addparam(\'logon script\', (\'STRING\'), None)\n_addparam(\'lppause command\', (\'STRING\'), \'\')\n_addparam(\'lpq cache time\', (\'INTEGER\'), \'30\')\n_addparam(\'lpq command\', (\'STRING\'), \'\')\n_addparam(\'lpresume command\', (\'STRING\'), \'\')\n_addparam(\'lprm command\', (\'STRING\'), \'\')\n_addparam(\'machine password timeout\', (\'INTEGER\'), \'604800\')\n_addparam(\'magic output\', (\'STRING\'), \'\')\n_addparam(\'magic script\', (\'STRING\'), \'\')\n_addparam(\'mangle prefix\', (\'INTEGER\'), \'1\')\n_addparam(\'mangled map\', (\'STRING\'), \'\')\n_addparam(\'mac extensions\', (\'BOOL\'), \'No\')\n_addparam(\'mangled names\', (\'BOOL\'), \'Yes\')\n_addparam(\'mangling char\', (\'CHAR\'), None)\n_addparam(\'mangling method\', (\'STRING\'), \'hash2\')\n_addparam(\'map acl inherit\', (\'BOOL\'), \'No\')\n_addparam(\'map archive\', (\'BOOL\'), \'No\')\n_addparam(\'map hidden\', (\'BOOL\'), \'No\')\n_addparam(\'map readonly\', (\'ENUM\', [\'no\', \'false\', \'0\', \'yes\', \'true\', \'1\', \'permissions\', \'perms\']), \'MAP_READONLY_YES\')\n_addparam(\'map system\', (\'BOOL\'), \'No\')\n_addparam(\'map to guest\', (\'ENUM\', [\'Never\', \'Bad User\', \'Bad Password\', \'Bad Uid\']), \'Never\')\n_addparam(\'map untrusted to domain\', (\'BOOL\'), \'false\')\n_addparam(\'max connections\', (\'INTEGER\'), \'0\')\n_addparam(\'max disk size\', (\'INTEGER\'), None)\n_addparam(\'max log size\', (\'INTEGER\'), \'0\')\n_addparam(\'max mux\', (\'INTEGER\'), \'50\')\n_addparam(\'max open files\', (\'INTEGER\'), \'max_open_files()\')\n_addparam(\'max print jobs\', (\'INTEGER\'), \'1000\')\n_addparam(\'max protocol\', (\'ENUM\', [\'NT1\', \'LANMAN2\', \'LANMAN1\', \'CORE\', \'COREPLUS\', \'CORE+\']), \'NT1\')\n_addparam(\'max reported print jobs\', (\'INTEGER\'), \'0\')\n_addparam(\'max smbd processes\', (\'INTEGER\'), \'0\')\n_addparam(\'max stat cache size\', (\'INTEGER\'), \'256\')\n_addparam(\'max ttl\', (\'INTEGER\'), \'259200\')\n_addparam(\'max wins ttl\', (\'INTEGER\'), \'518400\')\n_addparam(\'max xmit\', (\'INTEGER\'), \'0x4104\')\n_addparam(\'message command\', (\'STRING\'), None)\n_addparam(\'min print space\', (\'INTEGER\'), \'0\')\n_addparam(\'min protocol\', (\'ENUM\', [\'NT1\', \'LANMAN2\', \'LANMAN1\', \'CORE\', \'COREPLUS\', \'CORE+\']), \'CORE\')\n_addparam(\'min receivefile size\', (\'INTEGER\'), \'1\')\n_addparam(\'min wins ttl\', (\'INTEGER\'), \'21600\')\n_addparam(\'msdfs proxy\', (\'STRING\'), \'\')\n_addparam(\'msdfs root\', (\'BOOL\'), \'No\')\n_addparam(\'mtime now files\', (\'STRING\'), \'\')\n_addparam(\'mtime now slop\', (\'INTEGER\'), None)\n_addparam(\'mtime static files\', (\'STRING\'), \'\')\n_addparam(\'name cache timeout\', (\'INTEGER\'), \'660\')\n_addparam(\'name resolve order\', (\'STRING\'), \'lmhosts wins host bcast\')\n_addparam(\'netbios aliases\', (\'LIST\'), None)\n_addparam(\'netbios name\', (\'USTRING\'), \'global_myname()\')\n_addparam(\'netbios scope\', (\'USTRING\'), None)\n_addparam(\'no notify change\', (\'BOOL\'), \'No\')\n_addparam(\'nt acl support\', (\'BOOL\'), \'Yes\')\n_addparam(\'nt pipe support\', (\'BOOL\'), \'Yes\')\n_addparam(\'nt status support\', (\'BOOL\'), \'Yes\')\n_addparam(\'ntlm auth\', (\'BOOL\'), \'Yes\')\n_addparam(\'null passwords\', (\'BOOL\'), \'No\')\n_addparam(\'obey pam restrictions\', (\'BOOL\'), \'No\')\n_addparam(\'onefs: acl wire format\', (\'STRING\'), \'Format Windows SD\')\n_addparam(\'onefs: allow execute always\', (\'BOOL\'), \'No\')\n_addparam(\'onefs: atime now files\', (\'STRING\'), \'\')\n_addparam(\'onefs: atime now slop\', (\'INTEGER\'), \'0\')\n_addparam(\'onefs: atime static files\', (\'STRING\'), \'\')\n_addparam(\'onefs: atomic sendfile\', (\'BOOL\'), \'Yes\')\n_addparam(\'onefs: case insensitive lookup\', (\'BOOL\'), \'No\')\n_addparam(\'onefs: creator owner gets full control\', (\'BOOL\'), \'Yes\')\n_addparam(\'onefs: ctime now files\', (\'STRING\'), \'\')\n_addparam(\'onefs: ctime now slop\', (\'INTEGER\'), \'0\')\n_addparam(\'onefs: dot snap child accessible\', (\'BOOL\'), \'Yes\')\n_addparam(\'onefs: dot snap child visible\', (\'BOOL\'), \'No\')\n_addparam(\'onefs: dot snap root accessible\', (\'BOOL\'), \'Yes\')\n_addparam(\'onefs: dot snap root visible\', (\'BOOL\'), \'Yes\')\n_addparam(\'onefs: dot snap tilde\', (\'BOOL\'), \'Yes\')\n_addparam(\'onefs: ignore sacls\', (\'BOOL\'), \'No\')\n_addparam(\'onefs: ignore streams\', (\'BOOL\'), \'No\')\n_addparam(\'onefs: ignore unmappable sids\', (\'BOOL\'), \'No\')\n_addparam(\'onefs: mtime now files\', (\'STRING\'), \'\')\n_addparam(\'onefs: mtime now slop\', (\'INTEGER\'), \'0\')\n_addparam(\'onefs: mtime static files\', (\'STRING\'), \'\')\n_addparam(\'onefs: sendfile large reads\', (\'BOOL\'), \'No\')\n_addparam(\'onefs: sendfile safe\', (\'BOOL\'), \'Yes\')\n_addparam(\'onefs: simple file sharing compatibility mode\', (\'BOOL\'), \'No\')\n_addparam(\'onefs: unmappable sids deny everyone\', (\'BOOL\'), \'No\')\n_addparam(\'onefs: unmappable sids ignore list\', (\'LIST\'), \'\')\n_addparam(\'onefs: use readdirplus\', (\'BOOL\'), \'Yes\')\n_addparam(\'only user\', (\'BOOL\'), \'No\')\n_addparam(\'open files database hash size\', (\'INTEGER\'), \'SMB_OPEN_DATABASE_TDB_HASH_SIZE\')\n_addparam(\'oplock break wait time\', (\'INTEGER\'), \'0\')\n_addparam(\'oplock contention limit\', (\'INTEGER\'), \'2\')\n_addparam(\'oplocks\', (\'BOOL\'), \'Yes\')\n_addparam(\'os level\', (\'INTEGER\'), \'20\')\n_addparam(\'os2 driver map\', (\'STRING\'), None)\n_addparam(\'pam password change\', (\'BOOL\'), \'No\')\n_addparam(\'panic action\', (\'STRING\'), \'/bin/sleep 999999999\')\n_addparam(\'paranoid server security\', (\'BOOL\'), \'Yes\')\n_addparam(\'passdb backend\', (\'STRING\'), \'wbc_sam\')\n_addparam(\'passdb expand explicit\', (\'BOOL\'), \'No\')\n_addparam(\'passwd chat\', (\'STRING\'), \'*new*password* %n\\n *new*password* %n\\n *changed*\')\n_addparam(\'passwd chat debug\', (\'BOOL\'), \'No\')\n_addparam(\'passwd chat timeout\', (\'INTEGER\'), \'2\')\n_addparam(\'passwd program\', (\'STRING\'), \'\')\n_addparam(\'password level\', (\'INTEGER\'), \'0\')\n_addparam(\'password server\', (\'STRING\'), \'*\')\n_addparam(\'path\', (\'STRING\'), \'\')\n_addparam(\'pdc hostname\', (\'STRING\'), \'\')\n_addparam(\'perfcount module\', (\'STRING\'), \'pc_onefs\')\n_addparam(\'pid directory\', (\'STRING\'), \'get_dyn_PIDDIR()\')\n_addparam(\'posix locking\', (\'BOOL\'), \'No\')\n_addparam(\'postexec\', (\'STRING\'), \'\')\n_addparam(\'preexec\', (\'STRING\'), \'\')\n_addparam(\'preexec close\', (\'BOOL\'), \'No\')\n_addparam(\'preferred master\', (\'ENUM\', [\'No\', \'False\', \'0\', \'Yes\', \'True\', \'1\', \'Auto\']), None)\n_addparam(\'preload\', (\'STRING\'), None)\n_addparam(\'preload modules\', (\'LIST\'), None)\n_addparam(\'preserve case\', (\'BOOL\'), \'Yes\')\n_addparam(\'print command\', (\'STRING\'), \'\')\n_addparam(\'printable\', (\'BOOL\'), \'No\')\n_addparam(\'printcap cache time\', (\'INTEGER\'), \'750\')\n_addparam(\'printcap name\', (\'STRING\'), None)\n_addparam(\'printer admin\', (\'LIST\'), None)\n_addparam(\'printer name\', (\'STRING\'), \'\')\n_addparam(\'printing\', (\'ENUM\', [\'sysv\', \'aix\', \'hpux\', \'bsd\', \'qnx\', \'plp\', \'lprng\', \'cups\', \'iprint\', \'nt\', \'os2\', \'test\', \'vlp\']), \'nt\')\n_addparam(\'printjob username\', (\'STRING\'), \'\')\n_addparam(\'private dir\', (\'STRING\'), \'get_dyn_PRIVATE_DIR()\')\n_addparam(\'profile acls\', (\'BOOL\'), \'No\')\n_addparam(\'queuepause command\', (\'STRING\'), \'\')\n_addparam(\'queueresume command\', (\'STRING\'), \'\')\n_addparam(\'read bmpx\', (\'BOOL\'), \'No\')\n_addparam(\'read list\', (\'LIST\'), \'\')\n_addparam(\'read only\', (\'BOOL\'), \'No\')\n_addparam(\'read raw\', (\'BOOL\'), \'Yes\')\n_addparam(\'realm\', (\'USTRING\'), None)\n_addparam(\'registry shares\', (\'BOOL\'), \'No\')\n_addparam(\'remote announce\', (\'STRING\'), None)\n_addparam(\'remote browse sync\', (\'STRING\'), None)\n_addparam(\'rename user script\', (\'STRING\'), None)\n_addparam(\'reset on zero vc\', (\'BOOL\'), \'No\')\n_addparam(\'restrict anonymous\', (\'INTEGER\'), \'0\')\n_addparam(\'root directory\', (\'STRING\'), None)\n_addparam(\'root postexec\', (\'STRING\'), \'\')\n_addparam(\'root preexec\', (\'STRING\'), \'\')\n_addparam(\'root preexec close\', (\'BOOL\'), \'No\')\n_addparam(\'security\', (\'ENUM\', [\'SHARE\', \'USER\', \'SERVER\', \'DOMAIN\', \'ADS\']), \'SHARE\')\n_addparam(\'security mask\', (\'OCTAL\'), \'0777\')\n_addparam(\'server schannel\', (\'ENUM\', [\'No\', \'False\', \'0\', \'Yes\', \'True\', \'1\', \'Auto\']), \'Auto\')\n_addparam(\'server signing\', (\'ENUM\', [\'No\', \'False\', \'0\', \'Off\', \'disabled\', \'Yes\', \'True\', \'1\', \'On\', \'enabled\', \'auto\', \'required\', \'mandatory\', \'force\', \'forced\', \'enforced\']), \'No\')\n_addparam(\'server string\', (\'STRING\'), \'Isilon Server\')\n_addparam(\'set directory\', (\'BOOLREV\'), \'Yes\')\n_addparam(\'set primary group script\', (\'STRING\'), None)\n_addparam(\'set quota command\', (\'STRING\'), None)\n_addparam(\'share enum access check\', (\'BOOL\'), \'No\')\n_addparam(\'share modes\', (\'BOOL\'), \'Yes\')\n_addparam(\'short preserve case\', (\'BOOL\'), \'Yes\')\n_addparam(\'show add printer wizard\', (\'BOOL\'), \'Yes\')\n_addparam(\'shutdown script\', (\'STRING\'), None)\n_addparam(\'simple file sharing compatibility mode\', (\'BOOL\'), \'No\')\n_addparam(\'smb encrypt\', (\'ENUM\', [\'No\', \'False\', \'0\', \'Off\', \'disabled\', \'Yes\', \'True\', \'1\', \'On\', \'enabled\', \'auto\', \'required\', \'mandatory\', \'force\', \'forced\', \'enforced\']), \'Auto\')\n_addparam(\'smb passwd file\', (\'STRING\'), \'/usr/local/private/smbpasswd\')\n_addparam(\'smb ports\', (\'STRING\'), \'445 139\')\n_addparam(\'socket address\', (\'STRING\'), \'0.0.0.0\')\n_addparam(\'socket options\', (\'STRING\'), \'TCP_NODELAY\')\n_addparam(\'stat cache\', (\'BOOL\'), \'No\')\n_addparam(\'state directory\', (\'STRING\'), \'get_dyn_STATEDIR()\')\n_addparam(\'store dos attributes\', (\'BOOL\'), \'Yes\')\n_addparam(\'store dos attributes in ea\', (\'BOOL\'), \'No\')\n_addparam(\'strict allocate\', (\'BOOL\'), \'No\')\n_addparam(\'strict locking\', (\'ENUM\', [\'No\', \'False\', \'0\', \'Yes\', \'True\', \'1\', \'Auto\']), \'No\')\n_addparam(\'strict sync\', (\'BOOL\'), \'No\')\n_addparam(\'svcctl list\', (\'LIST\'), None)\n_addparam(\'sync always\', (\'BOOL\'), \'No\')\n_addparam(\'syslog\', (\'INTEGER\'), \'11\')\n_addparam(\'syslog only\', (\'BOOL\'), \'Yes\')\n_addparam(\'template homedir\', (\'STRING\'), \'/home/%D/%U\')\n_addparam(\'template shell\', (\'STRING\'), \'/bin/false\')\n_addparam(\'time offset\', (\'INTEGER\'), None)\n_addparam(\'time server\', (\'BOOL\'), \'No\')\n_addparam(\'unix charset\', (\'STRING\'), \'UTF-8\')\n_addparam(\'unix extensions\', (\'BOOL\'), \'No\')\n_addparam(\'unix password sync\', (\'BOOL\'), \'No\')\n_addparam(\'unmappable sids deny everyone\', (\'BOOL\'), None)\n_addparam(\'update encrypted\', (\'BOOL\'), \'No\')\n_addparam(\'use atomic sendfile\', (\'BOOL\'), \'Yes\')\n_addparam(\'use client driver\', (\'BOOL\'), \'No\')\n_addparam(\'use kerberos keytab\', (\'BOOL\'), None)\n_addparam(\'use localgrp\', (\'BOOL\'), \'No\')\n_addparam(\'use mmap\', (\'BOOL\'), \'Yes\')\n_addparam(\'use readdirplus\', (\'BOOL\'), \'Yes\')\n_addparam(\'use recvfile\', (\'BOOL\'), \'Yes\')\n_addparam(\'use sendfile\', (\'BOOL\'), \'Yes\')\n_addparam(\'use spnego\', (\'BOOL\'), \'Yes\')\n_addparam(\'use unexpected tdb\', (\'BOOL\'), \'No\')\n_addparam(\'username\', (\'STRING\'), \'\')\n_addparam(\'username level\', (\'INTEGER\'), \'0\')\n_addparam(\'username map\', (\'STRING\'), None)\n_addparam(\'username map script\', (\'STRING\'), None)\n_addparam(\'usershare allow guests\', (\'BOOL\'), \'No\')\n_addparam(\'usershare max shares\', (\'INTEGER\'), \'0\')\n_addparam(\'usershare owner only\', (\'BOOL\'), \'Yes\')\n_addparam(\'usershare path\', (\'STRING\'), \'s\')\n_addparam(\'usershare prefix allow list\', (\'LIST\'), None)\n_addparam(\'usershare prefix deny list\', (\'LIST\'), None)\n_addparam(\'usershare template share\', (\'STRING\'), \'\')\n_addparam(\'utmp\', (\'BOOL\'), None)\n_addparam(\'utmp directory\', (\'STRING\'), None)\n_addparam(\'valid users\', (\'LIST\'), \'\')\n_addparam(\'veto files\', (\'STRING\'), \'/.ifsvar/\')\n_addparam(\'veto oplock files\', (\'STRING\'), \'\')\n_addparam(\'vfs objects\', (\'LIST\'), \'onefs_shadow_copy onefs\')\n_addparam(\'visible child dotsnap\', (\'BOOL\'), \'No\')\n_addparam(\'visible root dotsnap\', (\'BOOL\'), \'Yes\')\n_addparam(\'volume\', (\'STRING\'), \'\')\n_addparam(\'wide links\', (\'BOOL\'), \'Yes\')\n_addparam(\'winbind cache time\', (\'INTEGER\'), \'300\')\n_addparam(\'winbind enum groups\', (\'BOOL\'), \'No\')\n_addparam(\'winbind enum users\', (\'BOOL\'), \'No\')\n_addparam(\'winbind expand groups\', (\'INTEGER\'), \'1\')\n_addparam(\'winbind ignore domains\', (\'LIST\'), None)\n_addparam(\'winbind local idmap group override\', (\'BOOL\'), \'No\')\n_addparam(\'winbind map domains\', (\'LIST\'), None)\n_addparam(\'winbind max clients\', (\'INTEGER\'), \'WINBINDD_MAX_SIMULTANEOUS_CLIENTS\')\n_addparam(\'winbind nested groups\', (\'BOOL\'), \'Yes\')\n_addparam(\'winbind normalize names\', (\'BOOL\'), None)\n_addparam(\'winbind nss info\', (\'LIST\'), \'str_list_make_v3(talloc_autofree_context(), "template", NULL)\')\n_addparam(\'winbind offline logon\', (\'BOOL\'), \'No\')\n_addparam(\'winbind reconnect delay\', (\'INTEGER\'), \'30\')\n_addparam(\'winbind refresh tickets\', (\'BOOL\'), \'No\')\n_addparam(\'winbind rpc only\', (\'BOOL\'), None)\n_addparam(\'winbind rpc query user\', (\'LIST\'), \'No\')\n_addparam(\'winbind separator\', (\'STRING\'), \'\\\\\')\n_addparam(\'winbind strict trusted domain groups only\', (\'BOOL\'), \'No\')\n_addparam(\'winbind strict trusted domains only\', (\'BOOL\'), \'No\')\n_addparam(\'winbind trust rescan time\', (\'INTEGER\'), \'300\')\n_addparam(\'winbind trusted domains only\', (\'BOOL\'), \'No\')\n_addparam(\'winbind use default domain\', (\'BOOL\'), \'No\')\n_addparam(\'wins hook\', (\'STRING\'), None)\n_addparam(\'wins proxy\', (\'BOOL\'), \'No\')\n_addparam(\'wins server\', (\'LIST\'), None)\n_addparam(\'wins support\', (\'BOOL\'), \'No\')\n_addparam(\'workgroup\', (\'USTRING\'), \'WORKGROUP\')\n_addparam(\'write cache size\', (\'INTEGER\'), \'0\')\n_addparam(\'write list\', (\'LIST\'), \'\')\n_addparam(\'write raw\', (\'BOOL\'), \'Yes\')\n_addparam(\'wtmp directory\', (\'STRING\'), None)\n\n# Aliases for known parameters\n_addalias(\'browseable\', \'browsable\')\n_addalias(\'case sensitive\', \'casesignames\')\n_addalias(\'create mask\', \'create mode\')\n_addalias(\'debug timestamp\', \'timestamp logs\')\n_addalias(\'default service\', \'default\')\n_addalias(\'directory mask\', \'directory mode\')\n_addalias(\'disable spoolss\', \'enable spoolss\')\n_addalias(\'force group\', \'group\')\n_addalias(\'guest ok\', \'public\')\n_addalias(\'guest only\', \'only guest\')\n_addalias(\'hosts allow\', \'allow hosts\')\n_addalias(\'hosts deny\', \'deny hosts\')\n_addalias(\'idmap gid\', \'winbind gid\')\n_addalias(\'idmap uid\', \'winbind uid\')\n_addalias(\'ldap passwd sync\', \'ldap password sync\')\n_addalias(\'lock directory\', \'lock dir\')\n_addalias(\'log level\', \'debuglevel\')\n_addalias(\'max protocol\', \'protocol\')\n_addalias(\'path\', \'directory\')\n_addalias(\'preexec\', \'exec\')\n_addalias(\'preferred master\', \'prefered master\')\n_addalias(\'preload\', \'auto services\')\n_addalias(\'printable\', \'print ok\')\n_addalias(\'printcap name\', \'printcap\')\n_addalias(\'printer name\', \'printer\')\n_addalias(\'read only\', \'write ok\')\n_addalias(\'read only\', \'writeable\')\n_addalias(\'read only\', \'writable\')\n_addalias(\'root directory\', \'root dir\')\n_addalias(\'root directory\', \'root\')\n_addalias(\'username\', \'user\')\n_addalias(\'username\', \'users\')\n_addalias(\'vfs objects\', \'vfs object\')\n\n# These type names come from samba_parameters.py, do not change\ntSTRING = (\'STRING\')\ntUSTRING = (\'USTRING\')\ntCHAR = (\'CHAR\')\ntINTEGER = (\'INTEGER\')\ntOCTAL = (\'OCTAL\')\ntBOOL = (\'BOOL\')\ntBOOLREV = (\'BOOLREV\')\ntLIST = (\'LIST\')\ntENUM_str = \'ENUM\'\ndef tENUM(possible):\n    return (tENUM_str, map(lambda x : x.lower(), possible))\n\ndef _param(name):\n    if global_alias_table.has_key(name):\n        return global_param_table[global_alias_table[name]]\n    else:\n        return None\n\n# __     ___    _    _   _ _____ ____\n# \\ \\   / / \\  | |  | | | | ____/ ___|\n#  \\ \\ / / _ \\ | |  | | | |  _| \\___ \\\n#   \\ V / ___ \\| |__| |_| | |___ ___) |\n#    \\_/_/   \\_\\_____\\___/|_____|____/\n\ndef _coerce_bool(str):\n    low = str.lower()\n    if low == \'no\' or low == \'false\' or low == \'0\':\n        return False\n    elif low == \'yes\' or low == \'true\' or low == \'1\':\n        return True\n    raise Exception(\'invalid boolean value\')\n\ndef coerce(str, param_obj):\n    type = param_obj[\'type\']\n    if type == tSTRING or type == tUSTRING:\n        return (str or \'\').strip().lower()\n    elif type == tCHAR:\n        if len(str) > 1:\n            raise Exception(\'character type too large\')\n        return str.lower()\n    elif type == tINTEGER:\n        return int(str)\n    elif type == tOCTAL:\n        return int(str, 8)\n    elif type == tBOOL:\n        return _coerce_bool(str)\n    elif type == tBOOLREV:\n        return not _coerce_bool(str)\n    elif type == tLIST:\n        return str.split()\n    elif type[0] == tENUM_str:\n        lower = str.lower()\n        if str.lower() not in type[1]:\n            raise Exception(\'invalid enum value (valid values: %s)\' % type[1])\n        return lower\n\ndef _safe_sub(list, k, default):\n    if k < len(list):\n        return list[k]\n    else:\n        return default\n\ndef version_compare(vleft, vright):\n    l = max(len(vleft), len(vright))\n    for k in range(0, l):\n        d = _safe_sub(vleft, k, 0) - _safe_sub(vright, k, 0)\n        if d:\n            return d\n    return 0\n\ndef version_name(v):\n    s = \'\'\n    for k in v:\n        s += \'%s.\' % k\n    return s[:-1]\n\ndef get_coerced_value(param_str, value_str):\n    param_obj = _param(param_str)\n    if not param_obj:\n        raise Exception(\'Unknown parameter: %s\' % param_str)\n\n    value = coerce(value_str, param_obj)\n\n    return value\n\ndef onefs_supported_value(version, scope, param_str, value_str, pfunc):\n    param_obj = _param(param_str)\n    if not param_obj:\n        return (WARNING, \'unknown parameter\')\n\n    try:\n        default = coerce(param_obj[\'default\'], param_obj)\n    except:\n        default = None\n\n    try:\n        value = coerce(value_str, param_obj)\n    except Exception, e:\n        return (WARNING, \'invalid value: %s: %s\' % (value_str, e))\n\n    if value == default:\n        return (SUPPORTED,)\n    elif not global_support_table.has_key((scope, param_str)):\n        return (ERROR, \'parameter is unsupported\') # default\n    else:\n        versions = global_support_table[(scope, param_str)]\n        v = None\n        for possible in versions:\n            if version_compare(version, possible[0]) >= 0:\n                v = possible\n\n        if not v:\n            return (ERROR, \'parameter is unsupported in this version\')\n\n        return v[1](value, pfunc)\n\ndef is_default_onefs_value(scope, param_str, value_str):\n    param_obj = _param(param_str)\n    if not param_obj:\n        raise Exception(\'unknown parameter\')\n\n    try:\n        default = coerce(param_obj[\'default\'], param_obj)\n    except:\n        default = None\n\n    try:\n        value = coerce(value_str, param_obj)\n    except Exception, e:\n        return (WARNING, \'invalid value: %s: %s\' % (value_str, e))\n\n    return value == default\n\n# Given a global/share db (generated by parse above), spit out a list\n# of issues in the form [ (scope, share, parameter, value, support, text) ]\n\ndef db_params(db):\n    for scope in [GLOBAL, SHARE]:\n        if not db.has_key(scope):\n            continue\n        for share in db[scope]:\n            for param in db[scope][share]:\n                yield (scope, share, param, db[scope][share][param])\n\ndef db_shares(db):\n    if SHARE not in db:\n        return\n    for share in db[SHARE]:\n        yield (share, db[SHARE][share])\n\ndef db_globals(db):\n    if GLOBAL not in db:\n        return\n    if None not in db[GLOBAL]:\n        return\n    for param in db[GLOBAL][None]:\n        yield (param, db[GLOBAL][None][param])\n\ndef get_global_value(db, param):\n    param_obj = _param(param)\n    if not param_obj:\n        raise Exception(\'%s not defined\', param)\n\n    try:\n        return db[GLOBAL][None][param]\n    except:\n        pass\n\n    try:\n        return coerce(param_obj[\'default\'], param_obj)\n    except:\n        return None\n\ndef supported_config(db, force_version = None):\n    """\n    Function parses result set into a list of tuples like:\n    \n    [(scope, share, param, value, severity, text), ...]\n    \n    @return list - [(scope, share, param, value, severity, text), ...]\n    """\n    ret = []\n    version = force_version or db[\'_version\']\n    for scope, share, param, value in db_params(db):\n        sup = onefs_supported_value(version, scope, param, value,\n                                    lambda param : get_global_value(db, param))\n        if sup[0] == SUPPORTED:\n            continue\n        ret.append((scope, share, param, value, sup[0], sup[1]))\n    return ret\n\ndef _trunc(s, l):\n    if len(s) < l:\n        return s\n    else:\n        return s[0:l-3] + \'...\'\n\ndef print_issues(issues, prefix = \'\'):\n    """\n    Parse (Using @see: parse_issues) and print an "issues" object\n    in order of severity (error, warning, other)\n    \n    ("issues" generated by method @see: supported_config)\n    """\n    (warn, err, other) = parse_issues(issues, prefix)\n    for e in err:\n        print e\n    for w in warn:\n        print w\n    for o in other:\n        print o\n\ndef parse_issues(issues, prefix = \'\'):\n    """\n    Parses "issues" object into lists of human readable strings sorted by \n    "warnings", "errors", and "others"\n    \n    ("issues" generated by method @see: supported_config) \n    \n    @return tupal - (list, list, list) - Warnings, Errors, Others\n    """\n    warnings = []\n    errors = []\n    others = []\n    for scope, share, param, value, sev, text in issues:\n        tmpstr = ""\n        \n        if scope == GLOBAL:\n            tmpstr += "%sglobal: %s: " % (prefix, sev)\n        else:\n            tmpstr += "%sshare \'%s\': %s: " % (prefix, share, sev)\n        tmpstr += "parameter \'%s\' / value \'%s\': %s" % \\\n                    (param, _trunc(value, 40), text)\n\n        if sev == WARNING:\n            warnings.append(tmpstr)\n        elif sev == ERROR:\n            errors.append(tmpstr)\n        else:\n            others.append(tmpstr)\n\n    return (warnings, errors, others)\n\ndef log_issues(issues, logger):\n    """\n    Parse and write an "issues" object out to default logger. \n    \n    ("issues" generated by method @see: supported_config) \n    """\n    for scope, share, param, value, sev, text in issues:\n        parm_msg = "parameter \'%s\' / value \'%s\': %s" % \\\n                   (param, _trunc(value, 40), text)\n        if scope == GLOBAL:\n            logger.warning("global: %s: %s" % (sev, parm_msg))\n        else:\n            logger.warning("share \'%s\': %s: :%s" % (share, sev, parm_msg))\n\n# __  ____  __ _\n# \\ \\/ /  \\/  | |\n#  \\  /| |\\/| | |\n#  /  \\| |  | | |___\n# /_/\\_\\_|  |_|_____|\n\ndef _db_add_share(db, scope, share):\n    if not db.has_key(scope):\n        db[scope] = {}\n    if not db[scope].has_key(share):\n        db[scope][share] = {}\n\ndef _db_add(db, scope, share, name, value):\n    _db_add_share(db, scope, share)\n\n    db[scope][share][name] = value\n\ndef _db_has_share(db, scope, share):\n    return db.has_key(scope) and db[scope].has_key(share)\n\ndef _parse_isi_datum(db, isi_datum, file, child_func):\n    assert isi_datum.hasAttribute(\'file\') and \\\n           isi_datum.getAttribute(\'file\') == file, \'Corrupt xml, wrong isi-data\'\n    for c in isi_datum.childNodes:\n        if c.nodeType == c.TEXT_NODE:\n            continue\n        child_func(db, c)\n\ndef _parse_isi_data(db, doc, file, child_func):\n    isi_data = doc.getElementsByTagName(\'isi-data\')\n    assert isi_data, \'Corrupt xml, no isi-data\'\n    for isi_datum in isi_data:\n        _parse_isi_datum(db, isi_datum, file, child_func)\n\ndef _parse_fields(db, scope, share, node):\n    fields = node.getElementsByTagName(\'field\')\n    assert fields, \'Corrupt xml, expected field\'\n    for field in fields:\n        assert field.hasAttribute(\'name\')\n        assert field.hasAttribute(\'value\')\n        _db_add(db, scope, share, str(field.getAttribute(\'name\')),\n                str(field.getAttribute(\'value\')))\n\ndef _parse_attribute(db, scope, share, node):\n    assert node.hasAttribute(\'id\'), \'Corrupt xml, modify-attribute has no id\'\n    assert node.hasAttribute(\'value\'), \'Corrupt xml, modify-attribute has no value\'\n\n    _db_add(db, scope, share, str(node.getAttribute(\'id\')),\n            str(node.getAttribute(\'value\')))\n\ndef parse_version(str):\n    return map(lambda x : int(x or 0), str.split(\'.\'))\n\ndef _parse_global_child(db, c):\n    if c.nodeName == \'modify-attribute\':\n        _parse_attribute(db, GLOBAL, None, c)\n    elif c.nodeName == \'add-tag\':\n        assert c.hasAttribute(\'id\'), \'Corrupt xml, add-tag has no id\'\n        if c.getAttribute(\'id\') == \'smbdglobal\':\n            _parse_fields(db, GLOBAL, None, c)\n        elif c.getAttribute(\'id\') == \'smbd1\':\n            v = c.getElementsByTagName(\'version\')\n            if not v:\n                return\n            assert len(v) == 1, \'Corrupt xml, multiple versions\'\n            v = v[0]\n            assert v.hasAttribute(\'value\'), \'Corrupt xml, version has no value\'\n            assert not db.has_key(\'_version\'), \'Corrupt xml, multiple versions\'\n\n            db[\'_version\'] = parse_version(v.getAttribute(\'value\'))\n\ndef parse_global_xml(db, smbd_xml=None):\n    if not smbd_xml:\n        smbd_xml = OVERRIDE_PATH + "/" + SMBD_XML\n\n    _parse_isi_data(db, xml.parse(smbd_xml), \'smbd\', _parse_global_child)\n\n    # Ensure that the version is always represented.\n    # If we couldn\'t find it in the XML, we assume it\'s pre-5.0\n    if not db.has_key(\'_version\'):\n        db[\'_version\'] = VOLD\n\ndef _parse_share(db, share):\n    assert share.hasAttribute(\'name\'), \'Corrupt xml, share has no name\'\n    share_name = str(share.getAttribute(\'name\'))\n    orig_share_name = share_name\n    while _db_has_share(db, SHARE, share_name):\n        share_name = \'+\' + share_name # Add illegal chars until no conflict\n    _parse_fields(db, SHARE, share_name, share)\n    if share_name != orig_share_name:\n        # Conflict, XXX: Handle this somewhere\n        _db_add(db, SHARE, share_name, SHARE_NAME_CONFLICT, orig_share_name)\n\ndef _parse_shares_child(db, c):\n    if c.nodeName == \'add-tag\':\n        if c.getAttribute(\'id\') == \'smbd1\':\n            # Normal share\n            shares = c.getElementsByTagName(\'share\')\n            for share in shares:\n                _parse_share(db, share)\n        elif c.getAttribute(\'id\') == \'ifs1\':\n            # ifs share configuration\n            _parse_fields(db, SHARE, \'ifs\', c)\n    elif c.nodeName == \'modify-attribute\':\n        _parse_attribute(db, SHARE, \'ifs\', c)\n    elif c.nodeName == \'delete-tag\':\n        assert c.hasAttribute(\'id\'), \'Corrupt xml, delete-tag without id\'\n        if c.getAttribute(\'id\') == \'ifs1\':\n            # Handle the ifs del/re-add case\n            if \'+ifs\' in db[SHARE] and \\\n            SHARE_NAME_CONFLICT in db[SHARE][\'+ifs\'] and \\\n            db[SHARE][\'+ifs\'][SHARE_NAME_CONFLICT] == \'ifs\':\n                db[SHARE][\'ifs\'] = db[SHARE].pop(\'+ifs\')\n                del db[SHARE][\'ifs\'][SHARE_NAME_CONFLICT]\n            # And now the simpler ifs del case\n            elif \'ifs\' in db[SHARE]:\n                del db[SHARE][\'ifs\']\n\ndef parse_share_xml(db, smbd_shares_xml=None):\n    # XXX In typical usage, this function doesn\'t appear to be called without\n    # a valid path to smbd_shares_xml. -- aaron.hachez\n    if not smbd_shares_xml:\n        smbd_shares_xml = OVERRIDE_PATH + "/" + SMBD_SHARES_XML\n\n    _db_add_share(db, SHARE, "ifs")\n    _db_add(db, SHARE, "ifs", "path", "/ifs")\n    _parse_isi_data(db, xml.parse(smbd_shares_xml), \'smbd_shares\',\n                    _parse_shares_child)\n\n\n#  _   _                           _        _____             _            \n# | | | |_ __   __ _ _ __ __ _  __| | ___  | ____|_ __   __ _(_)_ __   ___ \n# | | | | \'_ \\ / _` | \'__/ _` |/ _` |/ _ \\ |  _| | \'_ \\ / _` | | \'_ \\ / _ \\\n# | |_| | |_) | (_| | | | (_| | (_| |  __/ | |___| | | | (_| | | | | |  __/\n#  \\___/| .__/ \\__, |_|  \\__,_|\\__,_|\\___| |_____|_| |_|\\__, |_|_| |_|\\___|\n#       |_|    |___/                                    |___/              \n#   ____ _               _               ____  _          __  __ \n#  / ___| |__   ___  ___| | _____ _ __  / ___|| |_ _   _ / _|/ _|\n# | |   | \'_ \\ / _ \\/ __| |/ / _ \\ \'__| \\___ \\| __| | | | |_| |_ \n# | |___| | | |  __/ (__|   <  __/ |     ___) | |_| |_| |  _|  _|\n#  \\____|_| |_|\\___|\\___|_|\\_\\___|_|    |____/ \\__|\\__,_|_| |_|  \n\nclass _checker_SmbCheck:\n    def name(self):\n        """The name returned by this method may be used to filter this \n        particular check from being executed.\n        \n        XXX Filter functionality _not_ fully implemented.\n\n        @return string - The name of this check.\n        """\n        return \'smb_update\'\n\n    def supported_version_ranges(self):\n        """See docstring in _checker_DefaultCheck.supported_version_ranges()"""\n        return [ \n                ([5,5,1], [6,4])\n               ]\n\n    def do_check(self, cluster_info):\n        """\n        The do_check method should return a tuple of (errors,warnings,others)\n        where each of these are a list of strings\n\n        @return tuple of three string lists (errors,warnings,others)\n        """\n\n        import os\n\n        errors = []\n        warnings = []\n        others = []\n\n        path = OVERRIDE_PATH\n\n        if not os.path.exists(path):\n            errors.append("error: path \'%s\' not found" % path)\n            return (errors, warnings, others)\n\n        smbd_xml = os.path.join(path, SMBD_XML)\n        if not os.path.exists(smbd_xml):\n            errors.append("error: \'%s\' not found - "\\\n                "is \'%s\' the right place to find overrides? "\\\n                "(pre-4.7 clusters may not have a %s)" \\\n                % (smbd_xml, path, SMBD_XML))\n            return (errors, warnings, others)\n\n        db = {}\n        try:\n            parse_global_xml(db, smbd_xml)\n        except Exception, e:\n            errors.append("error: failed to parse \'%s\': %s" \\\n                    % (smbd_xml, e))\n            return (errors, warnings, others)\n\n        smbd_shares_xml = os.path.join(path, SMBD_SHARES_XML)\n        if os.path.exists(smbd_shares_xml):\n            parse_share_xml(db, smbd_shares_xml)\n\n        # Per Tim Prouty, version for check hard coded into upgrade script(V6_5)\n        issues = supported_config(db, CURRENT_VERSION)\n        (warnings, errors, others) = parse_issues(issues)\n\n        # XXXJDR to preserve existing behavior, clobber warnings / others\n        warnings = []\n        errors = errors\n        others = []\n\n        # Summary\n        others.append("Found %s issues (override v%s, "\\\n                "verification version %s)" % \\\n                  (len(errors),\n                  version_to_string(db[\'_version\']),\n                  get_version()))\n\n        return (errors, warnings, others)\n\ndef get_checks():\n    return [_checker_SmbCheck()]\n\n\n', 'class _checker_LegacyLdapCheck:\n    def name(self):\n        return \'legacy_ldap_update\'\n\n    def supported_version_ranges(self):\n        return [\n            ([6,0], [7]),\n            ([6,5], [7])\n            ]\n    \n    def do_check(self, cluster_info):\n        import isi.config.mxd as mxd\n        import os\n\n        OVERRIDE_LDAP_XML = "/etc/mcp/override/ldap.xml"\n        LDAP_XML = "/etc/mcp/sys/ldap.xml"\n\n        errors = []\n        warnings = []\n        others = []\n\n        # when upgrading mavericks, disallow legacy LDAP\n        try:\n            ldapdoc = mxd.loadmxd(LDAP_XML, OVERRIDE_LDAP_XML)\n        except mxd.error, e:\n            errors.append("error: possible corruption in file \'%s\' or \'%s\'" \n                          % (LDAP_XML, OVERRIDE_LDAP_XML))\n            return (errors, warnings, others)\n        ldaproot = ldapdoc.getroot()\n        enable = ldaproot.getattributes()[\'enable\']\n        if (int(enable) != 0) :\n            # Legacy LDAP is enabled.\n            errors.append("Legacy LDAP cannot be upgraded. Please migrate all "\n                    "settings under \'Legacy LDAP\' in the WebUI to the \'LDAP\' "\n                    "tab and validate correct LDAP functionality before "\n                    "upgrading.")\n        return (errors, warnings, others)\n\ndef get_checks():\n    return [_checker_LegacyLdapCheck()]\n', '#!/usr/bin/env python\n#\n# Copyright C 2002-2003 by Isilon Systems, Inc. All rights not expressly\n# granted herein are reserved.\n# Created in the United States of America.\n#\n# This digital media is protected by U.S. and international copyright and\n# intellectual property laws. Unless otherwise specified, all information\n# and screens appearing as part of this digital medium, including\n# software, services, documents, text, images, icons, and logos design;\n# the selection, assembly, arrangement, and design thereof; and the code\n# that enables its presentation, are the sole property of Isilon Systems,\n# Inc.\n#\n# Except as otherwise required by applicable law, no part of any\n# copyrighted material may be reproduced, modified, translated,\n# distributed, published, or transmitted by any means, electronic or\n# mechanical, for any purpose, without the prior written consent of Isilon\n# Systems.\n#\n# Isilon and Isilon Systems are registered trademarks of Isilon Systems,\n# Inc.  "Isilon IQ" is a trademark of Isilon Systems, Inc.  All other\n# trademarks and registered trademarks are the property of their\n# respective holders.\n#\n\n# XXX This entire file needs to be syntactically backwards compatible to \n# Python 2.3\n\nequivalence_classes = \\\n[\n    [ # CLASS 1:\n        {\n         "supports cto": False,\n         "chasses":[{"product name": "IQ 6000x"}]\n        },\n        {\n         "supports cto": False,\n         "chasses":[{"product name": "X200-6TB, 6GB RAM, 4x1GE"}]\n        },\n        {\n         "supports cto": False,\n         "chasses":[{"product name": "X200-6TB, 6GB RAM, 2x10GE SFP+ & 2x1GE"}]\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "X200"}],\n         "family code": "X",\n         "chassis code": "2U",\n         "generation code": "00",\n         "supported dram capacity": 6442450944,\n         "supported hdd capacity": 6597069766656,\n         "supported ssd capacity": 0,\n         "supported num hdds": 12,\n         "supported num ssds": 0,\n         "supported num self encrypting drives": 0\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "X201"}],\n         "family code": "X",\n         "chassis code": "2U",\n         "generation code": "01",\n         "supported dram capacity": 6442450944,\n         "supported hdd capacity": 6597069766656,\n         "supported ssd capacity": 0,\n         "supported num hdds": 12,\n         "supported num ssds": 0,\n         "supported num self encrypting drives": 0\n        }\n    ],\n    [ # CLASS 2:\n        {\n         "supports cto": False,\n         "chasses":[{"product name": "IQ 12000x"}]\n        },\n        {\n         "supports cto": False,\n         "chasses":[{"product name": "X200-12TB, 6GB RAM, 4x1GE"}]\n        },\n        {\n         "supports cto": False,\n         "chasses":[{"product name": "X200-12TB, 6GB RAM, 2x10GE SFP+ & 2x1GE"}]\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "X200"}],\n         "family code": "X",\n         "chassis code": "2U",\n         "generation code": "00",\n         "supported dram capacity": 6442450944,\n         "supported hdd capacity": 13194139533312,\n         "supported ssd capacity": 0,\n         "supported num hdds": 12,\n         "supported num ssds": 0,\n         "supported num self encrypting drives": 0\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "X201"}],\n         "family code": "X",\n         "chassis code": "2U",\n         "generation code": "01",\n         "supported dram capacity": 6442450944,\n         "supported hdd capacity": 13194139533312,\n         "supported ssd capacity": 0,\n         "supported num hdds": 12,\n         "supported num ssds": 0,\n         "supported num self encrypting drives": 0\n        }\n    ],\n    [ #CLASS 3:\n        {\n         "supports cto": False,\n         "chasses":[{"product name": "IQ 36000x"}]\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "X400"}],\n         "family code": "X",\n         "chassis code": "4U",\n         "generation code": "00",\n         "supported dram capacity": 25769803776,\n         "supported hdd capacity": 39582418599936,\n         "supported ssd capacity": 0,\n         "supported num hdds": 36,\n         "supported num ssds": 0,\n         "supported num self encrypting drives": 0\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "X401"}],\n         "family code": "X",\n         "chassis code": "4U",\n         "generation code": "01",\n         "supported dram capacity": 25769803776,\n         "supported hdd capacity": 39582418599936,\n         "supported ssd capacity": 0,\n         "supported num hdds": 36,\n         "supported num ssds": 0,\n         "supported num self encrypting drives": 0\n        }\n    ],\n    [ # CLASS 4:\n        {\n         "supports cto": False,\n         "chasses":[{"product name": "IQ 72000x"}]\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "X400"}],\n         "family code": "X",\n         "chassis code": "4U",\n         "generation code": "00",\n         "supported dram capacity": 25769803776,\n         "supported hdd capacity": 79164837199872,\n         "supported ssd capacity": 0,\n         "supported num hdds": 36,\n         "supported num ssds": 0,\n         "supported num self encrypting drives": 0\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "X401"}],\n         "family code": "X",\n         "chassis code": "4U",\n         "generation code": "01",\n         "supported dram capacity": 25769803776,\n         "supported hdd capacity": 79164837199872,\n         "supported ssd capacity": 0,\n         "supported num hdds": 36,\n         "supported num ssds": 0,\n         "supported num self encrypting drives": 0\n        }\n    ],\n    [ # CLASS 5:\n        {\n         "supports cto": False,\n         "chasses":[{"product name": "IQ 32000x-ssd"}]\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "X400"}],\n         "family code": "X",\n         "chassis code": "4U",\n         "generation code": "00",\n         "supported dram capacity": 25769803776,\n         "supported hdd capacity": 35184372088832,\n         "supported ssd capacity": 429496729600,\n         "supported num hdds": 32,\n         "supported num ssds": 4,\n         "supported num self encrypting drives": 0\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "X401"}],\n         "family code": "X",\n         "chassis code": "4U",\n         "generation code": "01",\n         "supported dram capacity": 25769803776,\n         "supported hdd capacity": 35184372088832,\n         "supported ssd capacity": 429496729600,\n         "supported num hdds": 32,\n         "supported num ssds": 4,\n         "supported num self encrypting drives": 0\n        }\n    ],\n    [ #CLASS 6:\n        {\n         "supports cto": False,\n         "chasses":[{"product name": "IQ 36NL"}]\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "NL400"}],\n         "family code": "N",\n         "chassis code": "4U",\n         "generation code": "00",\n         "supported dram capacity": 12884901888,\n         "supported hdd capacity": 39582418599936,\n         "supported ssd capacity": 0,\n         "supported num hdds": 36,\n         "supported num ssds": 0,\n         "supported num self encrypting drives": 0\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "NL401"}],\n         "family code": "N",\n         "chassis code": "4U",\n         "generation code": "01",\n         "supported dram capacity": 12884901888,\n         "supported hdd capacity": 39582418599936,\n         "supported ssd capacity": 0,\n         "supported num hdds": 36,\n         "supported num ssds": 0,\n         "supported num self encrypting drives": 0\n        }\n    ],\n    [ # CLASS 7:\n        {\n         "supports cto": False,\n         "chasses":[{"product name": "IQ 72NL"}]\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "NL400"}],\n         "family code": "N",\n         "chassis code": "4U",\n         "generation code": "00",\n         "supported dram capacity": 12884901888,\n         "supported hdd capacity": 79164837199872,\n         "supported ssd capacity": 0,\n         "supported num hdds": 36,\n         "supported num ssds": 0,\n         "supported num self encrypting drives": 0\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "NL401"}],\n         "family code": "N",\n         "chassis code": "4U",\n         "generation code": "01",\n         "supported dram capacity": 12884901888,\n         "supported hdd capacity": 79164837199872,\n         "supported ssd capacity": 0,\n         "supported num hdds": 36,\n         "supported num ssds": 0,\n         "supported num self encrypting drives": 0\n        }\n    ],\n    [ # CLASS 8:\n        {\n         "supports cto": False,\n         "chasses":[{"product name": "IQ 108NL"}]\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "NL400"}],\n         "family code": "N",\n         "chassis code": "4U",\n         "generation code": "00",\n         "supported dram capacity": 12884901888,\n         "supported hdd capacity": 118747255799808,\n         "supported ssd capacity": 0,\n         "supported num hdds": 36,\n         "supported num ssds": 0,\n         "supported num self encrypting drives": 0\n        },\n        {\n         "supports cto": True,\n         "chasses":[{"product name": "NL401"}],\n         "family code": "N",\n         "chassis code": "4U",\n         "generation code": "01",\n         "supported dram capacity": 12884901888,\n         "supported hdd capacity": 118747255799808,\n         "supported ssd capacity": 0,\n         "supported num hdds": 36,\n         "supported num ssds": 0,\n         "supported num self encrypting drives": 0\n        }\n    ],\n    [ # CLASS 9:\n        {\n         "supports cto": False,\n         "chasses":[{"product name": "S200-14.4TB, 24GB RAM, 4x1GE"}]\n        },\n        {\n         "supports cto": False,\n         "chasses":[{"product name": "S200-14.4TB & 200GB SSD, 24GB RAM, 4x1GE"}]\n        }\n    ]\n]\n\n##\n# This SKU-CTO parsing, normalizing, and comparing code is an ugly hack for\n# 6.5.5 because we do not have HDD, SSD, and DRAM capacity values in the\n# node_info cache for non-CTO nodes AND adding them in a dot release would\n# jeopardize rolling-upgrade compatibility.\n#\n# In Mavericks, this hack wasn\'t removed as to allow code sharing with\n# the pre upgrade check\n# \n\ndef parse_bfwf_sku_product_name(prod_name):\n    """Parse a Blueflame or Wingfoot SKU product name string. An\n    example Wingfoot SKU product name looks like:\n        S200-5.4TB & 600GB SSD, 24GB RAM, 2x10GE SFP+ & 2x1GE\n    Returns a 4-tuple of strings:\n        (series, hdd capacity, ssd capacity, ram).\n\n    """\n    # Split the string at the first comma to get:\n    #    [series and drive info, ram and nic info]\n    series_drives, ram_nics = prod_name.split(",", 1)\n\n    # Split at the dash to separate series and drive info.\n    series, drives = series_drives.split("-")\n\n    # If there\'s an ampersand, we have hdd and ssd info, otherwise\n    # just hdd.\n    if drives.find("&") != -1:\n        hdd, ssd_raw = drives.split("&")\n        ssd = ssd_raw.split()[0]\n    else:\n        hdd = drives\n        ssd = None\n\n    # Split the RAM and NIC info string, but don\'t be adamant about\n    # it since we throw out the network info.\n    ram = ram_nics.split(",")[0].split()[0]\n\n    # Strip extra whitespace and join our gathered parts and return\n    return (series.strip(), hdd.strip(),\n            ssd.strip() if ssd is not None else ssd, ram.strip())\n\ndef _normalize_sku_hdd(hdd_str):\n    # Normalize the SKU HDD capacity. As it appears in the Product\n    # string, the HDD capacity is a shortened form of the output\n    # of humanize_number. Multiplying the shortened form back up to\n    # a terabyte count then re-humanizing gives us a string that matches\n    # the normalized CTO HDD capacity.\n    import isi.app.lib.format as appfmt\n    \n    try:\n        numtb = float(hdd_str[:-2])\n    except (ValueError, TypeError):\n        numtb = 0.0\n\n    return appfmt.humanize_number(numtb * (1<<40), 7, "B",\n            (appfmt.HN_DECIMAL | appfmt.HN_NOSPACE))\n\ndef _normalize_sku_ram(ram_str):\n    # The RAM piece of the SKU Product strings is always in GB.\n    import isi.app.lib.format as appfmt\n    \n    try:\n        numgb = int(ram_str[:-2])\n    except (ValueError, TypeError):\n        numgb = 0\n\n    return appfmt.humanize_number(numgb * (1<<30), 7, "B",\n            (appfmt.HN_DECIMAL | appfmt.HN_NOSPACE))\n\ndef _normalize_sku_ssd(ssd_str):\n    # The SSD piece of the SKU Product strings is always in GB.\n    # This handles a None ssd_str correctly.\n    import isi.app.lib.format as appfmt\n    \n    try:\n        numgb = int(ssd_str[:-2])\n    except (ValueError, TypeError):\n        numgb = 0\n\n    return appfmt.humanize_number(numgb * (1<<30), 7, "B",\n            (appfmt.HN_DECIMAL | appfmt.HN_NOSPACE))\n\ndef _normalize_cto_hdd(hdd):\n    # Use the same call that hal_get_chassis_marketing_name() uses to\n    # format the HDD capacity on CTO nodes.\n    import isi.app.lib.format as appfmt\n    \n    return appfmt.humanize_number(hdd, 7, "B",\n            (appfmt.HN_DECIMAL | appfmt.HN_NOSPACE))\n\ndef _normalize_cto_ssd(ssd):\n    # Use the same call that hal_get_chassis_marketing_name() uses to\n    # format the SSD capacity on CTO nodes.\n    import isi.app.lib.format as appfmt\n    \n    return appfmt.humanize_number(ssd, 7, "B",\n            (appfmt.HN_DECIMAL | appfmt.HN_NOSPACE))\n\ndef _normalize_cto_ram(ram):\n    # Use the same call that hal_get_chassis_marketing_name() uses to\n    # format the RAM capacity on CTO nodes.\n    import isi.app.lib.format as appfmt\n    return appfmt.humanize_number(ram, 7, "B",\n            (appfmt.HN_DECIMAL | appfmt.HN_NOSPACE))\n            \ndef normalize_capabilities(ni):\n\n    if ni.get("supports cto", False):\n        hdd_norm = _normalize_cto_hdd(ni["supported hdd capacity"])\n        ssd_norm = _normalize_cto_ssd(ni["supported ssd capacity"])\n        ram_norm = _normalize_cto_ram(ni["supported dram capacity"])\n    else:\n        \n        (sku_series, sku_hdd, sku_ssd, sku_ram) = \\\n                parse_bfwf_sku_product_name(\n                ni.get("chasses")[0]["product name"])\n\n        hdd_norm = _normalize_sku_hdd(sku_hdd)\n        ssd_norm = _normalize_sku_ssd(sku_ssd)\n        ram_norm = _normalize_sku_ram(sku_ram)\n\n    supported_num_seds = ni.get(\'supported num self encrypting drives\', 0)\n    return (hdd_norm, ssd_norm, ram_norm, supported_num_seds)\n\n\ndef wingfoot_blueflame_capabilities_match(ni1, ni2):\n    # this API should only be used when at least one node is a non-CTO nodes\n    if ni1.get("supports cto", False) and ni2.get("supports cto", False):\n        return False\n\n    ni1_prod_name = ni1.get("chasses")[0]["product name"]\n    ni2_prod_name = ni2.get("chasses")[0]["product name"]\n\n    # If one or the other isn\'t a Blueflame or Wingfoot, the two nodes are\n    # definitely not equivalent.\n    if (ni1_prod_name[:4] not in ["X200", "S200"] or\n            ni2_prod_name[:4] not in ["X200", "S200"]):\n        return False\n\n    # If one is a Blueflame and one is a Wingfoot, the two nodes are\n    # definitely not equivalent.\n    if ni1_prod_name[:4] != ni2_prod_name[:4]:\n        return False\n\n    # Parse the BF/WF SKU product string\n    # pylint: disable=W0612\n    return normalize_capabilities(ni1) == normalize_capabilities(ni2)\n\n# There are enough drive SBB combinations that we \'could\' have a case where the \n# supported hdd/ssd capacity can match for different ratios of hdd to ssd, thus\n# we have to also compare the number of ssds to hdds as well.\ndef cto_tuple(ni):\n    num_hdds = ni.get("supported num hdds", 0)\n    num_ssds = ni.get("supported num ssds", 0)\n    num_seds = ni.get("supported num self encrypting drives", 0)\n    return tuple([ni["family code"],\n            ni["chassis code"],\n            ni["generation code"],\n            ni["supported dram capacity"],\n            ni["supported hdd capacity"],\n            ni["supported ssd capacity"],\n            num_hdds,\n            num_ssds,\n            num_seds])\n\ndef node_infos_same_type(ni1, ni2):\n    if ni1.get("supports cto", False) != ni2.get("supports cto", False):\n        return False\n    if ni1.get("supports cto", False):\n        # XXX Don\'t consider num hdds or ssds if we\'re a version that 6.5.5 can\n        # directly upgrade to (Jaws and before) because the 6.5.5 libraries\n        # won\'t report the right values when doing pre-upgrade checks.  Do not\n        # port this change past Jaws.\n        ni1_tuple = cto_tuple(ni1)\n        ni1_tuple = ni1_tuple[:6] + ni1_tuple[8:]\n        ni2_tuple = cto_tuple(ni2)\n        ni2_tuple = ni2_tuple[:6] + ni2_tuple[8:]\n\n        return ni1_tuple == ni2_tuple\n    else:\n        \n        if len(ni1["chasses"]) == len(ni2["chasses"]):\n            for idx, chas1 in enumerate(ni1["chasses"]):\n                chas2 = ni2["chasses"][idx]\n                if chas1["product name"] != chas2["product name"]:\n                    return False\n            return True\n        return False\n\ndef node_info_in_class(ni, klass):\n    for class_ni in klass:\n       if node_infos_same_type(ni, class_ni):\n           return True\n    return False\n\ndef node_infos_eq(ni1, ni2):\n    # This function is used both by the provisioning system to \n    # decide which node pool to put new nodes in, as well as\n    # the pre upgrade check that ensures a smooth upgrade between\n    # SmartPools v1 and Smartpools v2.\n    if node_infos_same_type(ni1, ni2):\n        return True\n    if wingfoot_blueflame_capabilities_match(ni1, ni2):\n        return True\n    for klass in equivalence_classes:\n        if node_info_in_class(ni1, klass):\n            return node_info_in_class(ni2, klass)\n    return False\n\ndef get_map_and_disk_pools():\n    # Returns a list of list of devids representing diskpools, along\n    # with a devid to lin map. \n    # XXX This function WILL NOT work on 7.0 or higher.  It is exclusively\n    # for use by 6.x via the pre-upgade check system.\n    import isi.fs.diskpool as fsdp\n    token, dps = fsdp.read_db()\n    if not dps:\n        return None, []\n    import isi.config.arrcfg as arrcfg\n    arr_conf = arrcfg.config_load()\n    devid_to_lnn_map = fsdp.get_devid_to_lnn_map(arr_conf)\n    lnn_to_devid_map = fsdp.get_lnn_to_devid_map(arr_conf)\n    \n    dps_as_devid_lists = []\n    for dp in dps:\n        nodes_as_devids = map(lambda lnn: lnn_to_devid_map[lnn], dp.nodes)\n        dps_as_devid_lists.append(nodes_as_devids)\n    return devid_to_lnn_map, dps_as_devid_lists\n\ndef get_devid_to_info_map(cluster_info):\n    devid_to_info = {}\n    for node_info in cluster_info["nodes"]:\n        devid_to_info[node_info["devid"]] = node_info\n    return devid_to_info\n\nclass _checker_CheckDiskpoolsMembership:\n    def supported_version_ranges(self):\n        return [([6], [6])] # This is just an odd way of saying all of v6.x\n    \n    def name(self):\n        return "CheckDiskpoolsMembership"\n\n    def do_check(self, cluster_info, dps=None):\n        # Note, this check needs to be runnable on all (and only) OneFS 6.x \n        # versions. This check verifies that all nodes are exactly segregated\n        # into diskpools by equivalency type.\n        errors = []\n        if dps is None:\n            devid_to_lnn_map, dps = get_map_and_disk_pools()\n        devid_to_info = get_devid_to_info_map(cluster_info)\n        for dp1 in dps:\n            for devid1 in dp1:\n                for dp2 in dps:\n                    for devid2 in dp2:\n                        if devid1 > devid2:\n                            # Only consider a given pair once\n                            continue\n                        if dp1 is dp2:\n                            if not node_infos_eq(devid_to_info[devid1],\n                                    devid_to_info[devid2]):\n                                errors.append("Nodes %d and %d are not of "\n                                        "equivalent type, and need to be in"\n                                        " different diskpools" % \n                                        (devid_to_lnn_map[devid1], \n                                        devid_to_lnn_map[devid2]))\n                                    \n                        else:\n                            if node_infos_eq(devid_to_info[devid1],\n                                    devid_to_info[devid2]):\n                                errors.append("Nodes %d and %d are of "\n                                        "equivalent type, and need to be in "\n                                        "the same diskpool" % \n                                        (devid_to_lnn_map[devid1], \n                                        devid_to_lnn_map[devid2]))\n        return (errors, [], [])\n\nclass _checker_CheckGNA:\n    def __init__(self, active=None, total=None, ssd=None):\n        # Some overridable variables for testing purposes\n        self._active = active\n        self._total = total\n        self._ssd = ssd\n\n    def active(self):\n        import isi.misc\n        return (self._active if self._active is not None else \n                isi.misc.sysctlbyname("efs.bam.layout.ssd.gna_active"))\n\n    def total(self):\n        import os\n        return (self._total if self._total is not None else \n                os.statvfs("/ifs").f_blocks)\n\n    def ssd(self):\n        import isi.misc\n        return (self._ssd if self._ssd is not None else \n                isi.misc.sysctlbyname("efs.bam.layout.ssd.total_ssd_blocks"))\n\n    def supported_version_ranges(self):\n        return [([6, 5, 1], [6])] # That is, all of 6.x greater than 6.5.1\n\n    def name(self):\n        return "CheckGNA"\n\n    def do_check(self, cluster_info):\n        errors = []\n\n        if self.active():\n            total_blocks = self.total()\n            ssd_blocks = self.ssd()\n\n            ssd_pmil = ssd_blocks * 1000 / total_blocks\n\n            if ssd_pmil < 15:\n                errors.append("Upgrade would deactivate Global Namespace "\n                        "Acceleration, as ssd storage is at %0.1f%% of total "\n                        "storage, which is below the new minimum of 1.5%%.  "\n                        "Either disable GNA, or call Isilon support.  "\n                        "Important: do NOT bypass this check "\n                        "if you are also failing the CheckDiskpoolsMembership "\n                        "check or any other upgrade check."\n                        % (ssd_pmil/10.0))\n        return (errors, [], [])\n\nclass _checker_CheckIFSVAR:\n    def supported_version_ranges(self):\n        return [([6], [6])] # This is just an odd way of saying all of v6.x\n\n    def name(self):\n        return "CheckIFSVAR"\n\n    def do_check(self, cluster_info):\n        import subprocess\n\n        errors = []\n        isi_get_proc = subprocess.Popen(["isi get -Dd /ifs/.ifsvar"],\n                                        shell=True, stdout=subprocess.PIPE)\n        text = isi_get_proc.stdout.read()\n\n        generic_error = "Please call Isilon support and reference emc314343 " +\\\n                        "for instructions."\n        if text.find(\'*  Disk pools:         policy system : any ->\') == -1:\n            errors.append("The disk pool policy for the .ifsvar directory "\n                          "is not configured correctly. " + generic_error)\n\n        if text.find(\'NEW FILE ATTRIBUTES\') != -1:\n            if text.find(\'*  Disk pools:         policy system:any\\n\') == -1:\n                errors.append("The disk pool policy for nfattrs on the .ifsvar "\n                              "directory is not configured correctly" \\\n                              + generic_error)\n\n        return (errors, [], [])\n    \ndef get_checks():\n    return [_checker_CheckDiskpoolsMembership(), _checker_CheckGNA(),\n            _checker_CheckIFSVAR()]\n']
