Skip to content
hv.py 6.17 KiB
Newer Older
import threading

from cloudcontrol.server.handlers import listed
from cloudcontrol.server.clients import Client, RegisteredCCHandler
from cloudcontrol.server.clients.host import HostClient
from cloudcontrol.server.db import RemoteTag

from cloudcontrol.common.tql.db.object import TqlObject
Antoine Millet's avatar
Antoine Millet committed
from cloudcontrol.common.tql.db.tag import StaticTag

from functools import partial


class HypervisorHandler(RegisteredCCHandler):
    """ Handler binded to an hv client.
    """

    @listed
    def register(self, obj_id, role):
        """ Register an object managed by the calling node.

        .. note:
           the obj_id argument passed to this handler is the object id of the
           registered object (not the fully qualified id, the server will
           preprend the id by "node_id." itself).

        :param obj_id: the id of the object to register
        :param role: the role of the object to register
        self.client.register(obj_id, role)

    @listed
    def unregister(self, obj_id):
        """ Unregister an object managed by the calling node.

        .. note:
           the obj_id argument passed to this handler is the object id of the
           unregistered object (not the fully qualified id, the server will
           preprend the id by "node_id." itself).

        :param obj_id: the id of the object to unregister
        self.client.unregister(obj_id)

    @listed
    def sub_tags_register(self, obj_id, name, ttl=None, value=None):
        """ Register a new remote tag for a child of the client.

        :param obj_id: child name
        :param name: name of the tag to register
        :param ttl: TTL of the tag if applicable (None = no TTL, the tag will
                never expire)
        :param value: value of the tag
        """
        self.client.sub_tags_register(obj_id, name, ttl, value)

    @listed
    def sub_tags_unregister(self, obj_id, name):
        """ Unregister a remote tag for a child of the client.

        :param obj_id: child name
        :param name: name of the tag to unregister
        """
        self.client.sub_tags_unregister(obj_id, name)

    @listed
    def sub_tags_drop(self, obj_id, name):
        """ Drop the cached value of a remote tag for a child of the client.

        :param obj_id: child name
        :param name: name of the tag to drop
        """
        self.client.sub_tags_drop(obj_id, name)

    @listed
    def sub_tags_update(self, obj_id, name, value=None, ttl=None):
        """ Update a remote tag for a child of the client.

        :param obj_id: child name
        :param name: name of the tag to update
        :param value: new value of the tag
        :param ttl: new ttl of the tag
        """
        self.client.sub_tags_update(obj_id, name, value, ttl)


class HvClient(HostClient):

    """ A hv client connected to the cc-server.
    """

    ROLE = 'hv'
    RPC_HANDLER = HypervisorHandler

    def __init__(self, *args, **kwargs):
        super(HvClient, self).__init__(*args, **kwargs)
        self._children = {}
        self._hv_lock = threading.RLock()

    @property
    def hvlock(self):
        """ The lock used on hypervirsors for migration.
        """
        return self._hv_lock

    #
    # Children specific methods:
    #

    def shutdown(self):
        # Unregister all children:
        for child in self._children.copy():
            self.unregister(child)
        super(HvClient, self).shutdown()

    def execute(self, command):
        return self.conn.call('execute_command', command)

    def get_child_remote_tags(self, obj_id, tag):
        return self.conn.call('sub_tags', obj_id, (tag,))[tag]

    def register(self, obj_id, role):
        """ Register a new child.
        """
        child = '%s.%s' % (self.login, obj_id)

        # Register the children in the tags database:
        obj = TqlObject(child)
        obj.register(StaticTag('r', role))
        obj.register(StaticTag('p', self.login))
        self._server.db.register(obj)
        self._children[obj_id] = obj

    def unregister(self, obj_id):
        """ Unregister a child.
        """
        child = '%s.%s' % (self.login, obj_id)
        del self._children[obj_id]
        # Unregister the children from the tags database:
        self._server.db.unregister(child)

    def vm_action(self, action, vms):
        return self.conn.call(action, vms)

    def sub_tags_register(self, obj_id, name, ttl=None, value=None):
        """ Register a new remote tag for a child of the client.

        :param obj_id: child name
        :param name: name of the tag to register
        :param ttl: TTL of the tag if applicable (None = no TTL, the tag will
                never expire)
        :param value: value of the tag
        """

        callback = partial(self.async_remote_sub_tags, obj_id)
        tag = RemoteTag(name, callback, ttl=ttl)
        self._children[obj_id].register(tag)

    def sub_tags_unregister(self, obj_id, name):
        """ Unregister a remote tag for a child of the client.

        :param obj_id: child name
        :param name: name of the tag to unregister
        """

        self._children[obj_id].unregister(name)

    def sub_tags_drop(self, obj_id, name):
        """ Drop the cached value of a remote tag for a child of the client.

        :param obj_id: child name
        :param name: name of the tag to drop
        """
        tag = self._children[obj_id].get(name)
        if tag is not None:
            tag.invalidate()

    def sub_tags_update(self, obj_id, name, value=None, ttl=None):
        """ Update a remote tag for a child of the client.

        :param obj_id: child name
        :param name: name of the tag to update
        :param value: new value of the tag
        :param ttl: new ttl of the tag
        """
        tag = self._children[obj_id].get(name)
        if tag is not None:
            if value is not None:
                tag.cached = value
            if ttl is not None:
                tag.ttl = ttl

    def async_remote_sub_tags(self, obj_id, watcher, robj, tags):
        """ Asynchronously update sub tags from the remote client using
            specified watcher.
        """
        watcher.register(self.conn, 'sub_tags', obj_id, tags, _data=(tags, robj))

Client.register_client_class(HvClient)