src/modules/client/api.py
changeset 1505 cc598d70bbbe
parent 1504 265a1d6b86bd
child 1516 8c950a3b4171
equal deleted inserted replaced
1504:265a1d6b86bd 1505:cc598d70bbbe
    41 import pkg.client.query_parser as query_p
    41 import pkg.client.query_parser as query_p
    42 import pkg.fmri as fmri
    42 import pkg.fmri as fmri
    43 import pkg.misc as misc
    43 import pkg.misc as misc
    44 import pkg.p5i as p5i
    44 import pkg.p5i as p5i
    45 import pkg.search_errors as search_errors
    45 import pkg.search_errors as search_errors
    46 import pkg.variant as variant
       
    47 import pkg.nrlock
    46 import pkg.nrlock
    48 
    47 
    49 from pkg.client.imageplan import EXECUTED_OK
    48 from pkg.client.imageplan import EXECUTED_OK
    50 from pkg.client import global_settings
    49 from pkg.client import global_settings
    51 
    50 
    52 CURRENT_API_VERSION = 23
    51 CURRENT_API_VERSION = 24
    53 CURRENT_P5I_VERSION = 1
    52 CURRENT_P5I_VERSION = 1
    54 
    53 
    55 logger = global_settings.logger
    54 logger = global_settings.logger
    56 
    55 
    57 class ImageInterface(object):
    56 class ImageInterface(object):
    86                 callbacks. cancel_state_callable is a function which the client
    85                 callbacks. cancel_state_callable is a function which the client
    87                 wishes to have called each time whether the operation can be
    86                 wishes to have called each time whether the operation can be
    88                 canceled changes. It can raise VersionException and
    87                 canceled changes. It can raise VersionException and
    89                 ImageNotFoundException."""
    88                 ImageNotFoundException."""
    90 
    89 
    91                 compatible_versions = set([23])
    90                 compatible_versions = set([CURRENT_API_VERSION])
    92 
    91 
    93                 if version_id not in compatible_versions:
    92                 if version_id not in compatible_versions:
    94                         raise api_errors.VersionException(CURRENT_API_VERSION,
    93                         raise api_errors.VersionException(CURRENT_API_VERSION,
    95                             version_id)
    94                             version_id)
    96 
    95 
   241                         self.log_operation_end(error=exc_value)
   240                         self.log_operation_end(error=exc_value)
   242                 self.__reset_unlock()
   241                 self.__reset_unlock()
   243                 self.__activity_lock.release()
   242                 self.__activity_lock.release()
   244                 raise
   243                 raise
   245 
   244 
   246 
   245         def plan_install(self, pkg_list, refresh_catalogs=True,
   247         def plan_install(self, pkg_list, filters, refresh_catalogs=True,
       
   248             noexecute=False, verbose=False, update_index=True):
   246             noexecute=False, verbose=False, update_index=True):
   249                 """Contructs a plan to install the packages provided in
   247                 """Contructs a plan to install the packages provided in
   250                 pkg_list.  pkg_list is a list of packages to install.  filters
   248                 pkg_list.  pkg_list is a list of packages to install.  
   251                 is a list of filters to apply to the actions of the installed
   249                 refresh_catalogs controls whether the catalogs will
   252                 packages.  refresh_catalogs controls whether the catalogs will
       
   253                 automatically be refreshed. noexecute determines whether the
   250                 automatically be refreshed. noexecute determines whether the
   254                 history will be recorded after planning is finished.  verbose
   251                 history will be recorded after planning is finished.  verbose
   255                 controls whether verbose debugging output will be printed to the
   252                 controls whether verbose debugging output will be printed to the
   256                 terminal.  Its existence is temporary.  It returns a boolean
   253                 terminal.  Its existence is temporary.  It returns a boolean
   257                 which tells the client whether there is anything to do.  It can
   254                 which tells the client whether there is anything to do.  It can
   266                                 self.__refresh_publishers()
   263                                 self.__refresh_publishers()
   267 
   264 
   268                         self.__img.make_install_plan(pkg_list,
   265                         self.__img.make_install_plan(pkg_list,
   269                             self.__progresstracker,
   266                             self.__progresstracker,
   270                             self.__check_cancelation, noexecute,
   267                             self.__check_cancelation, noexecute,
   271                             filters=filters, verbose=verbose)
   268                             verbose=verbose)
   272 
   269 
   273                         assert self.__img.imageplan
   270                         assert self.__img.imageplan
   274 
   271 
   275                         if self.__canceling:
   272                         if self.__canceling:
   276                                 raise api_errors.CanceledException()
   273                                 raise api_errors.CanceledException()
   387                                 except api_errors.ImageNotFoundException:
   384                                 except api_errors.ImageNotFoundException:
   388                                         # Can't do anything in this
   385                                         # Can't do anything in this
   389                                         # case; so proceed.
   386                                         # case; so proceed.
   390                                         pass
   387                                         pass
   391 
   388 
   392                         # XXX For now, strip the publisher prefix from FMRIs for
   389                         self.__img.make_update_plan(self.__progresstracker,
   393                         # packages that were installed from a publisher that was
   390                             self.__check_cancelation, noexecute,
   394                         # preferred at the time of installation.  However, when
   391                             verbose=verbose)
   395                         # the image starts using prioritised publishers, this
   392                             
   396                         # will have to be removed.  Newer versions of packages
       
   397                         # should only be a valid match if offered the same
       
   398                         # publisher since equivalence cannot be determined by
       
   399                         # package name alone.
       
   400                         ppub = self.__img.get_preferred_publisher()
       
   401                         pkg_list = [
       
   402                             p.get_pkg_stem(anarchy=self.__img.is_pkg_preferred(
       
   403                                 p))
       
   404                             for p in self.__img.gen_installed_pkgs()
       
   405                         ]
       
   406 
       
   407                         self.__img.make_install_plan(pkg_list,
       
   408                             self.__progresstracker, self.__check_cancelation,
       
   409                             noexecute, verbose=verbose, multimatch_ignore=True)
       
   410 
       
   411                         assert self.__img.imageplan
   393                         assert self.__img.imageplan
   412 
   394 
   413                         if self.__canceling:
   395                         if self.__canceling:
   414                                 raise api_errors.CanceledException()
   396                                 raise api_errors.CanceledException()
   415                         self.__set_can_be_canceled(False)
   397                         self.__set_can_be_canceled(False)
   431 
   413 
   432                 self.__plan_common_finish()
   414                 self.__plan_common_finish()
   433                 res = not self.__img.imageplan.nothingtodo()
   415                 res = not self.__img.imageplan.nothingtodo()
   434                 return res, opensolaris_image
   416                 return res, opensolaris_image
   435 
   417 
   436         def plan_change_variant(self, variants, noexecute=False,
   418         def plan_change_varcets(self, variants=None, facets=None,
   437             verbose=False, be_name=None):
   419             noexecute=False, verbose=False, be_name=None):
   438                 """Creates a plan to change the specified variants on an image.
   420                 """Creates a plan to change the specified variants/facets on an image.
   439                 There is option to refresh_catalogs since if we're changing
   421                 verbose controls
   440                 architectures, we have to download manifests that were
       
   441                 previously uncached.  noexecute determines whether the history
       
   442                 will be recorded after planning is finished.  verbose controls
       
   443                 whether verbose debugging output will be printed to the
   422                 whether verbose debugging output will be printed to the
   444                 terminal.  This function has two return values.  The first is
   423                 terminal.  This function has two return values.  The first is
   445                 a boolean which tells the client whether there is anything to
   424                 a boolean which tells the client whether there is anything to
   446                 do.  The third is either None, or an exception which indicates
   425                 do.  The third is either None, or an exception which indicates
   447                 partial success.  This is currently used to indicate a failure
   426                 partial success.  This is currently used to indicate a failure
   448                 in refreshing catalogs. It can raise CatalogRefreshException,
   427                 in refreshing catalogs. It can raise CatalogRefreshException,
   449                 IpkgOutOfDateException, NetworkUnavailableException,
   428                 IpkgOutOfDateException, NetworkUnavailableException,
   450                 PlanCreationException and PermissionsException."""
   429                 PlanCreationException and PermissionsException."""
   451 
   430 
   452                 self.__plan_common_start("change-variant")
   431                 self.__plan_common_start("change-variant")
       
   432                 if not variants and not facets:
       
   433                         raise ValueError, "Nothing to do"
   453                 try:
   434                 try:
   454                         self.check_be_name(be_name)
   435                         self.check_be_name(be_name)
   455                         self.be_name = be_name
   436                         self.be_name = be_name
   456 
   437 
   457                         self.__refresh_publishers()
   438                         self.__refresh_publishers()
   458 
   439 
   459                         self.__img.image_change_variant(variants,
   440                         self.__img.image_change_varcets(variants, 
       
   441                             facets,
   460                             self.__progresstracker,
   442                             self.__progresstracker,
   461                             self.__check_cancelation,
   443                             self.__check_cancelation,
   462                             noexecute, verbose=verbose)
   444                             noexecute, verbose=verbose)
   463 
   445 
   464                         assert self.__img.imageplan
   446                         assert self.__img.imageplan
   596                                 if self.__img.is_liveroot():
   578                                 if self.__img.is_liveroot():
   597                                         e = api_errors.ImageUpdateOnLiveImageException()
   579                                         e = api_errors.ImageUpdateOnLiveImageException()
   598                                         self.log_operation_end(error=e)
   580                                         self.log_operation_end(error=e)
   599                                         raise e
   581                                         raise e
   600                         else:
   582                         else:
   601                                 if self.__img.imageplan.actuators.reboot_needed() and \
   583                                 if self.__img.imageplan.reboot_needed() and \
   602                                     self.__img.is_liveroot():
   584                                     self.__img.is_liveroot():
   603                                         e = api_errors.RebootNeededOnLiveImageException()
   585                                         e = api_errors.RebootNeededOnLiveImageException()
   604                                         self.log_operation_end(error=e)
   586                                         self.log_operation_end(error=e)
   605                                         raise e
   587                                         raise e
   606 
   588 
  1051         def __set_history_PlanCreationException(self, e):
  1033         def __set_history_PlanCreationException(self, e):
  1052                 if e.unmatched_fmris or e.multiple_matches or \
  1034                 if e.unmatched_fmris or e.multiple_matches or \
  1053                     e.missing_matches or e.illegal:
  1035                     e.missing_matches or e.illegal:
  1054                         self.log_operation_end(error=e,
  1036                         self.log_operation_end(error=e,
  1055                             result=history.RESULT_FAILED_BAD_REQUEST)
  1037                             result=history.RESULT_FAILED_BAD_REQUEST)
  1056                 elif e.constraint_violations:
       
  1057                         self.log_operation_end(error=e,
       
  1058                             result=history.RESULT_FAILED_CONSTRAINED)
       
  1059                 else:
  1038                 else:
  1060                         self.log_operation_end(error=e)
  1039                         self.log_operation_end(error=e)
  1061 
  1040 
  1062         def local_search(self, query_lst):
  1041         def local_search(self, query_lst):
  1063                 """local_search takes a list of Query objects and performs
  1042                 """local_search takes a list of Query objects and performs
  1086                                     get_manifest_path=\
  1065                                     get_manifest_path=\
  1087                                         self.__img.get_manifest_path,
  1066                                         self.__img.get_manifest_path,
  1088                                     gen_installed_pkg_names=\
  1067                                     gen_installed_pkg_names=\
  1089                                         self.__img.gen_installed_pkg_names,
  1068                                         self.__img.gen_installed_pkg_names,
  1090                                     case_sensitive=q.case_sensitive)
  1069                                     case_sensitive=q.case_sensitive)
  1091                                 excludes = [variant.Variants(
       
  1092                                     {"variant.arch": self.__img.get_arch()}
       
  1093                                     ).allow_action]
       
  1094                                 res = query.search(
  1070                                 res = query.search(
  1095                                     self.__img.gen_installed_pkgs,
  1071                                     self.__img.gen_installed_pkgs,
  1096                                     self.__img.get_manifest_path, excludes)
  1072                                     self.__img.get_manifest_path,
       
  1073                                     self.__img.list_excludes())
  1097                         except search_errors.InconsistentIndexException, e:
  1074                         except search_errors.InconsistentIndexException, e:
  1098                                 raise api_errors.InconsistentIndexException(e)
  1075                                 raise api_errors.InconsistentIndexException(e)
  1099                         # i is being inserted to track which query the results
  1076                         # i is being inserted to track which query the results
  1100                         # are for.  None is being inserted since there is no
  1077                         # are for.  None is being inserted since there is no
  1101                         # publisher being searched against.
  1078                         # publisher being searched against.
  1265                 self.__img.update_index_dir()
  1242                 self.__img.update_index_dir()
  1266                 self.log_operation_start("rebuild-index")
  1243                 self.log_operation_start("rebuild-index")
  1267                 if not os.path.isdir(self.__img.index_dir):
  1244                 if not os.path.isdir(self.__img.index_dir):
  1268                         self.__img.mkdirs()
  1245                         self.__img.mkdirs()
  1269                 try:
  1246                 try:
  1270                         excludes = [variant.Variants(
       
  1271                             {"variant.arch": self.__img.get_arch()}).allow_action]
       
  1272                         ind = indexer.Indexer(self.__img, self.__img.get_manifest,
  1247                         ind = indexer.Indexer(self.__img, self.__img.get_manifest,
  1273                             self.__img.get_manifest_path,
  1248                             self.__img.get_manifest_path,
  1274                             self.__progresstracker, excludes)
  1249                             self.__progresstracker, self.__img.list_excludes())
  1275                         ind.rebuild_index_from_scratch(
  1250                         ind.rebuild_index_from_scratch(
  1276                             self.__img.gen_installed_pkgs())
  1251                             self.__img.gen_installed_pkgs())
  1277                 except search_errors.ProblematicPermissionsIndexException, e:
  1252                 except search_errors.ProblematicPermissionsIndexException, e:
  1278                         error = api_errors.ProblematicPermissionsIndexException(e)
  1253                         error = api_errors.ProblematicPermissionsIndexException(e)
  1279                         self.log_operation_end(error=error)
  1254                         self.log_operation_end(error=error)
  1305                         self.__img.add_publisher(pub,
  1280                         self.__img.add_publisher(pub,
  1306                             refresh_allowed=refresh_allowed,
  1281                             refresh_allowed=refresh_allowed,
  1307                             progtrack=self.__progresstracker)
  1282                             progtrack=self.__progresstracker)
  1308                 finally:
  1283                 finally:
  1309                         self.__img.cleanup_downloads()
  1284                         self.__img.cleanup_downloads()
       
  1285 
       
  1286         def get_pub_search_order(self):
       
  1287                 """Return current search order of publishers; includes
       
  1288                 disabled publishers"""
       
  1289                 return self.__img.cfg_cache.publisher_search_order
       
  1290 
       
  1291         def set_pub_search_after(self, being_moved_prefix, staying_put_prefix):
       
  1292                 """Change the publisher search order so that being_moved is
       
  1293                 searched after staying_put"""
       
  1294                 self.__img.pub_search_after(being_moved_prefix, staying_put_prefix)
       
  1295 
       
  1296         def set_pub_search_before(self, being_moved_prefix, staying_put_prefix):
       
  1297                 """Change the publisher search order so that being_moved is
       
  1298                 searched before staying_put"""
       
  1299                 self.__img.pub_search_before(being_moved_prefix, staying_put_prefix)
  1310 
  1300 
  1311         def get_preferred_publisher(self):
  1301         def get_preferred_publisher(self):
  1312                 """Returns the preferred publisher object for the image."""
  1302                 """Returns the preferred publisher object for the image."""
  1313                 return self.get_publisher(
  1303                 return self.get_publisher(
  1314                     prefix=self.__img.get_preferred_publisher())
  1304                     prefix=self.__img.get_preferred_publisher())
  1456 
  1446 
  1457                                 # Now remove the old publisher object using the
  1447                                 # Now remove the old publisher object using the
  1458                                 # iterator key since the prefix might be
  1448                                 # iterator key since the prefix might be
  1459                                 # different for the new publisher object.
  1449                                 # different for the new publisher object.
  1460                                 updated = True
  1450                                 updated = True
  1461                                 del publishers[key]
  1451 
       
  1452                                 # only if prefix is different - this
       
  1453                                 # preserves search order
       
  1454                                 if key != pub.prefix:
       
  1455                                         del publishers[key]
  1462 
  1456 
  1463                                 # Prepare the new publisher object.
  1457                                 # Prepare the new publisher object.
  1464                                 pub.meta_root = \
  1458                                 pub.meta_root = \
  1465                                     self.__img._get_publisher_meta_root(
  1459                                     self.__img._get_publisher_meta_root(
  1466                                     pub.prefix)
  1460                                     pub.prefix)