# -*- coding: utf-8 -*- # import os from django.conf import settings from django.core.files.storage import default_storage from django.utils.translation import ugettext as _ import jms_storage from common.tasks import send_mail_async from common.utils import get_logger, reverse from settings.models import Setting from . import const from .models import ReplayStorage, Session, Command logger = get_logger(__name__) def find_session_replay_local(session): # 新版本和老版本的文件后缀不同 session_path = session.get_rel_replay_path() # 存在外部存储上的路径 local_path = session.get_local_path() local_path_v1 = session.get_local_path(version=1) # 去default storage中查找 for _local_path in (local_path, local_path_v1, session_path): if default_storage.exists(_local_path): url = default_storage.url(_local_path) return _local_path, url return None, None def download_session_replay(session): session_path = session.get_rel_replay_path() # 存在外部存储上的路径 local_path = session.get_local_path() replay_storages = ReplayStorage.objects.all() configs = { storage.name: storage.config for storage in replay_storages if not storage.in_defaults() } if settings.SERVER_REPLAY_STORAGE: configs['SERVER_REPLAY_STORAGE'] = settings.SERVER_REPLAY_STORAGE if not configs: msg = "Not found replay file, and not remote storage set" return None, msg # 保存到storage的路径 target_path = os.path.join(default_storage.base_location, local_path) target_dir = os.path.dirname(target_path) if not os.path.isdir(target_dir): os.makedirs(target_dir, exist_ok=True) storage = jms_storage.get_multi_object_storage(configs) ok, err = storage.download(session_path, target_path) if not ok: msg = "Failed download replay file: {}".format(err) logger.error(msg) return None, msg url = default_storage.url(local_path) return local_path, url def get_session_replay_url(session): local_path, url = find_session_replay_local(session) if local_path is None: local_path, url = download_session_replay(session) return local_path, url def send_command_alert_mail(command): session_obj = Session.objects.get(id=command['session']) subject = _("Insecure Command Alert: [%(name)s->%(login_from)s@%(remote_addr)s] $%(command)s") % { 'name': command['user'], 'login_from': session_obj.get_login_from_display(), 'remote_addr': session_obj.remote_addr, 'command': command['input'] } recipient_list = settings.SECURITY_INSECURE_COMMAND_EMAIL_RECEIVER.split(',') message = _(""" Command: %(command)s
Asset: %(host_name)s (%(host_ip)s)
User: %(user)s
Level: %(risk_level)s
Session: session detail
""") % { 'command': command['input'], 'host_name': command['asset'], 'host_ip': session_obj.asset_obj.ip, 'user': command['user'], 'risk_level': Command.get_risk_level_str(command['risk_level']), 'session_detail_url': reverse('api-terminal:session-detail', kwargs={'pk': command['session']}, external=True, api_to_ui=True), } logger.debug(message) send_mail_async.delay(subject, message, recipient_list, html_message=message) class ComponentsMetricsUtil(object): def __init__(self, component_type=None): self.type = component_type self.components = [] self.initial_components() def initial_components(self): from .models import Terminal terminals = Terminal.objects.all().order_by('type') if self.type: terminals = terminals.filter(type=self.type) self.components = list(terminals) def get_metrics(self): total_count = normal_count = high_count = critical_count = session_active_total = 0 for component in self.components: total_count += 1 if not component.is_alive: critical_count += 1 continue session_active_total += component.state.get('session_active_count', 0) if component.is_normal: normal_count += 1 elif component.is_high: high_count += 1 else: critical_count += 1 metrics = { 'total': total_count, 'normal': normal_count, 'high': high_count, 'critical': critical_count, 'session_active': session_active_total } return metrics class ComponentsPrometheusMetricsUtil(ComponentsMetricsUtil): @staticmethod def get_status_metrics(metrics): return { 'any': metrics['total'], 'normal': metrics['normal'], 'high': metrics['high'], 'critical': metrics['critical'] } def get_prometheus_metrics_text(self): prometheus_metrics = [] prometheus_metrics.append('# JumpServer 各组件状态个数汇总') base_status_metric_text = 'jumpserver_components_status_total{component_type="%s", status="%s"} %s' for component in self.components: component_type = component.type base_metrics = self.get_metrics() prometheus_metrics.append(f'## 组件: {component_type}') status_metrics = self.get_status_metrics(base_metrics) for status, value in status_metrics.items(): metric_text = base_status_metric_text % (component_type, status, value) prometheus_metrics.append(metric_text) prometheus_metrics.append('\n') prometheus_metrics.append('# JumpServer 各组件在线会话数汇总') base_session_active_metric_text = 'jumpserver_components_session_active_total{component_type="%s"} %s' for component in self.components: component_type = component.type prometheus_metrics.append(f'## 组件: {component_type}') base_metrics = self.get_metrics() metric_text = base_session_active_metric_text % ( component_type, base_metrics['session_active'] ) prometheus_metrics.append(metric_text) prometheus_metrics.append('\n') prometheus_metrics.append('# JumpServer 各组件节点一些指标') base_system_state_metric_text = 'jumpserver_components_%s{component_type="%s", component="%s"} %s' system_states_name = [ 'system_cpu_load_1', 'system_memory_used_percent', 'system_disk_used_percent', 'session_active_count' ] for system_state_name in system_states_name: prometheus_metrics.append(f'## 指标: {system_state_name}') for component in self.components: if not component.is_alive: continue component_type = component.type metric_text = base_system_state_metric_text % ( system_state_name, component_type, component.name, component.state.get(system_state_name) ) prometheus_metrics.append(metric_text) prometheus_metrics_text = '\n'.join(prometheus_metrics) return prometheus_metrics_text