Commit 012be518 authored by Antoine Millet's avatar Antoine Millet
Browse files

Implemented static tags on VMs

parent fb6cc62b
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -418,6 +418,41 @@ class Handler(HostHandler):
        # update autostart value now instead of 10 seconds lag
        vm.tag_db['__main__']['autostart'].update_value()


    @libvirt_handler
    def tag_add(self, name, tag, value):
        """Add a static tag on specified VM.

        :param name: VM name
        :param tag: tag name
        :param value: tag value
        """

        vm = self.hypervisor.domains[name]
        vm.set_tag(tag, value)

    @libvirt_handler
    def tag_delete(self, name, tag):
        """Delete a static tag on specified VM.

        :param name: VM name
        :param tag: tag name
        """

        vm = self.hypervisor.domains[name]
        vm.delete_tag(tag)

    @libvirt_handler
    def tag_show(self, name):
        """Show static tags of the specified VM.

        :param name: VM name
        """

        vm = self.hypervisor.domains[name]
        return vm.tags


    @libvirt_handler
    def vol_create(self, pool, name, size):
        logger.debug('Volume create %s, pool %s, size %s', name, pool, size)
+85 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
# along with CloudControl.  If not, see <http://www.gnu.org/licenses/>.


import re
import errno
import logging
import socket
@@ -36,6 +37,10 @@ from cloudcontrol.node.exc import ConsoleAlreadyOpened, ConsoleError

logger = logging.getLogger(__name__)

REGEX_TAG_NAME = '[a-zA-Z0-9_-]+'
REGEX_TAG_VALUE = '.+'
REGEX_TAG_IN_DESCRIPTION = '^@(' + REGEX_TAG_NAME + ')[ ]*?=[ ]*?(' + REGEX_TAG_VALUE + ')$'
REGEX_TAG_REPLACE = '^@%s[ ]*?=[ ]*?(' + REGEX_TAG_VALUE + ')$'

NetworkInterface = namedtuple('NetworkInterface', ('source', 'mac', 'model'))

@@ -97,6 +102,9 @@ class VirtualMachine(object):

        self.redefine_on_stop = False  # for XML update (see KVM class)

        self._description_tags_db = TagDB(parent_db=self.tag_db)
        self.sync_description_tags()

    @property
    def state(self):
        return self._state
@@ -106,6 +114,67 @@ class VirtualMachine(object):
        self._state = value
        self.tag_db['__main__']['status'].update_value()
        self.tag_db['__main__']['vncport'].update_value()
        self.sync_description_tags()

    @property
    def description(self):
        descriptions = et.ElementTree().parse(StringIO(self.lv_dom.XMLDesc(0))).findall('description')
        if descriptions:
            return descriptions[0].text
        else:
            return ''

    @description.setter
    def description(self, value):
        try:
            xml = self.lv_dom.XMLDesc(0)
        except libvirt.libvirtError:
            logger.exception('Error while getting domain XML from libvirt, %s',
                             self.name)
            raise

        xml_tree = et.ElementTree()
        xml_tree.parse(StringIO(xml))
        desc = xml_tree.find('description')
        desc.text = value

        # write back the XML tree
        out = StringIO()
        xml_tree.write(out)
        try:
            self.hypervisor.vir_con.defineXML(out.getvalue())
        except libvirt.libvirtError:
            logger.exception('Cannot update XML file for domain %s', self.name)
            raise

    @property
    def tags(self):
        return dict(re.findall(REGEX_TAG_IN_DESCRIPTION, self.description, re.MULTILINE))

    def set_tag(self, tag, value):
        if not re.match(REGEX_TAG_NAME + '$', tag):
            raise RuntimeError('Bad tag name')
        elif not re.match(REGEX_TAG_VALUE + '$', value):
            raise RuntimeError('Bad tag value')

        tags = self.tags

        if tag in tags:
            self.description = re.sub(REGEX_TAG_REPLACE % re.escape(tag),
                                      '@%s=%s' % (tag, value),
                                      self.description,
                                      flags=re.MULTILINE)
        else:
            self.description += '\n@%s=%s' % (tag, value)

    def delete_tag(self, tag):
        tags = self.tags

        if tag in tags:
            self.description = re.sub(REGEX_TAG_REPLACE % tag,
                                      '',
                                      self.description,
                                      flags=re.MULTILINE)

    @property
    def lv_dom(self):
@@ -119,6 +188,22 @@ class VirtualMachine(object):

        self.lv_dom.createWithFlags(flags)

    def sync_description_tags(self):
        tags = dict(re.findall(REGEX_TAG_IN_DESCRIPTION, self.description, re.MULTILINE))

        # Add/update static tags:
        for k, v in tags.iteritems():
            tag = self._description_tags_db['__main__'].get(k)
            if tag is None:
                self._description_tags_db.add_tag(Tag(k, v, -1))
            else:
                tag.value = v

        # Purge not more defined static tags:
        for k in self._description_tags_db['__main__']:
            if k not in tags:
                self._description_tags_db.remove_tag(k)

    def stop(self):
        self.lv_dom.shutdown()