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 test_match_list_not_first_value(self): ''' Test that we match a value in the middle of the list ''' value = "foo" value_list = "bar foo bum" self.assertTrue(AIdb.is_in_list('dummy_crit', value, value_list, None))
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 find_colliding_manifests(criteria, db, collisions, append_manifest=None): """ For each manifest/instance pair in collisions check that the manifest criteria diverge (i.e. are not exactly the same) and that the ranges do not collide for ranges. Raises if: a range collides, or if the manifest has the same criteria as a manifest already in the database (SystemExit raised) Returns: Nothing Args: criteria - Criteria object holding the criteria that is to be added/set for a manifest. db - AI_database object for the install service. collisions - a dictionary with collisions, as produced by find_colliding_criteria() append_manifest - name of manifest we're appending criteria to. This arg is passed in when we're calling this function to find criteria collisions for an already published manifest that we're appending criteria to. """ # If we're appending criteria to an already published manifest, get a # dictionary of the criteria that's already published for that manifest. if append_manifest is not None: published_criteria = AIdb.getManifestCriteria(append_manifest, 0, db.getQueue(), humanOutput=True, onlyUsed=False) # check every manifest in collisions to see if manifest collides (either # identical criteria, or overlaping ranges) for man_inst in collisions: # get all criteria from this manifest/instance pair db_criteria = AIdb.getManifestCriteria(man_inst[0], man_inst[1], db.getQueue(), humanOutput=True, onlyUsed=False) # iterate over every criteria in the database for crit in AIdb.getCriteria(db.getQueue(), onlyUsed=False, strip=False): # Get the criteria name (i.e. no MIN or MAX) crit_name = crit.replace('MIN', '', 1).replace('MAX', '', 1) # Set man_criterion to the key of the DB criteria or None man_criterion = criteria[crit_name] if man_criterion and crit.startswith('MIN'): man_criterion = man_criterion[0] elif man_criterion and crit.startswith('MAX'): man_criterion = man_criterion[1] # If man_criterion is still None, and if we're appending criteria # to an already published manifest, look for criteria in the # published set of criteria for the manifest we're appending to # as well, because existing criteria might cause a collision, # which we need to compare for. if man_criterion is None and append_manifest is not None: man_criterion = published_criteria[str(crit)] # replace database NULL's with Python None if man_criterion == '': man_criterion = None # set the database criteria if db_criteria[str(crit)] == '': # replace database NULL's with a Python None db_criterion = None else: db_criterion = db_criteria[str(crit)] # Replace unbounded's in the criteria (i.e. 0/+inf) # with a Python None. if isinstance(man_criterion, basestring) and \ man_criterion == "unbounded": man_criterion = None # check to determine if this is a range collision by using # collisions and if not are the manifests divergent if ((crit.startswith('MIN') and collisions[man_inst].find(crit + ",") != -1) or (crit.startswith('MAX') and collisions[man_inst].find(crit + ",") != -1)): if str(db_criterion).lower() != str(man_criterion).lower(): raise SystemExit( _("Error:\tManifest has a range " "collision with manifest:%s/%i" "\n\tin criteria: %s!") % (man_inst[0], man_inst[1], crit.replace( 'MIN', '', 1).replace('MAX', '', 1))) # Either the range did not collide or this is not a range # criteria. (If the value of this criteria in the db does # not equal the value of this criteria for the set of criteria # to check, we can break out knowing we diverge for this # manifest/instance) elif not db_criterion and not man_criterion: # Neither the value for this criteria in the db nor # the value for for this criteria in the given set of # criteria to check are populated. Loop around to # check the next criteria. continue elif not db_criterion or not man_criterion: # One of the two are not populated, we can break knowing # they're different. break else: # Both are populated. If none of values in the list for # this criteria to be added are equal to any of the values # in the list for this criteria from the db, there will be # no collision. We can break out. if not [value for value in man_criterion if \ AIdb.is_in_list(crit, value, str(db_criterion), None)]: break # end of for loop and we never broke out (collision) else: raise SystemExit( _("Error:\tManifest has same criteria as " + "manifest: %s/%i!") % (man_inst[0], man_inst[1]))
def test_match_list_first_value(self): ''' Test that we match a value that is the first in the list ''' value = "foo" value_list = "foo bar bum" self.assertTrue(AIdb.is_in_list('dummy_crit', 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 find_colliding_criteria(criteria, db, exclude_manifests=None): """ Returns: A dictionary of colliding criteria with keys being manifest name and instance tuples and values being the DB column names which collided Args: criteria - Criteria object holding the criteria that is to be added/set for a manifest. db - AI_database object for the install service. exclude_manifests -A list of manifest names from DB to ignore. This arg is passed in when we're calling this function to find criteria collisions for an already published manifest. Raises: SystemExit if: criteria is not found in database value is not valid for type (integer and hexadecimal checks) range is improper """ class Fields(object): """ Define convenience indexes """ # manifest name is row index 0 MANNAME = 0 # manifest instance is row index 1 MANINST = 1 # criteria is row index 2 (when a single valued criteria) CRIT = 2 # minimum criteria is row index 2 (when a range valued criteria) MINCRIT = 2 # maximum criteria is row index 3 (when a range valued criteria) MAXCRIT = 3 # collisions is a dictionary to hold keys of the form (manifest name, # instance) which will point to a comma-separated string of colliding # criteria collisions = dict() # verify each range criteria in the manifest is well formed and collect # collisions with database entries for crit in criteria: # gather this criteria's values from the manifest man_criterion = criteria[crit] # Determine if this crit is a range criteria or not. is_range_crit = AIdb.isRangeCriteria(db.getQueue(), crit, AIdb.MANIFESTS_TABLE) # Process "value" criteria here (check if the criteria exists in # DB, and then find collisions) if not is_range_crit: # only check criteria in use in the DB if crit not in AIdb.getCriteria(db.getQueue(), onlyUsed=False, strip=False): raise SystemExit( _("Error:\tCriteria %s is not a " + "valid criteria!") % crit) # get all values in the database for this criteria (and # manifest/instance pairs for each value) db_criteria = AIdb.getSpecificCriteria( db.getQueue(), crit, provideManNameAndInstance=True, excludeManifests=exclude_manifests) # will iterate over a list of the form [manName, manInst, crit, # None] for row in db_criteria: # check if a value in the list of values to be added is equal # to a value in the list of values for this criteria for this # row for value in man_criterion: if AIdb.is_in_list(crit, value, str(row[Fields.CRIT]), None): # record manifest name, instance and criteria name try: collisions[row[Fields.MANNAME], row[Fields.MANINST]] += crit + "," except KeyError: collisions[row[Fields.MANNAME], row[Fields.MANINST]] = crit + "," # This is a range criteria. (Check that ranges are valid, that # "unbounded" gets set to 0/+inf, ensure the criteria exists # in the DB, then look for collisions.) else: # Clean-up NULL's and change "unbounded"s to 0 and # really large numbers in case this Python does # not support IEEE754. Note "unbounded"s are already # converted to lower case during manifest processing. if man_criterion[0] == "unbounded": man_criterion[0] = "0" if man_criterion[1] == "unbounded": man_criterion[1] = INFINITY if crit == "mac": # convert hex mac address (w/o colons) to a number try: man_criterion[0] = long(str(man_criterion[0]).upper(), 16) man_criterion[1] = long(str(man_criterion[1]).upper(), 16) except ValueError: raise SystemExit( _("Error:\tCriteria %s " "is not a valid hexadecimal value") % crit) else: # this is a decimal value try: man_criterion = [ long(str(man_criterion[0]).upper()), long(str(man_criterion[1]).upper()) ] except ValueError: raise SystemExit( _("Error:\tCriteria %s " "is not a valid integer value") % crit) # Check for a properly ordered range (with unbounded being 0 or # Inf.) but ensure both are not unbounded. # Check for: # a range of zero to inf -- not a valid range # and # min > max -- range order reversed # if (man_criterion[0] == 0 and man_criterion[1] == long(INFINITY)): raise SystemExit( _("Error:\tCriteria %s is not a valid range, " "MIN and MAX unbounded.") % crit) if ((man_criterion[0] != 0 and man_criterion[1] != long(INFINITY)) and (long(man_criterion[0]) > long(man_criterion[1]))): raise SystemExit( _("Error:\tCriteria %s is not a valid range, " "MIN > MAX.") % crit) # check to see that this criteria exists in the database columns man_crit = AIdb.getCriteria(db.getQueue(), onlyUsed=False, strip=False) if 'MIN' + crit not in man_crit and 'MAX' + crit not in man_crit: raise SystemExit( _("Error:\tCriteria %s is not a " "valid criteria!") % crit) db_criteria = AIdb.getSpecificCriteria( db.getQueue(), 'MIN' + crit, 'MAX' + crit, provideManNameAndInstance=True, excludeManifests=exclude_manifests) # will iterate over a list of the form [manName, manInst, mincrit, # maxcrit] for row in db_criteria: # arbitrarily large number in case this Python does # not support IEEE754 db_criterion = ["0", INFINITY] # now populate in valid database values (i.e. non-NULL values) if row[Fields.MINCRIT]: db_criterion[0] = row[Fields.MINCRIT] if row[Fields.MAXCRIT]: db_criterion[1] = row[Fields.MAXCRIT] if crit == "mac": # use a hexadecimal conversion db_criterion = [ long(str(db_criterion[0]), 16), long(str(db_criterion[1]), 16) ] else: # these are decimal numbers db_criterion = [ long(str(db_criterion[0])), long(str(db_criterion[1])) ] # these three criteria can determine if there's a range overlap if ((man_criterion[1] >= db_criterion[0] and db_criterion[1] >= man_criterion[0]) or man_criterion[0] == db_criterion[1]): # range overlap so record the collision try: collisions[row[Fields.MANNAME], row[Fields.MANINST]] += "MIN" + crit + "," collisions[row[Fields.MANNAME], row[Fields.MANINST]] += "MAX" + crit + "," except KeyError: collisions[row[Fields.MANNAME], row[Fields.MANINST]] = "MIN" + crit + "," collisions[row[Fields.MANNAME], row[Fields.MANINST]] += "MAX" + crit + "," return collisions
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_match_list_not_first_value(self): ''' Test that we match a value in the middle of the list ''' value = "foo" value_list = "bar foo bum" self.assertTrue(AIdb.is_in_list('dummy_crit', value, value_list, None))
def test_match_list_first_value(self): ''' Test that we match a value that is the first in the list ''' value = "foo" value_list = "foo bar bum" self.assertTrue(AIdb.is_in_list('dummy_crit', value, value_list, None))
def find_colliding_manifests(criteria, db, collisions, append_manifest=None): """ For each manifest/instance pair in collisions check that the manifest criteria diverge (i.e. are not exactly the same) and that the ranges do not collide for ranges. Raises if: a range collides, or if the manifest has the same criteria as a manifest already in the database (SystemExit raised) Returns: Nothing Args: criteria - Criteria object holding the criteria that is to be added/set for a manifest. db - AI_database object for the install service. collisions - a dictionary with collisions, as produced by find_colliding_criteria() append_manifest - name of manifest we're appending criteria to. This arg is passed in when we're calling this function to find criteria collisions for an already published manifest that we're appending criteria to. """ # If we're appending criteria to an already published manifest, get a # dictionary of the criteria that's already published for that manifest. if append_manifest is not None: published_criteria = AIdb.getManifestCriteria(append_manifest, 0, db.getQueue(), humanOutput=True, onlyUsed=False) # check every manifest in collisions to see if manifest collides (either # identical criteria, or overlaping ranges) for man_inst in collisions: # get all criteria from this manifest/instance pair db_criteria = AIdb.getManifestCriteria(man_inst[0], man_inst[1], db.getQueue(), humanOutput=True, onlyUsed=False) # iterate over every criteria in the database for crit in AIdb.getCriteria(db.getQueue(), onlyUsed=False, strip=False): # Get the criteria name (i.e. no MIN or MAX) crit_name = crit.replace('MIN', '', 1).replace('MAX', '', 1) # Set man_criterion to the key of the DB criteria or None man_criterion = criteria[crit_name] if man_criterion and crit.startswith('MIN'): man_criterion = man_criterion[0] elif man_criterion and crit.startswith('MAX'): man_criterion = man_criterion[1] # If man_criterion is still None, and if we're appending criteria # to an already published manifest, look for criteria in the # published set of criteria for the manifest we're appending to # as well, because existing criteria might cause a collision, # which we need to compare for. if man_criterion is None and append_manifest is not None: man_criterion = published_criteria[str(crit)] # replace database NULL's with Python None if man_criterion == '': man_criterion = None # set the database criteria if db_criteria[str(crit)] == '': # replace database NULL's with a Python None db_criterion = None else: db_criterion = db_criteria[str(crit)] # Replace unbounded's in the criteria (i.e. 0/+inf) # with a Python None. if isinstance(man_criterion, basestring) and \ man_criterion == "unbounded": man_criterion = None # check to determine if this is a range collision by using # collisions and if not are the manifests divergent if((crit.startswith('MIN') and collisions[man_inst].find(crit + ",") != -1) or (crit.startswith('MAX') and collisions[man_inst].find(crit + ",") != -1) ): if str(db_criterion).lower() != str(man_criterion).lower(): raise SystemExit(_("Error:\tManifest has a range " "collision with manifest:%s/%i" "\n\tin criteria: %s!") % (man_inst[0], man_inst[1], crit.replace('MIN', '', 1). replace('MAX', '', 1))) # Either the range did not collide or this is not a range # criteria. (If the value of this criteria in the db does # not equal the value of this criteria for the set of criteria # to check, we can break out knowing we diverge for this # manifest/instance) elif not db_criterion and not man_criterion: # Neither the value for this criteria in the db nor # the value for for this criteria in the given set of # criteria to check are populated. Loop around to # check the next criteria. continue elif not db_criterion or not man_criterion: # One of the two are not populated, we can break knowing # they're different. break else: # Both are populated. If none of values in the list for # this criteria to be added are equal to any of the values # in the list for this criteria from the db, there will be # no collision. We can break out. if not [value for value in man_criterion if \ AIdb.is_in_list(crit, value, str(db_criterion), None)]: break # end of for loop and we never broke out (collision) else: raise SystemExit(_("Error:\tManifest has same criteria as " + "manifest: %s/%i!") % (man_inst[0], man_inst[1]))
def find_colliding_criteria(criteria, db, exclude_manifests=None): """ Returns: A dictionary of colliding criteria with keys being manifest name and instance tuples and values being the DB column names which collided Args: criteria - Criteria object holding the criteria that is to be added/set for a manifest. db - AI_database object for the install service. exclude_manifests -A list of manifest names from DB to ignore. This arg is passed in when we're calling this function to find criteria collisions for an already published manifest. Raises: SystemExit if: criteria is not found in database value is not valid for type (integer and hexadecimal checks) range is improper """ class Fields(object): """ Define convenience indexes """ # manifest name is row index 0 MANNAME = 0 # manifest instance is row index 1 MANINST = 1 # criteria is row index 2 (when a single valued criteria) CRIT = 2 # minimum criteria is row index 2 (when a range valued criteria) MINCRIT = 2 # maximum criteria is row index 3 (when a range valued criteria) MAXCRIT = 3 # collisions is a dictionary to hold keys of the form (manifest name, # instance) which will point to a comma-separated string of colliding # criteria collisions = dict() # verify each range criteria in the manifest is well formed and collect # collisions with database entries for crit in criteria: # gather this criteria's values from the manifest man_criterion = criteria[crit] # Determine if this crit is a range criteria or not. is_range_crit = AIdb.isRangeCriteria(db.getQueue(), crit, AIdb.MANIFESTS_TABLE) # Process "value" criteria here (check if the criteria exists in # DB, and then find collisions) if not is_range_crit: # only check criteria in use in the DB if crit not in AIdb.getCriteria(db.getQueue(), onlyUsed=False, strip=False): raise SystemExit(_("Error:\tCriteria %s is not a " + "valid criteria!") % crit) # get all values in the database for this criteria (and # manifest/instance pairs for each value) db_criteria = AIdb.getSpecificCriteria( db.getQueue(), crit, provideManNameAndInstance=True, excludeManifests=exclude_manifests) # will iterate over a list of the form [manName, manInst, crit, # None] for row in db_criteria: # check if a value in the list of values to be added is equal # to a value in the list of values for this criteria for this # row for value in man_criterion: if AIdb.is_in_list(crit, value, str(row[Fields.CRIT]), None): # record manifest name, instance and criteria name try: collisions[row[Fields.MANNAME], row[Fields.MANINST]] += crit + "," except KeyError: collisions[row[Fields.MANNAME], row[Fields.MANINST]] = crit + "," # This is a range criteria. (Check that ranges are valid, that # "unbounded" gets set to 0/+inf, ensure the criteria exists # in the DB, then look for collisions.) else: # Clean-up NULL's and change "unbounded"s to 0 and # really large numbers in case this Python does # not support IEEE754. Note "unbounded"s are already # converted to lower case during manifest processing. if man_criterion[0] == "unbounded": man_criterion[0] = "0" if man_criterion[1] == "unbounded": man_criterion[1] = INFINITY if crit == "mac": # convert hex mac address (w/o colons) to a number try: man_criterion[0] = long(str(man_criterion[0]).upper(), 16) man_criterion[1] = long(str(man_criterion[1]).upper(), 16) except ValueError: raise SystemExit(_("Error:\tCriteria %s " "is not a valid hexadecimal value") % crit) else: # this is a decimal value try: man_criterion = [long(str(man_criterion[0]).upper()), long(str(man_criterion[1]).upper())] except ValueError: raise SystemExit(_("Error:\tCriteria %s " "is not a valid integer value") % crit) # Check for a properly ordered range (with unbounded being 0 or # Inf.) but ensure both are not unbounded. # Check for: # a range of zero to inf -- not a valid range # and # min > max -- range order reversed # if (man_criterion[0] == 0 and man_criterion[1] == long(INFINITY)): raise SystemExit(_("Error:\tCriteria %s is not a valid range, " "MIN and MAX unbounded.") % crit) if ((man_criterion[0] != 0 and man_criterion[1] != long(INFINITY)) and (long(man_criterion[0]) > long(man_criterion[1]))): raise SystemExit(_("Error:\tCriteria %s is not a valid range, " "MIN > MAX.") % crit) # check to see that this criteria exists in the database columns man_crit = AIdb.getCriteria(db.getQueue(), onlyUsed=False, strip=False) if 'MIN' + crit not in man_crit and 'MAX' + crit not in man_crit: raise SystemExit(_("Error:\tCriteria %s is not a " "valid criteria!") % crit) db_criteria = AIdb.getSpecificCriteria( db.getQueue(), 'MIN' + crit, 'MAX' + crit, provideManNameAndInstance=True, excludeManifests=exclude_manifests) # will iterate over a list of the form [manName, manInst, mincrit, # maxcrit] for row in db_criteria: # arbitrarily large number in case this Python does # not support IEEE754 db_criterion = ["0", INFINITY] # now populate in valid database values (i.e. non-NULL values) if row[Fields.MINCRIT]: db_criterion[0] = row[Fields.MINCRIT] if row[Fields.MAXCRIT]: db_criterion[1] = row[Fields.MAXCRIT] if crit == "mac": # use a hexadecimal conversion db_criterion = [long(str(db_criterion[0]), 16), long(str(db_criterion[1]), 16)] else: # these are decimal numbers db_criterion = [long(str(db_criterion[0])), long(str(db_criterion[1]))] # these three criteria can determine if there's a range overlap if((man_criterion[1] >= db_criterion[0] and db_criterion[1] >= man_criterion[0]) or man_criterion[0] == db_criterion[1]): # range overlap so record the collision try: collisions[row[Fields.MANNAME], row[Fields.MANINST]] += "MIN" + crit + "," collisions[row[Fields.MANNAME], row[Fields.MANINST]] += "MAX" + crit + "," except KeyError: collisions[row[Fields.MANNAME], row[Fields.MANINST]] = "MIN" + crit + "," collisions[row[Fields.MANNAME], row[Fields.MANINST]] += "MAX" + crit + "," return collisions