imip-agent

imiptools/handlers/scheduling/__init__.py

1040:8f2b373a311b
2016-02-08 Paul Boddie Introduced compound locking so that information can be in a consistent state for scheduling functions and confirmation functions within the same transaction, unchanged by concurrent transactions.
     1 #!/usr/bin/env python     2      3 """     4 Common 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(functions, handler):    32     33     """    34     Apply the given scheduling 'functions' in the current object of the given    35     'handler'.    36     """    37     38     # Obtain the actual scheduling functions with arguments.    39     # Also obtain functions to lock resources.    40     41     schedulers = get_function_calls(functions, scheduling_functions)    42     locks = get_function_calls(functions, locking_functions)    43     44     # First, lock the resources to be used.    45     46     for fn, args in locks:    47     48         # Not all scheduling functions require compound locking.    49     50         if fn:    51             fn(handler, args)    52     53     # Then, invoke the scheduling functions.    54     55     response = "ACCEPTED"    56     57     for fn, args in schedulers:    58     59         # NOTE: Should signal an error for incorrectly configured resources.    60     61         if not fn:    62             return "DECLINED"    63     64         # Keep evaluating scheduling functions, stopping only if one    65         # declines or gives a null response.    66     67         else:    68             result = fn(handler, args)    69     70             # Return a negative result immediately.    71     72             if not result or result == "DECLINED":    73                 return result    74     75             # Modify the eventual response from acceptance if a countering    76             # result is obtained.    77     78             elif response == "ACCEPTED":    79                 response = result    80     81     return response    82     83 def confirm_scheduling(functions, handler):    84     85     """    86     Confirm scheduling using the given listener 'functions' for the current    87     object of the given 'handler'.    88     """    89     90     # Obtain the actual listener functions with arguments.    91     92     functions = get_function_calls(functions, confirmation_functions)    93     apply_functions(functions, handler)    94     95 def finish_scheduling(functions, handler):    96     97     """    98     Finish scheduling using the given scheduling 'functions' for the current    99     object of the given 'handler'.   100     """   101    102     # Obtain functions to unlock resources.   103    104     locks = get_function_calls(functions, unlocking_functions)   105    106     # Unlock the resources that were used.   107    108     for fn, args in locks:   109    110         # Not all scheduling functions require compound locking.   111    112         if fn:   113             fn(handler, args)   114    115 def retract_scheduling(functions, handler):   116    117     """   118     Retract scheduling using the given listener 'functions' for the current   119     object of the given 'handler'.   120     """   121    122     # Obtain the actual listener functions with arguments.   123    124     functions = get_function_calls(functions, retraction_functions)   125     apply_functions(functions, handler)   126    127 def apply_functions(functions, handler):   128    129     """   130     Apply the given notification 'functions' for the current object of the given   131     'handler'.   132     """   133    134     for fn, args in functions:   135    136         # NOTE: Should signal an error for incorrectly configured resources.   137    138         if not fn:   139             continue   140    141         fn(handler, args)   142    143 # Function lookup.   144    145 def get_function_calls(lines, registry):   146    147     """   148     Parse the given 'lines', returning a list of (function, arguments) tuples,   149     with each function being a genuine function object and with the arguments   150     being a list of strings.   151    152     Each of the 'lines' should employ the function name and argument strings   153     separated by whitespace, with any whitespace inside arguments quoted using   154     single or double quotes.   155    156     The given 'registry' indicates the mapping from function names to actual   157     functions.   158     """   159    160     functions = []   161    162     for line in lines:   163         parts = parse_line(line)   164         functions.append((registry.get(parts[0]), parts[1:]))   165    166     return functions   167    168 # vim: tabstop=4 expandtab shiftwidth=4