Commit c4e8174b authored by Anael Beutot's avatar Anael Beutot Committed by Antoine Millet
Browse files

Handling for tag names conflicts

parent 0af7e62c
Loading
Loading
Loading
Loading
+77 −15
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@ from functools import partial, wraps
from itertools import chain
from collections import defaultdict

from cloudcontrol.common.client.exc import TagConflict


logger = logging.getLogger(__name__)

@@ -257,7 +259,7 @@ class TagDB(object):
            for tag in tags:
                self.add_sub_tag(sub_id, tag)

    def set_parent(self, parent):
    def set_parent(self, parent, ignore_errors=False):
        """Set parent tag database."""
        # check if previous parent
        if self._parent is not None:
@@ -271,7 +273,8 @@ class TagDB(object):
        self._parent = parent
        if self._parent is not None:
            # add tags in new parent
            self._parent.add_tags(self.db['__main__'].itervalues())
            self._parent.add_tags(self.db['__main__'].itervalues(),
                                  ignore_errors)

            for sub_id, db in self.db.iteritems():
                if sub_id == '__main__':
@@ -280,16 +283,30 @@ class TagDB(object):
                                            self._object_types[sub_id])

    # tag handling part, used by plugins
    def add_tags(self, tags):
    def add_tags(self, tags, ignore_errors=False):
        """
        :param iterable tags: list of tags to add
        """
        for tag in tags:
            try:
                self.add_tag(tag)

    def add_sub_tags(self, sub_id, tags):
            except TagConflict as exc:
                if not ignore_errors:
                    raise
                # else
                logger.warning('Ignoring error %s while adding tag %s',
                               exc, tag.name)

    def add_sub_tags(self, sub_id, tags, ignore_errors=False):
        for tag in tags:
            try:
                self.add_sub_tag(sub_id, tag)
            except TagConflict as exc:
                if not ignore_errors:
                    raise
                # else
                logger.warning('Ignoring error %s while adding tag %s (%s)',
                               exc, tag.name, sub_id)

    def remove_tags(self, tag_names):
        """
@@ -298,25 +315,45 @@ class TagDB(object):
        for name in tag_names:
            self.remove_tag(name)

    def check_tag(self, tag):
        """Checks that a given tag object is the same instance in the db

        Usefull for checking before removing.
        """
        return id(self.db['__main__'].get(tag.name, None)) == id(tag)

    def add_tag(self, tag):
        if tag.name in self.db['__main__']:
            raise TagConflict('A tag with the same name is already registered')

        # first add the tag to the child db, in case of conflict in the parent,
        # the tag is recorded in the child thus if the latter's parent is
        # changed it can be recorded again after
        self.db['__main__'][tag.name] = tag
        # set special attributes on tag instance
        if self._parent is not None:
            self._parent.add_tag(tag)
        self.db['__main__'][tag.name] = tag

    def remove_tag(self, tag_name):
        self.db['__main__'].pop(tag_name)
        if self._parent is not None:
        tag = self.db['__main__'].pop(tag_name)
        if self._parent is not None and self._parent.check_tag(tag):
            # remove tag in parent db only if it is the same instance
            self._parent.remove_tag(tag_name)

    def check_sub_tag(self, sub_id, tag):
        return id(self.db[sub_id].get(tag.name, None)) == id(tag)

    def add_sub_tag(self, sub_id, tag):
        if tag.name in self.db[sub_id]:
            raise TagConflict('A tag with the same name is already registered')

        self.db[sub_id][tag.name] = tag
        if self._parent is not None:
            self._parent.add_sub_tag(sub_id, tag)
        self.db[sub_id][tag.name] = tag

    def remove_sub_tag(self, sub_id, tag_name):
        self.db[sub_id].pop(tag_name)
        if self._parent is not None:
        tag = self.db[sub_id].pop(tag_name)
        if self._parent is not None and self._parent.check_tag(tag):
            self._parent.remove_sub_tag(sub_id, tag_name)

    def add_sub_object(self, sub_id, tags, type_):
@@ -357,11 +394,27 @@ def thread_check(func):
    @wraps(func)
    def decorated(self, *args, **kwargs):
        if threading.current_thread() is self.pyev_thread:
            # if called from main thread, don't do anything special
            return func(self, *args, **kwargs)
        else:
            self.queue.put(partial(func, self, *args, **kwargs))
            exc = None
            return_value = None
            event = threading.Event()
            def cb():
                try:
                    return_value = func(self, *args, **kwargs)
                except Exception as e:
                    exc = e
                finally:
                    event.set()
            self.queue.put(cb)
            self.async.send()
            # return None

            # wait for tag to be processed and raise error
            event.wait()
            if exc is not None:
                raise exc
            return return_value

    return decorated

@@ -507,6 +560,10 @@ class RootTagDB(TagDB):

    @thread_check
    def add_tag(self, tag):
        if tag.name in self.db['__main__']:
            raise TagConflict(
                'A tag with the name %s was already registered' % tag.name)

        # set special attributes on tag instance
        tag.db = self
        tag.sub_id = '__main__'
@@ -528,6 +585,11 @@ class RootTagDB(TagDB):

    @thread_check
    def add_sub_tag(self, sub_id, tag):
        if tag.name in self.db[sub_id]:
            raise TagConflict(
                'A tag with the name %s (%s) was already registered' %
                (tag.name, sub_id))

        tag.db = self
        tag.sub_id = sub_id
        tag.start(self.main.evloop)