コード例 #1
0
ファイル: supervisor_linux.py プロジェクト: bmhughes/freenas
    def devices_xml(self):
        boot_no = Nid(1)
        scsi_device_no = Nid(1)
        virtual_device_no = Nid(1)
        devices = []
        for device in filter(lambda d: d.is_available(), self.devices):
            if isinstance(device, (DISK, CDROM, RAW)):
                if device.data['attributes'].get('type') == 'VIRTIO':
                    disk_no = virtual_device_no()
                else:
                    disk_no = scsi_device_no()
                device_xml = device.xml(disk_number=disk_no,
                                        boot_number=boot_no())
            else:
                device_xml = device.xml()
            devices.extend(device_xml if isinstance(device_xml, (
                tuple, list)) else [device_xml])

        if self.vm_data['ensure_display_device'] and not any(
                isinstance(device, DISPLAY) for device in self.devices):
            # We should add a video device if there is no display device configured because most by
            # default if not all headless servers like ubuntu etc require it to boot
            devices.append(create_element('video'))

        devices.append(create_element('serial', type='pty'))
        return create_element('devices', attribute_dict={'children': devices})
コード例 #2
0
    def devices_xml(self):
        boot_no = Nid(1)
        scsi_device_no = Nid(1)
        virtual_device_no = Nid(1)
        devices = []
        for device in filter(lambda d: d.is_available(), self.devices):
            if isinstance(device, (DISK, CDROM, RAW)):
                if device.data['attributes'].get('type') == 'VIRTIO':
                    disk_no = virtual_device_no()
                else:
                    disk_no = scsi_device_no()
                device_xml = device.xml(disk_number=disk_no,
                                        boot_number=boot_no())
            else:
                device_xml = device.xml()
            devices.extend(device_xml if isinstance(device_xml, (
                tuple, list)) else [device_xml])

        spice_server_available = display_device_available = False
        for device in filter(lambda d: isinstance(d, DISPLAY), self.devices):
            display_device_available = True
            if device.is_spice_type:
                spice_server_available = True
                break

        if self.vm_data[
                'ensure_display_device'] and not display_device_available:
            # We should add a video device if there is no display device configured because most by
            # default if not all headless servers like ubuntu etc require it to boot
            devices.append(create_element('video'))

        if spice_server_available:
            # We always add spicevmc channel device when a spice display device is available to allow users
            # to install guest agents for improved vm experience
            devices.append(
                create_element('channel',
                               type='spicevmc',
                               attribute_dict={
                                   'children': [
                                       create_element(
                                           'target',
                                           type='virtio',
                                           name='com.redhat.spice.0')
                                   ]
                               }))

        devices.append(create_element('serial', type='pty'))
        return create_element('devices', attribute_dict={'children': devices})
コード例 #3
0
    def devices_xml(self):
        pptdev_choices = None
        boot_no = Nid(1)
        scsi_device_no = Nid(1)
        virtual_device_no = Nid(1)
        devices = []
        for device in self.devices:
            if isinstance(device, (DISK, CDROM, RAW)):
                if device.data['attributes'].get('type') == 'VIRTIO':
                    disk_no = virtual_device_no()
                else:
                    disk_no = scsi_device_no()
                device_xml = device.xml(disk_number=disk_no,
                                        boot_number=boot_no())
            elif isinstance(device, PCI):
                if pptdev_choices is None:
                    pptdev_choices = self.middleware.call_sync(
                        'vm.device.passthrough_device_choices')
                if device.passthru_device() not in pptdev_choices:
                    self.middleware.call_sync(
                        'alert.oneshot_create', 'PCIDeviceUnavailable', {
                            'pci': device.passthru_device(),
                            'vm_name': self.vm_data['name']
                        })
                    continue
                else:
                    self.middleware.call_sync('alert.oneshot_delete',
                                              'PCIDeviceUnavailable',
                                              device.passthru_device())
                device_xml = device.xml(passthrough_choices=pptdev_choices)
            else:
                device_xml = device.xml()
            devices.extend(device_xml if isinstance(device_xml, (
                tuple, list)) else [device_xml])

        if not any(isinstance(device, DISPLAY) for device in self.devices):
            # We should add a video device if there is no display device configured because most by
            # default if not all headless servers like ubuntu etc require it to boot
            devices.append(create_element('video'))

        devices.append(create_element('serial', type='pty'))
        return create_element('devices', attribute_dict={'children': devices})
コード例 #4
0
    def devices_xml(self):
        pptdev_choices = None
        boot_no = Nid(1)
        scsi_device_no = Nid(1)
        virtual_device_no = Nid(1)
        devices = []
        for device in self.devices:
            if isinstance(device, (DISK, CDROM, RAW)):
                if device.data['attributes'].get('type') == 'VIRTIO':
                    disk_no = virtual_device_no()
                else:
                    disk_no = scsi_device_no()
                device_xml = device.xml(disk_number=disk_no,
                                        boot_number=boot_no())
            elif isinstance(device, PCI):
                if pptdev_choices is None:
                    pptdev_choices = self.middleware.call_sync(
                        'vm.device.passthrough_device_choices')
                if device.passthru_device() not in pptdev_choices:
                    self.middleware.call_sync(
                        'alert.oneshot_create', 'PCIDeviceUnavailable', {
                            'pci': device.passthru_device(),
                            'vm_name': self.vm_data['name']
                        })
                    continue
                else:
                    self.middleware.call_sync('alert.oneshot_delete',
                                              'PCIDeviceUnavailable',
                                              device.passthru_device())
                device_xml = device.xml(passthrough_choices=pptdev_choices)
            else:
                device_xml = device.xml()
            devices.extend(device_xml if isinstance(device_xml, (
                tuple, list)) else [device_xml])

        devices.extend(
            [create_element('serial', type='pty'),
             create_element('video')])
        return create_element('devices', attribute_dict={'children': devices})
コード例 #5
0
    def devices_xml(self):
        devices = []
        pci_slot = Nid(3)
        controller_index = Nid(1)
        controller_base = {
            'index': None,
            'slot': None,
            'function': 0,
            'devices': 0
        }
        ahci_current_controller = controller_base.copy()
        virtio_current_controller = controller_base.copy()
        ppt_maps = []

        for device in self.devices:
            if isinstance(device, (DISK, CDROM, RAW)):
                # We classify all devices in 2 types:
                # 1) AHCI
                # 2) VIRTIO
                # Before deciding how we attach the disk/cdrom devices wrt slots/functions, following are few basic
                # rules:
                # We have a maximum of 32 slots ( 0-31 ) available which can be attached to the VM. Each slot supports
                # functions which for each slot can be up to 8 ( 0-7 ). For legacy reasons, we start with the 3rd
                # slot for numbering disks.

                # AHCI based devices can be up to 32 in number per function.
                # VIRTIO based disk devices consume a complete function meaning a maximum of 1 VIRTIO device can be
                # present in a function.

                # Libvirt / freebsd specific implementation
                # We do not have great support of bhyve driver in libvirt, so this is a best effort to emulate our
                # old implementation command. Following are a few points i have outlined to make the following logic
                # clearer:
                # 1) For AHCI based devices, libvirt assigns all of them to one slot ( a bug there ), we don't want
                # that of course as bhyve imposes a restriction of a maximum 32 devices per function for AHCI. To come
                # around this issue, controllers have been used for AHCI based devices which help us manage them
                # nicely allotting them on specific supplied slots/functions.
                # 2) For VIRTIO based disk devices, we use "pci" for their address type which helps us set
                # the slot/function number and it actually being respected. Reason this can't be used with AHCI is
                # that pci and sata bus are incompatible in AHCI and libvirt raises an error in this case.

                if device.data['attributes'].get('type') != 'VIRTIO':
                    virtio = False
                    current_controller = ahci_current_controller
                    max_devices = 32
                else:
                    virtio = True
                    current_controller = virtio_current_controller
                    max_devices = 1

                if not current_controller['slot'] or current_controller[
                        'devices'] == max_devices:
                    # Two scenarios will happen, either we bump function no or slot no
                    if not current_controller['slot'] or current_controller[
                            'function'] == 8:
                        # We need to add a new controller with a new slot
                        current_controller.update({
                            'slot': pci_slot(),
                            'function': 0,
                            'devices': 0,
                        })
                    else:
                        # We just need to bump the function here
                        current_controller.update({
                            'function':
                            current_controller['function'] + 1,
                            'devices':
                            0,
                        })

                    # We should add this to xml now
                    if not virtio:
                        current_controller['index'] = controller_index()
                        devices.append(
                            create_element(
                                'controller',
                                type='sata',
                                index=str(current_controller['index']),
                                attribute_dict={
                                    'children': [
                                        create_element(
                                            'address',
                                            type='pci',
                                            slot=str(
                                                current_controller['slot']),
                                            function=str(
                                                current_controller['function']
                                            ),
                                            multifunction='on')
                                    ]
                                }))

                current_controller['devices'] += 1

                if virtio:
                    address_dict = {
                        'type': 'pci',
                        'slot': str(current_controller['slot']),
                        'function': str(current_controller['function'])
                    }
                else:
                    address_dict = {
                        'type': 'drive',
                        'controller': str(current_controller['index']),
                        'target': str(current_controller['devices'])
                    }

                device_xml = device.xml(
                    child_element=create_element('address', **address_dict))
            elif isinstance(device, NIC):
                device_xml = device.xml(slot=pci_slot())
            elif isinstance(device, PCI):
                # PCI passthru section begins here
                # Check if ppt device is available for passthru. Map, only if available.
                host_bsf = device.ppt_map['host_bsf']
                if host_bsf is not None:
                    guest_bsf = self.guest_pptdev(ppt_maps, pci_slot, host_bsf)
                else:
                    guest_bsf = None
                device.ppt_map['guest_bsf'] = guest_bsf
                if guest_bsf is not None:
                    ppt_maps.append(device.ppt_map)
                device_xml = device.xml()
                # PCI passthru section ends here
            else:
                device_xml = device.xml()

            if device_xml is not None:
                devices.extend(device_xml if isinstance(
                    device_xml, (tuple, list)) else [device_xml])

        devices.append(
            create_element(
                'serial',
                type='nmdm',
                attribute_dict={
                    'children': [
                        create_element(
                            'source',
                            master=f'/dev/nmdm{self.vm_data["id"]}A',
                            slave=f'/dev/nmdm{self.vm_data["id"]}B')
                    ]
                }))

        return create_element('devices', attribute_dict={'children': devices})
コード例 #6
0
ファイル: vm.py プロジェクト: william-gr/freenas
    def run(self):
        args = [
            'bhyve',
            '-A',
            '-P',
            '-H',
            '-c', str(self.vm['vcpus']),
            '-m', str(self.vm['memory']),
            '-s', '0:0,hostbridge',
            '-s', '31,lpc',
            '-l', 'com1,/dev/nmdm{}A'.format(self.vm['id']),
        ]

        if self.vm['bootloader'] in ('UEFI', 'UEFI_CSM'):
            args += [
                '-l', 'bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI{}.fd'.format('_CSM' if self.vm['bootloader'] == 'UEFI_CSM' else ''),
            ]

        nid = Nid(3)
        for device in self.vm['devices']:
            if device['dtype'] == 'DISK':
                if device['attributes'].get('mode') == 'AHCI':
                    args += ['-s', '{},ahci-hd,{}'.format(nid(), device['attributes']['path'])]
                else:
                    args += ['-s', '{},virtio-blk,{}'.format(nid(), device['attributes']['path'])]
            elif device['dtype'] == 'CDROM':
                args += ['-s', '{},ahci-cd,{}'.format(nid(), device['attributes']['path'])]
            elif device['dtype'] == 'NIC':
                tapname = netif.create_interface('tap')
                tap = netif.get_interface(tapname)
                tap.up()
                self.taps.append(tapname)
                # If Bridge
                if True:
                    bridge = None
                    for name, iface in netif.list_interfaces().items():
                        if name.startswith('bridge'):
                            bridge = iface
                            break
                    if not bridge:
                        bridge = netif.get_interface(netif.create_interface('bridge'))
                    bridge.add_member(tapname)

                    defiface = Popen("route -nv show default|grep -w interface|awk '{ print $2 }'", stdout=subprocess.PIPE, shell=True).communicate()[0].strip()
                    if defiface and defiface not in bridge.members:
                        bridge.add_member(defiface)
                    bridge.up()
                if device['attributes'].get('type') == 'VIRTIO':
                    nictype = 'virtio-net'
                else:
                    nictype = 'e1000'
                args += ['-s', '{},{},{}'.format(nid(), nictype, tapname)]
            elif device['dtype'] == 'VNC':
                if device['attributes'].get('wait'):
                    wait = 'wait'
                else:
                    wait = ''
                args += [
                    '-s', '29,fbuf,tcp=0.0.0.0:{},w=1024,h=768,{}'.format(5900 + self.vm['id'], wait),
                    '-s', '30,xhci,tablet',
                ]

        args.append(self.vm['name'])

        self.logger.debug('Starting bhyve: {}'.format(' '.join(args)))
        self.proc = Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        for line in self.proc.stdout:
            self.logger.debug('{}: {}'.format(self.vm['name'], line))

        self.proc.wait()

        self.logger.info('Destroying {}'.format(self.vm['name']))

        Popen(['bhyvectl', '--destroy', '--vm={}'.format(self.vm['name'])], stdout=subprocess.PIPE, stderr=subprocess.PIPE).wait()

        while self.taps:
            netif.destroy_interface(self.taps.pop())

        self.manager._vm.pop(self.vm['id'], None)
コード例 #7
0
ファイル: vm.py プロジェクト: bopopescu/freenas
    async def run(self):
        args = [
            'bhyve',
            '-H',
            '-w',
            '-c',
            str(self.vm['vcpus']),
            '-m',
            str(self.vm['memory']),
            '-s',
            '0:0,hostbridge',
            '-s',
            '31,lpc',
            '-l',
            'com1,/dev/nmdm{}A'.format(self.vm['id']),
        ]

        if self.vm['bootloader'] in ('UEFI', 'UEFI_CSM'):
            args += [
                '-l',
                'bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI{}.fd'.
                format('_CSM' if self.vm['bootloader'] == 'UEFI_CSM' else ''),
            ]

        nid = Nid(3)
        for device in self.vm['devices']:
            if device['dtype'] == 'DISK' or device['dtype'] == 'RAW':

                disk_sector_size = device['attributes'].get('sectorsize', 0)
                if disk_sector_size > 0:
                    sectorsize_args = ",sectorsize=" + str(disk_sector_size)
                else:
                    sectorsize_args = ""

                if device['attributes'].get('type') == 'AHCI':
                    args += [
                        '-s',
                        '{},ahci-hd,{}{}'.format(nid(),
                                                 device['attributes']['path'],
                                                 sectorsize_args)
                    ]
                else:
                    args += [
                        '-s', '{},virtio-blk,{}{}'.format(
                            nid(), device['attributes']['path'],
                            sectorsize_args)
                    ]
            elif device['dtype'] == 'CDROM':
                args += [
                    '-s', '{},ahci-cd,{}'.format(nid(),
                                                 device['attributes']['path'])
                ]
            elif device['dtype'] == 'NIC':
                attach_iface = device['attributes'].get('nic_attach')

                self.logger.debug('====> NIC_ATTACH: {0}'.format(attach_iface))

                tapname = netif.create_interface('tap')
                tap = netif.get_interface(tapname)
                tap.up()
                self.taps.append(tapname)
                await self.bridge_setup(tapname, tap, attach_iface)

                if device['attributes'].get('type') == 'VIRTIO':
                    nictype = 'virtio-net'
                else:
                    nictype = 'e1000'
                mac_address = device['attributes'].get('mac', None)

                # By default we add one NIC and the MAC address is an empty string.
                # Issue: 24222
                if mac_address == "":
                    mac_address = None

                if mac_address == '00:a0:98:FF:FF:FF' or mac_address is None:
                    args += [
                        '-s', '{},{},{},mac={}'.format(nid(), nictype, tapname,
                                                       self.random_mac())
                    ]
                else:
                    args += [
                        '-s', '{},{},{},mac={}'.format(nid(), nictype, tapname,
                                                       mac_address)
                    ]
            elif device['dtype'] == 'VNC':
                if device['attributes'].get('wait'):
                    wait = 'wait'
                else:
                    wait = ''

                vnc_resolution = device['attributes'].get(
                    'vnc_resolution', None)
                vnc_port = int(device['attributes'].get(
                    'vnc_port', 5900 + self.vm['id']))
                vnc_bind = device['attributes'].get('vnc_bind', '0.0.0.0')
                vnc_password = device['attributes'].get('vnc_password', None)
                vnc_web = device['attributes'].get('vnc_web', None)

                vnc_password_args = ""
                if vnc_password:
                    vnc_password_args = ",password="******"==> Start WEBVNC at port {} with pid number {}".format(
                    vnc_web_port, self.web_proc.pid))

        while True:
            line = await self.proc.stdout.readline()
            if line == b'':
                break
            self.logger.debug('{}: {}'.format(self.vm['name'], line.decode()))

        # bhyve returns the following status code:
        # 0 - VM has been reset
        # 1 - VM has been powered off
        # 2 - VM has been halted
        # 3 - VM generated a triple fault
        # all other non-zero status codes are errors
        self.bhyve_error = await self.proc.wait()
        if self.bhyve_error == 0:
            self.logger.info(
                "===> Rebooting VM: {0} ID: {1} BHYVE_CODE: {2}".format(
                    self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.manager.restart(self.vm['id'])
            await self.manager.start(self.vm['id'])
        elif self.bhyve_error == 1:
            # XXX: Need a better way to handle the vmm destroy.
            self.logger.info(
                "===> Powered off VM: {0} ID: {1} BHYVE_CODE: {2}".format(
                    self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.destroy_vm()
        elif self.bhyve_error in (2, 3):
            self.logger.info(
                "===> Stopping VM: {0} ID: {1} BHYVE_CODE: {2}".format(
                    self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.manager.stop(self.vm['id'])
        elif self.bhyve_error not in (0, 1, 2, 3, None):
            self.logger.info(
                "===> Error VM: {0} ID: {1} BHYVE_CODE: {2}".format(
                    self.vm['name'], self.vm['id'], self.bhyve_error))
            await self.destroy_vm()