mirror of https://github.com/jumpserver/jumpserver
perf: 修改terminal statuts
perf: 优化status api perf: 优化 status api perf: 修改sesion参数 perf: 修改migrations perf: 优化数据结构 perf: 修改保留日志 perf: 优化之前的一个写法pull/5953/head^2
parent
a5179d1596
commit
9cd5675209
|
@ -5,4 +5,4 @@ from .session import *
|
||||||
from .command import *
|
from .command import *
|
||||||
from .task import *
|
from .task import *
|
||||||
from .storage import *
|
from .storage import *
|
||||||
from .component import *
|
from .status import *
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
|
|
||||||
import logging
|
|
||||||
from rest_framework import generics, status
|
|
||||||
from rest_framework.views import Response
|
|
||||||
|
|
||||||
from .. import serializers
|
|
||||||
from ..utils import ComponentsMetricsUtil
|
|
||||||
from common.permissions import IsAppUser, IsSuperUser
|
|
||||||
|
|
||||||
logger = logging.getLogger(__file__)
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
'ComponentsStateAPIView', 'ComponentsMetricsAPIView',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class ComponentsStateAPIView(generics.CreateAPIView):
|
|
||||||
""" koko, guacamole, omnidb 上报状态 """
|
|
||||||
permission_classes = (IsAppUser,)
|
|
||||||
serializer_class = serializers.ComponentsStateSerializer
|
|
||||||
|
|
||||||
|
|
||||||
class ComponentsMetricsAPIView(generics.GenericAPIView):
|
|
||||||
""" 返回汇总组件指标数据 """
|
|
||||||
permission_classes = (IsSuperUser,)
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
tp = request.query_params.get('type')
|
|
||||||
util = ComponentsMetricsUtil()
|
|
||||||
metrics = util.get_metrics(tp)
|
|
||||||
return Response(metrics, status=status.HTTP_200_OK)
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
from rest_framework import viewsets, generics
|
||||||
|
from rest_framework.views import Response
|
||||||
|
from rest_framework import status
|
||||||
|
|
||||||
|
from common.permissions import IsAppUser, IsOrgAdminOrAppUser, IsSuperUser
|
||||||
|
from ..models import Terminal, Status, Session
|
||||||
|
from .. import serializers
|
||||||
|
from ..utils import TypedComponentsStatusMetricsUtil
|
||||||
|
|
||||||
|
logger = logging.getLogger(__file__)
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'StatusViewSet',
|
||||||
|
'ComponentsMetricsAPIView',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class StatusViewSet(viewsets.ModelViewSet):
|
||||||
|
queryset = Status.objects.all()
|
||||||
|
serializer_class = serializers.StatusSerializer
|
||||||
|
permission_classes = (IsOrgAdminOrAppUser,)
|
||||||
|
session_serializer_class = serializers.SessionSerializer
|
||||||
|
task_serializer_class = serializers.TaskSerializer
|
||||||
|
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
self.handle_sessions()
|
||||||
|
self.perform_create(serializer)
|
||||||
|
tasks = self.request.user.terminal.task_set.filter(is_finished=False)
|
||||||
|
serializer = self.task_serializer_class(tasks, many=True)
|
||||||
|
return Response(serializer.data, status=201)
|
||||||
|
|
||||||
|
def handle_sessions(self):
|
||||||
|
session_ids = self.request.data.get('sessions', [])
|
||||||
|
# guacamole 上报的 session 是字符串
|
||||||
|
# "[53cd3e47-210f-41d8-b3c6-a184f3, 53cd3e47-210f-41d8-b3c6-a184f4]"
|
||||||
|
if isinstance(session_ids, str):
|
||||||
|
session_ids = session_ids[1:-1].split(',')
|
||||||
|
session_ids = [sid.strip() for sid in session_ids if sid.strip()]
|
||||||
|
Session.set_sessions_active(session_ids)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
terminal_id = self.kwargs.get("terminal", None)
|
||||||
|
if terminal_id:
|
||||||
|
terminal = get_object_or_404(Terminal, id=terminal_id)
|
||||||
|
return terminal.status_set.all()
|
||||||
|
return super().get_queryset()
|
||||||
|
|
||||||
|
def perform_create(self, serializer):
|
||||||
|
serializer.validated_data.pop('sessions', None)
|
||||||
|
serializer.validated_data["terminal"] = self.request.user.terminal
|
||||||
|
return super().perform_create(serializer)
|
||||||
|
|
||||||
|
def get_permissions(self):
|
||||||
|
if self.action == "create":
|
||||||
|
self.permission_classes = (IsAppUser,)
|
||||||
|
return super().get_permissions()
|
||||||
|
|
||||||
|
|
||||||
|
class ComponentsMetricsAPIView(generics.GenericAPIView):
|
||||||
|
""" 返回汇总组件指标数据 """
|
||||||
|
permission_classes = (IsSuperUser,)
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
util = TypedComponentsStatusMetricsUtil()
|
||||||
|
metrics = util.get_metrics()
|
||||||
|
return Response(metrics, status=status.HTTP_200_OK)
|
|
@ -4,8 +4,7 @@ import logging
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.shortcuts import get_object_or_404
|
from rest_framework import generics
|
||||||
from rest_framework import viewsets, generics
|
|
||||||
from rest_framework.views import APIView, Response
|
from rest_framework.views import APIView, Response
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -13,13 +12,13 @@ from django.conf import settings
|
||||||
|
|
||||||
from common.drf.api import JMSBulkModelViewSet
|
from common.drf.api import JMSBulkModelViewSet
|
||||||
from common.utils import get_object_or_none
|
from common.utils import get_object_or_none
|
||||||
from common.permissions import IsAppUser, IsOrgAdminOrAppUser, IsSuperUser, WithBootstrapToken
|
from common.permissions import IsAppUser, IsSuperUser, WithBootstrapToken
|
||||||
from ..models import Terminal, Status, Session
|
from ..models import Terminal
|
||||||
from .. import serializers
|
from .. import serializers
|
||||||
from .. import exceptions
|
from .. import exceptions
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'TerminalViewSet', 'StatusViewSet', 'TerminalConfig',
|
'TerminalViewSet', 'TerminalConfig',
|
||||||
'TerminalRegistrationApi',
|
'TerminalRegistrationApi',
|
||||||
]
|
]
|
||||||
logger = logging.getLogger(__file__)
|
logger = logging.getLogger(__file__)
|
||||||
|
@ -72,45 +71,6 @@ class TerminalViewSet(JMSBulkModelViewSet):
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
class StatusViewSet(viewsets.ModelViewSet):
|
|
||||||
queryset = Status.objects.all()
|
|
||||||
serializer_class = serializers.StatusSerializer
|
|
||||||
permission_classes = (IsOrgAdminOrAppUser,)
|
|
||||||
session_serializer_class = serializers.SessionSerializer
|
|
||||||
task_serializer_class = serializers.TaskSerializer
|
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
|
||||||
self.handle_sessions()
|
|
||||||
tasks = self.request.user.terminal.task_set.filter(is_finished=False)
|
|
||||||
serializer = self.task_serializer_class(tasks, many=True)
|
|
||||||
return Response(serializer.data, status=201)
|
|
||||||
|
|
||||||
def handle_sessions(self):
|
|
||||||
session_ids = self.request.data.get('sessions', [])
|
|
||||||
# guacamole 上报的 session 是字符串
|
|
||||||
# "[53cd3e47-210f-41d8-b3c6-a184f3, 53cd3e47-210f-41d8-b3c6-a184f4]"
|
|
||||||
if isinstance(session_ids, str):
|
|
||||||
session_ids = session_ids[1:-1].split(',')
|
|
||||||
session_ids = [sid.strip() for sid in session_ids if sid.strip()]
|
|
||||||
Session.set_sessions_active(session_ids)
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
terminal_id = self.kwargs.get("terminal", None)
|
|
||||||
if terminal_id:
|
|
||||||
terminal = get_object_or_404(Terminal, id=terminal_id)
|
|
||||||
self.queryset = terminal.status_set.all()
|
|
||||||
return self.queryset
|
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
|
||||||
serializer.validated_data["terminal"] = self.request.user.terminal
|
|
||||||
return super().perform_create(serializer)
|
|
||||||
|
|
||||||
def get_permissions(self):
|
|
||||||
if self.action == "create":
|
|
||||||
self.permission_classes = (IsAppUser,)
|
|
||||||
return super().get_permissions()
|
|
||||||
|
|
||||||
|
|
||||||
class TerminalConfig(APIView):
|
class TerminalConfig(APIView):
|
||||||
permission_classes = (IsAppUser,)
|
permission_classes = (IsAppUser,)
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ class ComponentStatusChoices(TextChoices):
|
||||||
critical = 'critical', _('Critical')
|
critical = 'critical', _('Critical')
|
||||||
high = 'high', _('High')
|
high = 'high', _('High')
|
||||||
normal = 'normal', _('Normal')
|
normal = 'normal', _('Normal')
|
||||||
|
offline = 'offline', _('Offline')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def status(cls):
|
def status(cls):
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
# Generated by Django 3.1 on 2021-03-29 09:11
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('terminal', '0032_auto_20210302_1853'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='status',
|
||||||
|
old_name='cpu_used',
|
||||||
|
new_name='cpu_load',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='status',
|
||||||
|
name='cpu_load',
|
||||||
|
field=models.FloatField(default=0, verbose_name='CPU Load'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='status',
|
||||||
|
name='disk_used',
|
||||||
|
field=models.FloatField(default=0, verbose_name='Disk Used'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='status',
|
||||||
|
name='boot_time',
|
||||||
|
field=models.FloatField(default=0, verbose_name='Boot Time'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='status',
|
||||||
|
name='connections',
|
||||||
|
field=models.IntegerField(default=0, verbose_name='Connections'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='status',
|
||||||
|
name='threads',
|
||||||
|
field=models.IntegerField(default=0, verbose_name='Threads'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -14,7 +14,6 @@ from assets.models import Asset
|
||||||
from orgs.mixins.models import OrgModelMixin
|
from orgs.mixins.models import OrgModelMixin
|
||||||
from common.db.models import ChoiceSet
|
from common.db.models import ChoiceSet
|
||||||
from ..backends import get_multi_command_storage
|
from ..backends import get_multi_command_storage
|
||||||
from .terminal import Terminal
|
|
||||||
|
|
||||||
|
|
||||||
class Session(OrgModelMixin):
|
class Session(OrgModelMixin):
|
||||||
|
@ -47,7 +46,7 @@ class Session(OrgModelMixin):
|
||||||
is_finished = models.BooleanField(default=False, db_index=True)
|
is_finished = models.BooleanField(default=False, db_index=True)
|
||||||
has_replay = models.BooleanField(default=False, verbose_name=_("Replay"))
|
has_replay = models.BooleanField(default=False, verbose_name=_("Replay"))
|
||||||
has_command = models.BooleanField(default=False, verbose_name=_("Command"))
|
has_command = models.BooleanField(default=False, verbose_name=_("Command"))
|
||||||
terminal = models.ForeignKey(Terminal, null=True, on_delete=models.DO_NOTHING, db_constraint=False)
|
terminal = models.ForeignKey('terminal.Terminal', null=True, on_delete=models.DO_NOTHING, db_constraint=False)
|
||||||
protocol = models.CharField(choices=PROTOCOL.choices, default='ssh', max_length=16, db_index=True)
|
protocol = models.CharField(choices=PROTOCOL.choices, default='ssh', max_length=16, db_index=True)
|
||||||
date_start = models.DateTimeField(verbose_name=_("Date start"), db_index=True, default=timezone.now)
|
date_start = models.DateTimeField(verbose_name=_("Date start"), db_index=True, default=timezone.now)
|
||||||
date_end = models.DateTimeField(verbose_name=_("Date end"), null=True)
|
date_end = models.DateTimeField(verbose_name=_("Date end"), null=True)
|
||||||
|
|
|
@ -3,26 +3,62 @@ from __future__ import unicode_literals
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.forms.models import model_to_dict
|
||||||
|
from django.core.cache import cache
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from .terminal import Terminal
|
from common.utils import get_logger
|
||||||
|
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class Status(models.Model):
|
class Status(models.Model):
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
session_online = models.IntegerField(verbose_name=_("Session Online"), default=0)
|
session_online = models.IntegerField(verbose_name=_("Session Online"), default=0)
|
||||||
cpu_used = models.FloatField(verbose_name=_("CPU Usage"))
|
cpu_load = models.FloatField(verbose_name=_("CPU Load"), default=0)
|
||||||
memory_used = models.FloatField(verbose_name=_("Memory Used"))
|
memory_used = models.FloatField(verbose_name=_("Memory Used"))
|
||||||
connections = models.IntegerField(verbose_name=_("Connections"))
|
disk_used = models.FloatField(verbose_name=_("Disk Used"), default=0)
|
||||||
threads = models.IntegerField(verbose_name=_("Threads"))
|
connections = models.IntegerField(verbose_name=_("Connections"), default=0)
|
||||||
boot_time = models.FloatField(verbose_name=_("Boot Time"))
|
threads = models.IntegerField(verbose_name=_("Threads"), default=0)
|
||||||
terminal = models.ForeignKey(Terminal, null=True, on_delete=models.CASCADE)
|
boot_time = models.FloatField(verbose_name=_("Boot Time"), default=0)
|
||||||
|
terminal = models.ForeignKey('terminal.Terminal', null=True, on_delete=models.CASCADE)
|
||||||
date_created = models.DateTimeField(auto_now_add=True)
|
date_created = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
CACHE_KEY = 'TERMINAL_STATUS_{}'
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'terminal_status'
|
db_table = 'terminal_status'
|
||||||
get_latest_by = 'date_created'
|
get_latest_by = 'date_created'
|
||||||
|
|
||||||
def __str__(self):
|
def save_to_cache(self):
|
||||||
return self.date_created.strftime("%Y-%m-%d %H:%M:%S")
|
if not self.terminal:
|
||||||
|
return
|
||||||
|
key = self.CACHE_KEY.format(self.terminal.id)
|
||||||
|
data = model_to_dict(self)
|
||||||
|
cache.set(key, data, 60*3)
|
||||||
|
return data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_terminal_latest_status(cls, terminal):
|
||||||
|
from ..utils import ComputeStatUtil
|
||||||
|
stat = cls.get_terminal_latest_stat(terminal)
|
||||||
|
return ComputeStatUtil.compute_component_status(stat)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_terminal_latest_stat(cls, terminal):
|
||||||
|
key = cls.CACHE_KEY.format(terminal.id)
|
||||||
|
data = cache.get(key)
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
data.pop('terminal', None)
|
||||||
|
stat = cls(**data)
|
||||||
|
stat.terminal = terminal
|
||||||
|
return stat
|
||||||
|
|
||||||
|
def save(self, force_insert=False, force_update=False, using=None,
|
||||||
|
update_fields=None):
|
||||||
|
self.terminal.set_alive(ttl=120)
|
||||||
|
return self.save_to_cache()
|
||||||
|
# return super().save()
|
||||||
|
|
||||||
|
|
|
@ -1,168 +1,63 @@
|
||||||
from __future__ import unicode_literals
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.core.cache import cache
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.cache import cache
|
|
||||||
|
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from users.models import User
|
from users.models import User
|
||||||
|
from .status import Status
|
||||||
from .. import const
|
from .. import const
|
||||||
|
from ..const import ComponentStatusChoices as StatusChoice
|
||||||
|
from .session import Session
|
||||||
|
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
|
||||||
|
|
||||||
class ComputeStatusMixin:
|
class TerminalStatusMixin:
|
||||||
|
ALIVE_KEY = 'TERMINAL_ALIVE_{}'
|
||||||
# system status
|
id: str
|
||||||
@staticmethod
|
|
||||||
def _common_compute_system_status(value, thresholds):
|
|
||||||
if thresholds[0] <= value <= thresholds[1]:
|
|
||||||
return const.ComponentStatusChoices.normal.value
|
|
||||||
elif thresholds[1] < value <= thresholds[2]:
|
|
||||||
return const.ComponentStatusChoices.high.value
|
|
||||||
else:
|
|
||||||
return const.ComponentStatusChoices.critical.value
|
|
||||||
|
|
||||||
def _compute_system_cpu_load_1_status(self, value):
|
|
||||||
thresholds = [0, 5, 20]
|
|
||||||
return self._common_compute_system_status(value, thresholds)
|
|
||||||
|
|
||||||
def _compute_system_memory_used_percent_status(self, value):
|
|
||||||
thresholds = [0, 85, 95]
|
|
||||||
return self._common_compute_system_status(value, thresholds)
|
|
||||||
|
|
||||||
def _compute_system_disk_used_percent_status(self, value):
|
|
||||||
thresholds = [0, 80, 99]
|
|
||||||
return self._common_compute_system_status(value, thresholds)
|
|
||||||
|
|
||||||
def _compute_system_status(self, state):
|
|
||||||
system_status_keys = [
|
|
||||||
'system_cpu_load_1', 'system_memory_used_percent', 'system_disk_used_percent'
|
|
||||||
]
|
|
||||||
system_status = []
|
|
||||||
for system_status_key in system_status_keys:
|
|
||||||
state_value = state.get(system_status_key)
|
|
||||||
if state_value is None:
|
|
||||||
msg = 'state: {}, state_key: {}, state_value: {}'
|
|
||||||
logger.debug(msg.format(state, system_status_key, state_value))
|
|
||||||
state_value = 0
|
|
||||||
status = getattr(self, f'_compute_{system_status_key}_status')(state_value)
|
|
||||||
system_status.append(status)
|
|
||||||
return system_status
|
|
||||||
|
|
||||||
def _compute_component_status(self, state):
|
|
||||||
system_status = self._compute_system_status(state)
|
|
||||||
if const.ComponentStatusChoices.critical in system_status:
|
|
||||||
return const.ComponentStatusChoices.critical
|
|
||||||
elif const.ComponentStatusChoices.high in system_status:
|
|
||||||
return const.ComponentStatusChoices.high
|
|
||||||
else:
|
|
||||||
return const.ComponentStatusChoices.normal
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _compute_component_status_display(status):
|
|
||||||
return getattr(const.ComponentStatusChoices, status).label
|
|
||||||
|
|
||||||
|
|
||||||
class TerminalStateMixin(ComputeStatusMixin):
|
|
||||||
CACHE_KEY_COMPONENT_STATE = 'CACHE_KEY_COMPONENT_STATE_TERMINAL_{}'
|
|
||||||
CACHE_TIMEOUT = 120
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cache_key(self):
|
def latest_status(self):
|
||||||
return self.CACHE_KEY_COMPONENT_STATE.format(str(self.id))
|
return Status.get_terminal_latest_status(self)
|
||||||
|
|
||||||
# get
|
|
||||||
def _get_from_cache(self):
|
|
||||||
return cache.get(self.cache_key)
|
|
||||||
|
|
||||||
def _set_to_cache(self, state):
|
|
||||||
cache.set(self.cache_key, state, self.CACHE_TIMEOUT)
|
|
||||||
|
|
||||||
# set
|
|
||||||
def _add_status(self, state):
|
|
||||||
status = self._compute_component_status(state)
|
|
||||||
status_display = self._compute_component_status_display(status)
|
|
||||||
state.update({
|
|
||||||
'status': status,
|
|
||||||
'status_display': status_display
|
|
||||||
})
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def latest_status_display(self):
|
||||||
state = self._get_from_cache()
|
return self.latest_status.label
|
||||||
return state or {}
|
|
||||||
|
|
||||||
@state.setter
|
|
||||||
def state(self, state):
|
|
||||||
self._add_status(state)
|
|
||||||
self._set_to_cache(state)
|
|
||||||
|
|
||||||
|
|
||||||
class TerminalStatusMixin(TerminalStateMixin):
|
|
||||||
|
|
||||||
# alive
|
|
||||||
@property
|
|
||||||
def is_alive(self):
|
|
||||||
return bool(self.state)
|
|
||||||
|
|
||||||
# status
|
|
||||||
@property
|
|
||||||
def status(self):
|
|
||||||
if self.is_alive:
|
|
||||||
return self.state['status']
|
|
||||||
else:
|
|
||||||
return const.ComponentStatusChoices.critical.value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def status_display(self):
|
def latest_stat(self):
|
||||||
return self._compute_component_status_display(self.status)
|
return Status.get_terminal_latest_stat(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_normal(self):
|
def is_normal(self):
|
||||||
return self.status == const.ComponentStatusChoices.normal.value
|
return self.latest_status == StatusChoice.normal
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_high(self):
|
def is_high(self):
|
||||||
return self.status == const.ComponentStatusChoices.high.value
|
return self.latest_status == StatusChoice.high
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_critical(self):
|
def is_critical(self):
|
||||||
return self.status == const.ComponentStatusChoices.critical.value
|
return self.latest_status == StatusChoice.critical
|
||||||
|
|
||||||
|
|
||||||
class Terminal(TerminalStatusMixin, models.Model):
|
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
|
||||||
name = models.CharField(max_length=128, verbose_name=_('Name'))
|
|
||||||
type = models.CharField(
|
|
||||||
choices=const.TerminalTypeChoices.choices, default=const.TerminalTypeChoices.koko.value,
|
|
||||||
max_length=64, verbose_name=_('type')
|
|
||||||
)
|
|
||||||
remote_addr = models.CharField(max_length=128, blank=True, verbose_name=_('Remote Address'))
|
|
||||||
ssh_port = models.IntegerField(verbose_name=_('SSH Port'), default=2222)
|
|
||||||
http_port = models.IntegerField(verbose_name=_('HTTP Port'), default=5000)
|
|
||||||
command_storage = models.CharField(max_length=128, verbose_name=_("Command storage"), default='default')
|
|
||||||
replay_storage = models.CharField(max_length=128, verbose_name=_("Replay storage"), default='default')
|
|
||||||
user = models.OneToOneField(User, related_name='terminal', verbose_name='Application User', null=True, on_delete=models.CASCADE)
|
|
||||||
is_accepted = models.BooleanField(default=False, verbose_name='Is Accepted')
|
|
||||||
is_deleted = models.BooleanField(default=False)
|
|
||||||
date_created = models.DateTimeField(auto_now_add=True)
|
|
||||||
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_active(self):
|
def is_alive(self):
|
||||||
if self.user and self.user.is_active:
|
key = self.ALIVE_KEY.format(self.id)
|
||||||
return True
|
# return self.latest_status != StatusChoice.offline
|
||||||
return False
|
return cache.get(key, False)
|
||||||
|
|
||||||
@is_active.setter
|
def set_alive(self, ttl=120):
|
||||||
def is_active(self, active):
|
key = self.ALIVE_KEY.format(self.id)
|
||||||
if self.user:
|
cache.set(key, True, ttl)
|
||||||
self.user.is_active = active
|
|
||||||
self.user.save()
|
|
||||||
|
class StorageMixin:
|
||||||
|
command_storage: str
|
||||||
|
replay_storage: str
|
||||||
|
|
||||||
def get_command_storage(self):
|
def get_command_storage(self):
|
||||||
from .storage import CommandStorage
|
from .storage import CommandStorage
|
||||||
|
@ -198,6 +93,44 @@ class Terminal(TerminalStatusMixin, models.Model):
|
||||||
config = self.get_replay_storage_config()
|
config = self.get_replay_storage_config()
|
||||||
return {"TERMINAL_REPLAY_STORAGE": config}
|
return {"TERMINAL_REPLAY_STORAGE": config}
|
||||||
|
|
||||||
|
|
||||||
|
class Terminal(StorageMixin, TerminalStatusMixin, models.Model):
|
||||||
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
|
name = models.CharField(max_length=128, verbose_name=_('Name'))
|
||||||
|
type = models.CharField(
|
||||||
|
choices=const.TerminalTypeChoices.choices, default=const.TerminalTypeChoices.koko.value,
|
||||||
|
max_length=64, verbose_name=_('type')
|
||||||
|
)
|
||||||
|
remote_addr = models.CharField(max_length=128, blank=True, verbose_name=_('Remote Address'))
|
||||||
|
ssh_port = models.IntegerField(verbose_name=_('SSH Port'), default=2222)
|
||||||
|
http_port = models.IntegerField(verbose_name=_('HTTP Port'), default=5000)
|
||||||
|
command_storage = models.CharField(max_length=128, verbose_name=_("Command storage"), default='default')
|
||||||
|
replay_storage = models.CharField(max_length=128, verbose_name=_("Replay storage"), default='default')
|
||||||
|
user = models.OneToOneField(User, related_name='terminal', verbose_name='Application User', null=True, on_delete=models.CASCADE)
|
||||||
|
is_accepted = models.BooleanField(default=False, verbose_name='Is Accepted')
|
||||||
|
is_deleted = models.BooleanField(default=False)
|
||||||
|
date_created = models.DateTimeField(auto_now_add=True)
|
||||||
|
comment = models.TextField(blank=True, verbose_name=_('Comment'))
|
||||||
|
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_active(self):
|
||||||
|
if self.user and self.user.is_active:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@is_active.setter
|
||||||
|
def is_active(self, active):
|
||||||
|
if self.user:
|
||||||
|
self.user.is_active = active
|
||||||
|
self.user.save()
|
||||||
|
|
||||||
|
def get_online_sessions(self):
|
||||||
|
return Session.objects.filter(terminal=self, is_finished=False)
|
||||||
|
|
||||||
|
def get_online_session_count(self):
|
||||||
|
return self.get_online_sessions().count()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_login_title_setting():
|
def get_login_title_setting():
|
||||||
login_title = None
|
login_title = None
|
||||||
|
|
|
@ -4,4 +4,3 @@ from .terminal import *
|
||||||
from .session import *
|
from .session import *
|
||||||
from .storage import *
|
from .storage import *
|
||||||
from .command import *
|
from .command import *
|
||||||
from .components import *
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
|
|
||||||
from rest_framework import serializers
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
|
|
||||||
class ComponentsStateSerializer(serializers.Serializer):
|
|
||||||
# system
|
|
||||||
system_cpu_load_1 = serializers.FloatField(
|
|
||||||
required=False, label=_("System cpu load (1 minutes)")
|
|
||||||
)
|
|
||||||
system_memory_used_percent = serializers.FloatField(
|
|
||||||
required=False, label=_('System memory used percent')
|
|
||||||
)
|
|
||||||
system_disk_used_percent = serializers.FloatField(
|
|
||||||
required=False, label=_('System disk used percent')
|
|
||||||
)
|
|
||||||
# sessions
|
|
||||||
session_active_count = serializers.IntegerField(
|
|
||||||
required=False, label=_("Session active count")
|
|
||||||
)
|
|
||||||
|
|
||||||
def save(self, **kwargs):
|
|
||||||
request = self.context['request']
|
|
||||||
terminal = request.user.terminal
|
|
||||||
terminal.state = self.validated_data
|
|
|
@ -9,15 +9,34 @@ from common.utils import get_request_ip
|
||||||
from ..models import (
|
from ..models import (
|
||||||
Terminal, Status, Session, Task, CommandStorage, ReplayStorage
|
Terminal, Status, Session, Task, CommandStorage, ReplayStorage
|
||||||
)
|
)
|
||||||
from .components import ComponentsStateSerializer
|
|
||||||
|
|
||||||
|
class StatusSerializer(serializers.ModelSerializer):
|
||||||
|
sessions = serializers.ListSerializer(
|
||||||
|
child=serializers.CharField(max_length=35), write_only=True
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
fields = [
|
||||||
|
'id',
|
||||||
|
'cpu_load', 'memory_used', 'disk_used',
|
||||||
|
'session_online', 'sessions',
|
||||||
|
'terminal', 'date_created',
|
||||||
|
]
|
||||||
|
extra_kwargs = {
|
||||||
|
"cpu_load": {'default': 0},
|
||||||
|
"memory_used": {'default': 0},
|
||||||
|
"disk_used": {'default': 0},
|
||||||
|
}
|
||||||
|
model = Status
|
||||||
|
|
||||||
|
|
||||||
class TerminalSerializer(BulkModelSerializer):
|
class TerminalSerializer(BulkModelSerializer):
|
||||||
session_online = serializers.SerializerMethodField()
|
session_online = serializers.SerializerMethodField()
|
||||||
is_alive = serializers.BooleanField(read_only=True)
|
is_alive = serializers.BooleanField(read_only=True)
|
||||||
status = serializers.CharField(read_only=True)
|
status = serializers.CharField(read_only=True, source='latest_status')
|
||||||
status_display = serializers.CharField(read_only=True)
|
status_display = serializers.CharField(read_only=True, source='latest_status_display')
|
||||||
state = ComponentsStateSerializer(read_only=True)
|
stat = StatusSerializer(read_only=True, source='latest_stat')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Terminal
|
model = Terminal
|
||||||
|
@ -25,7 +44,7 @@ class TerminalSerializer(BulkModelSerializer):
|
||||||
'id', 'name', 'type', 'remote_addr', 'http_port', 'ssh_port',
|
'id', 'name', 'type', 'remote_addr', 'http_port', 'ssh_port',
|
||||||
'comment', 'is_accepted', "is_active", 'session_online',
|
'comment', 'is_accepted', "is_active", 'session_online',
|
||||||
'is_alive', 'date_created', 'command_storage', 'replay_storage',
|
'is_alive', 'date_created', 'command_storage', 'replay_storage',
|
||||||
'status', 'status_display', 'state'
|
'status', 'status_display', 'stat'
|
||||||
]
|
]
|
||||||
read_only_fields = ['type', 'date_created']
|
read_only_fields = ['type', 'date_created']
|
||||||
|
|
||||||
|
@ -59,12 +78,6 @@ class TerminalSerializer(BulkModelSerializer):
|
||||||
return Session.objects.filter(terminal=obj, is_finished=False).count()
|
return Session.objects.filter(terminal=obj, is_finished=False).count()
|
||||||
|
|
||||||
|
|
||||||
class StatusSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
fields = ['id', 'terminal']
|
|
||||||
model = Status
|
|
||||||
|
|
||||||
|
|
||||||
class TaskSerializer(BulkModelSerializer):
|
class TaskSerializer(BulkModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
|
@ -29,7 +29,7 @@ logger = get_task_logger(__name__)
|
||||||
@after_app_ready_start
|
@after_app_ready_start
|
||||||
@after_app_shutdown_clean_periodic
|
@after_app_shutdown_clean_periodic
|
||||||
def delete_terminal_status_period():
|
def delete_terminal_status_period():
|
||||||
yesterday = timezone.now() - datetime.timedelta(days=1)
|
yesterday = timezone.now() - datetime.timedelta(days=7)
|
||||||
Status.objects.filter(date_created__lt=yesterday).delete()
|
Status.objects.filter(date_created__lt=yesterday).delete()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,6 @@ urlpatterns = [
|
||||||
path('command-storages/<uuid:pk>/test-connective/', api.CommandStorageTestConnectiveApi.as_view(), name='command-storage-test-connective'),
|
path('command-storages/<uuid:pk>/test-connective/', api.CommandStorageTestConnectiveApi.as_view(), name='command-storage-test-connective'),
|
||||||
# components
|
# components
|
||||||
path('components/metrics/', api.ComponentsMetricsAPIView.as_view(), name='components-metrics'),
|
path('components/metrics/', api.ComponentsMetricsAPIView.as_view(), name='components-metrics'),
|
||||||
path('components/state/', api.ComponentsStateAPIView.as_view(), name='components-state'),
|
|
||||||
# v2: get session's replay
|
# v2: get session's replay
|
||||||
# path('v2/sessions/<uuid:pk>/replay/',
|
# path('v2/sessions/<uuid:pk>/replay/',
|
||||||
# api.SessionReplayV2ViewSet.as_view({'get': 'retrieve'}),
|
# api.SessionReplayV2ViewSet.as_view({'get': 'retrieve'}),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
import os
|
import os
|
||||||
|
from itertools import groupby
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.files.storage import default_storage
|
from django.core.files.storage import default_storage
|
||||||
|
@ -10,9 +11,7 @@ import jms_storage
|
||||||
|
|
||||||
from common.tasks import send_mail_async
|
from common.tasks import send_mail_async
|
||||||
from common.utils import get_logger, reverse
|
from common.utils import get_logger, reverse
|
||||||
from settings.models import Setting
|
|
||||||
from . import const
|
from . import const
|
||||||
|
|
||||||
from .models import ReplayStorage, Session, Command
|
from .models import ReplayStorage, Session, Command
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
@ -141,23 +140,73 @@ def send_command_execution_alert_mail(command):
|
||||||
send_mail_async.delay(subject, message, recipient_list, html_message=message)
|
send_mail_async.delay(subject, message, recipient_list, html_message=message)
|
||||||
|
|
||||||
|
|
||||||
class ComponentsMetricsUtil(object):
|
class ComputeStatUtil:
|
||||||
|
# system status
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_components(tp=None):
|
def _common_compute_system_status(value, thresholds):
|
||||||
|
if thresholds[0] <= value <= thresholds[1]:
|
||||||
|
return const.ComponentStatusChoices.normal.value
|
||||||
|
elif thresholds[1] < value <= thresholds[2]:
|
||||||
|
return const.ComponentStatusChoices.high.value
|
||||||
|
else:
|
||||||
|
return const.ComponentStatusChoices.critical.value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _compute_system_stat_status(cls, stat):
|
||||||
|
system_stat_thresholds_mapper = {
|
||||||
|
'cpu_load': [0, 5, 20],
|
||||||
|
'memory_used': [0, 85, 95],
|
||||||
|
'disk_used': [0, 80, 99]
|
||||||
|
}
|
||||||
|
system_status = {}
|
||||||
|
for stat_key, thresholds in system_stat_thresholds_mapper.items():
|
||||||
|
stat_value = getattr(stat, stat_key)
|
||||||
|
if stat_value is None:
|
||||||
|
msg = 'stat: {}, stat_key: {}, stat_value: {}'
|
||||||
|
logger.debug(msg.format(stat, stat_key, stat_value))
|
||||||
|
stat_value = 0
|
||||||
|
status = cls._common_compute_system_status(stat_value, thresholds)
|
||||||
|
system_status[stat_key] = status
|
||||||
|
return system_status
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def compute_component_status(cls, stat):
|
||||||
|
if not stat:
|
||||||
|
return const.ComponentStatusChoices.offline
|
||||||
|
system_status_values = cls._compute_system_stat_status(stat).values()
|
||||||
|
if const.ComponentStatusChoices.critical in system_status_values:
|
||||||
|
return const.ComponentStatusChoices.critical
|
||||||
|
elif const.ComponentStatusChoices.high in system_status_values:
|
||||||
|
return const.ComponentStatusChoices.high
|
||||||
|
else:
|
||||||
|
return const.ComponentStatusChoices.normal
|
||||||
|
|
||||||
|
|
||||||
|
class TypedComponentsStatusMetricsUtil(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.components = []
|
||||||
|
self.grouped_components = []
|
||||||
|
self.get_components()
|
||||||
|
|
||||||
|
def get_components(self):
|
||||||
from .models import Terminal
|
from .models import Terminal
|
||||||
components = Terminal.objects.filter(is_deleted=False).order_by('type')
|
components = Terminal.objects.filter(is_deleted=False).order_by('type')
|
||||||
if tp:
|
grouped_components = groupby(components, lambda c: c.type)
|
||||||
components = components.filter(type=tp)
|
grouped_components = [(i[0], list(i[1])) for i in grouped_components]
|
||||||
return components
|
self.grouped_components = grouped_components
|
||||||
|
self.components = components
|
||||||
|
|
||||||
def get_metrics(self, tp=None):
|
def get_metrics(self):
|
||||||
components = self.get_components(tp)
|
metrics = []
|
||||||
total_count = normal_count = high_count = critical_count = offline_count = \
|
for _tp, components in self.grouped_components:
|
||||||
session_active_total = 0
|
normal_count = high_count = critical_count = 0
|
||||||
for component in components:
|
total_count = offline_count = session_online_total = 0
|
||||||
total_count += 1
|
|
||||||
if component.is_alive:
|
for component in components:
|
||||||
|
total_count += 1
|
||||||
|
if not component.is_alive:
|
||||||
|
offline_count += 1
|
||||||
|
continue
|
||||||
if component.is_normal:
|
if component.is_normal:
|
||||||
normal_count += 1
|
normal_count += 1
|
||||||
elif component.is_high:
|
elif component.is_high:
|
||||||
|
@ -165,20 +214,23 @@ class ComponentsMetricsUtil(object):
|
||||||
else:
|
else:
|
||||||
# critical
|
# critical
|
||||||
critical_count += 1
|
critical_count += 1
|
||||||
session_active_total += component.state.get('session_active_count', 0)
|
session_online_total += component.get_online_session_count()
|
||||||
else:
|
metrics.append({
|
||||||
offline_count += 1
|
'total': total_count,
|
||||||
return {
|
'normal': normal_count,
|
||||||
'total': total_count,
|
'high': high_count,
|
||||||
'normal': normal_count,
|
'critical': critical_count,
|
||||||
'high': high_count,
|
'offline': offline_count,
|
||||||
'critical': critical_count,
|
'session_active': session_online_total,
|
||||||
'offline': offline_count,
|
'type': _tp,
|
||||||
'session_active': session_active_total
|
})
|
||||||
}
|
return metrics
|
||||||
|
|
||||||
|
|
||||||
class ComponentsPrometheusMetricsUtil(ComponentsMetricsUtil):
|
class ComponentsPrometheusMetricsUtil(TypedComponentsStatusMetricsUtil):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.metrics = self.get_metrics()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def convert_status_metrics(metrics):
|
def convert_status_metrics(metrics):
|
||||||
|
@ -190,50 +242,74 @@ class ComponentsPrometheusMetricsUtil(ComponentsMetricsUtil):
|
||||||
'offline': metrics['offline']
|
'offline': metrics['offline']
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_prometheus_metrics_text(self):
|
def get_component_status_metrics(self):
|
||||||
prometheus_metrics = list()
|
prometheus_metrics = list()
|
||||||
|
|
||||||
# 各组件状态个数汇总
|
# 各组件状态个数汇总
|
||||||
prometheus_metrics.append('# JumpServer 各组件状态个数汇总')
|
prometheus_metrics.append('# JumpServer 各组件状态个数汇总')
|
||||||
status_metric_text = 'jumpserver_components_status_total{component_type="%s", status="%s"} %s'
|
status_metric_text = 'jumpserver_components_status_total{component_type="%s", status="%s"} %s'
|
||||||
for tp in const.TerminalTypeChoices.types():
|
for metric in self.metrics:
|
||||||
|
tp = metric['type']
|
||||||
prometheus_metrics.append(f'## 组件: {tp}')
|
prometheus_metrics.append(f'## 组件: {tp}')
|
||||||
metrics_tp = self.get_metrics(tp)
|
status_metrics = self.convert_status_metrics(metric)
|
||||||
status_metrics = self.convert_status_metrics(metrics_tp)
|
|
||||||
for status, value in status_metrics.items():
|
for status, value in status_metrics.items():
|
||||||
metric_text = status_metric_text % (tp, status, value)
|
metric_text = status_metric_text % (tp, status, value)
|
||||||
prometheus_metrics.append(metric_text)
|
prometheus_metrics.append(metric_text)
|
||||||
|
return prometheus_metrics
|
||||||
|
|
||||||
prometheus_metrics.append('\n')
|
def get_component_session_metrics(self):
|
||||||
|
prometheus_metrics = list()
|
||||||
# 各组件在线会话数汇总
|
# 各组件在线会话数汇总
|
||||||
prometheus_metrics.append('# JumpServer 各组件在线会话数汇总')
|
prometheus_metrics.append('# JumpServer 各组件在线会话数汇总')
|
||||||
session_active_metric_text = 'jumpserver_components_session_active_total{component_type="%s"} %s'
|
session_active_metric_text = 'jumpserver_components_session_active_total{component_type="%s"} %s'
|
||||||
for tp in const.TerminalTypeChoices.types():
|
|
||||||
|
for metric in self.metrics:
|
||||||
|
tp = metric['type']
|
||||||
prometheus_metrics.append(f'## 组件: {tp}')
|
prometheus_metrics.append(f'## 组件: {tp}')
|
||||||
metrics_tp = self.get_metrics(tp)
|
metric_text = session_active_metric_text % (tp, metric['session_active'])
|
||||||
metric_text = session_active_metric_text % (tp, metrics_tp['session_active'])
|
|
||||||
prometheus_metrics.append(metric_text)
|
prometheus_metrics.append(metric_text)
|
||||||
|
return prometheus_metrics
|
||||||
|
|
||||||
prometheus_metrics.append('\n')
|
def get_component_stat_metrics(self):
|
||||||
|
prometheus_metrics = list()
|
||||||
# 各组件节点指标
|
# 各组件节点指标
|
||||||
prometheus_metrics.append('# JumpServer 各组件一些指标')
|
prometheus_metrics.append('# JumpServer 各组件一些指标')
|
||||||
state_metric_text = 'jumpserver_components_%s{component_type="%s", component="%s"} %s'
|
state_metric_text = 'jumpserver_components_%s{component_type="%s", component="%s"} %s'
|
||||||
states = [
|
stats_key = [
|
||||||
|
'cpu_load', 'memory_used', 'disk_used', 'session_online'
|
||||||
|
]
|
||||||
|
old_stats_key = [
|
||||||
'system_cpu_load_1', 'system_memory_used_percent',
|
'system_cpu_load_1', 'system_memory_used_percent',
|
||||||
'system_disk_used_percent', 'session_active_count'
|
'system_disk_used_percent', 'session_active_count'
|
||||||
]
|
]
|
||||||
for state in states:
|
old_stats_key_mapper = dict(zip(stats_key, old_stats_key))
|
||||||
prometheus_metrics.append(f'## 指标: {state}')
|
|
||||||
components = self.get_components()
|
for stat_key in stats_key:
|
||||||
for component in components:
|
prometheus_metrics.append(f'## 指标: {stat_key}')
|
||||||
|
for component in self.components:
|
||||||
if not component.is_alive:
|
if not component.is_alive:
|
||||||
continue
|
continue
|
||||||
|
component_stat = component.latest_stat
|
||||||
|
if not component_stat:
|
||||||
|
continue
|
||||||
metric_text = state_metric_text % (
|
metric_text = state_metric_text % (
|
||||||
state, component.type, component.name, component.state.get(state)
|
stat_key, component.type, component.name, getattr(component_stat, stat_key)
|
||||||
)
|
)
|
||||||
prometheus_metrics.append(metric_text)
|
prometheus_metrics.append(metric_text)
|
||||||
|
old_stat_key = old_stats_key_mapper.get(stat_key)
|
||||||
|
old_metric_text = state_metric_text % (
|
||||||
|
old_stat_key, component.type, component.name, getattr(component_stat, stat_key)
|
||||||
|
)
|
||||||
|
prometheus_metrics.append(old_metric_text)
|
||||||
|
return prometheus_metrics
|
||||||
|
|
||||||
|
def get_prometheus_metrics_text(self):
|
||||||
|
prometheus_metrics = list()
|
||||||
|
for method in [
|
||||||
|
self.get_component_status_metrics,
|
||||||
|
self.get_component_session_metrics,
|
||||||
|
self.get_component_stat_metrics
|
||||||
|
]:
|
||||||
|
prometheus_metrics.extend(method())
|
||||||
|
prometheus_metrics.append('\n')
|
||||||
prometheus_metrics_text = '\n'.join(prometheus_metrics)
|
prometheus_metrics_text = '\n'.join(prometheus_metrics)
|
||||||
return prometheus_metrics_text
|
return prometheus_metrics_text
|
||||||
|
|
Loading…
Reference in New Issue