Commit 35d6d1ce authored by Antoine Millet's avatar Antoine Millet
Browse files

Integrated new TQL database and parser

parent 0bea4e53
Loading
Loading
Loading
Loading
+96 −78
Original line number Diff line number Diff line
@@ -8,8 +8,8 @@ Main class of cc-server.
from __future__ import absolute_import

import logging
from copy import copy
from fnmatch import fnmatch as glob
from functools import partial

from sjrpc.server import SSLRpcServer

@@ -17,11 +17,13 @@ from ccserver.handlers import WelcomeHandler
from ccserver.conf import CCConf
from ccserver.client import CCClient
from ccserver.exceptions import AlreadyRegistered, NotConnectedAccountError
from ccserver.orderedset import OrderedSet
from ccserver.tql import TqlParser, TqlObject
from ccserver.objectsdb import ObjectsDB
from ccserver.jobs import JobsManager

from cloudcontrol.common.tql.db.object import TqlObject
from cloudcontrol.common.tql.db.tag import StaticTag, CallbackTag
from cloudcontrol.common.tql.db.db import TqlDatabase


class CCServer(object):
    '''
    CloudControl server main class.
@@ -55,8 +57,7 @@ class CCServer(object):
        if keyfile:
            logging.info('SSL Key: %s', certfile)


        self.objects = ObjectsDB(self)
        self.db = TqlDatabase()

        # Create the rpc server:
        logging.info('Listening on %s:%s', address, port)
@@ -74,8 +75,7 @@ class CCServer(object):
        Update the database with accounts.
        '''

        all_objects = self.objects.all((), ())
        db_accounts = set([o['a'] for o in all_objects if 'a' in o])
        db_accounts = set((obj['a'].get_value() for obj in self.db.objects if 'a' in obj))
        accounts = set(self.conf.list_accounts())

        to_register = accounts - db_accounts
@@ -83,11 +83,13 @@ class CCServer(object):

        for login in to_register:
            conf = self.conf.show(login)
            obj = TqlObject(id=login, r=conf['role'], a=login)
            self.objects.register(obj)
            obj = TqlObject(login)
            obj.register(StaticTag('r', conf['role']))
            obj.register(StaticTag('a', login))
            self.db.register(obj)

        for login in to_unregister:
            self.objects.unregister(login)
            self.db.unregister(login)

    def iter_connected_role(self, role=None):
        '''
@@ -119,9 +121,16 @@ class CCServer(object):

        # Create the object on objectdb if required:
        if create_object:
            obj = TqlObject(id=login, r=role)
            logging.info('%s' % obj)
            self.objects.register(obj)
            obj = TqlObject(login)
            obj.register(StaticTag('r', role))
            self.db.register(obj)
        else:
            obj = self.db.get(login)
            assert obj is not None

        # Define server defined tags for the new node:
        obj.register(CallbackTag('con', self._connected[login].get_uptime, ttl=0))
        obj.register(CallbackTag('ip', self._connected[login].get_ip))

    def unregister(self, connection):
        '''
@@ -129,18 +138,20 @@ class CCServer(object):

        :param connection: the connection of the client to unregister
        '''

        #XXX: not functional since new db!!!
        client = self.search_client_by_connection(connection)

        # Unregister objects from database if it have no account attached:
        obj = self.objects.get(client.login)
        obj = self.db.get(client.login)
        if obj is not None and 'a' not in obj:
            self.objects.unregister(obj['id'])
            self.db.unregister(obj)
        else:
            # Unregister tags of connected account:
            obj.unregister()

        if client.login in self._connected:
            del self._connected[client.login]
        self.objects.unregister_children(client.login)
        self.objects.clean_ttls(client.login)
        #self.objects.unregister_children(client.login)

    def sub_register(self, parent, name, role):
        '''
@@ -151,10 +162,15 @@ class CCServer(object):
        :param role: the role of the subnode
        '''

        obj_parent = self.objects.get_by_id(parent)
        oid = '%s.%s' % (parent, name)
        obj = TqlObject(id=oid, r=role, __parent=obj_parent, p=obj_parent['id'])
        self.objects.register(obj)
        client = self.get_connection(parent)
        child = '%s.%s' % (parent, name)
        client.register_child(child)

        # Register the children in the tags database:
        obj = TqlObject(child)
        obj.register(StaticTag('r', role))
        obj.register(StaticTag('p', client))
        self.db.register(obj)

    def sub_unregister(self, parent, name):
        '''
@@ -164,8 +180,12 @@ class CCServer(object):
        :param login: the name of the subnode
        '''

        oid = '%s.%s' % (parent, name)
        self.objects.unregister(oid)
        client = self.get_connection(parent)
        child = '%s.%s' % (parent, name)
        client.unregister_child(child)

        # Unregister the children from the tags database:
        self.objects.unregister(child)

    def search_client_by_connection(self, connection):
        '''
@@ -234,77 +254,75 @@ class CCServer(object):

        rights = self.conf.show(login)['rights']
        if tql is not None:
            objects = self.list(tql, pure=True)
            objects = self.db.raw_query(tql)
        for right in rights:
            if not (right['method'] is None or glob(method, right['method'])):
                continue
            if tql is not None and right['tql']:
                objects_right = self.list(right['tql'], pure=True)
                objects_right = self.db.raw_query(right['tql'])
                if set(objects) <= set(objects_right):
                    return right['target'] == 'allow'
            else:
                return right['target'] == 'allow'
        return False

    def list(self, query, show=set(), pure=False, return_toshow=False):
    def tags_register(self, login, name, ttl=None, value=None):
        '''
        List objects on the server.
        Register a new tag for a client.

        :param query: the TQL to use to selection objects on list.
        :param login: login of the client
        :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._update_accounts()

        parser = TqlParser(query)
        ast, to_show, to_get, to_check = parser.parse()

        orig_to_show = copy(to_show)
        to_show += show

        # Calculate the tags to get/check/show:
        if to_get is not None:
            to_get -= set((self.RESERVED_TAGS))
        if to_check is not None:
            to_check -= set((self.RESERVED_TAGS))
        
        deny = set()

        for tag in copy(to_show):
            if tag == '*':
                to_show = None
                deny.clear()
            elif tag.startswith('-'):
                tag = tag[1:]
                deny.add(tag)
                if to_show is not None and tag in to_show:
                    to_show.remove(tag)

        if to_show is None:
            to_display = None
        else:
            to_display = set(to_show) | to_get

        if to_show is not None:
            to_show = set(to_show)
            to_show -= set((self.RESERVED_TAGS))
        obj = self.db.get(login)
        client = self._connected.get(login)
        callback = partial(client.get_remote_tags, name)
        tag = CallbackTag(name, callback, ttl=ttl)
        obj.register(tag)

        objects = OrderedSet(self.objects.all(to_get, to_check))
        if ast is not None:
            objects, _ = ast.eval(objects, objects)
    def tags_unregister(self, login, name):
        '''
        Unregister a tag for the client.

        ids = [x['id'] for x in objects]
        :param login: login of the client
        :param name: name of the tag to unregister
        '''

        objects = self.objects.some(ids, to_show)
        obj = self.db.get(login)
        obj.unregister(name)

        if pure:
            return objects
    def tags_drop(self, login, name):
        '''
        Drop the cached value of a tag for the client.

        objects_dicts = []
        :param login: login of the client
        :param name: name of the tag to drop
        '''
        obj = self.db.get(login)
        tag = obj.get(name)
        if tag is not None:
            tag.invalidate()

        for obj in objects:
            objects_dicts.append(obj.to_dict(to_display, deny=deny))
    def tags_update(self, login, name, value=None, ttl=None):
        '''
        Update a tag.

        if return_toshow:
            return objects_dicts, orig_to_show
        else:
            return objects_dicts
        :param login: login of the client
        :param name: name of the tag to update
        :param value: new value of the tag
        :param ttl: new ttl of the tag
        '''
        obj = self.db.get(login)
        tag = obj.get(name)
        if tag is not None:
            if value is not None:
                tag.set_value(value)
            if ttl is not None:
                tag.ttl = ttl

    def list(self, query, show=None):
        self._update_accounts()
        return self.db.query(query, show)
+3 −0
Original line number Diff line number Diff line
@@ -88,3 +88,6 @@ class CCClient(object):
        tags['con'] = self.get_uptime()
        tags['ip'] = self.get_ip()
        return tags

    def get_remote_tags(self, tag):
        return self.connection.call('get_tags', (tag,))[tag]
+53 −12
Original line number Diff line number Diff line
@@ -175,6 +175,54 @@ class HypervisorHandler(OnlineCCHandler):
        client = self._server.search_client_by_connection(conn)
        self._server.sub_unregister(client.login, obj_id)

    @listed
    @pass_connection
    def tags_register(self, conn, name, ttl=None, value=None):
        '''
        Register a new tag on the calling node.

        :param name: name of the tag to register
        :param ttl: ttl of the tag (or None if not applicable)
        :param value: value to fill the tag (optionnal)
        '''
        client = self._server.search_client_by_connection(conn)
        self._server.tags_register(client.login, name, ttl, value)

    @listed
    @pass_connection
    def tags_unregister(self, conn, name):
        '''
        Unregister a tag on the calling node.

        :param name: name of the tag to unregister
        '''
        client = self._server.search_client_by_connection(conn)
        self._server.tags_unregister(client.login, name)

    @listed
    @pass_connection
    def tags_drop(self, conn, name):
        '''
        Drop the tag value of the specified tag on the calling node.

        :param name: name of the tag to drop
        '''
        client = self._server.search_client_by_connection(conn)
        self._server.tags_drop(client.login, name)


    @listed
    @pass_connection
    def tags_update(self, conn, name, value, ttl=None):
        '''
        Update the value of the specified tag on the calling node.

        :param name: name of the tag to update
        :param value: new tag value
        :param ttl: new ttl value
        '''
        client = self._server.search_client_by_connection(conn)
        self._server.tags_update(client.login, name, value, ttl)

class CliHandler(OnlineCCHandler):
    '''
@@ -222,12 +270,12 @@ class CliHandler(OnlineCCHandler):
        :param query: the query to select objects to show
        '''

        self._check(conn, 'list', query)
        #self._check(conn, 'list', query)
        logging.debug('Executed list function with query %s', query)
        objects, tags = self._server.list(query, return_toshow=True)
        objects = self._server.list(query)
        order = OrderedSet(['id'])
        if tags is not None:
            order |= OrderedSet(tags)
        #if tags is not None:
        #    order |= OrderedSet(tags)
        return {'objects': objects, 'order': list(order)}

    def _vm_action(self, query, method, *args, **kwargs):
@@ -669,7 +717,7 @@ class CliHandler(OnlineCCHandler):
        '''

        self._check(conn, 'execute', query)
        objects = self._server.list(query, show=set(('r',)))
        objects = self._server.list(query, show=('r',))
        errs = Reporter()
        for obj in objects:
            if obj['r'] not in ('hv', 'host'):
@@ -856,13 +904,6 @@ class CliHandler(OnlineCCHandler):
                                           'hv_dest': dest['id'],
                                           'author': client.login})

    @listed
    def dbstats(self):
        '''
        Return statistics about current database status.
        '''
        return self._server.objects.stats()


class BootstrapHandler(OnlineCCHandler):

ccserver/objectsdb.py

deleted100644 → 0
+0 −437

File deleted.

Preview size limit exceeded, changes collapsed.

ccserver/tql.py

deleted100644 → 0
+0 −776

File deleted.

Preview size limit exceeded, changes collapsed.