usr/src/cmd/ai-webserver/publish_manifest.py
changeset 1160 6f7e708c38ec
parent 1151 95413393ef67
child 1221 31c6d2de5731
equal deleted inserted replaced
1159:fbde90ccfae9 1160:6f7e708c38ec
   193     """
   193     """
   194     Convert criteria list into dictionary. This function is intended to be
   194     Convert criteria list into dictionary. This function is intended to be
   195     called by a main function, or the options parser, so it can potentially
   195     called by a main function, or the options parser, so it can potentially
   196     raise the SystemExit exception.
   196     raise the SystemExit exception.
   197     Args: criteria in list format: [ criteria=value, criteria=value, ... ]
   197     Args: criteria in list format: [ criteria=value, criteria=value, ... ]
   198           where value can be a:  single value
   198           where value can be a:  single string value
       
   199                                  space-separated string value (list of values)
   199                                  range (<lower>-<upper>)
   200                                  range (<lower>-<upper>)
   200     Returns: dictionary of criteria { criteria: value, criteria: value, ... }
   201     Returns: dictionary of criteria { criteria: value, criteria: value, ... }
   201              with all keys and values in lower case
   202              with all keys in lower case, values are case-sensitive.
   202     Raises: ValueError on malformed name=value strings in input list.
   203     Raises: ValueError on malformed name=value strings in input list.
   203     """
   204     """
   204     cri_dict = {}
   205     cri_dict = {}
   205     for entry in criteria:
   206     for entry in criteria:
   206         entries = entry.lower().partition("=")
   207         entries = entry.partition("=")
   207 
   208 
   208         if entries[1]:
   209         if entries[1]:
   209             if not entries[0]:
   210             if not entries[0]:
   210                 raise ValueError(_("Missing criteria name in "
   211                 raise ValueError(_("Missing criteria name in "
   211                                    "'%s'\n") % entry)
   212                                    "'%s'\n") % entry)
   212             elif entries[0] in cri_dict:
   213             elif entries[0].lower() in cri_dict:
   213                 raise ValueError(_("Duplicate criteria: '%s'\n") %
   214                 raise ValueError(_("Duplicate criteria: '%s'\n") %
   214                              entries[0])
   215                              entries[0])
   215             elif not entries[2]:
   216             elif not entries[2]:
   216                 raise ValueError(_("Missing value for criteria "
   217                 raise ValueError(_("Missing value for criteria "
   217                                    "'%s'\n") % entries[0])
   218                                    "'%s'\n") % entries[0])
   218             cri_dict[entries[0]] = entries[2]
   219             cri_dict[entries[0].lower()] = entries[2]
   219         else:
   220         else:
   220             raise ValueError(_("Criteria must be of the form "
   221             raise ValueError(_("Criteria must be of the form "
   221                                "<criteria>=<value>\n"))
   222                                "<criteria>=<value>\n"))
   222 
   223 
   223     return cri_dict
   224     return cri_dict
   264     # collisions with database entries
   265     # collisions with database entries
   265     for crit in criteria:
   266     for crit in criteria:
   266         # gather this criteria's values from the manifest
   267         # gather this criteria's values from the manifest
   267         man_criterion = criteria[crit]
   268         man_criterion = criteria[crit]
   268 
   269 
   269         # check "value" criteria here (check the criteria exists in DB, and
   270         # Determine if this crit is a range criteria or not.
   270         # then find collisions)
   271         is_range_crit = AIdb.isRangeCriteria(db.getQueue(), crit,
   271         if isinstance(man_criterion, basestring):
   272             AIdb.MANIFESTS_TABLE)
       
   273 
       
   274         # Process "value" criteria here (check if the criteria exists in
       
   275         # DB, and then find collisions)
       
   276         if not is_range_crit:
   272             # only check criteria in use in the DB
   277             # only check criteria in use in the DB
   273             if crit not in AIdb.getCriteria(db.getQueue(),
   278             if crit not in AIdb.getCriteria(db.getQueue(),
   274                                             onlyUsed=False, strip=False):
   279                                             onlyUsed=False, strip=False):
   275                 raise SystemExit(_("Error:\tCriteria %s is not a " +
   280                 raise SystemExit(_("Error:\tCriteria %s is not a " +
   276                                    "valid criteria!") % crit)
   281                                    "valid criteria!") % crit)
   283                 excludeManifests=exclude_manifests)
   288                 excludeManifests=exclude_manifests)
   284 
   289 
   285             # will iterate over a list of the form [manName, manInst, crit,
   290             # will iterate over a list of the form [manName, manInst, crit,
   286             # None]
   291             # None]
   287             for row in db_criteria:
   292             for row in db_criteria:
   288                 # check if the database and manifest values differ
   293                 # check if a value in the list of values to be added is equal
   289                 if(str(row[Fields.CRIT]).lower() ==
   294                 # to a value in the list of values for this criteria for this
   290                    str(man_criterion).lower()):
   295                 # row
   291                     # record manifest name, instance and criteria name
   296                 for value in man_criterion:
   292                     try:
   297                     if AIdb.is_in_list(crit, value, str(row[Fields.CRIT]),
   293                         collisions[row[Fields.MANNAME],
   298                         None):
   294                                    row[Fields.MANINST]] += crit + ","
   299                         # record manifest name, instance and criteria name
   295                     except KeyError:
   300                         try:
   296                         collisions[row[Fields.MANNAME],
   301                             collisions[row[Fields.MANNAME],
   297                                    row[Fields.MANINST]] = crit + ","
   302                                        row[Fields.MANINST]] += crit + ","
       
   303                         except KeyError:
       
   304                             collisions[row[Fields.MANNAME],
       
   305                                        row[Fields.MANINST]] = crit + ","
   298 
   306 
   299         # This is a range criteria.  (Check that ranges are valid, that
   307         # This is a range criteria.  (Check that ranges are valid, that
   300         # "unbounded" gets set to 0/+inf, ensure the criteria exists
   308         # "unbounded" gets set to 0/+inf, ensure the criteria exists
   301         # in the DB, then look for collisions.)
   309         # in the DB, then look for collisions.)
   302         else:
   310         else:
   482                                        "\n\tin criteria: %s!") %
   490                                        "\n\tin criteria: %s!") %
   483                                      (man_inst[0], man_inst[1],
   491                                      (man_inst[0], man_inst[1],
   484                                       crit.replace('MIN', '', 1).
   492                                       crit.replace('MIN', '', 1).
   485                                       replace('MAX', '', 1)))
   493                                       replace('MAX', '', 1)))
   486 
   494 
   487             # the range did not collide or this is a single value (if we
   495             # Either the range did not collide or this is not a range
   488             # differ we can break out knowing we diverge for this
   496             # criteria.  (If the value of this criteria in the db does
       
   497             # not equal the value of this criteria for the set of criteria
       
   498             # to check, we can break out knowing we diverge for this
   489             # manifest/instance)
   499             # manifest/instance)
   490             elif str(db_criterion).lower() != str(man_criterion).lower():
   500             elif not db_criterion and not man_criterion:
   491                 # manifests diverge (they don't collide)
   501                 # Neither the value for this criteria in the db nor 
       
   502                 # the value for for this criteria in the given set of
       
   503                 # criteria to check are populated.  Loop around to
       
   504                 # check the next criteria.
       
   505                 continue
       
   506             elif not db_criterion or not man_criterion:
       
   507                 # One of the two are not populated, we can break knowing
       
   508                 # they're different.
   492                 break
   509                 break
   493 
   510             else:
   494         # end of for loop and we never broke out (diverged)
   511                 # Both are populated.  If none of values in the list for
       
   512                 # this criteria to be added are equal to any of the values
       
   513                 # in the list for this criteria from the db, there will be
       
   514                 # no collision.  We can break out.
       
   515                 if not [value for value in man_criterion if \
       
   516                     AIdb.is_in_list(crit, value, str(db_criterion), None)]:
       
   517                     break
       
   518 
       
   519         # end of for loop and we never broke out (collision)
   495         else:
   520         else:
   496             raise SystemExit(_("Error:\tManifest has same criteria as " +
   521             raise SystemExit(_("Error:\tManifest has same criteria as " +
   497                                "manifest: %s/%i!") %
   522                                "manifest: %s/%i!") %
   498                              (man_inst[0], man_inst[1]))
   523                              (man_inst[0], man_inst[1]))
   499 
   524 
   543                 query += "NULL,NULL,"
   568                 query += "NULL,NULL,"
   544             # this is a single value
   569             # this is a single value
   545             else:
   570             else:
   546                 query += "NULL,"
   571                 query += "NULL,"
   547 
   572 
   548         # this is a single criteria (not a range)
   573         # Else if this is a value criteria (not a range), insert the value
   549         elif isinstance(values, basestring):
   574         # as a space-separated list of values which will account for the case
   550             # translate "unbounded" to a database NULL
   575         # where a list of values have been given.
   551             if values == "unbounded":
   576         elif not crit.startswith('MAX'):
   552                 query += "NULL,"
   577             # Join the values of the list with a space separator.
   553             else:
   578             query += "'" + AIdb.sanitizeSQL(" ".join(values)) + "',"
   554                 # use lower case for text strings
       
   555                 query += "'" + AIdb.sanitizeSQL(str(values).lower()) + "',"
       
   556 
       
   557         # else values is a range
   579         # else values is a range
   558         else:
   580         else:
   559             for value in values:
   581             for value in values:
   560                 # translate "unbounded" to a database NULL
   582                 # translate "unbounded" to a database NULL
   561                 if value == "unbounded":
   583                 if value == "unbounded":
   693     root, errors = (verifyXML.verifyRelaxNGManifest(schema,
   715     root, errors = (verifyXML.verifyRelaxNGManifest(schema,
   694             StringIO.StringIO(lxml.etree.tostring(crit.getroot()))))
   716             StringIO.StringIO(lxml.etree.tostring(crit.getroot()))))
   695     logging.debug('criteria file passed RNG validation')
   717     logging.debug('criteria file passed RNG validation')
   696 
   718 
   697     if errors:
   719     if errors:
   698         raise ValueError(_("Error:\tFile %s failed validation:\n\t%s") %
   720         raise ValueError(_("Error:\tFile %s failed validation:\n"
   699                          (criteria_path, root.message))
   721                            "\tline %s: %s") % (criteria_path, errors.line,
       
   722                            errors.message))
   700     try:
   723     try:
   701         verifyXML.prepValuesAndRanges(root, db, table)
   724         verifyXML.prepValuesAndRanges(root, db, table)
   702     except ValueError, err:
   725     except ValueError, err:
   703         raise ValueError(_("Error:\tCriteria manifest error: %s") % err)
   726         raise ValueError(_("Error:\tCriteria manifest error: %s") % err)
   704 
   727 
   815                     raise AssertionError(_("Criteria contains no values"))
   838                     raise AssertionError(_("Criteria contains no values"))
   816 
   839 
   817     def get_criterion(self, criterion):
   840     def get_criterion(self, criterion):
   818         """
   841         """
   819         Return criterion out of the criteria DOM
   842         Return criterion out of the criteria DOM
   820         Returns: A list for range criterion with a min and max entry
   843         Returns: A two-item list for range criterion with a min and max entry
   821                  A string for value criterion
   844                  A list of one or more values for value criterion
   822         """
   845         """
   823 
   846 
   824         if self._criteria_root is None:
   847         if self._criteria_root is None:
   825             return None
   848             return None
   826 
   849 
   828         for tag in source.getiterator('ai_criteria'):
   851         for tag in source.getiterator('ai_criteria'):
   829             crit = tag.get('name')
   852             crit = tag.get('name')
   830             # compare criteria name case-insensitive
   853             # compare criteria name case-insensitive
   831             if crit.lower() == criterion.lower():
   854             if crit.lower() == criterion.lower():
   832                 for child in tag.getchildren():
   855                 for child in tag.getchildren():
   833                     if child.tag == "range":
   856                     if child.text is not None:
   834                         # this is a range response (split on white space)
   857                         # split on white space for both values and ranges
   835                         return child.text.split()
   858                         return child.text.split()
   836                     elif child.tag == "value":
       
   837                         # this is a value response (strip white space)
       
   838                         return child.text.strip()
       
   839                     # should not happen according to schema
   859                     # should not happen according to schema
   840                     elif child.text is None:
   860                     else:
   841                         raise AssertionError(_("Criteria contains no values"))
   861                         raise AssertionError(_("Criteria contains no values"))
   842         return None
   862         return None
   843 
   863 
   844     """
   864     """
   845     Look up a requested criteria (akin to dictionary access) but for an
   865     Look up a requested criteria (akin to dictionary access) but for an