Mini Shell

Direktori : /opt/cloudlinux/venv/lib/python3.11/site-packages/lvestats/plugins/generic/
Upload File :
Current File : //opt/cloudlinux/venv/lib/python3.11/site-packages/lvestats/plugins/generic/analyzers.py

# coding=utf-8
#
# Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2019 All Rights Reserved
#
# Licensed under CLOUD LINUX LICENSE AGREEMENT
# http://cloudlinux.com/docs/LICENSE.TXT

import logging

from lvestat import LVEStat
from lvestats.core.plugin import LveStatsPlugin

KB = 1024
FAULTS = ('cpu_fault', 'memphy_fault', 'mem_fault', 'io_fault', 'iops_fault', 'mep_fault', 'nproc_fault')
LIMITS = ('lcpu', 'lmemphy', 'lmem', 'io', 'liops', 'lep', 'lnproc')
STATS = ('cpu_usage', 'memphy', 'mem_usage', 'io_usage', 'iops', 'mep', 'nproc')
LVEUSAGESLOTS = ('lve_version', 'time', 'has_changed_limits', 'has_changed_nproc') + STATS + LIMITS + FAULTS

__author__ = 'iseletsk'

log = logging.getLogger('LVEUsage')


class LVEUsageAnalyzer(LveStatsPlugin):
    """
    Calculates lve usage and updates it in lve_data, in field 'lve_usage'
    """

    def set_config(self, config):
        self.config = config  # pylint: disable=attribute-defined-outside-init

    def execute(self, lve_data):
        """
        :param dict lve_data:
        """
        # from /proc/lve
        new_stats = lve_data['stats']
        old_stats = lve_data['old_stats']

        del lve_data['old_stats']

        old_now = lve_data.get('old_now', None)
        lve_data['old_now'] = self.now

        total_hz = lve_data['totalHz']
        procs = lve_data['procs']

        result = {}

        for _id, lve_stat in new_stats.items():
            u = LVEUsage(lve_version=lve_data['LVE_VERSION'])
            lve_stat_old = old_stats.get(_id, None)
            u.calc(lve_stat_old, lve_stat, total_hz, self.now - old_now if old_now else None, procs)
            # LVES-210: clear all data if EP and NPROC == 0 and all other data not changed
            if _id == 0 \
                    or lve_stat.nproc > 0 \
                    or lve_stat.mep > 0 \
                    or (lve_stat_old is not None and u.is_lve_data_changed(lve_stat_old, lve_stat)):
                result[_id] = u
        lve_usages = lve_data.get('lve_usages', [])
        lve_usages.append(result)
        lve_data['lve_usages_5s'] = [result]
        lve_data['lve_active_ids'] = list(result.keys())
        lve_data['lve_usages'] = lve_usages


class LVEUsage(object):
    __slots__ = LVEUSAGESLOTS

    def __init__(self, lve_version):
        self.lve_version = lve_version
        self.time = None
        self.has_changed_limits = False
        self.has_changed_nproc = False

        # if LVE_VERSION >= 4
        self.cpu_usage = 0
        self.cpu_fault = 0
        self.mep = 0
        self.mem_fault = 0
        self.mep_fault = 0
        self.mem_usage = 0
        self.lep = 0
        self.lcpu = 0
        self.lmem = 0

        # if LVE_VERSION >=6
        self.io = 0
        self.io_usage = 0
        self.io_fault = 0
        self.lmemphy = 0
        self.memphy = 0
        self.memphy_fault = 0
        self.lnproc = 0
        self.nproc = 0
        self.nproc_fault = 0

        # if LVE_VERSION >= 8
        self.liops = 0
        self.iops = 0
        self.iops_fault = 0

    def init_limits_from_lvestat(self, lvestat: LVEStat, procs):
        """
        Prepares LVEUsage obj taking limits from LVEStat
        """
        self.lep = lvestat.lep
        self.lcpu = self.convert_lcpu_to_new_kernel_format(lvestat.cpu,
                                                           self.lve_version,
                                                           procs)
        # CMT-509: the incorrect LVE I/O units on CMT dashboard
        # Proc saves this value is in KBps,
        # but we should send it is in Bps,
        # because for an active user this value is sent in Bps
        self.io = lvestat.io * KB
        self.lmemphy = lvestat.lmemphy
        self.lnproc = lvestat.lnproc

        if self.lve_version >= 8:
            self.liops = lvestat.liops
        return self

    def __repr__(self):
        representation = '<'
        for k in (k for k in dir(self) if not k.startswith("_")):
            v = getattr(self, k)
            if isinstance(v, (str, int, float, bool, type(None))):
                representation += f'{k}:{v}, '
        representation += '>'
        return representation

    def has_interesting_values(self):
        if any((self.cpu_usage, self.nproc, self.io_usage, self.iops)):
            return True
        if any((getattr(self, k) for k in FAULTS)):
            return True
        return False

    def _has_changed_limits(self, new, old):
        """
        :type old: lvestat.LVEStat
        :type new: lvestat.LVEStat
        """
        for attr in LIMITS:
            if getattr(new, attr, None) != getattr(old, attr, None):
                return True
        return False

    def _has_changed_nproc(self, new, old):
        """
        :type old: lvestat.LVEStat
        :type new: lvestat.LVEStat
        """
        return old.nproc != new.nproc

    def convert_lcpu_to_new_kernel_format(self, lcpu, lve_ver, procs):
        """
        New kernel format lcpu is 100 times bigger than previous. So that it's 0-10000
        """
        if lve_ver >= 8:
            return lcpu
        else:
            # new_kernel_format = (old_format * 10000 * procs / 100) = old_format * 100 * procs
            return lcpu * procs * 100

    def is_lve_data_changed(self, old, new):
        """
        Check if LVE data is changed
        :param old: Previous data
        :param new: Current data
        :return: True - changes, false - not
        """
        # Common data
        if old.cpu_usage != new.cpu_usage \
                or old.mep != new.mep \
                or old.mem_fault != new.mem_fault \
                or old.mep_fault != new.mep_fault \
                or old.mem_usage != new.mem_usage \
                or old.lep != new.lep \
                or old.io != new.io \
                or old.io_usage != new.io_usage:
            return True

        # LVE6+ data
        if (old.memphy != new.memphy or old.memphy_fault != new.memphy_fault or
                old.nproc != new.nproc or old.nproc_fault != new.nproc_fault):
            return True

        # LVE8+ data
        if self.lve_version >= 8 and old.iops != new.iops:
            return True

        return False

    def calc(self, old, new, hz, time, procs):
        self.time = time

        # LCPU 100% now is 100*100 = 10 000
        # LCPU 0% is 0
        self.lcpu = self.convert_lcpu_to_new_kernel_format(new.cpu, self.lve_version, procs)

        if bool(old):
            # Previous data present
            self.has_changed_limits = self._has_changed_limits(new, old)
            self.has_changed_nproc = self._has_changed_nproc(new, old)

            # CPU USAGE is 0-10000*procs
            # new_kernel_format = (old_format * 10000 * procs / 100) = old_format * 100 * procs;
            # (100 * (new.cpu_usage - self.cpu_usage) / (hz * time)) = old_format
            assert time is not None, "oldstats is not None, but time is unknown"
            assert time != 0, "oldstats is not None, but time is 0"
            if new.cpu_usage > old.cpu_usage:
                self.cpu_usage = int(round(10000 * (new.cpu_usage - old.cpu_usage) * procs / (hz * time)))

            if new.mem_fault > old.mem_fault:
                self.mem_fault = new.mem_fault - old.mem_fault
            if new.mep_fault > old.mep_fault:
                self.mep_fault = new.mep_fault - old.mep_fault
            if new.memphy_fault > old.memphy_fault:
                self.memphy_fault = new.memphy_fault - old.memphy_fault
            if new.nproc_fault > old.nproc_fault:
                self.nproc_fault = new.nproc_fault - old.nproc_fault
            if new.io_usage > old.io_usage:
                # bytes per second
                self.io_usage = int(round(KB * (new.io_usage - old.io_usage) / time))

            if self.lve_version >= 8:
                if new.iops > old.iops:
                    self.iops = int(round((new.iops - old.iops) / time))

        if self.cpu_usage < 0:
            self.cpu_usage = 0
        elif self.cpu_usage >= self.lcpu > 0:
            self.cpu_usage = self.lcpu
            self.cpu_fault += 1

        self.lmem = new.lmem
        if self.mem_fault > 0 or new.mem_usage > new.lmem > 0:
            self.mem_usage = new.lmem
        else:
            self.mem_fault = 0
            self.mem_usage = new.mem_usage

        self.lep = new.lep
        if self.mep_fault > 0 or new.mep > new.lep > 0:
            self.mep = new.lep
        else:
            self.mep_fault = 0
            self.mep = new.mep

        if self.lve_version >= 8:
            self.liops = new.liops
            if self.iops >= self.liops > 0:
                self.iops = self.liops
                self.iops_fault += 1

        self.io = KB * new.io  # limit in bytes per second
        if self.io_usage < 0:
            self.io_usage = 0
        elif self.io_usage >= self.io > 0:
            self.io_usage = self.io
            self.io_fault += 1

        self.lmemphy = new.lmemphy
        self.lnproc = new.lnproc

        if self.memphy_fault > 0 or new.memphy > new.lmemphy > 0:
            self.memphy = new.lmemphy
        else:
            self.memphy_fault = 0
            self.memphy = new.memphy

        if self.nproc_fault > 0 or new.nproc > new.lnproc > 0:
            self.nproc = new.lnproc
        else:
            self.nproc_fault = 0
            self.nproc = new.nproc

    def __str__(self):
        return "(cpu_usage=" + str(self.cpu_usage) + ", mep=" + str(self.mep) + ")"

    def __getitem__(self, key):
        return getattr(self, key)

Zerion Mini Shell 1.0