관리-도구
편집 파일: common.py
# coding=utf-8 # # Copyright © Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2023 All Rights Reserved # # Licensed under CLOUD LINUX LICENSE AGREEMENT # http://cloudlinux.com/docs/LICENSE.TXT import math import enum import json import typing from enum import StrEnum from types import SimpleNamespace from collections.abc import Sequence, Mapping from typing import NewType, TypedDict, Protocol, NamedTuple, TYPE_CHECKING if TYPE_CHECKING: from lveapi import PyLve SerializedLveId = NewType('SerializedLveId', int) LveId = NewType('LveId', int) Timestamp = NewType('Timestamp', int) class BurstingMultipliers(NamedTuple): cpu: float io: float @enum.unique class LveState(StrEnum): EXISTED = enum.auto() UNBURSTED = enum.auto() BURSTED = enum.auto() OVERUSING = enum.auto() def __str__(self) -> str: return self.name class LveStats(Protocol): cpu: int io: int # in KB reseller_id: int empty_stats = typing.cast(LveStats, SimpleNamespace( cpu=0, cpu_usage=0, io=0, io_usage=0, reseller_id=0, )) class LveUsage(Protocol): cpu_usage: int io_usage: int # in bytes empty_usage = typing.cast(LveUsage, SimpleNamespace( cpu_usage=0, io_usage=0, )) class AdjustStepData(NamedTuple): now: Timestamp lve_active_ids: Sequence[SerializedLveId] stats: Mapping[SerializedLveId, LveStats] lve_usages_by_id: Mapping[SerializedLveId, LveUsage] class LveLimits(TypedDict): cpu: int io: int class InvalidStateError(RuntimeError): pass class ApplyLveSettings(Protocol): def __call__(self, lve_id: LveId, lve_limits: LveLimits) -> None: ... class GetNormalLimits(Protocol): def __call__(self) -> Mapping[LveId, LveLimits]: ... def read_normal_limits_from_proc() -> Mapping[LveId, LveLimits]: with open('/var/run/cloudlinux/effective-normal-limits', 'r', encoding='utf-8') as f: result = json.load(f) result = {LveId(int(k)): v for k, v in result.items()} return result class PyLveSettingsApplier: def __init__(self, pylve: 'PyLve') -> None: self._pylve = pylve def __call__(self, lve_id: LveId, lve_limits: LveLimits) -> None: if lve_id == 0: raise RuntimeError('Cannot alter LVE with id 0') lve_settings = self._pylve.liblve_settings() lve_settings.ls_io = int(lve_limits['io']) lve_settings.ls_cpu = int(lve_limits['cpu']) lve_settings.ls_cpus = int(lve_limits['ncpu']) lve_settings.ls_memory = int(lve_limits['mem']) lve_settings.ls_enters = int(lve_limits['ep']) lve_settings.ls_memory_phy = int(lve_limits['pmem']) lve_settings.ls_nproc = int(lve_limits['nproc']) lve_settings.ls_iops = int(lve_limits['iops']) self._pylve.lve_setup( lve_id, lve_settings, err_msg=f'Can`t setup lve with id {lve_id}; error code {{code}}', ) def infer_lve_state( stats: LveStats, normal_limits: LveLimits, usage: LveUsage, ) -> LveState: normal_cpu_limit = normal_limits['cpu'] normal_io_limit = normal_limits['io'] * 1024 # to be in bytes kernel_cpu_limits = stats.cpu kernel_io_limits = stats.io * 1024 # to be in bytes current_cpu_usage = usage.cpu_usage current_io_usage = usage.io_usage # in bytes if math.isclose(kernel_cpu_limits, normal_cpu_limit) and math.isclose(kernel_io_limits, normal_io_limit): assert current_cpu_usage <= normal_cpu_limit, 'CPU usage is not expected to be greater than CPU limit!' assert current_io_usage <= normal_io_limit, 'IO usage is not expected to be greater than IO limit!' return LveState.UNBURSTED elif current_cpu_usage < normal_cpu_limit and current_io_usage < normal_io_limit: return LveState.BURSTED else: return LveState.OVERUSING def get_deserialized_lve_id(serialized_lve_id: SerializedLveId) -> LveId: # NOTE(vlebedev): This import requires some shared library to be present in order to succeed, # so deffer it until it's really needed to make unittests writing/running easier. from lvestats.lib.commons.func import deserialize_lve_id # pylint: disable=import-outside-toplevel lve_id, _ = deserialize_lve_id(serialized_lve_id) return typing.cast(LveId, lve_id) def calc_bursted_limits(normal_limits: LveLimits, bursting_multipliers: BurstingMultipliers) -> LveLimits: return { **normal_limits, 'cpu': int(normal_limits['cpu'] * bursting_multipliers.cpu), 'io': int(normal_limits['io'] * bursting_multipliers.io) }