Example #1
0
    def define(self):
        # define filter first
        filter_xml = LibvirtXMLBuilder.build_network_filter(
            name=self.network_name)
        self.driver.conn.nwfilterDefineXML(filter_xml)

        bridge_name = self.driver.get_available_device_name(prefix='virbr')

        # TODO(ddmitriev): check if 'vlan' package installed
        # Define tagged interfaces on the bridge
        for vlanid in self.vlan_ifaces:
            self.iface_define(name=bridge_name, vlanid=vlanid)

        # Define libvirt network
        ip_network_address = None
        ip_network_prefixlen = None
        dhcp_range_start = None
        dhcp_range_end = None
        addresses = []
        if self.address_pool is not None:
            # Reserved names 'l2_network_device' and 'dhcp'
            ip_network_address = self.address_pool.get_ip('l2_network_device')

            # Workaround for fuel-qa compatibility, if 'l2_network_device'
            # address was not reserved in the YAML template
            if not ip_network_address:
                ip_network_address = str(self.address_pool.ip_network[1])

            ip_network_prefixlen = str(self.address_pool.ip_network.prefixlen)
            dhcp_range_start = self.address_pool.ip_range_start('dhcp')
            dhcp_range_end = self.address_pool.ip_range_end('dhcp')

            for interface in self.interfaces:
                for address in interface.addresses:
                    ip_addr = netaddr.IPAddress(address.ip_address)
                    if ip_addr in self.address_pool.ip_network:
                        addresses.append(
                            dict(mac=str(interface.mac_address),
                                 ip=str(address.ip_address),
                                 name=interface.node.name))

        xml = LibvirtXMLBuilder.build_network_xml(
            network_name=self.network_name,
            bridge_name=bridge_name,
            addresses=addresses,
            forward=self.forward.mode,
            ip_network_address=ip_network_address,
            ip_network_prefixlen=ip_network_prefixlen,
            dhcp_range_start=dhcp_range_start,
            dhcp_range_end=dhcp_range_end,
            stp=self.driver.stp,
            has_pxe_server=self.has_pxe_server,
            has_dhcp_server=self.has_dhcp_server,
            tftp_root_dir=self.tftp_root_dir,
        )
        ret = self.driver.conn.networkDefineXML(xml)
        ret.setAutostart(True)
        self.uuid = ret.UUIDString()

        super(LibvirtL2NetworkDevice, self).define()
Example #2
0
    def __init__(self,
                 connection_string="qemu:///system",
                 storage_pool_name="default",
                 stp=True, hpet=True, use_host_cpu=True):
        """libvirt driver

        :param use_host_cpu: When creating nodes, should libvirt's
            CPU "host-model" mode be used to set CPU settings. If set to False,
            default mode ("custom") will be used.  (default: True)
        """
        libvirt.virInitialize()
        self.conn = libvirt.open(connection_string)
        self.xml_builder = LibvirtXMLBuilder(self)
        self.stp = stp
        self.hpet = hpet
        self.capabilities = None
        self.allocated_networks = None
        self.storage_pool_name = storage_pool_name
        self.reboot_timeout = None
        self.use_host_cpu = use_host_cpu
        self.use_hugepages = settings.USE_HUGEPAGES

        if settings.VNC_PASSWORD:
            self.vnc_password = settings.VNC_PASSWORD

        if settings.REBOOT_TIMEOUT:
            self.reboot_timeout = settings.REBOOT_TIMEOUT
Example #3
0
    def __init__(self,
                 connection_string="qemu:///system",
                 storage_pool_name="default"):
        libvirt.virInitialize()
        self.conn = libvirt.open(connection_string)
        self.xml_builder = LibvirtXMLBuilder(self)
        self.capabilities = None
        self.allocated_networks = None
        self.storage_pool_name = storage_pool_name

        if settings.VNC_PASSWORD:
            self.vnc_password = settings.VNC_PASSWORD
Example #4
0
    def define(self):
        filter_xml = LibvirtXMLBuilder.build_interface_filter(
            name=self.nwfilter_name,
            filterref=self.l2_network_device.network_name)
        self.driver.conn.nwfilterDefineXML(filter_xml)

        super(LibvirtInterface, self).define()
Example #5
0
    def define(self):
        name = underscored(
            deepgetattr(self, 'node.group.environment.name'),
            deepgetattr(self, 'node.name'),
            self.name,
        )

        backing_store_path = None
        backing_store_format = None
        if self.backing_store is not None:
            backing_store_path = self.backing_store.get_path()
            backing_store_format = self.backing_store.format

        if self.source_image is not None:
            capacity = get_file_size(self.source_image)
        else:
            capacity = int(self.capacity * 1024**3)

        pool_name = self.driver.storage_pool_name
        pool = self.driver.conn.storagePoolLookupByName(pool_name)
        xml = LibvirtXMLBuilder.build_volume_xml(
            name=name,
            capacity=capacity,
            vol_format=self.format,
            backing_store_path=backing_store_path,
            backing_store_format=backing_store_format,
        )
        libvirt_volume = pool.createXML(xml, 0)
        self.uuid = libvirt_volume.key()
        super(LibvirtVolume, self).define()

        # Upload predefined image to the volume
        if self.source_image is not None:
            self.upload(self.source_image)
Example #6
0
 def unblock(self):
     """Unblock traffic on interface"""
     filter_xml = LibvirtXMLBuilder.build_interface_filter(
         name=self.nwfilter_name,
         filterref=self.l2_network_device.network_name,
         uuid=self._nwfilter.UUIDString())
     self.driver.conn.nwfilterDefineXML(filter_xml)
Example #7
0
 def block(self):
     """Block all traffic in network"""
     filter_xml = LibvirtXMLBuilder.build_network_filter(
         name=self.network_name,
         uuid=self._nwfilter.UUIDString(),
         rule=dict(action='drop', direction='inout', priority='-1000'))
     self.driver.conn.nwfilterDefineXML(filter_xml)
Example #8
0
 def unblock(self):
     """Unblock traffic on interface"""
     filter_xml = LibvirtXMLBuilder.build_interface_filter(
         name=self.nwfilter_name,
         filterref=self.l2_network_device.network_name,
         uuid=self._nwfilter.UUIDString())
     self.driver.conn.nwfilterDefineXML(filter_xml)
Example #9
0
    def define(self):
        filter_xml = LibvirtXMLBuilder.build_interface_filter(
            name=self.nwfilter_name,
            filterref=self.l2_network_device.network_name)
        self.driver.conn.nwfilterDefineXML(filter_xml)

        super(LibvirtInterface, self).define()
Example #10
0
    def define(self):
        name = underscored(
            deepgetattr(self, 'node.group.environment.name'),
            deepgetattr(self, 'node.name'),
            self.name,
        )

        backing_store_path = None
        backing_store_format = None
        if self.backing_store is not None:
            backing_store_path = self.backing_store.get_path()
            backing_store_format = self.backing_store.format

        if self.source_image is not None:
            capacity = get_file_size(self.source_image)
        else:
            capacity = int(self.capacity * 1024 ** 3)

        pool_name = self.driver.storage_pool_name
        pool = self.driver.conn.storagePoolLookupByName(pool_name)
        xml = LibvirtXMLBuilder.build_volume_xml(
            name=name,
            capacity=capacity,
            vol_format=self.format,
            backing_store_path=backing_store_path,
            backing_store_format=backing_store_format,
        )
        libvirt_volume = pool.createXML(xml, 0)
        self.uuid = libvirt_volume.key()
        super(LibvirtVolume, self).define()

        # Upload predefined image to the volume
        if self.source_image is not None:
            self.upload(self.source_image)
Example #11
0
 def block(self):
     """Block traffic on interface"""
     filter_xml = LibvirtXMLBuilder.build_interface_filter(
         name=self.nwfilter_name,
         filterref=self.l2_network_device.network_name,
         uuid=self._nwfilter.UUIDString(),
         rule=dict(action='drop', direction='inout', priority='-950'))
     self.driver.conn.nwfilterDefineXML(filter_xml)
 def setUp(self):
     self.xml_builder = LibvirtXMLBuilder(Mock())
     self.xml_builder.driver.volume_path = Mock(
         return_value="volume_path_mock")
     self.xml_builder.driver.network_name = Mock(
         return_value="network_name_mock")
     self.net = Mock()
     self.vol = Mock()
     self.node = Mock()
Example #13
0
 def block(self):
     """Block all traffic in network"""
     filter_xml = LibvirtXMLBuilder.build_network_filter(
         name=self.network_name,
         uuid=self._nwfilter.UUIDString(),
         rule=dict(action='drop',
                   direction='inout',
                   priority='-1000'))
     self.driver.conn.nwfilterDefineXML(filter_xml)
Example #14
0
 def block(self):
     """Block traffic on interface"""
     filter_xml = LibvirtXMLBuilder.build_interface_filter(
         name=self.nwfilter_name,
         filterref=self.l2_network_device.network_name,
         uuid=self._nwfilter.UUIDString(),
         rule=dict(
             action='drop',
             direction='inout',
             priority='-950'))
     self.driver.conn.nwfilterDefineXML(filter_xml)
Example #15
0
    def iface_define(self, name, ip=None, prefix=None, vlanid=None):
        """Define bridge interface

        :type name: String
        :type ip: IPAddress
        :type prefix: Integer
        :type vlanid: Integer
            :rtype : None
        """
        self.driver.conn.interfaceDefineXML(
            LibvirtXMLBuilder.build_iface_xml(name, ip, prefix, vlanid))
Example #16
0
    def iface_define(self, name, ip=None, prefix=None, vlanid=None):
        """Define bridge interface

        :type name: String
        :type ip: IPAddress
        :type prefix: Integer
        :type vlanid: Integer
            :rtype : None
        """
        self.driver.conn.interfaceDefineXML(
            LibvirtXMLBuilder.build_iface_xml(name, ip, prefix, vlanid))
Example #17
0
 def setUp(self):
     # TODO(prmtl): make it fuzzy
     self.volume_path = "volume_path_mock"
     self.xml_builder = LibvirtXMLBuilder(mock.Mock())
     self.xml_builder.driver.volume_path = mock.Mock(
         return_value=self.volume_path)
     self.xml_builder.driver.network_name = mock.Mock(
         return_value="network_name_mock")
     self.xml_builder.driver.reboot_timeout = None
     self.net = mock.Mock()
     self.node = mock.Mock()
     self.xml_builder.driver.use_hugepages = None
Example #18
0
    def __init__(self,
                 connection_string="qemu:///system",
                 storage_pool_name="default",
                 stp=True, hpet=True):
        libvirt.virInitialize()
        self.conn = libvirt.open(connection_string)
        self.xml_builder = LibvirtXMLBuilder(self)
        self.stp = stp
        self.hpet = hpet
        self.capabilities = None
        self.allocated_networks = None
        self.storage_pool_name = storage_pool_name
        self.reboot_timeout = None

        if settings.VNC_PASSWORD:
            self.vnc_password = settings.VNC_PASSWORD

        if settings.REBOOT_TIMEOUT:
            self.reboot_timeout = settings.REBOOT_TIMEOUT
Example #19
0
    def define(self):
        """Define node

            :rtype : None
        """
        name = underscored(
            deepgetattr(self, 'group.environment.name'),
            self.name,
        )

        local_disk_devices = []
        for disk in self.disk_devices:
            local_disk_devices.append(
                dict(
                    disk_type=disk.type,
                    disk_device=disk.device,
                    disk_volume_format=disk.volume.format,
                    disk_volume_path=disk.volume.get_path(),
                    disk_bus=disk.bus,
                    disk_target_dev=disk.target_dev,
                    disk_serial=uuid.uuid4().hex,
                ))

        local_interfaces = []
        for interface in self.interfaces:
            if interface.type != 'network':
                raise NotImplementedError(
                    message='Interface types different from network are not '
                    'implemented yet')

            l2_dev = interface.l2_network_device
            filter_name = underscored(
                deepgetattr(self, 'group.environment.name'), l2_dev.name,
                interface.mac_address)
            target_dev = self.driver.get_available_device_name('virnet')
            local_interfaces.append(
                dict(
                    interface_type=interface.type,
                    interface_mac_address=interface.mac_address,
                    interface_network_name=l2_dev.network_name,
                    interface_target_dev=target_dev,
                    interface_model=interface.model,
                    interface_filter=filter_name,
                ))

        emulator = self.driver.get_capabilities().find(
            'guest/arch[@name="{0:>s}"]/'
            'domain[@type="{1:>s}"]/emulator'.format(self.architecture,
                                                     self.hypervisor)).text
        node_xml = LibvirtXMLBuilder.build_node_xml(
            name=name,
            hypervisor=self.hypervisor,
            use_host_cpu=self.driver.use_host_cpu,
            vcpu=self.vcpu,
            memory=self.memory,
            use_hugepages=self.driver.use_hugepages,
            hpet=self.driver.hpet,
            os_type=self.os_type,
            architecture=self.architecture,
            boot=self.boot,
            reboot_timeout=self.driver.reboot_timeout,
            bootmenu_timeout=self.bootmenu_timeout,
            emulator=emulator,
            has_vnc=self.has_vnc,
            vnc_password=self.driver.vnc_password,
            local_disk_devices=local_disk_devices,
            interfaces=local_interfaces,
            acpi=self.driver.enable_acpi,
            numa=self.numa,
        )
        logger.debug(node_xml)
        self.uuid = self.driver.conn.defineXML(node_xml).UUIDString()

        super(LibvirtNode, self).define()
Example #20
0
 def unblock(self):
     """Unblock all traffic in network"""
     filter_xml = LibvirtXMLBuilder.build_network_filter(
         name=self.network_name,
         uuid=self._nwfilter.UUIDString())
     self.driver.conn.nwfilterDefineXML(filter_xml)
Example #21
0
class DevopsDriver(object):
    def __init__(self,
                 connection_string="qemu:///system",
                 storage_pool_name="default",
                 stp=True, hpet=True, use_host_cpu=True):
        """libvirt driver

        :param use_host_cpu: When creating nodes, should libvirt's
            CPU "host-model" mode be used to set CPU settings. If set to False,
            default mode ("custom") will be used.  (default: True)
        """
        libvirt.virInitialize()
        self.conn = libvirt.open(connection_string)
        self.xml_builder = LibvirtXMLBuilder(self)
        self.stp = stp
        self.hpet = hpet
        self.capabilities = None
        self.allocated_networks = None
        self.storage_pool_name = storage_pool_name
        self.reboot_timeout = None
        self.use_host_cpu = use_host_cpu
        self.use_hugepages = settings.USE_HUGEPAGES

        if settings.VNC_PASSWORD:
            self.vnc_password = settings.VNC_PASSWORD

        if settings.REBOOT_TIMEOUT:
            self.reboot_timeout = settings.REBOOT_TIMEOUT

    def __del__(self):
        self.conn.close()

    def _get_name(self, *kwargs):
        return self.xml_builder._get_name(*kwargs)

    @retry()
    def get_capabilities(self):
        """Get host capabilities

        :rtype : ET
        """
        if self.capabilities is None:
            self.capabilities = self.conn.getCapabilities()
        return ET.fromstring(self.capabilities)

    @retry()
    def network_bridge_name(self, network):
        """Get bridge name from UUID

        :type network: Network
            :rtype : String
        """
        return self.conn.networkLookupByUUIDString(network.uuid).bridgeName()

    @retry()
    def network_name(self, network):
        """Get network name from UUID

        :type network: Network
            :rtype : String
        """
        return self.conn.networkLookupByUUIDString(network.uuid).name()

    @retry()
    def network_active(self, network):
        """Check if network is active

        :type network: Network
            :rtype : Boolean
        """
        return self.conn.networkLookupByUUIDString(network.uuid).isActive()

    @retry()
    def node_active(self, node):
        """Check if node is active

        :type node: Node
            :rtype : Boolean
        """
        return self.conn.lookupByUUIDString(node.uuid).isActive()

    @retry()
    def network_exists(self, network):
        """Check if network exists

        :type network: Network
            :rtype : Boolean
        """
        try:
            self.conn.networkLookupByUUIDString(network.uuid)
            return True
        except libvirt.libvirtError as e:
            if e.get_error_code() == libvirt.VIR_ERR_NO_NETWORK:
                return False
            else:
                raise

    @retry()
    def node_exists(self, node):
        """Check if node exists

        :type node: Node
            :rtype : Boolean
        """
        try:
            self.conn.lookupByUUIDString(node.uuid)
            return True
        except libvirt.libvirtError as e:
            if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
                return False
            else:
                raise

    @retry()
    def node_snapshot_exists(self, node, name):
        """Check if snapshot exists

        :type node: Node
        :type name: String
            :rtype : Boolean
        """
        ret = self.conn.lookupByUUIDString(node.uuid)
        return name in ret.snapshotListNames()

    @retry()
    def volume_exists(self, volume):
        """Check if volume exists

        :type volume: Volume
            :rtype : Boolean
        """
        try:
            self.conn.storageVolLookupByKey(volume.uuid)
            return True
        except libvirt.libvirtError as e:
            if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL:
                return False
            else:
                raise

    @retry()
    def network_define(self, network):
        """Define network

        :type network: Network
            :rtype : None
        """
        ret = self.conn.networkDefineXML(
            self.xml_builder.build_network_xml(network))
        ret.setAutostart(True)
        network.uuid = ret.UUIDString()

    @retry()
    def network_destroy(self, network):
        """Destroy network

        :type network: Network
            :rtype : None
        """
        self.conn.networkLookupByUUIDString(network.uuid).destroy()

    @retry()
    def network_undefine(self, network):
        """Undefine network

        :type network: Network
            :rtype : None
        """
        self.conn.networkLookupByUUIDString(network.uuid).undefine()

    @retry()
    def network_create(self, network):
        """Create network

        :type network: Network
            :rtype : None
        """
        self.conn.networkLookupByUUIDString(network.uuid).create()

    @retry()
    def node_define(self, node):
        """Define node

        :type node: Node
            :rtype : None
        """
        emulator = self.get_capabilities(
        ).find(
            'guest/arch[@name="{0:>s}"]/'
            'domain[@type="{1:>s}"]/emulator'.format(
                node.architecture, node.hypervisor)).text
        node_xml = self.xml_builder.build_node_xml(node, emulator)
        logger.info(node_xml)
        node.uuid = self.conn.defineXML(node_xml).UUIDString()

    @retry()
    def node_destroy(self, node):
        """Destroy node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).destroy()

    @retry()
    def node_undefine(self, node, undefine_snapshots=False):
        """Undefine domain.

        If undefine_snapshot is set, discard all snapshots.

        :type node: Node
        :type undefine_snapshots: Boolean
            :rtype : None

        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        if undefine_snapshots:
            domain.undefineFlags(
                libvirt.VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)
        else:
            domain.undefine()

    @retry()
    def node_undefine_by_name(self, node_name):
        """Undefine domain discarding all snapshots

        :type node_name: String
            :rtype : None
        """
        domain = self.conn.lookupByName(node_name)
        domain.undefineFlags(libvirt.VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)

    @retry()
    def node_get_vnc_port(self, node):
        """Get VNC port

        :type node: Node
            :rtype : String
        """
        xml_desc = ET.fromstring(
            self.conn.lookupByUUIDString(node.uuid).XMLDesc(0))
        vnc_element = xml_desc.find('devices/graphics[@type="vnc"][@port]')
        if vnc_element is not None:
            return vnc_element.get('port')

    @retry()
    def node_get_interface_target_dev(self, node, mac):
        """Get target device

        :type node: Node
        :type mac: String
            :rtype : String
        """
        xml_desc = ET.fromstring(
            self.conn.lookupByUUIDString(node.uuid).XMLDesc(0))
        target = xml_desc.find('.//mac[@address="%s"]/../target' % mac)
        if target is not None:
            return target.get('dev')

    @retry()
    def node_create(self, node):
        """Create node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).create()

    @retry()
    def node_list(self):
        # virConnect.listDefinedDomains() only returns stopped domains
        #   https://bugzilla.redhat.com/show_bug.cgi?id=839259
        return [item.name() for item in self.conn.listAllDomains()]

    @retry()
    def node_reset(self, node):
        """Reset node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).reset()

    @retry()
    def node_reboot(self, node):
        """Reboot node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).reboot()

    @retry()
    def node_suspend(self, node):
        """Suspend node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).suspend()

    @retry()
    def node_resume(self, node):
        """Resume node

        :type node: Node
            :rtype : None
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        if domain.info()[0] == libvirt.VIR_DOMAIN_PAUSED:
            domain.resume()

    @retry()
    def node_shutdown(self, node):
        """Shutdown node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).shutdown()

    @retry()
    def node_get_snapshots(self, node):
        """Get list of snapshots

        :rtype : List
            :type node: Node
        """

        snapshots = self.conn.lookupByUUIDString(node.uuid).listAllSnapshots(0)
        return [Snapshot(snap) for snap in snapshots]

    @retry()
    def node_create_snapshot(self, node, name=None, description=None):
        """Create snapshot

        :type description: String
        :type name: String
        :type node: Node
            :rtype : None
        """
        xml = self.xml_builder.build_snapshot_xml(name, description)
        logger.info(xml)
        domain = self.conn.lookupByUUIDString(node.uuid)
        logger.info(domain.state(0))
        domain.snapshotCreateXML(xml, 0)
        logger.info(domain.state(0))

    def _get_snapshot(self, domain, name):
        """Get snapshot

        :type domain: Node
        :type name: String
            :rtype : libvirt.virDomainSnapshot
        """
        if name is None:
            return domain.snapshotCurrent(0)
        else:
            return domain.snapshotLookupByName(name, 0)

    @retry()
    def node_revert_snapshot(self, node, name=None):
        """Revert snapshot for node

        :type node: Node
        :type name: String
            :rtype : None
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        snapshot = self._get_snapshot(domain, name)
        domain.revertToSnapshot(snapshot, 0)

    @retry()
    def node_delete_all_snapshots(self, node):
        """Delete all snapshots for node

        :type node: Node
        """

        domain = self.conn.lookupByUUIDString(node.uuid)
        for name in domain.snapshotListNames(
                libvirt.VIR_DOMAIN_SNAPSHOT_LIST_ROOTS):
            snapshot = self._get_snapshot(domain, name)
            snapshot.delete(libvirt.VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)

    @retry()
    def node_delete_snapshot(self, node, name=None):
        """Delete snapshot

        :type node: Node
        :type name: String
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        snapshot = self._get_snapshot(domain, name)
        snapshot.delete(0)

    @retry()
    def node_send_keys(self, node, keys):
        """Send keys to node

        :type node: Node
        :type keys: String
            :rtype : None
        """

        key_codes = scancodes.from_string(str(keys))
        for key_code in key_codes:
            if isinstance(key_code[0], str):
                if key_code[0] == 'wait':
                    sleep(1)
                continue
            self.conn.lookupByUUIDString(node.uuid).sendKey(0, 0,
                                                            list(key_code),
                                                            len(key_code), 0)

    @retry()
    def node_set_vcpu(self, node, vcpu):
        """Set VCPU

        :type volume: Volume
            :rtype : None
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        domain.setVcpusFlags(vcpu, 4)
        domain.setVcpusFlags(vcpu, 2)

    @retry()
    def node_set_memory(self, node, memory):
        """Set VCPU

        :type volume: Volume
            :rtype : None
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        domain.setMaxMemory(memory)
        domain.setMemoryFlags(memory, 2)

    @retry()
    def volume_define(self, volume, pool=None):
        """Define volume

        :type volume: Volume
        :type pool: String
            :rtype : None
        """
        if pool is None:
            pool = self.storage_pool_name
        libvirt_volume = self.conn.storagePoolLookupByName(pool).createXML(
            self.xml_builder.build_volume_xml(volume), 0)
        volume.uuid = libvirt_volume.key()

    @retry()
    def volume_allocation(self, volume):
        """Get volume allocation

        :type volume: Volume
            :rtype : Long
        """
        return self.conn.storageVolLookupByKey(volume.uuid).info()[2]

    @retry()
    def volume_path(self, volume):
        return self.conn.storageVolLookupByKey(volume.uuid).path()

    def chunk_render(self, stream, size, fd):
        return fd.read(size)

    @retry(count=2)
    def volume_upload(self, volume, path):
        size = _get_file_size(path)
        with open(path, 'rb') as fd:
            stream = self.conn.newStream(0)
            self.conn.storageVolLookupByKey(volume.uuid).upload(
                stream=stream, offset=0,
                length=size, flags=0)
            stream.sendAll(self.chunk_render, fd)
            stream.finish()

    @retry()
    def volume_delete(self, volume):
        """Delete volume

        :type volume: Volume
            :rtype : None
        """
        self.conn.storageVolLookupByKey(volume.uuid).delete(0)

    @retry()
    def volume_capacity(self, volume):
        """Get volume capacity

        :type volume: Volume
            :rtype : Long
        """
        return self.conn.storageVolLookupByKey(volume.uuid).info()[1]

    @retry()
    def volume_format(self, volume):
        """Get volume format

        :type volume: Volume
            :rtype : String
        """
        xml_desc = ET.fromstring(
            self.conn.storageVolLookupByKey(volume.uuid).XMLDesc(0))
        return xml_desc.find('target/format[@type]').get('type')

    @retry()
    def get_allocated_networks(self):
        """Get list of allocated networks

            :rtype : List
        """
        if self.allocated_networks is None:
            allocated_networks = []
            for network_name in self.conn.listDefinedNetworks():
                et = ET.fromstring(
                    self.conn.networkLookupByName(network_name).XMLDesc(0))
                ip = et.find('ip[@address]')
                if ip is not None:
                    address = ip.get('address')
                    prefix_or_netmask = ip.get('prefix') or ip.get('netmask')
                    allocated_networks.append(ipaddr.IPNetwork(
                        "{0:>s}/{1:>s}".format(address, prefix_or_netmask)))
            self.allocated_networks = allocated_networks
        return self.allocated_networks
Example #22
0
    def snapshot(self,
                 name=None,
                 force=False,
                 description=None,
                 disk_only=False,
                 external=False):

        # Erase existing snapshot or raise an error if already exists
        if self.has_snapshot(name):
            if force:
                self.erase_snapshot(name)
            else:
                raise DevopsError(
                    "Snapshot with name {0} already exists".format(name))

        # Check that existing snapshot has the same type
        self._assert_snapshot_type(external=external)

        local_disk_devices = []
        if external:
            # EXTERNAL SNAPSHOTS
            if self.driver.get_libvirt_version() < 1002012:
                raise DevopsError(
                    "For external snapshots we need libvirtd >= 1.2.12")

            # Check whether we have directory for snapshots, if not
            # create it
            if not os.path.exists(settings.SNAPSHOTS_EXTERNAL_DIR):
                os.makedirs(settings.SNAPSHOTS_EXTERNAL_DIR)

            # create new volume which will be used as
            # disk for snapshot changes
            self.snapshot_create_child_volumes(name)

            base_memory_file = '{0}/snapshot-memory-{1}_{2}.{3}'.format(
                settings.SNAPSHOTS_EXTERNAL_DIR,
                deepgetattr(self, 'group.environment.name'), self.name, name)
            file_count = 0
            memory_file = base_memory_file
            while os.path.exists(memory_file):
                memory_file = base_memory_file + '-' + str(file_count)
                file_count += 1

            for disk in self.disk_devices:
                if disk.device == 'disk':
                    local_disk_devices.append(
                        dict(
                            disk_volume_path=disk.volume.get_path(),
                            disk_target_dev=disk.target_dev,
                        ))

            if self.is_active() and not disk_only:
                create_xml_flag = libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT
            else:
                create_xml_flag = (
                    libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY
                    | libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT)

        else:
            # ORIGINAL SNAPSHOTS
            memory_file = ''
            create_xml_flag = 0

        xml = LibvirtXMLBuilder.build_snapshot_xml(
            name=name,
            description=description,
            external=external,
            disk_only=disk_only,
            memory_file=memory_file,
            domain_isactive=self.is_active(),
            local_disk_devices=local_disk_devices)

        domain = self._libvirt_node
        logger.debug(xml)
        logger.debug(domain.state(0))

        domain.snapshotCreateXML(xml, create_xml_flag)

        if external:
            self.set_snapshot_current(name)

        logger.debug(domain.state(0))
Example #23
0
    def define(self):
        # define filter first
        filter_xml = LibvirtXMLBuilder.build_network_filter(
            name=self.network_name)
        self.driver.conn.nwfilterDefineXML(filter_xml)

        bridge_name = self.driver.get_available_device_name(prefix='virbr')

        # TODO(ddmitriev): check if 'vlan' package installed
        # Define tagged interfaces on the bridge
        for vlanid in self.vlan_ifaces:
            self.iface_define(name=bridge_name, vlanid=vlanid)

        # Define libvirt network
        ip_network_address = None
        ip_network_prefixlen = None
        dhcp_range_start = None
        dhcp_range_end = None
        addresses = []
        if self.address_pool is not None:
            # Reserved names 'l2_network_device' and 'dhcp'
            ip_network_address = self.address_pool.get_ip('l2_network_device')

            # Workaround for fuel-qa compatibility, if 'l2_network_device'
            # address was not reserved in the YAML template
            if not ip_network_address:
                ip_network_address = str(self.address_pool.ip_network[1])

            ip_network_prefixlen = str(self.address_pool.ip_network.prefixlen)
            dhcp_range_start = self.address_pool.ip_range_start('dhcp')
            dhcp_range_end = self.address_pool.ip_range_end('dhcp')

            for interface in self.interfaces:
                for address in interface.addresses:
                    ip_addr = netaddr.IPAddress(address.ip_address)
                    if ip_addr in self.address_pool.ip_network:
                        addresses.append(dict(
                            mac=str(interface.mac_address),
                            ip=str(address.ip_address),
                            name=interface.node.name
                        ))

        xml = LibvirtXMLBuilder.build_network_xml(
            network_name=self.network_name,
            bridge_name=bridge_name,
            addresses=addresses,
            forward=self.forward.mode,
            ip_network_address=ip_network_address,
            ip_network_prefixlen=ip_network_prefixlen,
            dhcp_range_start=dhcp_range_start,
            dhcp_range_end=dhcp_range_end,
            stp=self.driver.stp,
            has_pxe_server=self.has_pxe_server,
            has_dhcp_server=self.has_dhcp_server,
            tftp_root_dir=self.tftp_root_dir,
        )
        ret = self.driver.conn.networkDefineXML(xml)
        ret.setAutostart(True)
        self.uuid = ret.UUIDString()

        super(LibvirtL2NetworkDevice, self).define()
Example #24
0
 def unblock(self):
     """Unblock all traffic in network"""
     filter_xml = LibvirtXMLBuilder.build_network_filter(
         name=self.network_name, uuid=self._nwfilter.UUIDString())
     self.driver.conn.nwfilterDefineXML(filter_xml)
Example #25
0
    def define(self):
        """Define node

            :rtype : None
        """
        name = underscored(
            deepgetattr(self, 'group.environment.name'),
            self.name,
        )

        local_disk_devices = []
        for disk in self.disk_devices:
            local_disk_devices.append(dict(
                disk_type=disk.type,
                disk_device=disk.device,
                disk_volume_format=disk.volume.format,
                disk_volume_path=disk.volume.get_path(),
                disk_bus=disk.bus,
                disk_target_dev=disk.target_dev,
                disk_serial=uuid.uuid4().hex,
            ))

        local_interfaces = []
        for interface in self.interfaces:
            if interface.type != 'network':
                raise NotImplementedError(
                    message='Interface types different from network are not '
                            'implemented yet')

            l2_dev = interface.l2_network_device
            filter_name = underscored(
                deepgetattr(self, 'group.environment.name'),
                l2_dev.name,
                interface.mac_address
            )
            target_dev = self.driver.get_available_device_name('virnet')
            local_interfaces.append(dict(
                interface_type=interface.type,
                interface_mac_address=interface.mac_address,
                interface_network_name=l2_dev.network_name,
                interface_target_dev=target_dev,
                interface_model=interface.model,
                interface_filter=filter_name,
            ))

        emulator = self.driver.get_capabilities().find(
            'guest/arch[@name="{0:>s}"]/'
            'domain[@type="{1:>s}"]/emulator'.format(
                self.architecture, self.hypervisor)).text
        node_xml = LibvirtXMLBuilder.build_node_xml(
            name=name,
            hypervisor=self.hypervisor,
            use_host_cpu=self.driver.use_host_cpu,
            vcpu=self.vcpu,
            memory=self.memory,
            use_hugepages=self.driver.use_hugepages,
            hpet=self.driver.hpet,
            os_type=self.os_type,
            architecture=self.architecture,
            boot=self.boot,
            reboot_timeout=self.driver.reboot_timeout,
            bootmenu_timeout=self.bootmenu_timeout,
            emulator=emulator,
            has_vnc=self.has_vnc,
            vnc_password=self.driver.vnc_password,
            local_disk_devices=local_disk_devices,
            interfaces=local_interfaces,
            acpi=self.driver.enable_acpi,
            numa=self.numa,
        )
        logger.debug(node_xml)
        self.uuid = self.driver.conn.defineXML(node_xml).UUIDString()

        super(LibvirtNode, self).define()
class DevopsDriver(object):
    def __init__(self,
                 connection_string="qemu:///system",
                 storage_pool_name="default",
                 stp=True, hpet=True, use_host_cpu=True):
        """libvirt driver

        :param use_host_cpu: When creating nodes, should libvirt's
            CPU "host-model" mode be used to set CPU settings. If set to False,
            default mode ("custom") will be used.  (default: True)
        """
        libvirt.virInitialize()
        self.conn = libvirt.open(connection_string)
        self.xml_builder = LibvirtXMLBuilder(self)
        self.stp = stp
        self.hpet = hpet
        self.capabilities = None
        self.allocated_networks = None
        self.storage_pool_name = storage_pool_name
        self.reboot_timeout = None
        self.use_host_cpu = use_host_cpu
        self.use_hugepages = settings.USE_HUGEPAGES

        if settings.VNC_PASSWORD:
            self.vnc_password = settings.VNC_PASSWORD

        if settings.REBOOT_TIMEOUT:
            self.reboot_timeout = settings.REBOOT_TIMEOUT

    def __del__(self):
        self.conn.close()

    def _get_name(self, *kwargs):
        return self.xml_builder._get_name(*kwargs)

    def get_libvirt_version(self):
        return self.conn.getLibVersion()

    @retry()
    def get_capabilities(self):
        """Get host capabilities

        :rtype : ET
        """
        if self.capabilities is None:
            self.capabilities = self.conn.getCapabilities()
        return ET.fromstring(self.capabilities)

    @retry()
    def network_bridge_name(self, network):
        """Get bridge name from UUID

        :type network: Network
            :rtype : String
        """
        return self.conn.networkLookupByUUIDString(network.uuid).bridgeName()

    @retry()
    def network_name(self, network):
        """Get network name from UUID

        :type network: Network
            :rtype : String
        """
        return self.conn.networkLookupByUUIDString(network.uuid).name()

    @retry()
    def network_active(self, network):
        """Check if network is active

        :type network: Network
            :rtype : Boolean
        """
        return self.conn.networkLookupByUUIDString(network.uuid).isActive()

    @retry()
    def node_active(self, node):
        """Check if node is active

        :type node: Node
            :rtype : Boolean
        """
        return self.conn.lookupByUUIDString(node.uuid).isActive()

    @retry()
    def network_exists(self, network):
        """Check if network exists

        :type network: Network
            :rtype : Boolean
        """
        try:
            self.conn.networkLookupByUUIDString(network.uuid)
            return True
        except libvirt.libvirtError as e:
            if e.get_error_code() == libvirt.VIR_ERR_NO_NETWORK:
                return False
            else:
                raise

    @retry()
    def node_exists(self, node):
        """Check if node exists

        :type node: Node
            :rtype : Boolean
        """
        try:
            self.conn.lookupByUUIDString(node.uuid)
            return True
        except libvirt.libvirtError as e:
            if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
                return False
            else:
                raise

    @retry()
    def node_snapshot_exists(self, node, name):
        """Check if snapshot exists

        :type node: Node
        :type name: String
            :rtype : Boolean
        """
        ret = self.conn.lookupByUUIDString(node.uuid)
        return name in ret.snapshotListNames()

    @retry()
    def volume_exists(self, volume):
        """Check if volume exists

        :type volume: Volume
            :rtype : Boolean
        """
        try:
            self.conn.storageVolLookupByKey(volume.uuid)
            return True
        except libvirt.libvirtError as e:
            if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL:
                return False
            else:
                raise

    @retry()
    def network_define(self, network):
        """Define network

        :type network: Network
            :rtype : None
        """
        ret = self.conn.networkDefineXML(
            self.xml_builder.build_network_xml(network))
        ret.setAutostart(True)
        network.uuid = ret.UUIDString()

    @retry()
    def network_destroy(self, network):
        """Destroy network

        :type network: Network
            :rtype : None
        """
        self.conn.networkLookupByUUIDString(network.uuid).destroy()

    @retry()
    def network_undefine(self, network):
        """Undefine network

        :type network: Network
            :rtype : None
        """
        self.conn.networkLookupByUUIDString(network.uuid).undefine()

    @retry()
    def network_create(self, network):
        """Create network

        :type network: Network
            :rtype : None
        """
        self.conn.networkLookupByUUIDString(network.uuid).create()

    @retry()
    def node_define(self, node):
        """Define node

        :type node: Node
            :rtype : None
        """
        emulator = self.get_capabilities(
        ).find(
            'guest/arch[@name="{0:>s}"]/'
            'domain[@type="{1:>s}"]/emulator'.format(
                node.architecture, node.hypervisor)).text
        node_xml = self.xml_builder.build_node_xml(node, emulator)
        logger.info(node_xml)
        node.uuid = self.conn.defineXML(node_xml).UUIDString()

    @retry()
    def node_destroy(self, node):
        """Destroy node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).destroy()

    @retry()
    def node_undefine(self, node, undefine_snapshots=False):
        """Undefine domain.

        If undefine_snapshot is set, discard all snapshots.

        :type node: Node
        :type undefine_snapshots: Boolean
            :rtype : None

        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        if undefine_snapshots:
            # Delete external snapshots
            snap_list = domain.listAllSnapshots(0)
            for snapshot in snap_list:
                self._delete_snapshot_files(snapshot)
            domain.undefineFlags(
                libvirt.VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)
        else:
            domain.undefine()

    @retry()
    def node_undefine_by_name(self, node_name):
        """Undefine domain discarding all snapshots

        :type node_name: String
            :rtype : None
        """
        domain = self.conn.lookupByName(node_name)
        domain.undefineFlags(libvirt.VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)

    @retry()
    def node_get_vnc_port(self, node):
        """Get VNC port

        :type node: Node
            :rtype : String
        """
        xml_desc = ET.fromstring(
            self.conn.lookupByUUIDString(node.uuid).XMLDesc(0))
        vnc_element = xml_desc.find('devices/graphics[@type="vnc"][@port]')
        if vnc_element is not None:
            return vnc_element.get('port')

    @retry()
    def node_get_interface_target_dev(self, node, mac):
        """Get target device

        :type node: Node
        :type mac: String
            :rtype : String
        """
        xml_desc = ET.fromstring(
            self.conn.lookupByUUIDString(node.uuid).XMLDesc(0))
        target = xml_desc.find('.//mac[@address="%s"]/../target' % mac)
        if target is not None:
            return target.get('dev')

    @retry()
    def node_create(self, node):
        """Create node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).create()

    @retry()
    def node_list(self):
        # virConnect.listDefinedDomains() only returns stopped domains
        #   https://bugzilla.redhat.com/show_bug.cgi?id=839259
        return [item.name() for item in self.conn.listAllDomains()]

    @retry()
    def node_reset(self, node):
        """Reset node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).reset()

    @retry()
    def node_reboot(self, node):
        """Reboot node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).reboot()

    @retry()
    def node_suspend(self, node):
        """Suspend node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).suspend()

    @retry()
    def node_resume(self, node):
        """Resume node

        :type node: Node
            :rtype : None
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        if domain.info()[0] == libvirt.VIR_DOMAIN_PAUSED:
            domain.resume()

    @retry()
    def node_shutdown(self, node):
        """Shutdown node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).shutdown()

    @retry()
    def node_get_snapshots(self, node):
        """Get list of snapshots

        :rtype : List
            :type node: Node
        """

        snapshots = self.conn.lookupByUUIDString(
            node.uuid).listAllSnapshots(0)
        return [Snapshot(snap) for snap in snapshots]

    def node_get_snapshot(self, node, name):
        """Get snapshot with name

        :rtype : Snapshot
            :type node: Node
            :type name: Snapshot name
        """

        snap = self.conn.lookupByUUIDString(
            node.uuid).snapshotLookupByName(name)
        return Snapshot(snap)

    def node_set_snapshot_current(self, node, name):
        domain = self.conn.lookupByUUIDString(node.uuid)
        snapshot = self._get_snapshot(domain, name)
        snapshot_xml = Snapshot(snapshot)._xml
        domain.snapshotCreateXML(
            snapshot_xml,
            libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
            libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)

    @retry()
    def node_create_snapshot(self, node, name=None, description=None,
                             disk_only=False, external=False):
        """Create snapshot

        :type description: String
        :type name: String
        :type node: Node
            :rtype : None
        """
        if self.node_snapshot_exists(node, name):
            logger.error("Snapshot with name {0} already exists".format(name))
            return

        domain = self.conn.lookupByUUIDString(node.uuid)

        # If domain has snapshots we must check their type
        snap_list = self.node_get_snapshots(node)
        if len(snap_list) > 0:
            snap_type = snap_list[0].get_type
            if external and snap_type == 'internal':
                logger.error(
                    "Cannot create external snapshot when internal exists")
                return
            if not external and snap_type == 'external':
                logger.error(
                    "Cannot create internal snapshot when external exists")
                return

        logger.info(domain.state(0))
        xml = self.xml_builder.build_snapshot_xml(
            name, description, node, disk_only, external,
            settings.SNAPSHOTS_EXTERNAL_DIR)
        logger.info(xml)
        if external:
            # Check whether we have directory for snapshots, if not
            # create it
            if not os.path.exists(settings.SNAPSHOTS_EXTERNAL_DIR):
                os.makedirs(settings.SNAPSHOTS_EXTERNAL_DIR)

            if domain.isActive() and not disk_only:
                domain.snapshotCreateXML(
                    xml,
                    libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT)
            else:
                domain.snapshotCreateXML(
                    xml,
                    libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
                    libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT)
            self.node_set_snapshot_current(node, name)
        else:
            domain.snapshotCreateXML(xml)
        logger.info(domain.state(0))

    def _delete_snapshot_files(self, snapshot):
        """Delete snapshot external files"""
        snap_type = Snapshot(snapshot).get_type
        if snap_type == 'external':
            for snap_file in self._get_snapshot_files(snapshot):
                if os.path.isfile(snap_file):
                    try:
                        os.remove(snap_file)
                        logger.info(
                            "Delete external snapshot file {0}".format(
                                snap_file))
                    except Exception:
                        logger.info(
                            "Cannot delete external snapshot file {0}"
                            " must be deleted from cron script".format(
                                snap_file))

    def _get_snapshot(self, domain, name):
        """Get snapshot

        :type domain: Node
        :type name: String
            :rtype : libvirt.virDomainSnapshot
        """
        if name is None:
            return domain.snapshotCurrent(0)
        else:
            return domain.snapshotLookupByName(name, 0)

    def _get_snapshot_files(self, snapshot):
        """Return snapshot files"""
        xml_tree = ET.fromstring(snapshot.getXMLDesc())
        snap_files = []
        snap_memory = xml_tree.findall('./memory')[0]
        if snap_memory.get('file') is not None:
            snap_files.append(snap_memory.get('file'))
        return snap_files

    @retry()
    def node_revert_snapshot_recreate_disks(self, node, name):
        """Recreate snapshot disks."""
        domain = self.conn.lookupByUUIDString(node.uuid)
        snapshot = Snapshot(self._get_snapshot(domain, name))

        if snapshot.children_num == 0:
            for s_disk, s_disk_data in snapshot.disks.items():
                logger.info("Recreate {0}".format(s_disk_data))

                # Save actual volume XML, delete volume and create
                # new from saved XML
                volume = self.conn.storageVolLookupByKey(s_disk_data)
                volume_xml = volume.XMLDesc()
                volume_pool = volume.storagePoolLookupByVolume()
                volume.delete()
                volume_pool.createXML(volume_xml)

    @retry()
    def node_revert_snapshot(self, node, name=None):
        """Revert snapshot for node

        :type node: Node
        :type name: String
            :rtype : None
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        snapshot = Snapshot(self._get_snapshot(domain, name))

        if snapshot.get_type == 'external':
            logger.info("Revert {0} ({1}) from external snapshot {2}".format(
                node.name, snapshot.state, name))

            if self.node_active(node):
                self.node_destroy(node)

            # When snapshot dont have children we need to update disks in XML
            # used for reverting, standard revert function will restore links
            # to original disks, but we need to use disks with snapshot point,
            # we dont want to change original data
            #
            # For snapshot with children we need to create new snapshot chain
            # and we need to start from original disks, this disks will get new
            # snapshot point in node class
            xml_domain = snapshot._xml_tree.find('domain')
            if snapshot.children_num == 0:
                domain_disks = xml_domain.findall('./devices/disk')
                for s_disk, s_disk_data in snapshot.disks.items():
                    for d_disk in domain_disks:
                        d_disk_dev = d_disk.find('target').get('dev')
                        d_disk_device = d_disk.get('device')
                        if d_disk_dev == s_disk and d_disk_device == 'disk':
                            d_disk.find('source').set('file', s_disk_data)

            if snapshot.state == 'shutoff':
                # Redefine domain for snapshot without memory save
                self.conn.defineXML(ET.tostring(xml_domain))
            else:
                self.conn.restoreFlags(
                    snapshot.memory_file,
                    dxml=ET.tostring(xml_domain),
                    flags=libvirt.VIR_DOMAIN_SAVE_PAUSED)

            # set snapshot as current
            self.node_set_snapshot_current(node, name)

        else:
            logger.info("Revert {0} ({1}) to internal snapshot {2}".format(
                node.name, snapshot.state, name))
            domain.revertToSnapshot(snapshot._snapshot, 0)

    @retry()
    def node_delete_all_snapshots(self, node):
        """Delete all snapshots for node

        :type node: Node
        """

        domain = self.conn.lookupByUUIDString(node.uuid)

        # Delete all external snapshots end return
        snap_list = domain.listAllSnapshots(0)
        if len(snap_list) > 0:
            snap_type = Snapshot(snap_list[0]).get_type
            if snap_type == 'external':
                for snapshot in snap_list:
                    snapshot.delete(2)
                return

        for name in domain.snapshotListNames(
                libvirt.VIR_DOMAIN_SNAPSHOT_LIST_ROOTS):
            snapshot = self._get_snapshot(domain, name)
            snapshot.delete(libvirt.VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)

    @retry()
    def node_delete_snapshot(self, node, name=None):
        """Delete snapshot

        :type node: Node
        :type name: String
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        snapshot = self._get_snapshot(domain, name)
        snap_type = Snapshot(snapshot).get_type
        if snap_type == 'external':
            if snapshot.numChildren() > 0:
                logger.error("Cannot delete external snapshots with children")
                return

            if domain.isActive():
                domain.destroy()

            # Update domain to snapshot state
            xml_tree = ET.fromstring(snapshot.getXMLDesc())
            xml_domain = xml_tree.find('domain')
            self.conn.defineXML(ET.tostring(xml_domain))
            self._delete_snapshot_files(snapshot)
            snapshot.delete(2)
        else:
            snapshot.delete(0)

    @retry()
    def node_send_keys(self, node, keys):
        """Send keys to node

        :type node: Node
        :type keys: String
            :rtype : None
        """

        key_codes = scancodes.from_string(str(keys))
        for key_code in key_codes:
            if isinstance(key_code[0], str):
                if key_code[0] == 'wait':
                    sleep(1)
                continue
            self.conn.lookupByUUIDString(node.uuid).sendKey(0, 0,
                                                            list(key_code),
                                                            len(key_code), 0)

    @retry()
    def node_set_vcpu(self, node, vcpu):
        """Set VCPU

        :type volume: Volume
            :rtype : None
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        domain.setVcpusFlags(vcpu, 4)
        domain.setVcpusFlags(vcpu, 2)

    @retry()
    def node_set_memory(self, node, memory):
        """Set VCPU

        :type volume: Volume
            :rtype : None
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        domain.setMaxMemory(memory)
        domain.setMemoryFlags(memory, 2)

    @retry()
    def volume_define(self, volume, pool=None):
        """Define volume

        :type volume: Volume
        :type pool: String
            :rtype : None
        """
        if pool is None:
            pool = self.storage_pool_name
        libvirt_volume = self.conn.storagePoolLookupByName(pool).createXML(
            self.xml_builder.build_volume_xml(volume), 0)
        volume.uuid = libvirt_volume.key()

    @retry()
    def volume_list(self, pool=None):
        if pool is None:
            pool = self.storage_pool_name
        return self.conn.storagePoolLookupByName(pool).listAllVolumes()

    @retry()
    def volume_allocation(self, volume):
        """Get volume allocation

        :type volume: Volume
            :rtype : Long
        """
        return self.conn.storageVolLookupByKey(volume.uuid).info()[2]

    @retry()
    def volume_path(self, volume):
        return self.conn.storageVolLookupByKey(volume.uuid).path()

    def chunk_render(self, stream, size, fd):
        return fd.read(size)

    @retry(count=2)
    def volume_upload(self, volume, path):
        size = _get_file_size(path)
        with open(path, 'rb') as fd:
            stream = self.conn.newStream(0)
            self.conn.storageVolLookupByKey(volume.uuid).upload(
                stream=stream, offset=0,
                length=size, flags=0)
            stream.sendAll(self.chunk_render, fd)
            stream.finish()

    @retry()
    def volume_delete(self, volume):
        """Delete volume

        :type volume: Volume
            :rtype : None
        """
        self.conn.storageVolLookupByKey(volume.uuid).delete(0)

    @retry()
    def volume_capacity(self, volume):
        """Get volume capacity

        :type volume: Volume
            :rtype : Long
        """
        return self.conn.storageVolLookupByKey(volume.uuid).info()[1]

    @retry()
    def volume_format(self, volume):
        """Get volume format

        :type volume: Volume
            :rtype : String
        """
        xml_desc = ET.fromstring(
            self.conn.storageVolLookupByKey(volume.uuid).XMLDesc(0))
        return xml_desc.find('target/format[@type]').get('type')

    @retry()
    def get_allocated_networks(self):
        """Get list of allocated networks

            :rtype : List
        """
        if self.allocated_networks is None:
            allocated_networks = []
            for network_name in self.conn.listDefinedNetworks():
                et = ET.fromstring(
                    self.conn.networkLookupByName(network_name).XMLDesc(0))
                ip = et.find('ip[@address]')
                if ip is not None:
                    address = ip.get('address')
                    prefix_or_netmask = ip.get('prefix') or ip.get('netmask')
                    allocated_networks.append(ipaddr.IPNetwork(
                        "{0:>s}/{1:>s}".format(address, prefix_or_netmask)))
            self.allocated_networks = allocated_networks
        return self.allocated_networks
Example #27
0
    def snapshot(self, name=None, force=False, description=None,
                 disk_only=False, external=False):

        # Erase existing snapshot or raise an error if already exists
        if self.has_snapshot(name):
            if force:
                self.erase_snapshot(name)
            else:
                raise DevopsError("Snapshot with name {0} already exists"
                                  .format(name))

        # Check that existing snapshot has the same type
        self._assert_snapshot_type(external=external)

        local_disk_devices = []
        if external:
            # EXTERNAL SNAPSHOTS
            if self.driver.get_libvirt_version() < 1002012:
                raise DevopsError(
                    "For external snapshots we need libvirtd >= 1.2.12")

            # Check whether we have directory for snapshots, if not
            # create it
            if not os.path.exists(settings.SNAPSHOTS_EXTERNAL_DIR):
                os.makedirs(settings.SNAPSHOTS_EXTERNAL_DIR)

            # create new volume which will be used as
            # disk for snapshot changes
            self.snapshot_create_child_volumes(name)

            base_memory_file = '{0}/snapshot-memory-{1}_{2}.{3}'.format(
                settings.SNAPSHOTS_EXTERNAL_DIR,
                deepgetattr(self, 'group.environment.name'),
                self.name,
                name)
            file_count = 0
            memory_file = base_memory_file
            while os.path.exists(memory_file):
                memory_file = base_memory_file + '-' + str(file_count)
                file_count += 1

            for disk in self.disk_devices:
                if disk.device == 'disk':
                    local_disk_devices.append(dict(
                        disk_volume_path=disk.volume.get_path(),
                        disk_target_dev=disk.target_dev,
                    ))

            if self.is_active() and not disk_only:
                create_xml_flag = libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT
            else:
                create_xml_flag = (
                    libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
                    libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT
                )

        else:
            # ORIGINAL SNAPSHOTS
            memory_file = ''
            create_xml_flag = 0

        xml = LibvirtXMLBuilder.build_snapshot_xml(
            name=name,
            description=description,
            external=external,
            disk_only=disk_only,
            memory_file=memory_file,
            domain_isactive=self.is_active(),
            local_disk_devices=local_disk_devices
        )

        domain = self._libvirt_node
        logger.debug(xml)
        logger.debug(domain.state(0))

        domain.snapshotCreateXML(xml, create_xml_flag)

        if external:
            self.set_snapshot_current(name)

        logger.debug(domain.state(0))
Example #28
0
class DevopsDriver(object):
    def __init__(self,
                 connection_string="qemu:///system",
                 storage_pool_name="default"):
        libvirt.virInitialize()
        self.conn = libvirt.open(connection_string)
        self.xml_builder = LibvirtXMLBuilder(self)
        self.capabilities = None
        self.allocated_networks = None
        self.storage_pool_name = storage_pool_name

        if settings.VNC_PASSWORD:
            self.vnc_password = settings.VNC_PASSWORD

    def __del__(self):
        self.conn.close()

    def _get_name(self, *kwargs):
        return self.xml_builder._get_name(*kwargs)

    @retry()
    def get_capabilities(self):
        """
        :rtype : ET
        """
        if self.capabilities is None:
            self.capabilities = self.conn.getCapabilities()
        return ET.fromstring(self.capabilities)

    @retry()
    def network_bridge_name(self, network):
        """
        :type network: Network
            :rtype : String
        """
        return self.conn.networkLookupByUUIDString(network.uuid).bridgeName()

    @retry()
    def network_name(self, network):
        """
        :type network: Network
            :rtype : String
        """
        return self.conn.networkLookupByUUIDString(network.uuid).name()

    @retry()
    def network_active(self, network):
        """
        :type network: Network
            :rtype : Boolean
        """
        return self.conn.networkLookupByUUIDString(network.uuid).isActive()

    @retry()
    def node_active(self, node):
        """
        :type node: Node
            :rtype : Boolean
        """
        return self.conn.lookupByUUIDString(node.uuid).isActive()

    @retry()
    def network_exists(self, network):
        """
        :type network: Network
            :rtype : Boolean
        """
        try:
            self.conn.networkLookupByUUIDString(network.uuid)
            return True
        except libvirt.libvirtError, e:
            if e.get_error_code() == libvirt.VIR_ERR_NO_NETWORK:
                return False
            else:
                raise
Example #29
0
class DevopsDriver(object):
    def __init__(self,
                 connection_string="qemu:///system",
                 storage_pool_name="default",
                 stp=True, hpet=True):
        libvirt.virInitialize()
        self.conn = libvirt.open(connection_string)
        self.xml_builder = LibvirtXMLBuilder(self)
        self.stp = stp
        self.hpet = hpet
        self.capabilities = None
        self.allocated_networks = None
        self.storage_pool_name = storage_pool_name
        self.reboot_timeout = None

        if settings.VNC_PASSWORD:
            self.vnc_password = settings.VNC_PASSWORD

        if settings.REBOOT_TIMEOUT:
            self.reboot_timeout = settings.REBOOT_TIMEOUT

    def __del__(self):
        self.conn.close()

    def _get_name(self, *kwargs):
        return self.xml_builder._get_name(*kwargs)

    @retry()
    def get_capabilities(self):
        """Get host capabilities

        :rtype : ET
        """
        if self.capabilities is None:
            self.capabilities = self.conn.getCapabilities()
        return ET.fromstring(self.capabilities)

    @retry()
    def network_bridge_name(self, network):
        """Get bridge name from UUID

        :type network: Network
            :rtype : String
        """
        return self.conn.networkLookupByUUIDString(network.uuid).bridgeName()

    @retry()
    def network_name(self, network):
        """Get network name from UUID

        :type network: Network
            :rtype : String
        """
        return self.conn.networkLookupByUUIDString(network.uuid).name()

    @retry()
    def network_active(self, network):
        """Check if network is active

        :type network: Network
            :rtype : Boolean
        """
        return self.conn.networkLookupByUUIDString(network.uuid).isActive()

    @retry()
    def node_active(self, node):
        """Check if node is active

        :type node: Node
            :rtype : Boolean
        """
        return self.conn.lookupByUUIDString(node.uuid).isActive()

    @retry()
    def network_exists(self, network):
        """Check if network exists

        :type network: Network
            :rtype : Boolean
        """
        try:
            self.conn.networkLookupByUUIDString(network.uuid)
            return True
        except libvirt.libvirtError as e:
            if e.get_error_code() == libvirt.VIR_ERR_NO_NETWORK:
                return False
            else:
                raise

    @retry()
    def node_exists(self, node):
        """Check if node exists

        :type node: Node
            :rtype : Boolean
        """
        try:
            self.conn.lookupByUUIDString(node.uuid)
            return True
        except libvirt.libvirtError as e:
            if e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN:
                return False
            else:
                raise

    @retry()
    def node_snapshot_exists(self, node, name):
        """Check if snapshot exists

        :type node: Node
        :type name: String
            :rtype : Boolean
        """
        ret = self.conn.lookupByUUIDString(node.uuid)
        return name in ret.snapshotListNames()

    @retry()
    def volume_exists(self, volume):
        """Check if volume exists

        :type volume: Volume
            :rtype : Boolean
        """
        try:
            self.conn.storageVolLookupByKey(volume.uuid)
            return True
        except libvirt.libvirtError as e:
            if e.get_error_code() == libvirt.VIR_ERR_NO_STORAGE_VOL:
                return False
            else:
                raise

    @retry()
    def network_define(self, network):
        """Define network

        :type network: Network
            :rtype : None
        """
        ret = self.conn.networkDefineXML(
            self.xml_builder.build_network_xml(network))
        ret.setAutostart(True)
        network.uuid = ret.UUIDString()

    @retry()
    def network_destroy(self, network):
        """Destroy network

        :type network: Network
            :rtype : None
        """
        self.conn.networkLookupByUUIDString(network.uuid).destroy()

    @retry()
    def network_undefine(self, network):
        """Undefine network

        :type network: Network
            :rtype : None
        """
        self.conn.networkLookupByUUIDString(network.uuid).undefine()

    @retry()
    def network_create(self, network):
        """Create network

        :type network: Network
            :rtype : None
        """
        self.conn.networkLookupByUUIDString(network.uuid).create()

    @retry()
    def node_define(self, node):
        """Define node

        :type node: Node
            :rtype : None
        """
        emulator = self.get_capabilities(
        ).find(
            'guest/arch[@name="{0:>s}"]/'
            'domain[@type="{1:>s}"]/emulator'.format(
                node.architecture, node.hypervisor)).text
        node_xml = self.xml_builder.build_node_xml(node, emulator)
        logger.info(node_xml)
        node.uuid = self.conn.defineXML(node_xml).UUIDString()

    @retry()
    def node_destroy(self, node):
        """Destroy node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).destroy()

    @retry()
    def node_undefine(self, node, undefine_snapshots=False):
        """Undefine domain.

        If undefine_snapshot is set, discard all snapshots.

        :type node: Node
        :type undefine_snapshots: Boolean
            :rtype : None

        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        if undefine_snapshots:
            domain.undefineFlags(
                libvirt.VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)
        else:
            domain.undefine()

    @retry()
    def node_undefine_by_name(self, node_name):
        """Undefine domain discarding all snapshots

        :type node_name: String
            :rtype : None
        """
        domain = self.conn.lookupByName(node_name)
        domain.undefineFlags(libvirt.VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)

    @retry()
    def node_get_vnc_port(self, node):
        """Get VNC port

        :type node: Node
            :rtype : String
        """
        xml_desc = ET.fromstring(
            self.conn.lookupByUUIDString(node.uuid).XMLDesc(0))
        vnc_element = xml_desc.find('devices/graphics[@type="vnc"][@port]')
        if vnc_element is not None:
            return vnc_element.get('port')

    @retry()
    def node_get_interface_target_dev(self, node, mac):
        """Get target device

        :type node: Node
        :type mac: String
            :rtype : String
        """
        xml_desc = ET.fromstring(
            self.conn.lookupByUUIDString(node.uuid).XMLDesc(0))
        target = xml_desc.find('.//mac[@address="%s"]/../target' % mac)
        if target is not None:
            return target.get('dev')

    @retry()
    def node_create(self, node):
        """Create node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).create()

    @retry()
    def node_list(self):
        # virConnect.listDefinedDomains() only returns stopped domains
        #   https://bugzilla.redhat.com/show_bug.cgi?id=839259
        return [item.name() for item in self.conn.listAllDomains()]

    @retry()
    def node_reset(self, node):
        """Reset node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).reset()

    @retry()
    def node_reboot(self, node):
        """Reboot node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).reboot()

    @retry()
    def node_suspend(self, node):
        """Suspend node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).suspend()

    @retry()
    def node_resume(self, node):
        """Resume node

        :type node: Node
            :rtype : None
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        if domain.info()[0] == libvirt.VIR_DOMAIN_PAUSED:
            domain.resume()

    @retry()
    def node_shutdown(self, node):
        """Shutdown node

        :type node: Node
            :rtype : None
        """
        self.conn.lookupByUUIDString(node.uuid).shutdown()

    @retry()
    def node_get_snapshots(self, node):
        """Get list of snapshots

        :rtype : List
            :type node: Node
        """
        return self.conn.lookupByUUIDString(node.uuid).snapshotListNames(0)

    @retry()
    def node_create_snapshot(self, node, name=None, description=None):
        """Create snapshot

        :type description: String
        :type name: String
        :type node: Node
            :rtype : None
        """
        xml = self.xml_builder.build_snapshot_xml(name, description)
        logger.info(xml)
        domain = self.conn.lookupByUUIDString(node.uuid)
        logger.info(domain.state(0))
        domain.snapshotCreateXML(xml, 0)
        logger.info(domain.state(0))

    def _get_snapshot(self, domain, name):
        """Get snapshot

        :type domain: Node
        :type name: String
            :rtype : libvirt.virDomainSnapshot
        """
        if name is None:
            return domain.snapshotCurrent(0)
        else:
            return domain.snapshotLookupByName(name, 0)

    @retry()
    def node_revert_snapshot(self, node, name=None):
        """Revert snapshot for node

        :type node: Node
        :type name: String
            :rtype : None
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        snapshot = self._get_snapshot(domain, name)
        domain.revertToSnapshot(snapshot, 0)

    @retry()
    def node_delete_all_snapshots(self, node):
        """Delete all snapshots for node

        :type node: Node
        """

        domain = self.conn.lookupByUUIDString(node.uuid)
        for name in domain.snapshotListNames(
                libvirt.VIR_DOMAIN_SNAPSHOT_LIST_ROOTS):
            snapshot = self._get_snapshot(domain, name)
            snapshot.delete(libvirt.VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)

    @retry()
    def node_delete_snapshot(self, node, name=None):
        """Delete snapshot

        :type node: Node
        :type name: String
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        snapshot = self._get_snapshot(domain, name)
        snapshot.delete(0)

    @retry()
    def node_send_keys(self, node, keys):
        """Send keys to node

        :type node: Node
        :type keys: String
            :rtype : None
        """

        key_codes = scancodes.from_string(str(keys))
        for key_code in key_codes:
            if isinstance(key_code[0], str):
                if key_code[0] == 'wait':
                    sleep(1)
                continue
            self.conn.lookupByUUIDString(node.uuid).sendKey(0, 0,
                                                            list(key_code),
                                                            len(key_code), 0)

    @retry()
    def node_set_vcpu(self, node, vcpu):
        """Set VCPU

        :type volume: Volume
            :rtype : None
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        domain.setVcpusFlags(vcpu, 4)
        domain.setVcpusFlags(vcpu, 2)

    @retry()
    def node_set_memory(self, node, memory):
        """Set VCPU

        :type volume: Volume
            :rtype : None
        """
        domain = self.conn.lookupByUUIDString(node.uuid)
        domain.setMaxMemory(memory)
        domain.setMemoryFlags(memory, 2)

    @retry()
    def volume_define(self, volume, pool=None):
        """Define volume

        :type volume: Volume
        :type pool: String
            :rtype : None
        """
        if pool is None:
            pool = self.storage_pool_name
        libvirt_volume = self.conn.storagePoolLookupByName(pool).createXML(
            self.xml_builder.build_volume_xml(volume), 0)
        volume.uuid = libvirt_volume.key()

    @retry()
    def volume_allocation(self, volume):
        """Get volume allocation

        :type volume: Volume
            :rtype : Long
        """
        return self.conn.storageVolLookupByKey(volume.uuid).info()[2]

    @retry()
    def volume_path(self, volume):
        return self.conn.storageVolLookupByKey(volume.uuid).path()

    def chunk_render(self, stream, size, fd):
        return fd.read(size)

    @retry(count=2)
    def volume_upload(self, volume, path):
        size = _get_file_size(path)
        with open(path, 'rb') as fd:
            stream = self.conn.newStream(0)
            self.conn.storageVolLookupByKey(volume.uuid).upload(
                stream=stream, offset=0,
                length=size, flags=0)
            stream.sendAll(self.chunk_render, fd)
            stream.finish()

    @retry()
    def volume_delete(self, volume):
        """Delete volume

        :type volume: Volume
            :rtype : None
        """
        self.conn.storageVolLookupByKey(volume.uuid).delete(0)

    @retry()
    def volume_capacity(self, volume):
        """Get volume capacity

        :type volume: Volume
            :rtype : Long
        """
        return self.conn.storageVolLookupByKey(volume.uuid).info()[1]

    @retry()
    def volume_format(self, volume):
        """Get volume format

        :type volume: Volume
            :rtype : String
        """
        xml_desc = ET.fromstring(
            self.conn.storageVolLookupByKey(volume.uuid).XMLDesc(0))
        return xml_desc.find('target/format[@type]').get('type')

    @retry()
    def get_allocated_networks(self):
        """Get list of allocated networks

            :rtype : List
        """
        if self.allocated_networks is None:
            allocated_networks = []
            for network_name in self.conn.listDefinedNetworks():
                et = ET.fromstring(
                    self.conn.networkLookupByName(network_name).XMLDesc(0))
                ip = et.find('ip[@address]')
                if ip is not None:
                    address = ip.get('address')
                    prefix_or_netmask = ip.get('prefix') or ip.get('netmask')
                    allocated_networks.append(ipaddr.IPNetwork(
                        "{0:>s}/{1:>s}".format(address, prefix_or_netmask)))
            self.allocated_networks = allocated_networks
        return self.allocated_networks
Example #30
0
 def __init__(self, connection_string="qemu:///system"):
     libvirt.virInitialize()
     self.conn = libvirt.open(connection_string)
     self.xml_builder = LibvirtXMLBuilder(self)
     self.capabilities = None
     self.allocated_networks = None