imip-agent

Annotated imiptools/handlers/scheduling/__init__.py

1039:a12150034cbd
2016-02-08 Paul Boddie Added a journal storage area, maintaining quota and collective scheduling data for scheduling decisions. Introduced confirmation and retraction functions for resource scheduling so that quotas and collective schedules can be maintained and thus queried by scheduling functions. Updated the documentation, tools and tests.
paul@938 1
#!/usr/bin/env python
paul@938 2
paul@938 3
"""
paul@938 4
Common scheduling functionality.
paul@938 5
paul@1025 6
Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk>
paul@938 7
paul@938 8
This program is free software; you can redistribute it and/or modify it under
paul@938 9
the terms of the GNU General Public License as published by the Free Software
paul@938 10
Foundation; either version 3 of the License, or (at your option) any later
paul@938 11
version.
paul@938 12
paul@938 13
This program is distributed in the hope that it will be useful, but WITHOUT
paul@938 14
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
paul@938 15
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
paul@938 16
details.
paul@938 17
paul@938 18
You should have received a copy of the GNU General Public License along with
paul@938 19
this program.  If not, see <http://www.gnu.org/licenses/>.
paul@938 20
"""
paul@938 21
paul@1031 22
from imiptools.text import parse_line
paul@1039 23
from imiptools.handlers.scheduling.manifest import confirmation_functions, \
paul@1039 24
                                                   retraction_functions, \
paul@1039 25
                                                   scheduling_functions
paul@1039 26
paul@1039 27
# Function application/invocation.
paul@938 28
paul@1025 29
def apply_scheduling_functions(functions, handler):
paul@1025 30
paul@1025 31
    """
paul@1025 32
    Apply the given scheduling 'functions' in the current object of the given
paul@1025 33
    'handler'.
paul@1025 34
    """
paul@1025 35
paul@1031 36
    # Obtain the actual scheduling functions with arguments.
paul@1031 37
paul@1039 38
    functions = get_function_calls(functions, scheduling_functions)
paul@1031 39
paul@1025 40
    response = "ACCEPTED"
paul@1025 41
paul@1031 42
    for fn, args in functions:
paul@1025 43
paul@1025 44
        # NOTE: Should signal an error for incorrectly configured resources.
paul@1025 45
paul@1025 46
        if not fn:
paul@1025 47
            return "DECLINED"
paul@1025 48
paul@1025 49
        # Keep evaluating scheduling functions, stopping only if one
paul@1025 50
        # declines or gives a null response.
paul@1025 51
paul@1025 52
        else:
paul@1031 53
            result = fn(handler, args)
paul@1025 54
paul@1025 55
            # Return a negative result immediately.
paul@1025 56
paul@1025 57
            if not result or result == "DECLINED":
paul@1025 58
                return result
paul@1025 59
paul@1025 60
            # Modify the eventual response from acceptance if a countering
paul@1025 61
            # result is obtained.
paul@1025 62
paul@1025 63
            elif response == "ACCEPTED":
paul@1025 64
                response = result
paul@1025 65
paul@1025 66
    return response
paul@1025 67
paul@1039 68
def confirm_scheduling(functions, handler):
paul@1039 69
paul@1039 70
    """
paul@1039 71
    Confirm scheduling using the given listener 'functions' for the current
paul@1039 72
    object of the given 'handler'.
paul@1039 73
    """
paul@1039 74
paul@1039 75
    # Obtain the actual listener functions with arguments.
paul@1039 76
paul@1039 77
    functions = get_function_calls(functions, confirmation_functions)
paul@1039 78
    apply_functions(functions, handler)
paul@1039 79
paul@1039 80
def retract_scheduling(functions, handler):
paul@1039 81
paul@1039 82
    """
paul@1039 83
    Retract scheduling using the given listener 'functions' for the current
paul@1039 84
    object of the given 'handler'.
paul@1039 85
    """
paul@1039 86
paul@1039 87
    # Obtain the actual listener functions with arguments.
paul@1039 88
paul@1039 89
    functions = get_function_calls(functions, retraction_functions)
paul@1039 90
    apply_functions(functions, handler)
paul@1039 91
paul@1039 92
def apply_functions(functions, handler):
paul@1039 93
paul@1039 94
    """
paul@1039 95
    Apply the given notification 'functions' for the current object of the given
paul@1039 96
    'handler'.
paul@1039 97
    """
paul@1039 98
paul@1039 99
    for fn, args in functions:
paul@1039 100
paul@1039 101
        # NOTE: Should signal an error for incorrectly configured resources.
paul@1039 102
paul@1039 103
        if not fn:
paul@1039 104
            continue
paul@1039 105
paul@1039 106
        fn(handler, args)
paul@1039 107
paul@1039 108
# Function lookup.
paul@1039 109
paul@1039 110
def get_function_calls(lines, registry):
paul@1031 111
paul@1031 112
    """
paul@1031 113
    Parse the given 'lines', returning a list of (function, arguments) tuples,
paul@1031 114
    with each function being a genuine function object and with the arguments
paul@1031 115
    being a list of strings.
paul@1031 116
paul@1031 117
    Each of the 'lines' should employ the function name and argument strings
paul@1031 118
    separated by whitespace, with any whitespace inside arguments quoted using
paul@1031 119
    single or double quotes.
paul@1039 120
paul@1039 121
    The given 'registry' indicates the mapping from function names to actual
paul@1039 122
    functions.
paul@1031 123
    """
paul@1031 124
paul@1031 125
    functions = []
paul@1031 126
paul@1031 127
    for line in lines:
paul@1031 128
        parts = parse_line(line)
paul@1039 129
        functions.append((registry.get(parts[0]), parts[1:]))
paul@1031 130
paul@1031 131
    return functions
paul@1031 132
paul@938 133
# vim: tabstop=4 expandtab shiftwidth=4