def test_arch_no_exclude(self):
     '''Verify arch query string with no exclude option'''
     criteria = "arch"
     queue = self.files.database.getQueue()
     AIdb.getSpecificCriteria(queue, criteria)
     expect_query = "SELECT arch FROM manifests WHERE arch IS NOT NULL"
     self.assertEquals(expect_query, self.mockquery.query)
Ejemplo n.º 2
0
 def test_no_match_fqhn_value(self):
     ''' Test that we don't match a hostname with fqhn in the list'''
     value = "foo"
     value_list = "bar foo.com bum"
     matched = AIdb.match_hostname(value, value_list, 1)
     self.assertFalse(AIdb.match_hostname(value, value_list, 0))
     self.assertEqual(len(matched), 0)
Ejemplo n.º 3
0
 def test_mem_formatValue(self):
     '''Ensure that memory criteria is formatted appropriately'''
     fmt = AIdb.formatValue('MINmem', self.mem)
     self.assertEqual(fmt.split(' ')[0], self.mem)
     self.assertEqual(fmt.split(' ')[1], 'MB')
     fmt = AIdb.formatValue('MINmem', self.mem, units=False)
     self.assertEqual(fmt, self.mem)
def check_published_manifest(service, dbn, manifest_name):
    """
    Used for checking that a manifest is already published in the
    install service specified.  Checks to make sure manifest
    exists in the install service's DB, and that the manifest also
    exists in the install service's published files area.
    Args:
          service - service object for service
          dbn - dbn object of install service to check against.
          manifest_name - name of manifest to check.
    Postconditions: None
    Returns: True if manifest exists in install service
             False if manifest does not exist.
    """

    # Check if manifest exists in the service's criteria DB.
    if AIdb.sanitizeSQL(manifest_name) not in AIdb.getManNames(dbn.getQueue()):
        print(_("Error: install service does not contain the specified "
                "manifest: %s") % manifest_name)
        return False

    # Check if manifest file exists in the service's published area.
    published_path = os.path.join(service.manifest_dir, manifest_name)

    if not os.path.exists(published_path):
        print(_("Error: manifest missing from published area: %s") %
                published_path)
        return False

    return True
Ejemplo n.º 5
0
 def test_match_fqhn_value(self):
     ''' Test that we match a fqhn value '''
     value = "foo.com"
     value_list = "foo bar bum"
     matched = AIdb.match_hostname(value, value_list, 1)
     self.assertTrue(AIdb.match_hostname(value, value_list, 0))
     self.assertEqual(matched, "foo")
 def test_mem_formatValue(self):
     '''Ensure that memory criteria is formatted appropriately'''
     fmt = AIdb.formatValue('MINmem', self.mem)
     self.assertEqual(fmt.split(' ')[0], self.mem)
     self.assertEqual(fmt.split(' ')[1], 'MB')
     fmt = AIdb.formatValue('MINmem', self.mem, units=False)
     self.assertEqual(fmt, self.mem)
Ejemplo n.º 7
0
 def test_arch_no_exclude(self):
     '''Verify arch query string with no exclude option'''
     criteria = "arch"
     queue = self.files.database.getQueue()
     AIdb.getSpecificCriteria(queue, criteria)
     expect_query = "SELECT arch FROM manifests WHERE arch IS NOT NULL"
     self.assertEquals(expect_query, self.mockquery.query)
Ejemplo n.º 8
0
def validate_internal(profile_list, database, table, image_dir):
    ''' given a list of profile files and the profile database and table,
        validate the list of profiles
    Args:
        profile_list - list of profile path names
        database - name of database
        table - name of database table
        image_dir - path of service image, used to locate service_bundle
    Returns True if all profiles are valid, return False if any are invalid
    '''
    # Open the database
    dbn = AIdb.DB(database, commit=True)
    dbn.verifyDBStructure()
    isvalid = True
    queue = dbn.getQueue()
    if not profile_list:
        profile_list = [None]
    for profile in profile_list:
        qstr = "SELECT name, file FROM %s WHERE name = %s" % \
                (table, AIdb.format_value('name', profile))
        query = AIdb.DBrequest(qstr, commit=True)
        queue.put(query)
        query.waitAns()
        # check response, if failure, getResponse prints error
        if query.getResponse() is None:  # database error
            return False  # give up
        if len(query.getResponse()) == 0:
            print >> sys.stderr, \
                    _('No profiles in database with basename ') + profile
            isvalid = False
            continue  # to the next profile
        for response in query.getResponse():
            if not df.validate_file(response[0], response[1], image_dir):
                isvalid = False
    return isvalid
def delete_profiles(profs, dbo, table):
    ''' deletes all database entries matching user's command line options
    Args:
        profs - list of profiles to delete by name
        dbo - database object
        table - database table name
    Returns: True if any errors encountered, False otherwise
    Exceptions: none
    '''
    # if any serious errors encountered, set exit status
    has_errors = False
    queue = dbo.getQueue()
    # Build a list of criteria for WHERE clause
    db_cols = [u'rowid'] + [u'file']
    # loop through all profiles from command line and delete them
    for profile_name in profs:
        query_str = "SELECT " + ", ".join(db_cols) + " FROM " + table + \
                " WHERE name=" + AIdb.format_value('name', profile_name)
        logging.debug("query=" + query_str)
        query = AIdb.DBrequest(query_str, commit=True)
        queue.put(query)
        query.waitAns()
        # check response, if failure, getResponse prints error
        rsp = query.getResponse()
        if rsp is None:
            has_errors = True
            continue
        if len(rsp) == 0:
            print >> sys.stderr, _("\tProfile %s not found.") % profile_name
            has_errors = True
            continue
        # delete database record and any accompanying internal profile file
        for response in rsp:
            deldict = dict()
            iresponse = iter(response)
            for crit in db_cols:
                deldict[crit] = next(iresponse)
            query_str = "DELETE FROM %s WHERE rowid=%d" % \
                    (table, deldict['rowid'])
            delquery = AIdb.DBrequest(query_str, commit=True)
            queue.put(delquery)
            delquery.waitAns()
            # check response, if failure, getResponse prints error
            if delquery.getResponse() is None:
                has_errors = True
                continue
            print >> sys.stderr, _("\tDeleted profile %s.") % profile_name
            # delete static (internal) files only
            if deldict['file'] is None or \
                not deldict['file'].startswith(sc.INTERNAL_PROFILE_DIRECTORY):
                continue
            try:
                os.unlink(deldict['file'])
            except OSError, (errno, errmsg):
                if errno != ENOENT:  # does not exist
                    print >> sys.stderr, _(
                            "Error (%s):  Problem deleting %s (%s): %s") \
                            % (errno, profile_name, deldict['file'], errmsg)
                has_errors = True
                continue
Ejemplo n.º 10
0
def check_published_manifest(service, dbn, manifest_name):
    """
    Used for checking that a manifest is already published in the
    install service specified.  Checks to make sure manifest
    exists in the install service's DB, and that the manifest also
    exists in the install service's published files area.
    Args:
          service - service object for service
          dbn - dbn object of install service to check against.
          manifest_name - name of manifest to check.
    Postconditions: None
    Returns: True if manifest exists in install service
             False if manifest does not exist.
    """

    # Check if manifest exists in the service's criteria DB.
    if AIdb.sanitizeSQL(manifest_name) not in AIdb.getManNames(dbn.getQueue()):
        print(
            _("Error: install service does not contain the specified "
              "manifest: %s") % manifest_name)
        return False

    # Check if manifest file exists in the service's published area.
    published_path = os.path.join(service.manifest_dir, manifest_name)

    if not os.path.exists(published_path):
        print(
            _("Error: manifest missing from published area: %s") %
            published_path)
        return False

    return True
Ejemplo n.º 11
0
 def test_MAXipv4(self):
     '''Verify single MAX query string '''
     criteria = "MAXipv4"
     queue = self.files.database.getQueue()
     AIdb.getSpecificCriteria(queue, criteria)
     expect_query = "SELECT MAXipv4 FROM manifests WHERE MAXipv4 IS " + \
                    "NOT NULL"
     self.assertEquals(expect_query, self.mockquery.query)
 def test_MAXipv4(self):
     '''Verify single MAX query string '''
     criteria = "MAXipv4"
     queue = self.files.database.getQueue()
     AIdb.getSpecificCriteria(queue, criteria)
     expect_query = "SELECT MAXipv4 FROM manifests WHERE MAXipv4 IS " + \
                    "NOT NULL"
     self.assertEquals(expect_query, self.mockquery.query)
 def test_arch_exclude(self):
     '''Verify arch query string with exclude option'''
     criteria = "arch"
     queue = self.files.database.getQueue()
     AIdb.getSpecificCriteria(queue, criteria, excludeManifests=["suexml"])
     expect_query = "SELECT arch FROM manifests WHERE arch IS NOT NULL " + \
                    "AND name IS NOT 'suexml'"
     self.assertEquals(expect_query, self.mockquery.query)
Ejemplo n.º 14
0
 def test_arch_exclude(self):
     '''Verify arch query string with exclude option'''
     criteria = "arch"
     queue = self.files.database.getQueue()
     AIdb.getSpecificCriteria(queue, criteria, excludeManifests=["suexml"])
     expect_query = "SELECT arch FROM manifests WHERE arch IS NOT NULL " + \
                    "AND name IS NOT 'suexml'"
     self.assertEquals(expect_query, self.mockquery.query)
Ejemplo n.º 15
0
 def test_other_formatValue(self):
     '''Ensure that formatValue does nothing with all other criteria'''
     fmt = AIdb.formatValue('arch', self.arch)
     self.assertEqual(fmt, self.arch)
     fmt = AIdb.formatValue('platform', self.platform)
     self.assertEqual(fmt, self.platform)
     fmt = AIdb.formatValue('cpu', self.cpu)
     self.assertEqual(fmt, self.cpu)
 def test_other_formatValue(self):
     '''Ensure that formatValue does nothing with all other criteria'''
     fmt = AIdb.formatValue('arch', self.arch)
     self.assertEqual(fmt, self.arch)
     fmt = AIdb.formatValue('platform', self.platform)
     self.assertEqual(fmt, self.platform)
     fmt = AIdb.formatValue('cpu', self.cpu)
     self.assertEqual(fmt, self.cpu)
Ejemplo n.º 17
0
 def test_MIN_MAXmem(self):
     '''Verify mem range query string '''
     criteria = "MINmem"
     criteria2 = "MAXmem"
     queue = self.files.database.getQueue()
     AIdb.getSpecificCriteria(queue, criteria, criteria2=criteria2)
     expect_query = "SELECT MINmem, MAXmem FROM manifests WHERE " + \
                    "(MINmem IS NOT NULL OR MAXmem IS NOT NULL)"
     self.assertEquals(expect_query, self.mockquery.query)
Ejemplo n.º 18
0
 def test_MIN_MAXmac(self):
     '''Verify mac range query string '''
     criteria = "MINmac"
     criteria2 = "MAXmac"
     queue = self.files.database.getQueue()
     AIdb.getSpecificCriteria(queue, criteria, criteria2=criteria2)
     expect_query = "SELECT HEX(MINmac), HEX(MAXmac) FROM manifests " + \
                    "WHERE (MINmac IS NOT NULL OR MAXmac IS NOT NULL)"
     self.assertEquals(expect_query, self.mockquery.query)
 def test_MIN_MAXmem(self):
     '''Verify mem range query string '''
     criteria = "MINmem"
     criteria2 = "MAXmem"
     queue = self.files.database.getQueue()
     AIdb.getSpecificCriteria(queue, criteria, criteria2=criteria2)
     expect_query = "SELECT MINmem, MAXmem FROM manifests WHERE " + \
                    "(MINmem IS NOT NULL OR MAXmem IS NOT NULL)"
     self.assertEquals(expect_query, self.mockquery.query)
 def test_MIN_MAXmac(self):
     '''Verify mac range query string '''
     criteria = "MINmac"
     criteria2 = "MAXmac"
     queue = self.files.database.getQueue()
     AIdb.getSpecificCriteria(queue, criteria, criteria2=criteria2)
     expect_query = "SELECT HEX(MINmac), HEX(MAXmac) FROM manifests " + \
                    "WHERE (MINmac IS NOT NULL OR MAXmac IS NOT NULL)"
     self.assertEquals(expect_query, self.mockquery.query)
Ejemplo n.º 21
0
def send_needed_criteria(port):
    '''Replies to the old client with the needed criteria

    Args
        port - the originating port for the old client

    Returns
        None

    Raises
        None
    
    '''
    # Establish the service SQL database based upon the
    # port number for the service
    path = os.path.join(com.AI_SERVICE_DIR_PATH, str(port), 'AI.db')
    if os.path.exists(path):
        try:
            aisql = AIdb.DB(path)
            aisql.verifyDBStructure()
        except StandardError as err:
            # internal error, record the error in the server error_log
            sys.stderr.write(_('error:AI database access error\n%s\n') % err)
            # report the error to the requesting client
            print "Content-Type: text/html"  # HTML is following
            print  # blank line, end of headers
            sys.stdout.write(_("error:AI database access error\n%s\n") % err)
            sys.exit(1)
    else:
        # not an internal error, report to the requesting client only
        print "Content-Type: text/html"  # HTML is following
        print  # blank line, end of headers
        print _("Error:unable to determine criteria "
                "for service associated with port"), port
        return

    # build the required criteria list
    xml = lxml.etree.Element("CriteriaList")
    # old version number
    version_value = lxml.etree.Element("Version")
    version_value.attrib["Number"] = COMPATIBILITY_VERSION
    xml.append(version_value)
    # pull the required criteria from the SQL database
    for crit in AIdb.getCriteria(aisql.getQueue(), strip=True):
        tag = lxml.etree.Element("Criteria")
        tag.attrib["Name"] = crit
        xml.append(tag)
    xmlstr = lxml.etree.tostring(xml, pretty_print=True)

    # report the results
    print "Content-Length:", len(xmlstr)  # Length of XML reply
    print "Content-Type: text/xml"  # XML is following
    print  # blank line, end of headers
    print xmlstr
Ejemplo n.º 22
0
def is_name_in_table(name, queue, table):
    ''' Determine if profile already registered for service and same basename
    Args:
        name - profile name
        queue - database queue for profiles
        table - profile table name
    Returns True if any records are found, False if no records found
    '''
    query_str = "SELECT * FROM %s WHERE name='%s'" % \
        (table, AIdb.sanitizeSQL(name))
    query = AIdb.DBrequest(query_str)
    queue.put(query)
    query.waitAns()
    return len(query.getResponse()) > 0
Ejemplo n.º 23
0
def do_export_profile(options):
    '''
    Export a profile.
    '''
    save_errno = 0

    # Open the database
    aisql = AIdb.DB(options.service.database_path, commit=True)
    aisql.verifyDBStructure()

    queue = aisql.getQueue()
    for pname in options.pnames:
        # sanitize and format for SELECT
        fmtname = AIdb.format_value('name', pname)
        q_str = "SELECT file FROM  " + AIdb.PROFILES_TABLE + \
                " WHERE name=" + fmtname
        query = AIdb.DBrequest(q_str)
        queue.put(query)
        query.waitAns()
        # check response, if failure, getResponse prints error
        if query.getResponse() is None:
            continue
        if len(query.getResponse()) == 0:
            print >> sys.stderr, _("Profile %s not found.") % fmtname
            continue
        for row in query.getResponse():
            profpath = row['file']

            if options.output_isdir:
                output_name = "/".join([options.output_name, pname])
            else:
                output_name = options.output_name

            if output_name == SCREEN and options.file_count > 1:
                display_file_header(_("profile: ") + pname)

            try:
                shutil.copyfile(profpath, output_name)
            except IOError as err:
                print >> sys.stderr, _(
                    "Error exporting profile: "
                    "%(error)s: %(file)s") % ({
                        "error": err.strerror,
                        "file": err.filename
                    })
                save_errno = err.errno
            print
    return save_errno
def delete_profiles(profs, dbo, table):
    ''' deletes all database entries matching user's command line options
    Args:
        profs - list of profiles to delete by name
        dbo - database object
        table - database table name
    Returns: True if any errors encountered, False otherwise
    Exceptions: none
    '''
    # if any serious errors encountered, set exit status
    has_errors = False
    queue = dbo.getQueue()
    # Build a list of criteria for WHERE clause
    db_cols = [u'rowid'] + [u'file']
    # loop through all profiles from command line and delete them
    for profile_name in profs:
        query_str = "SELECT " + ", ".join(db_cols) + " FROM " + table + \
                " WHERE name=" + AIdb.format_value('name', profile_name)
        logging.debug("query=" + query_str)
        query = AIdb.DBrequest(query_str, commit=True)
        queue.put(query)
        query.waitAns()
        # check response, if failure, getResponse prints error
        rsp = query.getResponse()
        if rsp is None:
            has_errors = True
            continue
        if len(rsp) == 0:
            print >> sys.stderr, _("\tProfile %s not found.") % profile_name
            has_errors = True
            continue
        # delete database record and any accompanying internal profile file
        for response in rsp:
            deldict = dict()
            iresponse = iter(response)
            for crit in db_cols:
                deldict[crit] = next(iresponse)
            query_str = "DELETE FROM %s WHERE rowid=%d" % \
                    (table, deldict['rowid'])
            delquery = AIdb.DBrequest(query_str, commit=True)
            queue.put(delquery)
            delquery.waitAns()
            # check response, if failure, getResponse prints error
            if delquery.getResponse() is None:
                has_errors = True
                continue
            print >> sys.stderr, _("\tDeleted profile %s.") % profile_name
            # delete static (internal) files only
            if deldict['file'] is None or \
                not deldict['file'].startswith(sc.INTERNAL_PROFILE_DIRECTORY):
                continue
            try:
                os.unlink(deldict['file'])
            except OSError, (errno, errmsg):
                if errno != ENOENT:  # does not exist
                    print >> sys.stderr, _(
                            "Error (%s):  Problem deleting %s (%s): %s") \
                            % (errno, profile_name, deldict['file'], errmsg)
                has_errors = True
                continue
Ejemplo n.º 25
0
def remove_client_dhcp_config(client_id):
    '''
    If a local DHCP server is running, remove any client configuration for
    this client from its configuration. If not, inform end-user that the
    client-service binding should no longer be referenced in the DHCP
    configuration.
    '''
    server = dhcp.DHCPServer()
    if server.is_configured():
        # A local DHCP server is configured. Check for a host entry and remove
        # it if found.
        mac_address = client_id[2:]
        mac_address = AIdb.formatValue('mac', mac_address)
        if server.host_is_configured(mac_address):
            print cw(
                _("Removing host entry '%s' from local DHCP "
                  "configuration.") % mac_address)
            server.remove_host(mac_address)

            if server.is_online():
                try:
                    server.control('restart')
                except dhcp.DHCPServerError as err:
                    print >> sys.stderr, cw(
                        _("Unable to restart the DHCP "
                          "SMF service: %s" % err))
                    return
    else:
        # No local DHCP configuration, inform user that it needs to be
        # unconfigured elsewhere.
        print cw(
            _("No local DHCP configuration found. Unless it will be "
              "reused, the bootfile '%s' may be removed from the DHCP "
              "configuration\n" % client_id))
Ejemplo n.º 26
0
    def __init__(self, sname):
        '''
        Reads profile names associated with this service from database,
        creates objects for them and stores these objects into instance
        attributes
        '''
        ServicePrintObject.__init__(self, sname)

        self.profiles = list()
        self.max_profman_len = 0
        self.max_crit_len = 0

        try:
            # Read all profiles for this service
            for name in AIdb.getNames(self.aiqueue, AIdb.PROFILES_TABLE):
                # Record the longest profile name
                if self.max_profman_len < len(name):
                    self.max_profman_len = len(name)
                profile = ProfilePrintObject(self.aiqueue, name)
                # Record the longest criteria in this service
                if profile.get_max_crit_len() > self.max_crit_len:
                    self.max_crit_len = profile.get_max_crit_len()
                self.profiles.append(profile)

        except StandardError as err:
            sys.stderr.write(_('Error: AI database access error\n%s\n') % err)
            raise
Ejemplo n.º 27
0
 def __init__(self, data_loc):
     self.base_dir = data_loc
     if os.path.exists(os.path.join(self.base_dir, 'AI.db')):
         self.AISQL = AIdb.DB(os.path.join(self.base_dir, 'AI.db'))
     else:
         raise SystemExit(_("Error:\tNo AI.db database"))
     self.AISQL.verifyDBStructure()
Ejemplo n.º 28
0
 def test_building_query_str(self):
     ''' test that we get reasonable query str '''
     cri_list = ['MINipv4', 'MAXipv4', 'arch', 'cpu', 'platform',
               'MINmac', 'MAXmac', 'MINmem', 'MAXmem',
               'MINnetwork', 'MAXnetwork']
     # Artificially small list to test filter functionality.
     all_cri_list = ['arch']
     my_crit_dict = {
                     'ipv4': '020025224125',
                     'arch': 'i86pc',
                     'platform': 'myplatform',
                     'cpu': 'i386',
                     'network': '010000002000',
                     'mem': '2048',
                     'mac': 'aabbccddeeff'
                    }
     query_str = AIdb.build_query_str(my_crit_dict, cri_list, all_cri_list)
     self.assertTrue(query_str.startswith("SELECT name"))
     self.assertTrue("FROM manifests WHERE " in query_str)
     self.assertTrue("MAXmem >= 2048 OR MAXmem IS NULL" in query_str)
     self.assertTrue("MINmem <= 2048 OR MINmem IS NULL" in query_str)
     self.assertTrue("MAXipv4 >= 020025224125" in query_str)
     self.assertTrue("MINipv4 <= 020025224125" in query_str)
     self.assertTrue("MAXnetwork >= 010000002000" in query_str)
     self.assertTrue("MINnetwork <= 010000002000" in query_str)
     self.assertTrue("HEX(MINmac) <= HEX(x'aabbccddeeff'" in query_str)
     self.assertTrue("HEX(MAXmac) >= HEX(x'aabbccddeeff'" in query_str)
     self.assertTrue("is_in_list('arch', 'i86pc', arch, 'None')" \
         in query_str)
     self.assertTrue("is_in_list('platform', 'myplatform', platform, " +
         "'None')" in query_str)
     self.assertTrue("NOT ((arch IS NULL)" in query_str)
     self.assertFalse("(cpu IS NULL)" in query_str)
     self.assertTrue(query_str.endswith("LIMIT 1"))
Ejemplo n.º 29
0
def do_delete_profile(cmd_options=None):
    ''' external entry point for installadm
    Arg: cmd_options - command line options
    Effect: delete profiles per command line
    '''
    # check for authorization and euid
    try:
        check_auth_and_euid(PROFILE_AUTH)
    except UnauthorizedUserError as err:
        raise SystemExit(err)

    options = parse_options(cmd_options)

    # get AI service directory, database name
    service = AIService(options.service_name)
    dbname = service.database_path

    # Open the database
    aisql = AIdb.DB(dbname, commit=True)
    aisql.verifyDBStructure()

    # delete profiles per command line
    errs = delete_profiles(options.profile_name, aisql, AIdb.PROFILES_TABLE)
    if errs:
        sys.exit(1)
def validate_internal(profile_list, database, table, image_dir):
    ''' given a list of profile files and the profile database and table,
        validate the list of profiles
    Args:
        profile_list - list of profile path names
        database - name of database
        table - name of database table
        image_dir - path of service image, used to locate service_bundle
    Returns True if all profiles are valid, return False if any are invalid
    '''
    # Open the database
    dbn = AIdb.DB(database, commit=True)
    dbn.verifyDBStructure()
    isvalid = True
    queue = dbn.getQueue()
    if not profile_list:
        profile_list = [None]
    for profile in profile_list:
        qstr = "SELECT name, file FROM %s WHERE name = %s" % \
                (table, AIdb.format_value('name', profile))
        query = AIdb.DBrequest(qstr, commit=True)
        queue.put(query)
        query.waitAns()
        # check response, if failure, getResponse prints error
        if query.getResponse() is None:  # database error
            return False  # give up
        if len(query.getResponse()) == 0:
            print >> sys.stderr, \
                    _('No profiles in database with basename ') + profile
            isvalid = False
            continue  # to the next profile
        for response in query.getResponse():
            if not df.validate_file(response[0], response[1], image_dir):
                isvalid = False
    return isvalid
Ejemplo n.º 31
0
    def __init__(self, sname):
        '''
        Opens database for given service and sets database request queue
        '''
        self.name = sname
        try:
            self.service = AIService(sname)

        except VersionError as err:
            warn_version(err)
            raise

        path = self.service.database_path

        if os.path.exists(path):
            try:
                maisql = AIdb.DB(path)
                maisql.verifyDBStructure()
                self.aiqueue = maisql.getQueue()

            except StandardError as err:
                sys.stderr.write(
                    _('Error: AI database access error\n%s\n') % err)
                raise
        else:
            sys.stderr.write(
                _('Error: unable to locate AI database for "%s" '
                  'on server\n') % sname)
            # I can't read from service database and I should raise an error
            # for this condition.
            raise StandardError
Ejemplo n.º 32
0
def do_delete_manifest(cmd_options=None):
    '''
    Delete a manifest from an install service.

    '''
    # check for authorization and euid
    try:
        check_auth_and_euid(MANIFEST_AUTH)
    except UnauthorizedUserError as err:
        raise SystemExit(err)

    options = parse_options(cmd_options)

    if not os.path.exists(os.path.join(options.svcdir_path, "AI.db")):
        raise SystemExit(_("Error: Need a valid AI service directory"))

    aisql = AIdb.DB(os.path.join(options.svcdir_path, 'AI.db'), commit=True)
    aisql.verifyDBStructure()
    try:
        delete_manifest_from_db(aisql,
                                (options.manifest_name, options.instance),
                                options.service_name,
                                options.svcdir_path)
    except ValueError as error:
        raise SystemExit(error)
def remove_client_dhcp_config(client_id):
    '''
    If a local DHCP server is running, remove any client configuration for
    this client from its configuration. If not, inform end-user that the
    client-service binding should no longer be referenced in the DHCP
    configuration.
    '''
    server = dhcp.DHCPServer()
    if server.is_configured():
        # A local DHCP server is configured. Check for a host entry and remove
        # it if found.
        mac_address = client_id[2:]
        mac_address = AIdb.formatValue('mac', mac_address)
        if server.host_is_configured(mac_address):
            print cw(_("Removing host entry '%s' from local DHCP "
                       "configuration.") % mac_address)
            server.remove_host(mac_address)

            if server.is_online():
                try:
                    server.control('restart')
                except dhcp.DHCPServerError as err:
                    print >> sys.stderr, cw(_("Unable to restart the DHCP "
                                              "SMF service: %s" % err))
                    return
    else:
        # No local DHCP configuration, inform user that it needs to be
        # unconfigured elsewhere.
        print cw(_("No local DHCP configuration found. Unless it will be "
                   "reused, the bootfile '%s' may be removed from the DHCP "
                   "configuration\n" % client_id))
 def test_building_query_str(self):
     ''' test that we get reasonable query str '''
     cri_list = ['MINipv4', 'MAXipv4', 'arch', 'cpu', 'platform',
               'MINmac', 'MAXmac', 'MINmem', 'MAXmem',
               'MINnetwork', 'MAXnetwork']
     # Artificially small list to test filter functionality.
     all_cri_list = ['arch']
     my_crit_dict = {
                     'ipv4': '020025224125',
                     'arch': 'i86pc',
                     'platform': 'myplatform',
                     'cpu': 'i386',
                     'network': '010000002000',
                     'mem': '2048',
                     'mac': 'aabbccddeeff'
                    }
     query_str = AIdb.build_query_str(my_crit_dict, cri_list, all_cri_list)
     self.assertTrue(query_str.startswith("SELECT name"))
     self.assertTrue("FROM manifests WHERE " in query_str)
     self.assertTrue("MAXmem >= 2048 OR MAXmem IS NULL" in query_str)
     self.assertTrue("MINmem <= 2048 OR MINmem IS NULL" in query_str)
     self.assertTrue("MAXipv4 >= 020025224125" in query_str)
     self.assertTrue("MINipv4 <= 020025224125" in query_str)
     self.assertTrue("MAXnetwork >= 010000002000" in query_str)
     self.assertTrue("MINnetwork <= 010000002000" in query_str)
     self.assertTrue("HEX(MINmac) <= HEX(x'aabbccddeeff'" in query_str)
     self.assertTrue("HEX(MAXmac) >= HEX(x'aabbccddeeff'" in query_str)
     self.assertTrue("is_in_list('arch', 'i86pc', arch, 'None')" \
         in query_str)
     self.assertTrue("is_in_list('platform', 'myplatform', platform, " +
         "'None')" in query_str)
     self.assertTrue("NOT ((arch IS NULL)" in query_str)
     self.assertFalse("(cpu IS NULL)" in query_str)
     self.assertTrue(query_str.endswith("LIMIT 1"))
Ejemplo n.º 35
0
    def __init__(self, aiqueue, name, instance, dbtable):
        '''
        Reads criteria from database and stores them into class attribute

        Args:
            aiqueue = database request queue

            name = either the name of the manifest or the name of
                   the profile to which this set of criteria belongs

            instance = instance number

            dbtable = database table, distinguishing manifests from profiles
                Assumed to be one of AIdb.MANIFESTS_TABLE or
                AIdb.PROFILES_TABLE
        '''
        # Set to True if there is at least one non-empty criteria
        self.has_crit = False
        # Store criteria in dictionary
        self.crit = dict()
        # Initialize length of the longest criteria to length of 'None' word
        self.max_crit_len = len(_('None'))
        # We need non-human output to be able to distiguish empty criteria
        criteria = AIdb.getTableCriteria(name,
                                         instance,
                                         aiqueue,
                                         dbtable,
                                         humanOutput=False,
                                         onlyUsed=True)
        if criteria is not None:
            for key in criteria.keys():
                if criteria[key] is not None:
                    self.has_crit = True
                    break
            if self.has_crit:
                # We need criteria in human readable form to be able to
                # print it
                hrcrit = AIdb.getTableCriteria(name,
                                               instance,
                                               aiqueue,
                                               dbtable,
                                               humanOutput=True,
                                               onlyUsed=True)
                # convert criteria into printable values
                self.get_criteria_info(hrcrit)
Ejemplo n.º 36
0
def add_profile(criteria, profile_name, profile_file, queue, table):
    """
    Set a profile record in the database with the criteria provided.
    Args:
        criteria - criteria object
        profile_name - name of profile to add
        profile_file - path of profile to add
        queue - database request queue
        table - profile table in database
    Returns: True if successful, false otherwise
    Effects:
        database record added
        stored resulting profile in internal profile directory
    """
    # get lists prepared for SQLite WHERE, INSERT VALUES from command line
    (wherel, insertl, valuesl) = \
        sc.sql_values_from_criteria(criteria, queue, table)

    # clear any profiles exactly matching the criteria
    wherel += ["name=" + AIdb.format_value('name', profile_name)]
    q_str = "DELETE FROM " + table + " WHERE " + " AND ".join(wherel)
    query = AIdb.DBrequest(q_str, commit=True)
    queue.put(query)
    query.waitAns()
    if query.getResponse() is None:
        return False

    # add profile to database
    insertl += ["name"]
    valuesl += [AIdb.format_value('name', profile_name)]
    insertl += ["file"]
    valuesl += [AIdb.format_value('name', profile_file)]
    q_str = "INSERT INTO " + table + "(" + ", ".join(insertl) + \
            ") VALUES (" + ", ".join(valuesl) + ")"
    query = AIdb.DBrequest(q_str, commit=True)
    queue.put(query)
    query.waitAns()
    if query.getResponse() is None:
        return False

    print >> sys.stderr, _('Profile %s added to database.') % profile_name
    return True
def send_needed_criteria(port):
    '''Replies to the old client with the needed criteria

    Args
        port - the originating port for the old client

    Returns
        None

    Raises
        None
    
    '''
    # Establish the service SQL database based upon the
    # port number for the service
    path = os.path.join(com.AI_SERVICE_DIR_PATH, str(port), 'AI.db')
    if os.path.exists(path):
        try:
            aisql = AIdb.DB(path)
            aisql.verifyDBStructure()
        except StandardError as err:
            # internal error, record the error in the server error_log
            sys.stderr.write(_('error:AI database access error\n%s\n') % err)
            # report the error to the requesting client
            print "Content-Type: text/html"    # HTML is following
            print                              # blank line, end of headers
            sys.stdout.write(_("error:AI database access error\n%s\n") % err)
            sys.exit(1)
    else:
        # not an internal error, report to the requesting client only
        print "Content-Type: text/html"    # HTML is following
        print                              # blank line, end of headers
        print _("Error:unable to determine criteria "
                "for service associated with port"), port
        return

    # build the required criteria list
    xml = lxml.etree.Element("CriteriaList")
    # old version number
    version_value = lxml.etree.Element("Version")
    version_value.attrib["Number"] = COMPATIBILITY_VERSION
    xml.append(version_value)
    # pull the required criteria from the SQL database
    for crit in AIdb.getCriteria(aisql.getQueue(), strip=True):
        tag = lxml.etree.Element("Criteria")
        tag.attrib["Name"] = crit
        xml.append(tag)
    xmlstr = lxml.etree.tostring(xml, pretty_print=True)

    # report the results
    print "Content-Length:", len(xmlstr)  # Length of XML reply
    print "Content-Type: text/xml"        # XML is following
    print                                 # blank line, end of headers
    print xmlstr
Ejemplo n.º 38
0
def find_clients(lservices, sname=None):
    """
    find_clients() returns a dictionary that contains a list of
    dictionaries.

    The service name is the key for the main dictionary and the
    client, image path, and arch are members of the subdictionary,
    as follows:

        {
          'service1': [
                { 'ipath':<path1>, 'client':<client1>, 'arch': <arch>},
                ....
                      ],
          ....
        }

    Args
        lservices = config.get_all_service_props()
        sname - service name, if only interesetd in clients of a
                specific service

    Returns
        dictionary of a list of dictionaries

    Raises
        None

    """
    sdict = dict()
    for servicename in lservices.keys():
        if sname and sname != servicename:
            continue
        try:
            service = AIService(servicename)
        except VersionError as version_err:
            warn_version(version_err)
            continue
        arch = which_arch(service)
        image_path = [service.image.path]
        client_info = config.get_clients(servicename)
        for clientkey in client_info:
            # strip off the leading '01' and reinsert ':'s
            client = AIdb.formatValue('mac', clientkey[2:])
            tdict = {'client': client, 'ipath': image_path, 'arch': arch}
            if servicename in sdict:  # existing service name
                slist = sdict[servicename]
                slist.extend([tdict])
                sdict[servicename] = slist
            else:  # new service name key
                sdict[servicename] = [tdict]
    return sdict
Ejemplo n.º 39
0
def find_clients(lservices, sname=None):
    """
    find_clients() returns a dictionary that contains a list of
    dictionaries.

    The service name is the key for the main dictionary and the
    client, image path, and arch are members of the subdictionary,
    as follows:

        {
          'service1': [
                { 'ipath':<path1>, 'client':<client1>, 'arch': <arch>},
                ....
                      ],
          ....
        }

    Args
        lservices = config.get_all_service_props()
        sname - service name, if only interesetd in clients of a
                specific service

    Returns
        dictionary of a list of dictionaries

    Raises
        None

    """
    sdict = dict()
    for servicename in lservices.keys():
        if sname and sname != servicename:
            continue
        try:
            service = AIService(servicename)
        except VersionError as version_err:
            warn_version(version_err)
            continue
        arch = which_arch(service)
        image_path = [service.image.path]
        client_info = config.get_clients(servicename)
        for clientkey in client_info:
            # strip off the leading '01' and reinsert ':'s
            client = AIdb.formatValue('mac', clientkey[2:])
            tdict = {'client': client, 'ipath': image_path, 'arch': arch}
            if servicename in sdict:  # existing service name
                slist = sdict[servicename]
                slist.extend([tdict])
                sdict[servicename] = slist
            else:  # new service name key
                sdict[servicename] = [tdict]
    return sdict
Ejemplo n.º 40
0
 def test_ipv4_match(self):
     ''' test manifest match on ipv4 '''
     my_crit_dict = {
                     'ipv4': '020000000025',
                     'arch': 'i86pc',
                     'platform': 'myplatform',
                     'cpu': 'i386',
                     'network': '010000002000',
                     'mem': '2048',
                     'mac': 'aabbccddeef0'
                    }
     manifest = AIdb.findManifest(my_crit_dict, self.aidb)
     self.assertEqual(manifest, "ipv4_max_unbound")
Ejemplo n.º 41
0
 def test_cpu_match(self):
     ''' test manifest match on cpu '''
     my_crit_dict = {
                     'ipv4': '010000000225',
                     'arch': 'sparc',
                     'platform': 'otherplatform',
                     'cpu': 'i386',
                     'network': '010000002000',
                     'mem': '2048',
                     'mac': 'aabbccddeef0'
                    }
     manifest = AIdb.findManifest(my_crit_dict, self.aidb)
     self.assertEqual(manifest, "cpu_man")
Ejemplo n.º 42
0
 def test_manifest_nomatch(self):
     ''' test that findManifest returns 0 for no matching manifest '''
     my_crit_dict = {
                     'ipv4': '010000000225',
                     'arch': 'sparc',
                     'platform': 'otherplatform',
                     'cpu': 'sun4v',
                     'network': '010000002100',
                     'mem': '3000',
                     'mac': 'bbbbccddeef0'
                    }
     manifest = AIdb.findManifest(my_crit_dict, self.aidb)
     self.assertEquals(manifest, None)
 def test_manifest_nomatch(self):
     ''' test that findManifest returns 0 for no matching manifest '''
     my_crit_dict = {
                     'ipv4': '010000000225',
                     'arch': 'sparc',
                     'platform': 'otherplatform',
                     'cpu': 'sun4v',
                     'network': '010000002100',
                     'mem': '3000',
                     'mac': 'bbbbccddeef0'
                    }
     manifest = AIdb.findManifest(my_crit_dict, self.aidb)
     self.assertEquals(manifest, None)
Ejemplo n.º 44
0
 def test_mem_match(self):
     ''' test manifest match on mem '''
     my_crit_dict = {
                     'ipv4': '010000000225',
                     'arch': 'sparc',
                     'platform': 'otherplatform',
                     'cpu': 'sun4v',
                     'network': '010000002100',
                     'mem': '2048',
                     'mac': 'bbbbccddeef0'
                    }
     manifest = AIdb.findManifest(my_crit_dict, self.aidb)
     self.assertEqual(manifest, "mem_min_unbound")
 def test_mem_match(self):
     ''' test manifest match on mem '''
     my_crit_dict = {
                     'ipv4': '010000000225',
                     'arch': 'sparc',
                     'platform': 'otherplatform',
                     'cpu': 'sun4v',
                     'network': '010000002100',
                     'mem': '2048',
                     'mac': 'bbbbccddeef0'
                    }
     manifest = AIdb.findManifest(my_crit_dict, self.aidb)
     self.assertEqual(manifest, "mem_min_unbound")
 def test_cpu_match(self):
     ''' test manifest match on cpu '''
     my_crit_dict = {
                     'ipv4': '010000000225',
                     'arch': 'sparc',
                     'platform': 'otherplatform',
                     'cpu': 'i386',
                     'network': '010000002000',
                     'mem': '2048',
                     'mac': 'aabbccddeef0'
                    }
     manifest = AIdb.findManifest(my_crit_dict, self.aidb)
     self.assertEqual(manifest, "cpu_man")
 def test_ipv4_match(self):
     ''' test manifest match on ipv4 '''
     my_crit_dict = {
                     'ipv4': '020000000025',
                     'arch': 'i86pc',
                     'platform': 'myplatform',
                     'cpu': 'i386',
                     'network': '010000002000',
                     'mem': '2048',
                     'mac': 'aabbccddeef0'
                    }
     manifest = AIdb.findManifest(my_crit_dict, self.aidb)
     self.assertEqual(manifest, "ipv4_max_unbound")
 def test_unique_criteria_match(self):
     ''' test manifest match on mac and ipv4 value '''
     my_crit_dict = {
                     'ipv4': '020000000025',
                     'arch': 'i86pc',
                     'platform': 'myplatform',
                     'cpu': 'i386',
                     'network': '010000002000',
                     'mem': '2048',
                     'mac': 'aabbccddeeff'
                    }
     manifest = AIdb.findManifest(my_crit_dict, self.aidb)
     self.assertEqual(manifest, "mac_ipv4_man")
Ejemplo n.º 49
0
 def test_unique_criteria_match(self):
     ''' test manifest match on mac and ipv4 value '''
     my_crit_dict = {
                     'ipv4': '020000000025',
                     'arch': 'i86pc',
                     'platform': 'myplatform',
                     'cpu': 'i386',
                     'network': '010000002000',
                     'mem': '2048',
                     'mac': 'aabbccddeeff'
                    }
     manifest = AIdb.findManifest(my_crit_dict, self.aidb)
     self.assertEqual(manifest, "mac_ipv4_man")
def is_name_in_table(name, queue, table):
    ''' Determine if profile already registered for service and same basename
    Args:
        name - profile name
        queue - database queue for profiles
        table - profile table name
    Returns True if any records are found, False if no records found
    '''
    query_str = "SELECT * FROM %s WHERE name='%s'" % \
        (table, AIdb.sanitizeSQL(name))
    query = AIdb.DBrequest(query_str)
    queue.put(query)
    query.waitAns()
    return len(query.getResponse()) > 0
Ejemplo n.º 51
0
def do_export_profile(options):
    '''
    Export a profile.
    '''
    save_errno = 0

    # Open the database
    aisql = AIdb.DB(options.service.database_path, commit=True)
    aisql.verifyDBStructure()

    queue = aisql.getQueue()
    for pname in options.pnames:
        # sanitize and format for SELECT
        fmtname = AIdb.format_value('name', pname)
        q_str = "SELECT file FROM  " + AIdb.PROFILES_TABLE + \
                " WHERE name=" + fmtname
        query = AIdb.DBrequest(q_str)
        queue.put(query)
        query.waitAns()
        # check response, if failure, getResponse prints error
        if query.getResponse() is None:
            continue
        if len(query.getResponse()) == 0:
            print >> sys.stderr, _("Profile %s not found.") % fmtname
            continue
        for row in query.getResponse():
            profpath = row['file']

            if options.output_isdir:
                output_name = "/".join([options.output_name, pname])
            else:
                output_name = options.output_name

            if output_name == SCREEN and options.file_count > 1:
                display_file_header(_("profile: ") + pname)

            try:
                shutil.copyfile(profpath, output_name)
            except IOError as err:
                print >> sys.stderr, _("Error exporting profile: "
                                       "%(error)s: %(file)s") % (
                                       {"error": err.strerror,
                                        "file": err.filename})
                save_errno = err.errno
            print
    return save_errno
Ejemplo n.º 52
0
def get_criteria_info(crit_dict):
    """
    Iterates over the criteria which consists of a dictionary with
    possibly arch, min memory, max memory, min ipv4, max ipv4, min mac,
    max mac, cpu, platform, min network, max network and zonename converting
    it into a dictionary with arch, mem, ipv4, mac, cpu, platform, network
    and zonename.  Any min/max attributes are stored as a range within the
    new dictionary.

    Args
        crit_dict = dictionary of the criteria

    Returns
        dictionary of combined min/max and other criteria, formatted
           with possible endings such as MB
        maximum criteria width

    Raises
        None
    """

    if crit_dict is None:
        return dict(), 0

    # tdict values are formatted strings, with possible endings
    # such as MB.
    tdict = dict()

    crit_width = 0
    for key in crit_dict.keys():
        if key == 'service':
            continue
        is_range_crit = key.startswith('MIN') or key.startswith('MAX')
        # strip off the MAX or MIN for a new keyname
        if is_range_crit:
            keyname = key[3:]  # strip off the MAX or MIN for a new keyname
        else:
            keyname = key
        tdict.setdefault(keyname, '')
        db_value = crit_dict[key]
        if not db_value and not is_range_crit:
            # For non-range (value) criteria, None means it isn't set.
            # For range criteria, None means unbounded if the other
            # criteria in the MIN/MAX pair is set.
            continue    # value criteria not set
        crit_width = max(crit_width, len(keyname))
        fmt_value = AIdb.formatValue(key, db_value)
        if is_range_crit:
            if not db_value:
                fmt_value = "unbounded"
            if tdict[keyname] != '':
                if tdict[keyname] != fmt_value:  # dealing with range
                    if key.startswith('MAX'):
                        tdict[keyname] = tdict[keyname] + ' - ' + fmt_value
                    else:
                        tdict[keyname] = fmt_value + ' - ' + tdict[keyname]
                elif tdict[keyname] == "unbounded":
                    # MIN and MAX both unbounded, which means neither is
                    # set in db. Clear tdict value.
                    tdict[keyname] = ''   # no values for range, reset tdict
            else:  # first value, not range yet
                tdict[keyname] = fmt_value
                # if the partner MIN/MAX criterion is not set in the db,
                # handle now because otherwise it won't be processed.
                if key.startswith('MIN'):
                    if 'MAX' + keyname not in crit_dict.keys():
                        if fmt_value == "unbounded":
                            tdict[keyname] = ''
                        else:
                            tdict[keyname] = tdict[keyname] + ' - unbounded'
                else:
                    if 'MIN' + keyname not in crit_dict.keys():
                        if fmt_value == "unbounded":
                            tdict[keyname] = ''
                        else:
                            tdict[keyname] = 'unbounded - ' + tdict[keyname]
        else:
            tdict[keyname] = fmt_value

    return tdict, crit_width
 def test_match_case_sensitive(self):
     ''' Test that we match a value based on a case senstive criteria '''
     value = "FoO"
     value_list = "bar FoO blah"
     self.assertTrue(AIdb.is_in_list('zonename', value, value_list, None))
 def test_no_match_case_sensitive(self):
     ''' Test that we don't match a value on the wrong case.'''
     value = "FoO"
     value_list = "bar foo blah"
     self.assertFalse(AIdb.is_in_list('zonename', value, value_list, None))
def setup_x86_client(service, mac_address, bootargs=''):
    ''' Set up an x86 client

    Creates a relative symlink from the <svcname>'s bootfile to
        /etc/netboot/<client_id>
    Creates /etc/netboot/menu.lst.<client_id> boot configuration file
    Adds client info to AI_SERVICE_DIR_PATH/<svcname>/.config file

    Arguments:
              image_path - directory path to AI image
              mac_address - client MAC address (as formed by
                            MACAddress class, i.e., 'ABABABABABAB')
              bootargs = bootargs of client (x86)
    Returns: Nothing

    '''
    # create a client-identifier (01 + MAC ADDRESS)
    client_id = "01" + mac_address

    menulst = os.path.join(service.config_dir, grub.MENULST)
    client_menulst = _menulst_path(client_id)

    # copy service's menu.lst file to menu.lst.<client_id>
    try:
        shutil.copy(menulst, client_menulst)
    except IOError as err:
        print >> sys.stderr, cw(_("Unable to copy grub menu.lst file: %s") %
           err.strerror)
        return

    # create a symlink from the boot directory to the sevice's bootfile.
    # note this must be relative from the boot directory.
    bootfile, pxegrub_path = _pxegrub_path(client_id)
    os.symlink("./" + service.dhcp_bootfile, pxegrub_path)

    clientinfo = {config.FILES: [client_menulst, pxegrub_path]}

    # if the client specifies bootargs, use them. Otherwise, inherit
    # the bootargs specified in the service (do nothing)
    if bootargs:
        grub.update_bootargs(client_menulst, service.bootargs, bootargs)
        clientinfo[config.BOOTARGS] = bootargs

    config.add_client_info(service.name, client_id, clientinfo)

    # Configure DHCP for this client if the configuration is local, otherwise
    # suggest the configuration addition. Note we only need to do this for
    # x86-based clients, not SPARC.
    server = dhcp.DHCPServer()
    if server.is_configured():
        # We'll need the actual hardware ethernet address for the DHCP entry,
        # rather than the non-delimited string that 'mac_address' is.
        full_mac = AIdb.formatValue('mac', mac_address)
        try:
            print cw(_("Adding host entry for %s to local DHCP configuration.")
                       % full_mac)
            server.add_host(full_mac, bootfile)
        except dhcp.DHCPServerError as err:
            print cw(_("Unable to add host (%s) to DHCP configuration: %s") %
                      (full_mac, err))
            return

        if server.is_online():
            try:
                server.control('restart')
            except dhcp.DHCPServerError as err:
                print >> sys.stderr, cw(_("\nUnable to restart the DHCP SMF "
                                          "service: %s\n" % err))
                return
        else:
            print cw(_("\nLocal DHCP configuration complete, but the DHCP "
                       "server SMF service is offline. To enable the "
                       "changes made, enable: %s.\nPlease see svcadm(1M) "
                       "for further information.\n") % 
                       dhcp.DHCP_SERVER_IPV4_SVC)
    else:
        # No local DHCP, tell the user all about their boot configuration
        valid_nets = list(com.get_valid_networks())
        if valid_nets:
            server_ip = valid_nets[0]

        print _(_PXE_CLIENT_DHCP_CONFIG % (server_ip, bootfile))

        if len(valid_nets) > 1:
            print cw(_("\nNote: determined more than one IP address "
                       "configured for use with AI. Please ensure the above "
                       "'Boot server IP' is correct.\n"))
Ejemplo n.º 56
0
def get_manifest_or_profile_names(services, dbtable):
    """
    Iterate through the services retrieving
    all the stored manifest or profile names.

    Args
        services = dictionary of service properties
        dbtable = database table, distinguishing manifests from profiles

    Returns
        a dictionary of service manifests or profiles within a list:

            {
                servicename1:
                    [
                        [name, has_criteria (boolean), {crit:value, ... }],
                        ... 
                    ],
                ...
            }

        the width of the longest service name (swidth)

        the width of the longest manifest name (mwidth)

        the width of the longest criteria (cwidth)

    Raises
        None
    """
    swidth = 0
    mwidth = 0
    cwidth = 0
    sdict = dict()
    for sname in sorted(services.keys()):
        try:
            service = AIService(sname)
        except VersionError as err:
            warn_version(err)
            continue
        
        path = service.database_path
        
        if os.path.exists(path):
            try:
                maisql = AIdb.DB(path)
                maisql.verifyDBStructure()
                aiqueue = maisql.getQueue()
                swidth = max(len(sname), swidth)
                if not AIdb.tableExists(aiqueue, dbtable):
                    continue
                for name in AIdb.getNames(aiqueue, dbtable):
                    mwidth = max(len(name), mwidth)
                    tdict = dict()
                    if dbtable == 'manifests':
                        instances = AIdb.numInstances(name, aiqueue)
                        for instance in range(0, instances):
                            criteria = AIdb.getTableCriteria(name,
                                            instance, aiqueue, dbtable,
                                            humanOutput=False,
                                            onlyUsed=True)
                            has_criteria = False
                            if criteria is not None:
                                for key in criteria.keys():
                                    if criteria[key] is not None:
                                        has_criteria = True
                                        break
                                if has_criteria:
                                    # We need criteria in human readable form
                                    hrcrit = AIdb.getTableCriteria(name,
                                                  instance, aiqueue, dbtable,
                                                  humanOutput=True,
                                                  onlyUsed=True)
                                    tdict, twidth = get_criteria_info(hrcrit)
                                    cwidth = max(twidth, cwidth)
                    else:
                        criteria = AIdb.getTableCriteria(name,
                                        None, aiqueue, dbtable,
                                        humanOutput=False,
                                        onlyUsed=True)
                        has_criteria = False
                        if criteria is not None:
                            for key in criteria.keys():
                                if criteria[key] is not None:
                                    has_criteria = True
                                    break
                    if sname in sdict:
                        slist = sdict[sname]
                        slist.append([name, has_criteria, tdict])
                        sdict[sname] = slist
                    else:
                        sdict[sname] = [[name, has_criteria, tdict]]
            except StandardError as err:
                sys.stderr.write(_('Error: AI database access error\n%s\n')
                                   % err)
                continue
        else:
            sys.stderr.write(_('Error: unable to locate AI database for "%s" '
                               'on server\n') % sname)
            continue

    return sdict, swidth, mwidth, cwidth
Ejemplo n.º 57
0
def prepValuesAndRanges(criteriaRoot, database, table=AIdb.MANIFESTS_TABLE):
# =============================================================================
    """
    Processes criteria manifest data already read into memory but before
    it is stored in the AI database.

    Does the following:
    - When a criterion range of one is given by a single <value>, morph
            that value so it can be stored in the database as a <range>.
    - Pad the digit strings of MAC addresses so that the six values between
            the colons are two hex digits each.
    - Pad the digit strings of IP addresses so that the four values between
            the dots are three digits each and between 0 and 255.
    - Strip off colons from MAC addresses and dots from IPv4 addresses.

    Args:
      - criteriaRoot: Tree root for criteria manifest.  This is where
            data is checked / modified.
      - database: Used to find which criteria are range criteria.

    Returns: Nothing.  However, data may be checked and modified per above.

    Raises:
    - Exception: ValueError - a range criteria provided as a list of values
                            - a non-range criteria provided as a range
    - Exceptions raised by database calls, and calls to
            - checkIPv4()
            - checkMAC()
    """
# =============================================================================

    # Find from the database which criteria are range criteria.
    # Range criteria named xxx have names bounds values MINxxx and MAXxxx.
    # Assume that MINxxx is a good enough check.
    # All criteria names in database are stored as lower case, except
    # for their "MIN" and "MAX" prefixes.
    range_crit = list()
    for crit_name in AIdb.getCriteria(database.getQueue(), table,
        onlyUsed=False, strip=False):
        if (crit_name.startswith("MIN")):
            range_crit.append(crit_name.replace("MIN", "", 1))

    # Loop through all criteria elements.
    for crit in criteriaRoot.findall('.//ai_criteria'):
        crit_name = crit.attrib['name'].lower()
        val_range = crit.getchildren()[0]

        # <range>'s here are a single element with a single
        # string containing two space-separated values for MIN and MAX
        # <value>'s here are a single element with a single
        # string containing one value or a space-separated list of values.
        value_list = val_range.text.split()
        num_values = len(value_list)

        # val_range.tag will be either 'value' or 'range'.
        # This is syntactically validated by the schema.
        if val_range.tag == "value":
            # Allow a list of values to be provided with the 'value' tag.
            # However, for criteria that can be provided as a range, we
            # currently do not support lists for them.
            if num_values > 1 and crit_name in range_crit:
                raise ValueError("Criteria '" + crit_name + "' is not "
                    "supported to be provided as a list of values")
        else:
            # For ranges, make sure it is indeed a range criteria
            if crit_name not in range_crit:
                raise ValueError("Criteria '" + crit_name + "' can not "
                    "be passed as a range pair")

        # For value criteria, there is no need to do anything to store
        # single value into val_range.text.  It is already there.
        # Just check architecture and cpu values because it is common to
        # confuse i86pc and i386 or sparc and sun4v
        if crit_name == "arch":
            for one_value in value_list:
                try:
                    checkArch(one_value)
                except ValueError as err:
                    # Just print warning
                    print >> sys.stderr, err
        elif crit_name == "cpu":
            for one_value in value_list:
                try:
                    checkCPU(one_value)
                except ValueError as err:
                    # Just print warning
                    print >> sys.stderr, err
        #
        # For some types supported by range criteria, some additional
        # format checking is needed.  Also, range criteria that are passed
        # as single values need to be split into a range where min=max.

        # Current criterion is a range criterion.
        if range_crit.count(crit_name) > 0:

            # Each value will have already been checked against the
            # schema.  IPv4 values will be 4 numbers ranging from
            # 0-255, separated by dots.  MAC values will be 6 hex
            # numbers ranging from 0-FF, separated by colons.
            # There may be one or two values.

            new_values = ""
            for one_value in value_list:

                # Space between (range) values.
                if new_values != "":
                    new_values += " "

                # Handle "unbounded" keyword; and pass lowercase
                lowered_value = one_value.lower()
                if lowered_value == "unbounded":
                    new_values += lowered_value

                # Handle IPv4 addressses.
                elif crit_name == "ipv4" or crit_name == "network":
                    new_values += checkIPv4(one_value)

                # Handle MAC addresses.
                elif crit_name == "mac":
                    new_values += checkMAC(one_value)

                # Handle everything else by passing through.
                else:
                    new_values += one_value

                # Single values which come in under a "value"
                # tag but represent a range (e.g. a single ipv4
                # value) are "converted" into the form a range
                # value pair would take (a single string
                # consisting of two items) where
                # the min value = max value.
                if val_range.tag == "value":
                    # Change to a range.
                    # Set min = max = value.
                    val_range.tag = "range"
                    val_range.text = \
                        new_values + " " + new_values
                elif val_range.tag == "range":
                    # values will be a list of 2 already.
                    val_range.text = new_values
def insert_SQL(files):
    """
    Ensures all data is properly sanitized and formatted, then inserts it into
    the database
    Args: None
    Returns: None
    """
    query = "INSERT INTO manifests VALUES("

    # add the manifest name to the query string
    query += "'" + AIdb.sanitizeSQL(files.manifest_name) + "',"
    # check to see if manifest name is already in database (affects instance
    # number)
    if AIdb.sanitizeSQL(files.manifest_name) in \
        AIdb.getManNames(files.database.getQueue()):
            # database already has this manifest name get the number of
            # instances
        instance = AIdb.numInstances(AIdb.sanitizeSQL(files.manifest_name),
                                     files.database.getQueue())
    # this a new manifest
    else:
        instance = 0

    # actually add the instance to the query string
    query += str(instance) + ","

    # we need to fill in the criteria or NULLs for each criteria the database
    # supports (so iterate over each criteria)
    for crit in AIdb.getCriteria(files.database.getQueue(),
                                 onlyUsed=False, strip=False):
        # for range values trigger on the MAX criteria (skip the MIN's
        # arbitrary as we handle rows in one pass)
        if crit.startswith('MIN'):
            continue

        # get the values from the manifest
        values = files.criteria[crit.replace('MAX', '', 1)]

        # If the critera manifest didn't specify this criteria, fill in NULLs
        if values is None:
            # use the criteria name to determine if this is a range
            if crit.startswith('MAX'):
                query += "NULL,NULL,"
            # this is a single value
            else:
                query += "NULL,"

        # Else if this is a value criteria (not a range), insert the value
        # as a space-separated list of values which will account for the case
        # where a list of values have been given.
        elif not crit.startswith('MAX'):
            # Join the values of the list with a space separator.
            query += "'" + AIdb.sanitizeSQL(" ".join(values)) + "',"
        # else values is a range
        else:
            for value in values:
                # translate "unbounded" to a database NULL
                if value == "unbounded":
                    query += "NULL,"
                # we need to deal with mac addresses specially being
                # hexadecimal
                elif crit.endswith("mac"):
                    # need to insert with hex operand x'<val>'
                    # use an upper case string for hex values
                    query += "x'" + AIdb.sanitizeSQL(str(value).upper()) + \
                             "',"
                else:
                    query += AIdb.sanitizeSQL(str(value).upper()) + ","

    # strip trailing comma and close parentheses
    query = query[:-1] + ")"

    # update the database
    query = AIdb.DBrequest(query, commit=True)
    files.database.getQueue().put(query)
    query.waitAns()
    # in case there's an error call the response function (which will print the
    # error)
    query.getResponse()
def verifyCriteriaDict(schema, criteria_dict, db, table=AIdb.MANIFESTS_TABLE):
    """
    Used for verifying and loading criteria from a dictionary of criteria.
    Args:       schema - path to schema file for criteria manifest.
                criteria_dict - dictionary of criteria to verify, in the form
                                of { criteria: value, criteria: value, ... }
                db - database object for install service
                table - database table, distinguishing manifests from profiles
    Raises IOError:
               * if the schema does not open
           ValueError:
                * if the criteria_dict dictionary is empty
                * if the XML is invalid according to the schema
           AssertionError:
                * if a value in the dictionary is empty
    Returns:    A valid XML DOM of the criteria and all MAC and IPV4 values
                are formatted according to verifyXML.prepValuesAndRanges().
    """
    schema = open(schema, 'r')

    if not criteria_dict:
        raise ValueError("Error:\tCriteria dictionary empty: %s\n"
                         % criteria_dict)

    root = lxml.etree.Element("ai_criteria_manifest")

    for name, value_or_range in criteria_dict.iteritems():

        if value_or_range is None:
            raise AssertionError(_("Error: Missing value for criteria "
                                   "'%s'") % name)

        crit = lxml.etree.SubElement(root, "ai_criteria")
        crit.set("name", name)

        # If criteria is a range, split on "-" and add to
        # XML DOM as a range element.
        if AIdb.isRangeCriteria(db.getQueue(), name, table):
            # Split on "-"
            range_value = value_or_range.split('-', 1)

            # If there was only a single value, means user specified
            # this range criteria as a single value, add it as a single
            # value
            if len(range_value) == 1:
                value_elem = lxml.etree.SubElement(crit, "value")
                value_elem.text = value_or_range
            else:
                range_elem = lxml.etree.SubElement(crit, "range")
                range_elem.text = " ".join(range_value)
        else:
            value_elem = lxml.etree.SubElement(crit, "value")
            value_elem.text = value_or_range

    # Verify the generated criteria DOM
    root, errors = verifyXML.verifyRelaxNGManifest(schema,
                        StringIO.StringIO(lxml.etree.tostring(root)))
    if errors:
        raise ValueError(_("Error: Criteria failed validation:\n\t%s") %
                           errors.message)
    try:
        verifyXML.prepValuesAndRanges(root, db, table)
    except ValueError, err:
        raise ValueError(_("Error:\tCriteria error: %s") % err)
Ejemplo n.º 60
0
def get_mfest_or_profile_criteria(sname, services, dbtable):
    """
    Iterate through all the manifests or profiles for the named service (sname)
    pointed to by the SCF service.

    Args
        sname = service name
        services = config.get_all_service_props()
        dbtable = database table, distinguishing manifests from profiles
            Assumed to be one of AIdb.MANIFESTS_TABLE or AIdb.PROFILES_TABLE

    Returns
        a dictionary of the criteria for the named service within a list:

            {
                servicename1:[
                             { 'arch':arch1, 'mem':memory1, 'ipv4':ipaddress1,
                               'mac':macaddr1, 'platform':platform1,
                               'network':network1, 'cpu':cpu1, 'zonename':z1 },
                             ...
                            ]
            }

        * Note1: platform, network and cpu are currently not-implemented
                 upstream.
        * Note2: could simply use a list of dictionaries but implemented as a
                 dictionary of a list of dictionary which will allow for
                 multiple services to be listed at the same time.

        width of longest manifest or profile name

        width of longest criteria

    Raises
        None
    """
    sdict = dict()
    width = 0
    cwidth = 0
    # ensure the named service is in our service dictionary.
    lservices = services.keys()
    if sname in lservices:
        try:
            path = AIService(sname).database_path
        except VersionError as version_err:
            warn_version(version_err)
            return sdict, width, cwidth

        if os.path.exists(path):
            try:
                maisql = AIdb.DB(path)
                maisql.verifyDBStructure()
                aiqueue = maisql.getQueue()
                if dbtable == AIdb.MANIFESTS_TABLE:
                    for name in AIdb.getNames(aiqueue, dbtable):
                        sdict[name] = list()
                        instances = AIdb.numInstances(name, aiqueue)
                        for instance in range(0, instances):
                            width = max(len(name), width)
                            criteria = AIdb.getManifestCriteria(name,
                                            instance, aiqueue,
                                            humanOutput=True,
                                            onlyUsed=True)
                            if criteria:
                                tdict, twidth = get_criteria_info(criteria)
                                cwidth = max(twidth, cwidth)
                                sdict[name].append(tdict)
                elif dbtable == AIdb.PROFILES_TABLE:
                    for name in AIdb.getNames(aiqueue, dbtable):
                        sdict[name] = list()
                        criteria = AIdb.getProfileCriteria(name,
                                        aiqueue,
                                        humanOutput=True,
                                        onlyUsed=True)
                        width = max(len(name), width)
                        tdict, twidth = get_criteria_info(criteria)
                        cwidth = max(twidth, cwidth)

                        sdict[name].append(tdict)
                else:
                    raise ValueError("Invalid value for dbtable: %s" % dbtable)

            except StandardError as err:
                sys.stderr.write(_('Error: AI database access error\n%s\n')
                                   % err)
                sys.exit(1)
        else:
            sys.stderr.write(_('Error: unable to locate AI database on server '
                               'for %s\n') % sname)
            sys.exit(1)

    return sdict, width, cwidth