perf: 命令存储ES可根据日期动态建立索引 (#8180)

* perf: 命令存储ES可根据日期动态建立索引

* perf: 优化合并字段

* feat: 修改逻辑
pull/8207/head
jiangweidong 2022-05-09 16:37:31 +08:00 committed by GitHub
parent ab737ae09b
commit 64eda5f28b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 98 additions and 27 deletions

View File

@ -32,6 +32,10 @@ def local_now_display(fmt='%Y-%m-%d %H:%M:%S'):
return local_now().strftime(fmt) return local_now().strftime(fmt)
def local_now_date_display(fmt='%Y-%m-%d'):
return local_now().strftime(fmt)
_rest_dt_field = DateTimeField() _rest_dt_field = DateTimeField()
dt_parser = _rest_dt_field.to_internal_value dt_parser = _rest_dt_field.to_internal_value
dt_formatter = _rest_dt_field.to_representation dt_formatter = _rest_dt_field.to_representation

View File

@ -30,7 +30,7 @@ msgstr "Acls"
#: orgs/models.py:65 perms/models/base.py:83 rbac/models/role.py:29 #: orgs/models.py:65 perms/models/base.py:83 rbac/models/role.py:29
#: settings/models.py:29 settings/serializers/sms.py:6 #: settings/models.py:29 settings/serializers/sms.py:6
#: terminal/models/endpoint.py:10 terminal/models/endpoint.py:58 #: terminal/models/endpoint.py:10 terminal/models/endpoint.py:58
#: terminal/models/storage.py:23 terminal/models/task.py:16 #: terminal/models/storage.py:24 terminal/models/task.py:16
#: terminal/models/terminal.py:100 users/forms/profile.py:32 #: terminal/models/terminal.py:100 users/forms/profile.py:32
#: users/models/group.py:15 users/models/user.py:661 #: users/models/group.py:15 users/models/user.py:661
#: xpack/plugins/cloud/models.py:28 #: xpack/plugins/cloud/models.py:28
@ -62,7 +62,7 @@ msgstr "アクティブ"
#: assets/models/label.py:23 ops/models/adhoc.py:38 orgs/models.py:68 #: assets/models/label.py:23 ops/models/adhoc.py:38 orgs/models.py:68
#: perms/models/base.py:93 rbac/models/role.py:37 settings/models.py:34 #: perms/models/base.py:93 rbac/models/role.py:37 settings/models.py:34
#: terminal/models/endpoint.py:20 terminal/models/endpoint.py:68 #: terminal/models/endpoint.py:20 terminal/models/endpoint.py:68
#: terminal/models/storage.py:26 terminal/models/terminal.py:114 #: terminal/models/storage.py:27 terminal/models/terminal.py:114
#: tickets/models/comment.py:24 tickets/models/ticket.py:154 #: tickets/models/comment.py:24 tickets/models/ticket.py:154
#: users/models/group.py:16 users/models/user.py:698 #: users/models/group.py:16 users/models/user.py:698
#: xpack/plugins/change_auth_plan/models/base.py:44 #: xpack/plugins/change_auth_plan/models/base.py:44
@ -305,7 +305,7 @@ msgstr "カテゴリ"
#: assets/models/cmd_filter.py:82 assets/models/user.py:246 #: assets/models/cmd_filter.py:82 assets/models/user.py:246
#: perms/models/application_permission.py:24 #: perms/models/application_permission.py:24
#: perms/serializers/application/user_permission.py:34 #: perms/serializers/application/user_permission.py:34
#: terminal/models/storage.py:55 terminal/models/storage.py:119 #: terminal/models/storage.py:56 terminal/models/storage.py:136
#: tickets/models/flow.py:56 tickets/models/ticket.py:131 #: tickets/models/flow.py:56 tickets/models/ticket.py:131
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:29 #: tickets/serializers/ticket/meta/ticket_type/apply_application.py:29
#: xpack/plugins/change_auth_plan/models/app.py:28 #: xpack/plugins/change_auth_plan/models/app.py:28
@ -4639,7 +4639,7 @@ msgstr "オンラインセッションを持つ"
msgid "Terminals" msgid "Terminals"
msgstr "ターミナル管理" msgstr "ターミナル管理"
#: terminal/backends/command/es.py:26 #: terminal/backends/command/es.py:28
msgid "Invalid elasticsearch config" msgid "Invalid elasticsearch config"
msgstr "無効なElasticsearch構成" msgstr "無効なElasticsearch構成"
@ -4883,15 +4883,15 @@ msgstr "スレッド"
msgid "Boot Time" msgid "Boot Time"
msgstr "ブート時間" msgstr "ブート時間"
#: terminal/models/storage.py:25 #: terminal/models/storage.py:26
msgid "Default storage" msgid "Default storage"
msgstr "デフォルトのストレージ" msgstr "デフォルトのストレージ"
#: terminal/models/storage.py:113 terminal/models/terminal.py:108 #: terminal/models/storage.py:130 terminal/models/terminal.py:108
msgid "Command storage" msgid "Command storage"
msgstr "コマンドストレージ" msgstr "コマンドストレージ"
#: terminal/models/storage.py:173 terminal/models/terminal.py:109 #: terminal/models/storage.py:190 terminal/models/terminal.py:109
msgid "Replay storage" msgid "Replay storage"
msgstr "再生ストレージ" msgstr "再生ストレージ"
@ -5008,14 +5008,26 @@ msgid "Port invalid"
msgstr "ポートが無効" msgstr "ポートが無効"
#: terminal/serializers/storage.py:159 #: terminal/serializers/storage.py:159
msgid "Index by date"
msgstr "日付による索引付け"
#: terminal/serializers/storage.py:160
msgid "Whether to create an index by date"
msgstr "現在の日付に基づいてインデックスを動的に作成するかどうか"
#: terminal/serializers/storage.py:163
msgid "Index prefix"
msgstr "インデックス接頭辞"
#: terminal/serializers/storage.py:166
msgid "Index" msgid "Index"
msgstr "インデックス" msgstr "インデックス"
#: terminal/serializers/storage.py:161 #: terminal/serializers/storage.py:168
msgid "Doc type" msgid "Doc type"
msgstr "Docタイプ" msgstr "Docタイプ"
#: terminal/serializers/storage.py:163 #: terminal/serializers/storage.py:170
msgid "Ignore Certificate Verification" msgid "Ignore Certificate Verification"
msgstr "証明書の検証を無視する" msgstr "証明書の検証を無視する"

View File

@ -29,7 +29,7 @@ msgstr "访问控制"
#: orgs/models.py:65 perms/models/base.py:83 rbac/models/role.py:29 #: orgs/models.py:65 perms/models/base.py:83 rbac/models/role.py:29
#: settings/models.py:29 settings/serializers/sms.py:6 #: settings/models.py:29 settings/serializers/sms.py:6
#: terminal/models/endpoint.py:10 terminal/models/endpoint.py:58 #: terminal/models/endpoint.py:10 terminal/models/endpoint.py:58
#: terminal/models/storage.py:23 terminal/models/task.py:16 #: terminal/models/storage.py:24 terminal/models/task.py:16
#: terminal/models/terminal.py:100 users/forms/profile.py:32 #: terminal/models/terminal.py:100 users/forms/profile.py:32
#: users/models/group.py:15 users/models/user.py:661 #: users/models/group.py:15 users/models/user.py:661
#: xpack/plugins/cloud/models.py:28 #: xpack/plugins/cloud/models.py:28
@ -61,7 +61,7 @@ msgstr "激活中"
#: assets/models/label.py:23 ops/models/adhoc.py:38 orgs/models.py:68 #: assets/models/label.py:23 ops/models/adhoc.py:38 orgs/models.py:68
#: perms/models/base.py:93 rbac/models/role.py:37 settings/models.py:34 #: perms/models/base.py:93 rbac/models/role.py:37 settings/models.py:34
#: terminal/models/endpoint.py:20 terminal/models/endpoint.py:68 #: terminal/models/endpoint.py:20 terminal/models/endpoint.py:68
#: terminal/models/storage.py:26 terminal/models/terminal.py:114 #: terminal/models/storage.py:27 terminal/models/terminal.py:114
#: tickets/models/comment.py:24 tickets/models/ticket.py:154 #: tickets/models/comment.py:24 tickets/models/ticket.py:154
#: users/models/group.py:16 users/models/user.py:698 #: users/models/group.py:16 users/models/user.py:698
#: xpack/plugins/change_auth_plan/models/base.py:44 #: xpack/plugins/change_auth_plan/models/base.py:44
@ -300,7 +300,7 @@ msgstr "类别"
#: assets/models/cmd_filter.py:82 assets/models/user.py:246 #: assets/models/cmd_filter.py:82 assets/models/user.py:246
#: perms/models/application_permission.py:24 #: perms/models/application_permission.py:24
#: perms/serializers/application/user_permission.py:34 #: perms/serializers/application/user_permission.py:34
#: terminal/models/storage.py:55 terminal/models/storage.py:119 #: terminal/models/storage.py:56 terminal/models/storage.py:136
#: tickets/models/flow.py:56 tickets/models/ticket.py:131 #: tickets/models/flow.py:56 tickets/models/ticket.py:131
#: tickets/serializers/ticket/meta/ticket_type/apply_application.py:29 #: tickets/serializers/ticket/meta/ticket_type/apply_application.py:29
#: xpack/plugins/change_auth_plan/models/app.py:28 #: xpack/plugins/change_auth_plan/models/app.py:28
@ -4565,7 +4565,7 @@ msgstr "有在线会话"
msgid "Terminals" msgid "Terminals"
msgstr "终端管理" msgstr "终端管理"
#: terminal/backends/command/es.py:26 #: terminal/backends/command/es.py:28
msgid "Invalid elasticsearch config" msgid "Invalid elasticsearch config"
msgstr "无效的 Elasticsearch 配置" msgstr "无效的 Elasticsearch 配置"
@ -4809,15 +4809,15 @@ msgstr "线程数"
msgid "Boot Time" msgid "Boot Time"
msgstr "运行时间" msgstr "运行时间"
#: terminal/models/storage.py:25 #: terminal/models/storage.py:26
msgid "Default storage" msgid "Default storage"
msgstr "默认存储" msgstr "默认存储"
#: terminal/models/storage.py:113 terminal/models/terminal.py:108 #: terminal/models/storage.py:130 terminal/models/terminal.py:108
msgid "Command storage" msgid "Command storage"
msgstr "命令存储" msgstr "命令存储"
#: terminal/models/storage.py:173 terminal/models/terminal.py:109 #: terminal/models/storage.py:190 terminal/models/terminal.py:109
msgid "Replay storage" msgid "Replay storage"
msgstr "录像存储" msgstr "录像存储"
@ -4934,14 +4934,26 @@ msgid "Port invalid"
msgstr "端口无效" msgstr "端口无效"
#: terminal/serializers/storage.py:159 #: terminal/serializers/storage.py:159
msgid "Index by date"
msgstr "按日期建索引"
#: terminal/serializers/storage.py:160
msgid "Whether to create an index by date"
msgstr "是否根据日期动态建立索引"
#: terminal/serializers/storage.py:163
msgid "Index prefix"
msgstr "索引前缀"
#: terminal/serializers/storage.py:166
msgid "Index" msgid "Index"
msgstr "索引" msgstr "索引"
#: terminal/serializers/storage.py:161 #: terminal/serializers/storage.py:168
msgid "Doc type" msgid "Doc type"
msgstr "文档类型" msgstr "文档类型"
#: terminal/serializers/storage.py:163 #: terminal/serializers/storage.py:170
msgid "Ignore Certificate Verification" msgid "Ignore Certificate Verification"
msgstr "忽略证书认证" msgstr "忽略证书认证"

View File

@ -1,11 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
import pytz
import inspect
from datetime import datetime from datetime import datetime
from functools import reduce, partial from functools import reduce, partial
from itertools import groupby from itertools import groupby
import pytz
from uuid import UUID from uuid import UUID
import inspect
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.db.models import QuerySet as DJQuerySet from django.db.models import QuerySet as DJQuerySet
@ -15,6 +16,7 @@ from elasticsearch.exceptions import RequestError, NotFoundError
from common.utils.common import lazyproperty from common.utils.common import lazyproperty
from common.utils import get_logger from common.utils import get_logger
from common.utils.timezone import local_now_date_display, utc_now
from common.exceptions import JMSException from common.exceptions import JMSException
from .models import AbstractSessionCommand from .models import AbstractSessionCommand
@ -28,12 +30,13 @@ class InvalidElasticsearch(JMSException):
class CommandStore(object): class CommandStore(object):
def __init__(self, config): def __init__(self, config):
hosts = config.get("HOSTS")
kwargs = config.get("OTHER", {})
self.index = config.get("INDEX") or 'jumpserver'
self.doc_type = config.get("DOC_TYPE") or '_doc' self.doc_type = config.get("DOC_TYPE") or '_doc'
self.index_prefix = config.get('INDEX') or 'jumpserver'
self.is_index_by_date = bool(config.get('INDEX_BY_DATE'))
self.exact_fields = {} self.exact_fields = {}
self.match_fields = {} self.match_fields = {}
hosts = config.get("HOSTS")
kwargs = config.get("OTHER", {})
ignore_verify_certs = kwargs.pop('IGNORE_VERIFY_CERTS', False) ignore_verify_certs = kwargs.pop('IGNORE_VERIFY_CERTS', False)
if ignore_verify_certs: if ignore_verify_certs:
@ -50,6 +53,17 @@ class CommandStore(object):
else: else:
self.match_fields.update(may_exact_fields) self.match_fields.update(may_exact_fields)
self.init_index(config)
def init_index(self, config):
if self.is_index_by_date:
date = local_now_date_display()
self.index = '%s-%s' % (self.index_prefix, date)
self.query_index = '%s-alias' % self.index_prefix
else:
self.index = config.get("INDEX") or 'jumpserver'
self.query_index = config.get("INDEX") or 'jumpserver'
def is_new_index_type(self): def is_new_index_type(self):
if not self.ping(timeout=3): if not self.ping(timeout=3):
return False return False
@ -101,10 +115,17 @@ class CommandStore(object):
else: else:
mappings = {'mappings': {'properties': properties}} mappings = {'mappings': {'properties': properties}}
if self.is_index_by_date:
mappings['aliases'] = {
self.query_index: {}
}
try: try:
self.es.indices.create(self.index, body=mappings) self.es.indices.create(self.index, body=mappings)
return return
except RequestError as e: except RequestError as e:
if e.error == 'resource_already_exists_exception':
logger.warning(e)
else:
logger.exception(e) logger.exception(e)
@staticmethod @staticmethod
@ -141,7 +162,7 @@ class CommandStore(object):
body = self.get_query_body(**query) body = self.get_query_body(**query)
data = self.es.search( data = self.es.search(
index=self.index, doc_type=self.doc_type, body=body, from_=from_, size=size, index=self.query_index, doc_type=self.doc_type, body=body, from_=from_, size=size,
sort=sort sort=sort
) )
source_data = [] source_data = []
@ -154,7 +175,7 @@ class CommandStore(object):
def count(self, **query): def count(self, **query):
body = self.get_query_body(**query) body = self.get_query_body(**query)
data = self.es.count(index=self.index, doc_type=self.doc_type, body=body) data = self.es.count(index=self.query_index, doc_type=self.doc_type, body=body)
return data["count"] return data["count"]
def __getattr__(self, item): def __getattr__(self, item):

View File

@ -1,6 +1,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import os import os
from importlib import import_module from importlib import import_module
import jms_storage import jms_storage
@ -10,6 +11,7 @@ from django.conf import settings
from common.mixins import CommonModelMixin from common.mixins import CommonModelMixin
from common.utils import get_logger from common.utils import get_logger
from common.db.fields import EncryptJsonDictTextField from common.db.fields import EncryptJsonDictTextField
from common.utils.timezone import local_now_date_display
from terminal.backends import TYPE_ENGINE_MAPPING from terminal.backends import TYPE_ENGINE_MAPPING
from .terminal import Terminal from .terminal import Terminal
from .command import Command from .command import Command
@ -63,6 +65,10 @@ class CommandStorage(CommonStorageModelMixin, CommonModelMixin):
def type_server(self): def type_server(self):
return self.type == const.CommandStorageTypeChoices.server.value return self.type == const.CommandStorageTypeChoices.server.value
@property
def type_es(self):
return self.type == const.CommandStorageTypeChoices.es.value
@property @property
def type_null_or_server(self): def type_null_or_server(self):
return self.type_null or self.type_server return self.type_null or self.type_server
@ -73,6 +79,18 @@ class CommandStorage(CommonStorageModelMixin, CommonModelMixin):
config.update({'TYPE': self.type}) config.update({'TYPE': self.type})
return config return config
@property
def valid_config(self):
config = self.config
if self.type_es and config.get('INDEX_BY_DATE'):
engine_mod = import_module(TYPE_ENGINE_MAPPING[self.type])
store = engine_mod.CommandStore(config)
store._ensure_index_exists()
index_prefix = config.get('INDEX') or 'jumpserver'
date = local_now_date_display()
config['INDEX'] = '%s-%s' % (index_prefix, date)
return config
def is_valid(self): def is_valid(self):
if self.type_null_or_server: if self.type_null_or_server:
return True return True

View File

@ -68,7 +68,7 @@ class StorageMixin:
def get_command_storage_config(self): def get_command_storage_config(self):
s = self.get_command_storage() s = self.get_command_storage()
if s: if s:
config = s.config config = s.valid_config
else: else:
config = settings.DEFAULT_TERMINAL_COMMAND_STORAGE config = settings.DEFAULT_TERMINAL_COMMAND_STORAGE
return config return config

View File

@ -155,6 +155,10 @@ class CommandStorageTypeESSerializer(serializers.Serializer):
child=serializers.CharField(validators=[command_storage_es_host_format_validator]), child=serializers.CharField(validators=[command_storage_es_host_format_validator]),
label=_('Hosts'), help_text=_(hosts_help_text), allow_null=True label=_('Hosts'), help_text=_(hosts_help_text), allow_null=True
) )
INDEX_BY_DATE = serializers.BooleanField(
default=False, label=_('Index by date'),
help_text=_('Whether to create an index by date')
)
INDEX = serializers.CharField( INDEX = serializers.CharField(
max_length=1024, default='jumpserver', label=_('Index'), allow_null=True max_length=1024, default='jumpserver', label=_('Index'), allow_null=True
) )