Commit 83adf2c3 authored by Anael Beutot's avatar Anael Beutot
Browse files

Update storage pools when VMs are created or removed.

parent 72e028f2
Loading
Loading
Loading
Loading
+73 −5
Original line number Diff line number Diff line
@@ -602,7 +602,7 @@ class Hypervisor(object):
        self.vir_con = libvirt.open('qemu:///system')  # currently only support KVM

        # findout storage
        self.storage = StorageIndex(self.vir_con)
        self.storage = StorageIndex(handler, self.vir_con)

        logger.debug('Storages: %s', self.storage.paths)

@@ -652,6 +652,8 @@ class Hypervisor(object):
        event = EVENTS[event]

        if event == 'Added':
            # update Storage pools in case VM has volumes that were created
            self.storage.update()
            if dom.name() in self.domains:
                # sometimes libvirt send us the same event multiple times
                # this can be the result of a change in the domain configuration
@@ -667,6 +669,8 @@ class Hypervisor(object):
            vm = self.domains.pop(dom.name())
            logger.info('Removed domain %s', vm.name)
            self.handler.tag_db.remove_sub_object(vm.name)
            # update Storage pools in case VM had volumes that were deleted
            self.storage.update()
        elif event in ('Started', 'Suspended', 'Resumed', 'Stopped', 'Saved',
                       'Restored'):
            vm = self.domains.get(dom.name())
@@ -726,10 +730,13 @@ class Hypervisor(object):

class StorageIndex(object):
    """Keep an index of all storage volume paths."""
    def __init__(self, lv_con):
    def __init__(self, handler, lv_con):
        """
        :param handler: Hypervisor handler instance
        :param lv_con: Libvirt connection
        """
        self.handler = handler
        self.lv_con = lv_con
        self.storages = dict(
            (s.name, s) for s in imap(
                Storage,
@@ -743,6 +750,40 @@ class StorageIndex(object):
            ),
        )

        self.paths = None
        self.update_path_index()


    def update(self):
        """Update storage pools and volumes."""
        # go through all storage pools and check if it is already in the index
        for lv_storage in imap(
            self.lv_con.storagePoolLookupByName,
            chain(
                self.lv_con.listDefinedStoragePools(),
                self.lv_con.listStoragePools(),
            ),
        ):
            if lv_storage.name() in self.storages:
                # update
                self.storages[lv_storage.name()].update()
            else:
                # add storage pool
                s = Storage(lv_storage)
                self.storages[s.name] = s
                # add tags
                self.handler.tag_db.add_tags((
                    Tag('sto%s_state' % s.name, lambda: s.state, 5, 5),
                    Tag('sto%s_size' % s.name, lambda: s.capacity, 5, 5),
                    Tag('sto%s_free' % s.name, lambda: s.available, 5, 5),
                    Tag('sto%s_used' % s.name,
                        lambda: s.capacity - s.available, 5, 5),
                    Tag('sto%s_type' % s.name, lambda: s.type, 5, 5),
                ))

        self.update_path_index()

    def update_path_index(self):
        self.paths = dict(
            (v.path, v) for v in chain.from_iterable(imap(
                lambda s: s.volumes.itervalues(),
@@ -825,8 +866,8 @@ class Storage(object):
        self.name = lv_storage.name()
        self.lv_storage = lv_storage

        self.state, self.capacity, self.allocation, self.available = lv_storage.info()
        self.state = STORAGE_STATES[self.state]
        self.state, self.capacity = None, None
        self.allocation, self.available = None, None

        self.type = et.ElementTree().parse(
            StringIO(lv_storage.XMLDesc(0))).get('type')
@@ -837,6 +878,29 @@ class Storage(object):
             lv_storage.listVolumes()),
        ))

        self.update_attr()

    def update(self):
        self.update_attr()

        # update volumes
        for vol_name in self.lv_storage.listVolumes():
            if vol_name in self.volumes:
                # update volume
                self.volumes[vol_name].update()
            else:
                # add volume
                v = Volume(self.lv_storage.storageVolLookupByName(vol_name))
                self.volumes[v.name] = v

    def update_attr(self):
        self.state, self.capacity, self.allocation, self.available = self.lv_storage.info()
        self.state = STORAGE_STATES[self.state]

        self.type = et.ElementTree().parse(
            StringIO(self.lv_storage.XMLDesc(0))).get('type')



class Volume(object):
    """Volume abstraction."""
@@ -847,5 +911,9 @@ class Volume(object):
        self.storage = lv_volume.storagePoolLookupByVolume().name()
        self.path = lv_volume.path()
        self.name = lv_volume.name()
        self.capacity, self.allocation = lv_volume.info()[1:]
        self.capacity, self.allocation = None, None
        self.lv_volume = lv_volume
        self.update()

    def update(self):
        self.capacity, self.allocation = self.lv_volume.info()[1:]