imip-agent

imiptools/handlers/scheduling/__init__.py

1363:96314da27b34
2017-10-24 Paul Boddie Updated materialise method usage.
     1 #!/usr/bin/env python     2      3 """     4 Autonomous scheduling functionality.     5      6 Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>     7      8 This program is free software; you can redistribute it and/or modify it under     9 the terms of the GNU General Public License as published by the Free Software    10 Foundation; either version 3 of the License, or (at your option) any later    11 version.    12     13 This program is distributed in the hope that it will be useful, but WITHOUT    14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    15 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    16 details.    17     18 You should have received a copy of the GNU General Public License along with    19 this program.  If not, see <http://www.gnu.org/licenses/>.    20 """    21     22 from imiptools.text import parse_line    23 from imiptools.handlers.scheduling.manifest import confirmation_functions, \    24                                                    locking_functions, \    25                                                    retraction_functions, \    26                                                    scheduling_functions, \    27                                                    unlocking_functions    28     29 # Function application/invocation.    30     31 def apply_scheduling_functions(handler):    32     33     """    34     Apply the scheduling functions for the current object of the given    35     'handler'. This function starts a transaction that should be finalised using    36     the 'finish_scheduling' function.    37     38     Return a tuple containing the scheduling decision and any accompanying    39     description.    40     """    41     42     # First, lock the resources to be used.    43     44     start_scheduling(handler)    45     46     # Obtain the actual scheduling functions with arguments.    47     48     schedulers = get_function_calls(handler.get_scheduling_functions(), scheduling_functions)    49     50     # Then, invoke the scheduling functions.    51     52     response = "ACCEPTED"    53     description = None    54     55     for fn, args in schedulers:    56     57         # NOTE: Should signal an error for incorrectly configured resources.    58     59         if not fn:    60             return "DECLINED", None    61     62         # Keep evaluating scheduling functions, stopping if one declines or    63         # gives a null response, or if one delegates to another resource.    64     65         else:    66             result = fn(handler, args)    67             result, description = result or ("DECLINED", None)    68     69             # Return a negative result immediately.    70     71             if result in ("DECLINED", "DELEGATED"):    72                 return result, description    73     74             # Modify the eventual response from acceptance if a countering    75             # result is obtained.    76     77             elif response == "ACCEPTED":    78                 response = result    79     80     return response, description    81     82 def confirm_scheduling(handler):    83     84     """    85     Confirm scheduling using confirmation functions for the current object of    86     the given 'handler'. This function continues a transaction that should be    87     finalised using the 'finish_scheduling' function.    88     """    89     90     # Obtain the actual confirmation functions with arguments.    91     92     functions = get_function_calls(handler.get_scheduling_functions(), confirmation_functions)    93     apply_functions(functions, handler)    94     95 def retract_scheduling(handler):    96     97     """    98     Retract scheduling using retraction functions for the current object of the    99     given 'handler'. This function is a complete transaction in itself.   100     """   101    102     # First, lock the resources to be used.   103    104     start_scheduling(handler)   105     try:   106    107         # Obtain the actual retraction functions with arguments.   108    109         functions = get_function_calls(handler.get_scheduling_functions(), retraction_functions)   110         apply_functions(functions, handler)   111    112     # Finally, unlock the resources.   113    114     finally:   115         finish_scheduling(handler)   116    117 def start_scheduling(handler):   118    119     """   120     Apply locking functions for the given scheduling 'functions' and for the   121     current object of the given 'handler'.   122     """   123    124     # Obtain functions to lock resources.   125    126     functions = get_function_calls(handler.get_scheduling_functions(), locking_functions)   127     apply_functions(functions, handler)   128    129 def finish_scheduling(handler):   130    131     """   132     Finish scheduling using the given scheduling 'functions' for the current   133     object of the given 'handler'.   134     """   135    136     # Obtain functions to unlock resources.   137    138     functions = get_function_calls(handler.get_scheduling_functions(), unlocking_functions)   139     apply_functions(functions, handler)   140    141 def apply_functions(functions, handler):   142    143     """   144     Apply the given notification 'functions' for the current object of the given   145     'handler'. Where functions are provided more than once, they will be called   146     only once for each distinct set of arguments.   147     """   148    149     applied = set()   150    151     for fn, args in functions:   152    153         # NOTE: Should signal an error for incorrectly configured resources.   154    155         if not fn or (fn, args) in applied:   156             continue   157    158         fn(handler, args)   159         applied.add((fn, args))   160    161 # Function lookup.   162    163 def get_function_calls(lines, registry):   164    165     """   166     Parse the given 'lines', returning a list of (function, arguments) tuples,   167     with each function being a genuine function object and with the arguments   168     being a list of strings.   169    170     Each of the 'lines' should employ the function name and argument strings   171     separated by whitespace, with any whitespace inside arguments quoted using   172     single or double quotes.   173    174     The given 'registry' indicates the mapping from function names to actual   175     functions.   176     """   177    178     functions = []   179    180     for line in lines:   181         parts = parse_line(line)   182    183         # A sequence of functions is provided for each name.   184    185         l = registry.get(parts[0])   186         if l:   187             for function in l:   188                 functions.append((function, tuple(parts[1:])))   189    190     return functions   191    192 # vim: tabstop=4 expandtab shiftwidth=4