Пример #1
0
    def __init__(self, connection):

        self._wait_timeout = 30
        self._connection = ConnectionManager(connection)
        self._domain = DomainManager(connection)

        super(LibVirtMachineManager, self).__init__()
Пример #2
0
    def test_delete(self):
        return
        # TODO: test delete is incompatible with test driver.
        # we simply pass this test and add a workaround later
        with self.assertRaises(DomainManagerError):
            with DomainManager(self.uri) as dm:
                self.assertIsInstance(dm, DomainManager)
                delete = dm.delete('fv0')

        with DomainManager(self.uri) as dm:
            stop = dm.stop('fv0')
            delete = dm.delete('fv0')
            self.assertIsTrue(delete)
Пример #3
0
    def __init__(self, connection):

        self._wait_timeout = 30
        self._connection = ConnectionManager(connection)
        self._domain = DomainManager(connection)

        super(LibVirtMachineManager, self).__init__()
Пример #4
0
 def test_state_with_name(self):
     with DomainManager(self.uri) as dm:
         self.assertIsInstance(dm, DomainManager)
         state = dm.state('4dea22b31d52d8f32516782e98ab3fa0')
         self.assertIsInstance(state, tuple)
         self.assertIsNotNone(state[0])
         self.assertIsNotNone(state[1])
Пример #5
0
 def test_list(self):
     with DomainManager(self.uri) as dm:
         self.assertIsInstance(dm, DomainManager)
         machines = dm.list()
         self.assertIsInstance(machines, tuple)
         self.assertEqual(len(machines), 2)
         self.assertTrue('fv0' in machines)
         self.assertTrue('fc4' in machines)
Пример #6
0
 def test_stop_with_name(self):
     with DomainManager(self.uri) as dm:
         self.assertIsInstance(dm, DomainManager)
         # start test machines
         dm.start('4dea22b31d52d8f32516782e98ab3fa0')
         # perform tests
         stop = dm.stop('4dea22b31d52d8f32516782e98ab3fa0')
         self.assertTrue(stop)
         stop = dm.stop('4dea22b31d52d8f32516782e98ab3fa0')
         self.assertFalse(stop)
Пример #7
0
 def test_clone(self):
     return
     # TODO: test clone needs specific libvirt configuration
     # we simply pass this test and add a workaround later
     with DomainManager(self.uri) as dm:
         self.assertIsInstance(dm, DomainManager)
         # clone a started machine
         clone = dm.clone('fv0', 'fv1')
         self.assertIsNone(clone)
         # clone a stopped machine
         dm.stop('fv0')
         clone = dm.clone('fv0', 'fv1')
Пример #8
0
 def test_start_with_dict(self):
     with DomainManager(self.uri) as dm:
         self.assertIsInstance(dm, DomainManager)
         # stop test machines
         stop = dm.stop('4dea22b31d52d8f32516782e98ab3fa0')
         # perform tests
         start = dm.start({
             'domain': '4dea22b31d52d8f32516782e98ab3fa0',
             'flags': 0
         })
         self.assertTrue(start)
         start = dm.start('4dea22b31d52d8f32516782e98ab3fa0')
         self.assertFalse(start)
Пример #9
0
 def test_lookup_with_name(self):
     with DomainManager(self.uri) as dm:
         # query by name
         self.assertIsInstance(dm, DomainManager)
         fv0 = dm.lookup('fv0')
         self.assertIsInstance(fv0, libvirt.virDomain)
         fc4 = dm.lookup('fc4')
         self.assertIsInstance(fc4, libvirt.virDomain)
         # query by name with a list
         fv0, fc4, dummy = dm.lookup(['fv0', 'fc4', 'dummy'])
         self.assertIsInstance(fv0, libvirt.virDomain)
         self.assertIsInstance(fc4, libvirt.virDomain)
         self.assertIsNone(dummy)
Пример #10
0
    def test_state_with_list(self):
        with DomainManager(self.uri) as dm:
            self.assertIsInstance(dm, DomainManager)
            state = dm.state([
                '4dea22b31d52d8f32516782e98ab3fa0',
                '4e57708ad8a14031b86c2822c4d006a3',
            ])
            self.assertIsInstance(state, tuple)
            self.assertIsInstance(state[0], tuple)
            self.assertIsNotNone(state[0][0])
            self.assertIsNotNone(state[0][1])

            self.assertIsInstance(state[1], tuple)
            self.assertIsNotNone(state[1][0])
            self.assertIsNotNone(state[1][1])
Пример #11
0
 def test_lookup_with_uuid(self):
     with DomainManager(self.uri) as dm:
         # query by name
         self.assertIsInstance(dm, DomainManager)
         fv0 = dm.lookup('4dea22b31d52d8f32516782e98ab3fa0')
         self.assertIsInstance(fv0, libvirt.virDomain)
         fc4 = dm.lookup('4E57708AD8A14031B86C2822C4D006A3')
         self.assertIsInstance(fc4, libvirt.virDomain)
         # query by name with a list
         fv0, fc4, dummy = dm.lookup([
             '4dea22b31d52d8f32516782e98ab3fa0',  # fv0
             '4e57708ad8a14031b86c2822c4d006a3',  # fc4
             'deadbeef1d52d8f32516782e98ab3fbb'
         ])
         self.assertIsInstance(fv0, libvirt.virDomain)
         self.assertIsInstance(fc4, libvirt.virDomain)
         self.assertIsNone(dummy)
Пример #12
0
 def test_lookup_with_id(self):
     with DomainManager(self.uri) as dm:
         self.assertIsInstance(dm, DomainManager)
         fv0 = dm.lookup('4dea22b31d52d8f32516782e98ab3fa0')
         fc4 = dm.lookup('4E57708AD8A14031B86C2822C4D006A3')
         dm.start(fv0)
         dm.start(fc4)
         fv0 = fv0.ID()
         fc4 = fc4.ID()
         # query by name with a list
         fv0, fc4 = dm.lookup([fv0, fc4])
         self.assertIsInstance(fv0, libvirt.virDomain)
         self.assertIsInstance(fc4, libvirt.virDomain)
         # lookup with digits
         fv0, fc4 = dm.lookup(['1', '2'])
         self.assertIsInstance(fv0, libvirt.virDomain)
         self.assertIsInstance(fc4, libvirt.virDomain)
Пример #13
0
 def test_start_with_list(self):
     with DomainManager(self.uri) as dm:
         self.assertIsInstance(dm, DomainManager)
         # stop test machines
         fv0, fc4, dummy = dm.stop([
             '4dea22b31d52d8f32516782e98ab3fa0',
             '4e57708ad8a14031b86c2822c4d006a3',
             'deadbeef1d52d8f32516782e98ab3fbb',
         ])
         # perform tests
         fv0, fc4, dummy = dm.start([
             '4dea22b31d52d8f32516782e98ab3fa0',
             '4e57708ad8a14031b86c2822c4d006a3',
             'deadbeef1d52d8f32516782e98ab3fbb',
         ])
         self.assertTrue(fv0)
         self.assertTrue(fc4)
         self.assertIsNone(dummy)
Пример #14
0
class LibVirtMachineManager(VirtualMachineManager, ParametricSingleton):
    """Machine manager based on libvirt"""

    # ============================
    #  parametric singleton stuff
    # ============================

    @staticmethod
    def depends_on(cls, *args, **kwargs):
        # singleton is based on the uri, extracted from the libvirt handler
        (handler,) = args[0]
        if isinstance(handler, basestring):
            handler = ConnectionManager(handler)
        if isinstance(handler, ConnectionManager):
            handler = handler.connection
        if not isinstance(handler, libvirt.virConnect):
            what = type(handler)
            reason = "Invalid type for 'connection' field: {0}".format(what)
            raise DomainManagerError(reason)

        try:
            uri = handler.getURI()
        except libvirt.libvirtError as e:
            reason = "unable to get domain uri from connection handle"
            raise DomainManagerError(reason)
        return uri

    # ===================================
    #  Constructor and destructor stuffs
    # ===================================

    def __init__(self, connection):

        self._wait_timeout = 30
        self._connection = ConnectionManager(connection)
        self._domain = DomainManager(connection)

        super(LibVirtMachineManager, self).__init__()

    # =======================
    #  context manager stuff
    # =======================

    def __enter__(self):
        return self

    # =================
    #  Private methods
    # =================

    def _wait(self, label, state, timeout=0):
        """ wait for a vm status to be set.

        :param label: virtual machine name.
        :param state: virtual machine status, accepts many states with a list.
        :raise IrmaMachineManagerError:
            if timeout expire or virtual machine
        """
        if isinstance(state, int):
            state = [state]

        seconds = 0
        current, desc = self._domain.state(label)
        while current not in state:
            if timeout and seconds > int(timeout):
                reason = "status change timeout for '{0}'".format(label)
                raise IrmaMachineManagerError(reason)
            time.sleep(1)
            seconds += 1
            current, desc = self._domain.state(label)

    # ================
    #  public methods
    # ================

    ACTIVE = VirtualMachineManager.ACTIVE
    INACTIVE = VirtualMachineManager.INACTIVE

    def list(self, filter=ACTIVE | INACTIVE):
        """ List all (running and inactive) virtual machines

        :return:
            list of virtual machines names
        :raise IrmaMachineManagerError:
            if unable to list machines
        """
        labels = list()
        try:
            labels.extend(self._domain.list(filter))
        except DomainManagerError as e:
            raise IrmaMachineManagerError(e)
        return labels

    def start(self, label):
        """ Start a machine

        :param label: virtual machine name
        :raise IrmaMachineManagerError:
            if unable to start virtual machine.
        """
        state, desc = self._domain.state(label)
        if state != DomainManager.SHUTOFF:
            reason = "{0} should be off, currently {0} {1}".format(label, desc)
            raise IrmaMachineManagerError(reason)
        try:
            res = self._domain.start(label)
            self._wait(label, DomainManager.RUNNING, self._wait_timeout)
        except DomainManagerError as e:
            raise IrmaMachineManagerError(e)

    def stop(self, label, force=False):
        """ Stop a virtual machine
        :param label: machine name
        :param force: if True, halt machine immediatly instead of gracefully
        :raise IrmaMachineManagerError:
            if unable to stop virtual machine or find it.
        """
        state, desc = self._domain.state(label)
        if state != DomainManager.RUNNING:
            reason = "{0} should be running, {1} instead".format(label, desc)
            raise IrmaMachineManagerError(reason)
        try:
            self._domain.stop(label, force)
            self._wait(label, DomainManager.SHUTOFF, self._wait_timeout)
        except DomainManagerError as e:
            raise IrmaMachineManagerError(e)

    def clone(self, origin, clone, use_backing_file=True):
        """ Clone a machine
        :param src_label: source machine name
        :param dst_label: destination machine name
        :raise IrmaMachineManagerError:
             if the machine exists or is currently running
        """
        # TODO: move checking in the lib.virt.core api
        state, desc = self._domain.state(origin)
        if state != DomainManager.SHUTOFF:
            reason = "{0} should be off, {1} instead".format(origin, desc)
            raise IrmaMachineManagerError(reason)
        if self._domain.lookup(clone):
            reason = "clone {0} already exists".format(clone, desc)
            raise IrmaMachineManagerError(reason)
        try:
            orig_dict = self._domain.info(origin)
            # if we do not want to use backing files, simply clone
            if not use_backing_file:
                self._domain.clone(origin, clone)
            # we want backing files, check for disks
            else:
                clone_dict = orig_dict
                # generate a new uuid
                while True:
                    uuid = UUID.generate()
                    if not self._domain.lookup(uuid):
                        break
                # set new name and new uuid
                clone_dict['name'] = clone
                clone_dict['uuid'] = uuid
                # change devices
                for type, device in clone_dict['devices'].items():
                    if type == 'interface':
                        interfaces = device
                        if not isinstance(interfaces, list):
                            interfaces = [interfaces]
                        for interface in interfaces:
                            interface['mac']['@address'] = MAC.generate()
                    elif type == 'disk':
                        disks = device
                        if not isinstance(disks, list):
                            disks = [disks]
                        for disk in disks:
                            disk_path = disk['source']['@file']
                            vman = StorageVolumeManager(self._connection, None)
                            pman = StoragePoolManager(self._connection)
                            volume = vman.lookup(disk_path)
                            vman.pool = pman.lookupByVolume(volume)
                            # TODO: pool is not defined, have to create one
                            volume = vman.info(disk_path)
                            # check if has a backing storage
                            if volume.backingstore is not None:
                                from_disk = orig_dict['name']
                                disk_ext = volume.target['format']['@type']
                                to_disk = '.'.join([clone, disk_ext])
                                new_vol = vman.clone(from_disk, to_disk)
                                disk['source']['@file'] = new_vol.path()
                            # create a backing storage
                            else:
                                backingvol = volume
                                backingvol.key = None
                                # retreive path
                                basedir = backingvol.target['path']
                                basedir = os.path.dirname(basedir)
                                disk_ext = volume.target['format']['@type']
                                disk_name = '.'.join([clone, disk_ext])
                                backingvol.target['path'] = \
                                    os.path.join(basedir, disk_name)
                                backingvol.backingstore = \
                                    {'path': disk_path, 'format':
                                        {'@type': disk_ext}}
                                backingvol.name = '.'.join([clone, disk_ext])
                                new_vol = vman.create(backingvol)
                                disk['source']['@file'] = new_vol.path()
                self._domain.create(clone_dict)
        except DomainManagerError as e:
            raise IrmaMachineManagerError(e)

    def delete(self, label):
        """Delete a machine
        @param label: machine name
        @raise NotImplementedError: this method is abstract.
        """
        state, desc = self._domain.state(label)
        if state != DomainManager.SHUTOFF:
            reason = "{0} should be off, {1} instead".format(label, desc)
            raise IrmaMachineManagerError(reason)
        try:
            # TODO: add the possibility to keep some disk
            self._domain.delete(label)
        except DomainManagerError as e:
            raise IrmaMachineManagerError(e)

    def import_config(self, ordered_dict):
        try:
            self._domain.create(ordered_dict)
        except DomainManagerError as e:
            raise IrmaMachineManagerError(e)

    def export_config(self, label):
        try:
            return self._domain.info(label)
        except DomainManagerError as e:
            raise IrmaMachineManagerError(e)
Пример #15
0
class LibVirtMachineManager(VirtualMachineManager, ParametricSingleton):
    """Machine manager based on libvirt"""

    # ============================
    #  parametric singleton stuff
    # ============================

    @staticmethod
    def depends_on(cls, *args, **kwargs):
        # singleton is based on the uri, extracted from the libvirt handler
        (handler, ) = args[0]
        if isinstance(handler, basestring):
            handler = ConnectionManager(handler)
        if isinstance(handler, ConnectionManager):
            handler = handler.connection
        if not isinstance(handler, libvirt.virConnect):
            what = type(handler)
            reason = "Invalid type for 'connection' field: {0}".format(what)
            raise DomainManagerError(reason)

        try:
            uri = handler.getURI()
        except libvirt.libvirtError as e:
            reason = "unable to get domain uri from connection handle"
            raise DomainManagerError(reason)
        return uri

    # ===================================
    #  Constructor and destructor stuffs
    # ===================================

    def __init__(self, connection):

        self._wait_timeout = 30
        self._connection = ConnectionManager(connection)
        self._domain = DomainManager(connection)

        super(LibVirtMachineManager, self).__init__()

    # =======================
    #  context manager stuff
    # =======================

    def __enter__(self):
        return self

    # =================
    #  Private methods
    # =================

    def _wait(self, label, state, timeout=0):
        """ wait for a vm status to be set.

        :param label: virtual machine name.
        :param state: virtual machine status, accepts many states with a list.
        :raise IrmaMachineManagerError:
            if timeout expire or virtual machine
        """
        if isinstance(state, int):
            state = [state]

        seconds = 0
        current, desc = self._domain.state(label)
        while current not in state:
            if timeout and seconds > int(timeout):
                reason = "status change timeout for '{0}'".format(label)
                raise IrmaMachineManagerError(reason)
            time.sleep(1)
            seconds += 1
            current, desc = self._domain.state(label)

    # ================
    #  public methods
    # ================

    ACTIVE = VirtualMachineManager.ACTIVE
    INACTIVE = VirtualMachineManager.INACTIVE

    def list(self, filter=ACTIVE | INACTIVE):
        """ List all (running and inactive) virtual machines

        :return:
            list of virtual machines names
        :raise IrmaMachineManagerError:
            if unable to list machines
        """
        labels = list()
        try:
            labels.extend(self._domain.list(filter))
        except DomainManagerError as e:
            raise IrmaMachineManagerError(e)
        return labels

    def start(self, label):
        """ Start a machine

        :param label: virtual machine name
        :raise IrmaMachineManagerError:
            if unable to start virtual machine.
        """
        state, desc = self._domain.state(label)
        if state != DomainManager.SHUTOFF:
            reason = "{0} should be off, currently {0} {1}".format(label, desc)
            raise IrmaMachineManagerError(reason)
        try:
            res = self._domain.start(label)
            self._wait(label, DomainManager.RUNNING, self._wait_timeout)
        except DomainManagerError as e:
            raise IrmaMachineManagerError(e)

    def stop(self, label, force=False):
        """ Stop a virtual machine
        :param label: machine name
        :param force: if True, halt machine immediatly instead of gracefully
        :raise IrmaMachineManagerError:
            if unable to stop virtual machine or find it.
        """
        state, desc = self._domain.state(label)
        if state != DomainManager.RUNNING:
            reason = "{0} should be running, {1} instead".format(label, desc)
            raise IrmaMachineManagerError(reason)
        try:
            self._domain.stop(label, force)
            self._wait(label, DomainManager.SHUTOFF, self._wait_timeout)
        except DomainManagerError as e:
            raise IrmaMachineManagerError(e)

    def clone(self, origin, clone, use_backing_file=True):
        """ Clone a machine
        :param src_label: source machine name
        :param dst_label: destination machine name
        :raise IrmaMachineManagerError:
             if the machine exists or is currently running
        """
        # TODO: move checking in the lib.virt.core api
        state, desc = self._domain.state(origin)
        if state != DomainManager.SHUTOFF:
            reason = "{0} should be off, {1} instead".format(origin, desc)
            raise IrmaMachineManagerError(reason)
        if self._domain.lookup(clone):
            reason = "clone {0} already exists".format(clone, desc)
            raise IrmaMachineManagerError(reason)
        try:
            orig_dict = self._domain.info(origin)
            # if we do not want to use backing files, simply clone
            if not use_backing_file:
                self._domain.clone(origin, clone)
            # we want backing files, check for disks
            else:
                clone_dict = orig_dict
                # generate a new uuid
                while True:
                    uuid = UUID.generate()
                    if not self._domain.lookup(uuid):
                        break
                # set new name and new uuid
                clone_dict['name'] = clone
                clone_dict['uuid'] = uuid
                # change devices
                for type, device in clone_dict['devices'].items():
                    if type == 'interface':
                        interfaces = device
                        if not isinstance(interfaces, list):
                            interfaces = [interfaces]
                        for interface in interfaces:
                            interface['mac']['@address'] = MAC.generate()
                    elif type == 'disk':
                        disks = device
                        if not isinstance(disks, list):
                            disks = [disks]
                        for disk in disks:
                            disk_path = disk['source']['@file']
                            vman = StorageVolumeManager(self._connection, None)
                            pman = StoragePoolManager(self._connection)
                            volume = vman.lookup(disk_path)
                            vman.pool = pman.lookupByVolume(volume)
                            # TODO: pool is not defined, have to create one
                            volume = vman.info(disk_path)
                            # check if has a backing storage
                            if volume.backingstore is not None:
                                from_disk = orig_dict['name']
                                disk_ext = volume.target['format']['@type']
                                to_disk = '.'.join([clone, disk_ext])
                                new_vol = vman.clone(from_disk, to_disk)
                                disk['source']['@file'] = new_vol.path()
                            # create a backing storage
                            else:
                                backingvol = volume
                                backingvol.key = None
                                # retreive path
                                basedir = backingvol.target['path']
                                basedir = os.path.dirname(basedir)
                                disk_ext = volume.target['format']['@type']
                                disk_name = '.'.join([clone, disk_ext])
                                backingvol.target['path'] = \
                                    os.path.join(basedir, disk_name)
                                backingvol.backingstore = \
                                    {'path': disk_path, 'format':
                                        {'@type': disk_ext}}
                                backingvol.name = '.'.join([clone, disk_ext])
                                new_vol = vman.create(backingvol)
                                disk['source']['@file'] = new_vol.path()
                self._domain.create(clone_dict)
        except DomainManagerError as e:
            raise IrmaMachineManagerError(e)

    def delete(self, label):
        """Delete a machine
        @param label: machine name
        @raise NotImplementedError: this method is abstract.
        """
        state, desc = self._domain.state(label)
        if state != DomainManager.SHUTOFF:
            reason = "{0} should be off, {1} instead".format(label, desc)
            raise IrmaMachineManagerError(reason)
        try:
            # TODO: add the possibility to keep some disk
            self._domain.delete(label)
        except DomainManagerError as e:
            raise IrmaMachineManagerError(e)

    def import_config(self, ordered_dict):
        try:
            self._domain.create(ordered_dict)
        except DomainManagerError as e:
            raise IrmaMachineManagerError(e)

    def export_config(self, label):
        try:
            return self._domain.info(label)
        except DomainManagerError as e:
            raise IrmaMachineManagerError(e)
Пример #16
0
 def test_with(self):
     with DomainManager(self.uri) as dm:
         self.assertIsInstance(dm, DomainManager)
Пример #17
0
 def test_constructor_error(self):
     with self.assertRaises(DomainManagerError):
         dummy = True
         dm = DomainManager(dummy)
Пример #18
0
 def test_constructor_with_connection_manager(self):
     with ConnectionManager(self.uri) as cm:
         dm = DomainManager(cm)
         self.assertIsNotNone(dm)
         self.assertIsInstance(dm, DomainManager)
Пример #19
0
 def test_constructor_with_basestring(self):
     dm = DomainManager(self.uri)
     self.assertIsNotNone(dm)
     self.assertIsInstance(dm, DomainManager)
Пример #20
0
 def test_constructor_with_virconnect(self):
     connection = libvirt.open(self.uri)
     dm = DomainManager(connection)
     self.assertIsNotNone(dm)
     self.assertIsInstance(dm, DomainManager)
     connection.close()
Пример #21
0
 def test_info(self):
     with DomainManager(self.uri) as dm:
         # query by name
         self.assertIsInstance(dm, DomainManager)
         info = dm.info('4dea22b31d52d8f32516782e98ab3fa0')
         self.assertIsNotNone(info)