src/modules/client/actuator.py
changeset 2708 4dac3e277ccf
parent 2690 11a8cae074e0
child 3014 a88a867e3a9d
equal deleted inserted replaced
2707:26c37de57d61 2708:4dac3e277ccf
    23 #
    23 #
    24 # Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
    24 # Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
    25 #
    25 #
    26 
    26 
    27 import pkg.smf as smf
    27 import pkg.smf as smf
       
    28 import pkg.actions
    28 import os
    29 import os
    29 
    30 
    30 import pkg.misc
    31 import pkg.misc
    31 
    32 
    32 from pkg.client.debugvalues import DebugValues
    33 from pkg.client.debugvalues import DebugValues
    33 from pkg.client.imagetypes import IMG_USER, IMG_ENTIRE
    34 from pkg.client.imagetypes import IMG_USER, IMG_ENTIRE
    34 
    35 
    35 class GenericActuator(object):
    36 
       
    37 class Actuator(object):
    36         """Actuators are action attributes that cause side effects
    38         """Actuators are action attributes that cause side effects
    37         on live images when those actions are updated, installed
    39         on live images when those actions are updated, installed
    38         or removed.  Since no side effects are caused when the
    40         or removed.  Since no side effects are caused when the
    39         affected image isn't the current root image, the OS may
    41         affected image isn't the current root image, the OS may
    40         need to cause the equivalent effect during boot.
    42         need to cause the equivalent effect during boot.
    41         """
    43         This is Solaris specific for now. """
    42 
       
    43         actuator_attrs = set()
       
    44 
       
    45         def __init__(self):
       
    46                 self.install = {}
       
    47                 self.removal = {}
       
    48                 self.update =  {}
       
    49 
       
    50         def __nonzero__(self):
       
    51                 return bool(self.install or self.removal or self.update)
       
    52 
       
    53         def scan_install(self, attrs):
       
    54                 self.__scan(self.install, attrs)
       
    55 
       
    56         def scan_removal(self, attrs):
       
    57                 self.__scan(self.removal, attrs)
       
    58 
       
    59         def scan_update(self, attrs):
       
    60                 self.__scan(self.update, attrs)
       
    61 
       
    62         def __scan(self, dictionary, attrs):
       
    63                 for a in set(attrs.keys()) & self.actuator_attrs:
       
    64                         values = attrs[a]
       
    65 
       
    66                         if not isinstance(values, list):
       
    67                                 values = [values]
       
    68 
       
    69                         dictionary.setdefault(a, set()).update(values)
       
    70 
       
    71         def reboot_needed(self):
       
    72                 return False
       
    73 
       
    74         def exec_prep(self, image):
       
    75                 pass
       
    76 
       
    77         def exec_pre_actuators(self, image):
       
    78                 pass
       
    79 
       
    80         def exec_post_actuators(self, image):
       
    81                 pass
       
    82 
       
    83         def exec_fail_actuators(self, image):
       
    84                 pass
       
    85 
       
    86         def __str__(self):
       
    87                 return "Removals: %s\nInstalls: %s\nUpdates: %s\n" % \
       
    88                     (self.removal, self.install, self.update)
       
    89 
       
    90 
       
    91 class Actuator(GenericActuator):
       
    92         """Solaris specific Actuator implementation..."""
       
    93 
    44 
    94         actuator_attrs = set([
    45         actuator_attrs = set([
    95             "reboot-needed",    # have to reboot to update this file
    46             "reboot-needed",    # have to reboot to update this file
       
    47             "release-note",     # conditionally include this file
       
    48                                 # in release notes
    96             "refresh_fmri",     # refresh this service on any change
    49             "refresh_fmri",     # refresh this service on any change
    97             "restart_fmri",     # restart this service on any change
    50             "restart_fmri",     # restart this service on any change
    98             "suspend_fmri",     # suspend this service during update
    51             "suspend_fmri",     # suspend this service during update
    99             "disable_fmri"      # disable this service prior to removal
    52             "disable_fmri"      # disable this service prior to removal
   100         ])
    53         ])
   102         __state__desc = {
    55         __state__desc = {
   103                 "install": {
    56                 "install": {
   104                     "disable_fmri": set(),
    57                     "disable_fmri": set(),
   105                     "reboot-needed": set(),
    58                     "reboot-needed": set(),
   106                     "refresh_fmri": set(),
    59                     "refresh_fmri": set(),
       
    60                     "release-note": [(pkg.actions.generic.NSG, pkg.fmri.PkgFmri)],
   107                     "restart_fmri": set(),
    61                     "restart_fmri": set(),
   108                     "suspend_fmri": set(),
    62                     "suspend_fmri": set(),
   109                 },
    63                 },
   110                 "removal": {
    64                 "removal": {
   111                     "disable_fmri": set(),
    65                     "disable_fmri": set(),
   112                     "reboot-needed": set(),
    66                     "reboot-needed": set(),
   113                     "refresh_fmri": set(),
    67                     "refresh_fmri": set(),
       
    68                     "release-note": [(pkg.actions.generic.NSG, pkg.fmri.PkgFmri)],
   114                     "restart_fmri": set(),
    69                     "restart_fmri": set(),
   115                     "suspend_fmri": set(),
    70                     "suspend_fmri": set(),
   116                 },
    71                 },
   117                 "update": {
    72                 "update": {
   118                     "disable_fmri": set(),
    73                     "disable_fmri": set(),
   119                     "reboot-needed": set(),
    74                     "reboot-needed": set(),
   120                     "refresh_fmri": set(),
    75                     "refresh_fmri": set(),
       
    76                     "release-note": [(pkg.actions.generic.NSG, pkg.fmri.PkgFmri)],
   121                     "restart_fmri": set(),
    77                     "restart_fmri": set(),
   122                     "suspend_fmri": set(),
    78                     "suspend_fmri": set(),
   123                 },
    79                 },
   124         }
    80         }
   125 
    81 
   126         def __init__(self):
    82         def __init__(self):
   127                 GenericActuator.__init__(self)
    83                 self.install = {}
       
    84                 self.removal = {}
       
    85                 self.update =  {}
   128                 self.suspend_fmris = None
    86                 self.suspend_fmris = None
   129                 self.tmp_suspend_fmris = None
    87                 self.tmp_suspend_fmris = None
   130                 self.do_nothing = True
    88                 self.do_nothing = True
   131                 self.cmd_path = ""
    89                 self.cmd_path = ""
   132 
    90 
   161                 return rv
   119                 return rv
   162 
   120 
   163         def __bool__(self):
   121         def __bool__(self):
   164                 return self.install or self.removal or self.update
   122                 return self.install or self.removal or self.update
   165 
   123 
       
   124         def __nonzero__(self):
       
   125                 return bool(self.install or self.removal or self.update)
       
   126 
       
   127         # scan_* functions take ActionPlan arguments (see imageplan.py)
       
   128         def scan_install(self, ap):
       
   129                 self.__scan(self.install, ap.dst, ap.p.destination_fmri)
       
   130 
       
   131         def scan_removal(self, ap):
       
   132                 self.__scan(self.removal, ap.src, ap.p.origin_fmri)
       
   133 
       
   134         def scan_update(self, ap):
       
   135                 if ap.src:
       
   136                         self.__scan(self.update, ap.src, ap.p.destination_fmri)
       
   137                 self.__scan(self.update, ap.dst, ap.p.destination_fmri)
       
   138 
       
   139         def __scan(self, dictionary, act, fmri):
       
   140                 attrs = act.attrs
       
   141                 for a in set(attrs.keys()) & self.actuator_attrs:
       
   142                         if a != "release-note":
       
   143                                 values = attrs[a]
       
   144                                 if not isinstance(values, list):
       
   145                                         values = [values]
       
   146                                 dictionary.setdefault(a, set()).update(values)
       
   147                         else:
       
   148                                 if act.name == "file": # ignore for non-files
       
   149                                         dictionary.setdefault(a, list()).append(
       
   150                                             (act, fmri))
       
   151 
   166         def get_list(self):
   152         def get_list(self):
   167                 """Returns a list of actuator value pairs, suitable for printing"""
   153                 """Returns a list of actuator value pairs, suitable for printing"""
   168                 def check_val(dfmri):
   154                 def check_val(dfmri):
   169                         # For actuators which are a single, global function that
   155                         # For actuators which are a single, global function that
   170                         # needs to get executed, simply print true.
   156                         # needs to get executed, simply print true.
   171                         if callable(dfmri):
   157                         if callable(dfmri) or isinstance(dfmri, list):
   172                                 return [ "true" ]
   158                                 return [ "true" ]
   173                         else:
   159                         else:
   174                                 return dfmri
   160                                 return dfmri
   175 
   161 
   176                 merge = {}
   162                 merge = {}
   186                 return [(fmri, smf)
   172                 return [(fmri, smf)
   187                         for fmri in merge
   173                         for fmri in merge
   188                         for smf in merge[fmri]
   174                         for smf in merge[fmri]
   189                         ]
   175                         ]
   190 
   176 
       
   177         def get_release_note_info(self):
       
   178                 """Returns a list of tuples of possible release notes"""
       
   179                 return self.update.get("release-note", []) + \
       
   180                     self.install.get("release-note", [])
       
   181                 
   191         def get_services_list(self):
   182         def get_services_list(self):
   192                 """Returns a list of services that would be restarted"""
   183                 """Returns a list of services that would be restarted"""
   193                 return [(fmri, smf) for fmri, smf in self.get_list()
   184                 return [(fmri, smf) for fmri, smf in self.get_list()
   194                     if smf not in ["true", "false"]]
   185                     if smf not in ["true", "false"]]
   195 
   186 
   208                 environment."""
   199                 environment."""
   209 
   200 
   210                 return bool("true" in self.update.get("reboot-needed", [])) or \
   201                 return bool("true" in self.update.get("reboot-needed", [])) or \
   211                     bool("true" in self.removal.get("reboot-needed", []))
   202                     bool("true" in self.removal.get("reboot-needed", []))
   212 
   203 
   213         def exec_prep(self, image):                
   204         def exec_prep(self, image):
   214                 if not image.is_liveroot():
   205                 if not image.is_liveroot():
   215                         # we're doing off-line pkg ops; we need
   206                         # we're doing off-line pkg ops; we need
   216                         # to support self-assembly milestone
   207                         # to support self-assembly milestone
   217                         # so create the necessary marker file
   208                         # so create the necessary marker file
   218 
   209