Esempio n. 1
0
    def get(self, request, *args, **kwargs):
        center_id = str_to_int_or_default(request.GET.get('center', 0), 0)
        group_id = str_to_int_or_default(request.GET.get('group', 0), 0)
        host_id = str_to_int_or_default(request.GET.get('host', 0), 0)
        user_id = str_to_int_or_default(request.GET.get('user', 0), 0)
        search = request.GET.get('search', '')

        # 超级用户可以有用户下拉框选项
        auth = request.user
        if auth.is_superuser:
            users = User.objects.all()
        else:  # 普通用户只能查看自己的虚拟机,无用户下拉框选项
            users = None
            user_id = auth.id

        v_manager = VmManager()
        try:
            queryset = v_manager.filter_vms_queryset(
                center_id=center_id,
                group_id=group_id,
                host_id=host_id,
                search=search,
                user_id=user_id,
                all_no_filters=auth.is_superuser)
        except VmError as e:
            return render(request, 'error.html',
                          {'errors': ['查询虚拟机时错误', str(e)]})

        queryset = queryset.prefetch_related('vdisk_set')  # 反向预查询硬盘(避免多次访问数据库)
        try:
            c_manager = CenterManager()
            g_manager = GroupManager()
            centers = c_manager.get_center_queryset()
            if center_id > 0:
                groups = c_manager.get_group_queryset_by_center(center_id)
            else:
                groups = g_manager.get_group_queryset()

            if group_id > 0:
                hosts = g_manager.get_all_host_queryset_by_group(group_id)
            else:
                hosts = None
        except ComputeError as e:
            return render(request, 'error.html',
                          {'errors': ['查询虚拟机时错误', str(e)]})

        context = {
            'center_id': center_id if center_id > 0 else None,
            'centers': centers,
            'groups': groups,
            'group_id': group_id if group_id > 0 else None,
            'hosts': hosts,
            'host_id': host_id if host_id > 0 else None,
            'search': search,
            'users': users,
            'user_id': user_id
        }
        context = self.get_vms_list_context(request, queryset, context)
        return render(request, 'vms_list.html', context=context)
Esempio n. 2
0
    def get(self, request, *args, **kwargs):
        center_id = str_to_int_or_default(request.GET.get('center', 0), 0)
        group_id = str_to_int_or_default(request.GET.get('group', 0), 0)
        host_id = str_to_int_or_default(request.GET.get('host', 0), 0)
        type_id = str_to_int_or_default(request.GET.get('type', 0), 0)
        search = request.GET.get('search', '')
        user = request.user

        c_manager = CenterManager()
        g_manager = GroupManager()
        p_manager = PCIDeviceManager()
        p_manager._group_manager = g_manager
        try:
            queryset = p_manager.filter_pci_queryset(center_id=center_id,
                                                     group_id=group_id,
                                                     host_id=host_id,
                                                     search=search,
                                                     type_id=type_id,
                                                     user=user,
                                                     all_no_filters=True)
        except DeviceError as e:
            return render(request, 'error.html',
                          {'errors': ['查询PCI设备时错误', str(e)]})

        try:
            centers = c_manager.get_center_queryset()
            if center_id > 0:
                groups = c_manager.get_user_group_queryset_by_center(
                    center_or_id=center_id, user=user)
            else:
                groups = c_manager.get_user_group_queryset(user=user)

            if group_id > 0:
                hosts = g_manager.get_all_host_queryset_by_group(group_id)
            else:
                hosts = None
        except ComputeError as e:
            return render(request, 'error.html',
                          {'errors': ['查询PCI设备时错误', str(e)]})

        context = {
            'center_id': center_id if center_id > 0 else None,
            'centers': centers,
            'groups': groups,
            'group_id': group_id if group_id > 0 else None,
            'hosts': hosts,
            'host_id': host_id if host_id > 0 else None,
            'search': search,
            'types': PCIDevice.CHOICES_TYPE,
            'type_id': type_id
        }
        context = self.get_vms_list_context(request, queryset, context)
        return render(request, 'pci_list.html', context=context)
Esempio n. 3
0
    def schedule_quota(self, size: int, user, center=None, group=None):
        """
        分配合适的硬盘CEPH存储池

        :param size:
        :param user:
        :param center:
        :param group:
        :return:
            Quota()     #
            None        # 没有合适的硬盘CEPH存储池可用

        :raises: VdiskError
        """
        if group:
            if isinstance(group, int):
                group = GroupManager().get_group_by_id(group)
                if group is None:
                    raise errors.VdiskError.from_error(
                        errors.NotFoundError(msg='指定的宿主机组不存在'))

            if not group.user_has_perms(user):
                raise errors.VdiskError.from_error(
                    errors.GroupAccessDeniedError())

            queryset = self.get_quota_queryset_by_group(group=group)
        elif center:
            ids = user.group_set.filter(center=center).values_list('id',
                                                                   flat=True)
            queryset = self.get_quota_queryset_by_group_ids(ids)
        else:
            raise errors.VdiskInvalidParams(msg='必须指定一个"group"或者"center"')

        schedule_quota = None
        for quota in queryset:
            if not quota.check_disk_size_limit(size=size):
                continue

            if not quota.meet_needs(size=size):
                continue

            # 向硬盘CEPH存储池申请容量
            if not quota.claim(size=size):
                continue

            schedule_quota = quota
            break

        if schedule_quota:
            return schedule_quota

        return None
Esempio n. 4
0
    def get(self, request, *args, **kwargs):
        center_id = str_to_int_or_default(request.GET.get('center', 0), 0)
        group_id = str_to_int_or_default(request.GET.get('group', 0), 0)
        quota_id = str_to_int_or_default(request.GET.get('quota', 0), 0)
        user_id = str_to_int_or_default(request.GET.get('user', 0), 0)
        search = request.GET.get('search', '')

        # 超级用户可以有用户下拉框选项
        auth = request.user
        if auth.is_superuser:
            users = User.objects.all()
        else:  # 普通用户只能查看自己的虚拟机,无用户下拉框选项
            users = None
            user_id = auth.id

        manager = VdiskManager()
        try:
            queryset = manager.filter_vdisk_queryset(
                center_id=center_id,
                group_id=group_id,
                quota_id=quota_id,
                search=search,
                user_id=user_id,
                all_no_filters=auth.is_superuser)
        except VdiskError as e:
            return render(request, 'error.html',
                          {'errors': ['查询云硬盘时错误', str(e)]})

        try:
            c_manager = CenterManager()
            centers = c_manager.get_center_queryset()
            if center_id > 0:
                groups = c_manager.get_group_queryset_by_center(center_id)
            else:
                groups = GroupManager().get_group_queryset()
        except ComputeError as e:
            return render(request, 'error.html',
                          {'errors': ['查询机组时错误', str(e)]})

        if group_id > 0:
            quotas = manager.get_quota_queryset_by_group(group_id)
        else:
            quotas = None

        context = {}
        context['center_id'] = center_id if center_id > 0 else None
        context['centers'] = centers
        context['groups'] = groups
        context['group_id'] = group_id if group_id > 0 else None
        context['quotas'] = quotas
        context['quota_id'] = quota_id if quota_id > 0 else None
        context['search'] = search
        context['users'] = users
        context['user_id'] = user_id
        context = self.get_disks_list_context(request, queryset, context)
        return render(request, 'vdisk_list.html', context=context)
Esempio n. 5
0
    def get_user_pci_queryset(self, user):
        """
        用户有访问权限的PCI设备查询集

        :param user: 用户对象
        :return:
            QuerySet()

        :raises: DeviceError
        """
        try:
            h_ids = GroupManager().get_user_host_ids(user=user)
            qs = self.get_device_queryset().filter(id__in=h_ids).all()
        except ComputeError as e:
            raise DeviceError(msg=str(e))
        return qs
Esempio n. 6
0
    def get_host_list(group):
        """
        获取指定宿主机组的宿主机列表

        :param group: 宿主机组Group(),只获取此组的宿主机
        :return:
            list                    # success
            raise ScheduleError     # failed ,未找到宿主机或发生错误

        :raise ScheduleError
        """
        try:
            host_list = list(GroupManager().get_enable_host_queryset_by_group(group_or_id=group))
        except (ComputeError, Exception) as e:
            raise ScheduleError(msg=f'获取宿主机list错误,{str(e)}')

        return host_list
Esempio n. 7
0
    def get(self, request, *args, **kwargs):
        if not request.user.is_superuser:
            return HttpResponse('您无权访问此页面')

        centers = CenterManager().get_stat_center_queryset().values(
            'id', 'name', 'mem_total', 'mem_allocated', 'real_cpu',
            'vcpu_total', 'vcpu_allocated', 'vm_created')
        groups = GroupManager().get_stat_group_queryset().values(
            'id', 'name', 'center__name', 'mem_total', 'mem_allocated',
            'real_cpu', 'vcpu_total', 'vcpu_allocated', 'vm_created')
        hosts = Host.objects.select_related('group').values(
            'id', 'ipv4', 'group__name', 'mem_total', 'mem_allocated',
            'real_cpu', 'vcpu_total', 'vcpu_allocated', 'vm_created').all()
        return render(request,
                      'reports_list.html',
                      context={
                          'centers': centers,
                          'groups': groups,
                          'hosts': hosts
                      })
Esempio n. 8
0
    def _get_host_list(self, group, vlan=None):
        '''
        获取指定宿主机组的属于vlan子网的宿主机列表

        :param vlan: 子网对象Vlan()
        :param group_id: 宿主机组Group(),只获取此组的宿主机
        :return:
            list                    # success
            raise ScheduleError     # failed ,未找到宿主机或发生错误

        :raise ScheduleError
        '''
        try:
            if vlan:
                host_list = HostManager().get_hosts_by_group_and_vlan(
                    group_or_id=group, vlan=vlan)
            else:
                host_list = list(GroupManager().get_host_queryset_by_group(
                    group_or_id=group))
        except (ComputeError, Exception) as e:
            raise ScheduleError(msg=f'获取宿主机list错误,{str(e)}')

        return host_list
Esempio n. 9
0
    def filter_vlan_queryset(self,
                             center: int = None,
                             group: int = None,
                             is_public: bool = None,
                             user=None):
        """
        筛选vlan查询集

        :param center: 分中心id
        :param group: 宿主机组id
        :param is_public: 公网或私网
        :param user: 用户实例,用于过滤用户有权限使用的vlan
        :return:
            QuerySet()
        """
        group_set = None
        if user:
            group_set = user.group_set.all()

        if group:
            if not group_set:
                group_set = GroupManager().get_group_queryset()

            group_set = group_set.filter(id=group)
        elif center:
            if group_set:
                group_set = group_set.filter(center=center)
            else:
                group_set = CenterManager().get_group_queryset_by_center(
                    center)

        queryset = self.get_vlan_queryset()
        if is_public is True:
            queryset = queryset.filter(tag=Vlan.NET_TAG_PUBLIC)
        elif is_public is False:
            queryset = queryset.filter(tag=Vlan.NET_TAG_PRIVATE)

        if group_set:
            queryset = queryset.filter(
                group__in=Subquery(group_set.values('id'))).all()

        return queryset
Esempio n. 10
0
class PCIDeviceManager:
    DeviceError = DeviceError

    def __init__(self):
        self._center_manager = CenterManager()
        self._group_manager = GroupManager()
        self._host_manager = HostManager()

    def get_device_queryset(self):
        '''
        获取所有PCI设备的查询集
        :return: QuerySet()
        '''
        return PCIDevice.objects.all()

    def get_device_by_id(self, device_id: int, related_fields=('host', )):
        '''
        :return:
            PCIDevice()     # success
            None            # not exists
        :raises:  DeviceError
        '''
        qs = self.get_device_queryset()
        try:
            if related_fields:
                qs = qs.select_related(*related_fields).all()
            return qs.filter(pk=device_id).first()
        except Exception as e:
            raise DeviceError(msg=str(e))

    def get_device_by_address(self, address: str):
        '''
        :return:
            PCIDevice()     # success
            None            # not exists
        '''
        return self.get_device_queryset().filter(address=address).first()

    def get_user_pci_queryset(self, user):
        """
        用户有访问权限的PCI设备查询集

        :param user: 用户对象
        :return:
            QuerySet()

        :raises: DeviceError
        """
        try:
            h_ids = GroupManager().get_user_host_ids(user=user)
            qs = self.get_device_queryset().filter(id__in=h_ids).all()
        except ComputeError as e:
            raise DeviceError(msg=str(e))
        return qs

    def get_pci_queryset_by_center(self, center):
        """
        分中心下的PCI设备查询集

        :param center: Center对象或id
        :return:
            QuerySet()

        :raises: DeviceError
        """
        try:
            group_ids = self._center_manager.get_group_ids_by_center(center)
            host_ids = self._group_manager.get_host_ids_by_group_ids(group_ids)
        except ComputeError as e:
            raise DeviceError(msg=str(e))

        return self.get_device_queryset().filter(host__in=host_ids).all()

    def get_user_pci_queryset_by_center(self, center, user):
        """
        用户有访问权限的,分中心下的PCI设备查询集

        :param center: Center对象或id
        :param user: 用户对象
        :return:
            QuerySet()

        :raises: DeviceError
        """
        try:
            group_ids = self._center_manager.get_user_group_ids_by_center(
                center=center, user=user)
            host_ids = self._group_manager.get_host_ids_by_group_ids(group_ids)
        except ComputeError as e:
            raise DeviceError(msg=str(e))

        return self.get_device_queryset().filter(host__in=host_ids).all()

    def get_pci_queryset_by_group(self, group):
        '''
        宿主机组下的PCI设备查询集

        :param group: Group对象或id
        :return:
            QuerySet()

        :raises: DeviceError
        '''
        try:
            ids = self._group_manager.get_host_ids_by_group(group_or_id=group)
        except ComputeError as e:
            raise DeviceError(msg=str(e))

        return self.get_device_queryset().filter(host__in=ids).all()

    def get_user_pci_queryset_by_group(self, group, user):
        '''
        用户有访问权限的,机组下的PCI设备查询集

        :param group: Group对象或id
        :param user: 用户对象
        :return:
            QuerySet()

        :raises: DeviceError
        '''
        gm = self._group_manager

        try:
            group = gm.enforce_group_obj(group)
            if not group.user_has_perms(user=user):
                raise DeviceError(msg='无宿主机组的访问权限')
            ids = gm.get_host_ids_by_group(group_or_id=group)
        except ComputeError as e:
            raise DeviceError(msg=str(e))

        return self.get_device_queryset().filter(host__in=ids).all()

    def get_pci_queryset_by_host(self, host):
        """
        宿主机的PCI设备查询集

        :param host: Host对象或id
        :return:
            QuerySet()

        :raises: DeviceError
        """
        return self.get_device_queryset().filter(host=host).all()

    def get_user_pci_queryset_by_host(self, host, user):
        """
        用户有访问权限的,宿主机的PCI设备查询集

        :param host: Host对象或id
        :param user: 用户对象
        :return:
            QuerySet()

        :raises: DeviceError
        """
        try:
            host = self._host_manager.enforce_host_obj(host)
        except ComputeError as e:
            raise DeviceError(msg=str(e))

        if not host.user_has_perms(user=user):
            raise DeviceError(msg='无宿主机的访问权限')

        return self.get_device_queryset().filter(host=host).all()

    def device_wrapper(self, device: PCIDevice):
        '''
        PCI设备对象的包装器

        :param device:PCI设备对象
        :return:
            BasePCIDevice子类     # GPUDevice

        :raises:  DeviceError
        '''
        if device.type == device.TYPE_GPU:
            return GPUDevice(db=device)

        return DeviceError(msg='未知设备')

    def mount_to_vm(self, device: PCIDevice, vm):
        '''
        挂载设备到虚拟机

        :param device: pci设备对象
        :param vm: 虚拟机对象
        :return:
            True    # success

        :raises: DeviceError
        '''
        host = vm.host
        dev = self.device_wrapper(device)
        if dev.need_in_same_host():
            if dev.host_id != host.id:
                raise DeviceError(msg='设备和虚拟机不在同一宿主机')

        try:
            dev.mount(vm=vm)
        except DeviceError as e:
            raise DeviceError(msg=f'与虚拟机建立挂载关系失败, {str(e)}')

        xml_desc = dev.xml_desc
        try:
            if VirtAPI().attach_device(host_ipv4=host.ipv4,
                                       vm_uuid=vm.hex_uuid,
                                       xml=xml_desc):
                return True
            raise VirtError(msg='挂载到虚拟机失败')
        except VirtError as e:
            try:
                dev.umount()
            except:
                pass
            raise DeviceError(msg=str(e))

    def umount_from_vm(self, device: PCIDevice):
        '''
        卸载设备从虚拟机

        :param device: pci设备对象
        :return:
            True    # success

        :raises: DeviceError
        '''
        dev = self.device_wrapper(device)
        vm = dev.vm
        if not vm:
            return True

        host = vm.host
        xml_desc = dev.xml_desc
        v_api = VirtAPI()
        try:
            if not v_api.detach_device(
                    host_ipv4=host.ipv4, vm_uuid=vm.hex_uuid, xml=xml_desc):
                raise VirtError(msg='从虚拟机卸载设备失败')
        except VirtError as e:
            raise DeviceError(msg=str(e))

        try:
            dev.umount()
        except DeviceError as e:
            v_api.attach_device(host_ipv4=host.ipv4,
                                vm_uuid=vm.hex_uuid,
                                xml=xml_desc)
            raise DeviceError(msg=f'与虚拟机解除挂载关系失败, {str(e)}')

        return True

    def filter_pci_queryset(self,
                            center_id: int = 0,
                            group_id: int = 0,
                            host_id: int = 0,
                            type_id: int = 0,
                            search: str = '',
                            user=None,
                            all_no_filters: bool = False,
                            related_fields: tuple = ()):
        """
        通过条件筛选虚拟机查询集

        :param center_id: 分中心id,大于0有效
        :param group_id: 机组id,大于0有效
        :param host_id: 宿主机id,大于0有效
        :param type_id: 设备类型id,大于0有效
        :param search: 关键字筛选条件
        :param user: 用户对象
        :param all_no_filters: 筛选条件都无效时;True: 返回所有; False: 抛出错误
        :param related_fields: 外键字段;外键字段直接一起获取,而不是惰性的用时再获取
        :return:
            QuerySet    # success

        :raise: DeviceError
        """
        if not related_fields:
            related_fields = ('host__group', 'vm__mac_ip')

        if center_id <= 0 and group_id <= 0 and host_id <= 0 and type_id <= 0 and not search:
            if user and user.id:
                return self.get_user_pci_queryset(user=user)

            if not all_no_filters:
                raise DeviceError(msg='无有效的查询条件')

            return self.get_device_queryset().select_related(
                *related_fields).all()

        queryset = None
        if host_id > 0:
            queryset = self.get_user_pci_queryset_by_host(host=host_id,
                                                          user=user)
        elif group_id > 0:
            queryset = self.get_user_pci_queryset_by_group(group_id, user=user)
        elif center_id > 0:
            queryset = self.get_user_pci_queryset_by_center(center=center_id,
                                                            user=user)

        if type_id > 0:
            if queryset is not None:
                queryset = queryset.filter(type=type_id).all()
            else:
                queryset = self.get_device_queryset().filter(
                    type=type_id).all()

        if search:
            if queryset is not None:
                queryset = queryset.filter(
                    Q(remarks__icontains=search)
                    | Q(host__ipv4__icontains=search)).all()
            else:
                queryset = self.get_device_queryset().filter(
                    Q(remarks__icontains=search)
                    | Q(host__ipv4__icontains=search)).all()

        return queryset.select_related(*related_fields).all()
Esempio n. 11
0
 def __init__(self):
     self._center_manager = CenterManager()
     self._group_manager = GroupManager()
     self._host_manager = HostManager()