controller.py 3.41 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
from __future__ import print_function

import logging

logger = logging.getLogger('nrm')


class Action(object):

    """Information about a control action."""

12
    def __init__(self, target, command, delta):
13 14
        self.target = target
        self.command = command
15 16
        self.delta = delta

17 18 19 20 21 22 23 24 25 26 27
class PowerActuator(object):

    """Actuator in charge of power control."""

    def __init__(self, sm):
        self.sensor_manager = sm

    def available_actions(self, target):
        actions = []
        pl = self.sensor_manager.get_powerlimits()
        logger.info("power limits: %r:", pl)
28 29
        if target == 'i':
            for k in pl:
30
                r = range(int(pl[k]['curW'])+1, int(pl[k]['maxW']))
31 32 33
                actions.extend([Action(k, s, s - r[0]) for s in r])
        elif target == 'd':
            for k in pl:
34 35
                r = range(1, int(pl[k]['curW']))
                actions.extend([Action(k, s, r[-1] - s) for s in r])
36 37 38
        return actions

    def execute(self, action):
Valentin Reis's avatar
Valentin Reis committed
39 40 41 42
        logger.info("changing power limit. command: %r, delta: %r, target: %r",
                    action.command, action.delta, action.target)
        # sensor_manager is a SensorManager, which is not only about sensing
        # but also about setting power limits.
43
        # self.sensor_manager.set_powerlimit(action.target, action.command)
44 45 46 47

    def update(self, action):
        pass

48 49 50 51 52

class Controller(object):

    """Implements a control loop for resource management."""

53 54
    def __init__(self, actuators):
        self.actuators = actuators
55 56 57 58

    def planify(self, target, machineinfo):
        """Plan the next action for the control loop."""
        total_power = machineinfo['energy']['power']['total']
59
        direction = None
60
        if total_power < target:
61
            direction = 'i'
62
        elif total_power > target:
63 64 65
            direction = 'd'

        if direction:
66 67 68 69
            actions = []
            for act in self.actuators:
                newactions = act.available_actions(direction)
                actions.extend([(a, act) for a in newactions])
70 71
            if actions:
                # TODO: better choice
72
                actions.sort(key=lambda x: x[0].delta)
73
                return actions.pop(0)
74
            else:
75
                return (None, None)
76

77
    def execute(self, action, actuator):
78
        """Build the action for the appropriate manager."""
79
        actuator.execute(action)
80

81
    def update(self, action, actuator):
82
        """Update tracking across the board to reflect the last action."""
83
        actuator.update(action)
84 85 86 87

    def run_policy(self, containers):
        """Run policies on containers with policies set."""
        for container in containers:
88
            pp = containers[container].power
89 90 91 92 93 94 95 96 97 98 99 100
            if pp['policy']:
                apps = self.actuators[0].application_manager.applications
                if apps:
                    app = next(apps[a] for a in apps if apps[a].container_uuid
                               == container)
                    ids = containers[container].resources['cpus']
                    # Run policy only if all phase contexts have been received
                    if not filter(lambda i: not app.phase_contexts[i]['set'],
                                  ids):
                        pp['manager'].run_policy(app.phase_contexts)
                        if filter(lambda i: app.phase_contexts[i]['set'], ids):
                            logger.debug("Phase context not reset %r", app)