mirror of https://github.com/jumpserver/jumpserver
parent
d4037998c8
commit
e3648d11b1
|
@ -273,6 +273,7 @@ class Config(dict):
|
||||||
'SESSION_COOKIE_SECURE': False,
|
'SESSION_COOKIE_SECURE': False,
|
||||||
'CSRF_COOKIE_SECURE': False,
|
'CSRF_COOKIE_SECURE': False,
|
||||||
'REFERER_CHECK_ENABLED': False,
|
'REFERER_CHECK_ENABLED': False,
|
||||||
|
'SERVER_REPLAY_STORAGE': {}
|
||||||
}
|
}
|
||||||
|
|
||||||
def compatible_auth_openid_of_key(self):
|
def compatible_auth_openid_of_key(self):
|
||||||
|
|
|
@ -12,6 +12,17 @@ DEFAULT_TERMINAL_COMMAND_STORAGE = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
TERMINAL_COMMAND_STORAGE = DYNAMIC.TERMINAL_COMMAND_STORAGE or {}
|
TERMINAL_COMMAND_STORAGE = DYNAMIC.TERMINAL_COMMAND_STORAGE or {}
|
||||||
|
|
||||||
|
# Server 类型的录像存储
|
||||||
|
SERVER_REPLAY_STORAGE = CONFIG.SERVER_REPLAY_STORAGE
|
||||||
|
# SERVER_REPLAY_STORAGE = {
|
||||||
|
# 'TYPE': 's3',
|
||||||
|
# 'BUCKET': '',
|
||||||
|
# 'ACCESS_KEY': '',
|
||||||
|
# 'SECRET_KEY': '',
|
||||||
|
# 'ENDPOINT': ''
|
||||||
|
# }
|
||||||
|
|
||||||
DEFAULT_TERMINAL_REPLAY_STORAGE = {
|
DEFAULT_TERMINAL_REPLAY_STORAGE = {
|
||||||
"default": {
|
"default": {
|
||||||
"TYPE": "server",
|
"TYPE": "server",
|
||||||
|
|
|
@ -125,7 +125,7 @@ class SessionReplayViewSet(AsyncApiMixin, viewsets.ViewSet):
|
||||||
|
|
||||||
if serializer.is_valid():
|
if serializer.is_valid():
|
||||||
file = serializer.validated_data['file']
|
file = serializer.validated_data['file']
|
||||||
name, err = session.save_to_storage(file)
|
name, err = session.save_replay_to_storage(file)
|
||||||
if not name:
|
if not name:
|
||||||
msg = "Failed save replay `{}`: {}".format(session_id, err)
|
msg = "Failed save replay `{}`: {}".format(session_id, err)
|
||||||
logger.error(msg)
|
logger.error(msg)
|
||||||
|
@ -155,6 +155,7 @@ class SessionReplayViewSet(AsyncApiMixin, viewsets.ViewSet):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def is_need_async(self):
|
def is_need_async(self):
|
||||||
|
return False
|
||||||
if self.action != 'retrieve':
|
if self.action != 'retrieve':
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.utils.functional import LazyObject
|
||||||
|
|
||||||
from .command.serializers import SessionCommandSerializer
|
from .command.serializers import SessionCommandSerializer
|
||||||
from ..const import COMMAND_STORAGE_TYPE_SERVER
|
from ..const import COMMAND_STORAGE_TYPE_SERVER
|
||||||
|
|
||||||
|
@ -17,6 +19,13 @@ def get_command_storage():
|
||||||
return storage
|
return storage
|
||||||
|
|
||||||
|
|
||||||
|
def get_server_replay_storage():
|
||||||
|
from jms_storage import get_object_storage
|
||||||
|
config = settings.SERVER_REPLAY_STORAGE
|
||||||
|
storage = get_object_storage(config)
|
||||||
|
return storage
|
||||||
|
|
||||||
|
|
||||||
def get_terminal_command_storages():
|
def get_terminal_command_storages():
|
||||||
from ..models import CommandStorage
|
from ..models import CommandStorage
|
||||||
storage_list = {}
|
storage_list = {}
|
||||||
|
@ -40,3 +49,15 @@ def get_multi_command_storage():
|
||||||
return storage
|
return storage
|
||||||
|
|
||||||
|
|
||||||
|
class ServerReplayStorage(LazyObject):
|
||||||
|
def _setup(self):
|
||||||
|
self._wrapped = get_server_replay_storage()
|
||||||
|
|
||||||
|
|
||||||
|
class ServerCommandStorage(LazyObject):
|
||||||
|
def _setup(self):
|
||||||
|
self._wrapped = get_command_storage()
|
||||||
|
|
||||||
|
|
||||||
|
server_command_storage = ServerCommandStorage()
|
||||||
|
server_replay_storage = ServerReplayStorage()
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
"""
|
||||||
|
Replay 的 backend 已移动到 jms_storage 模块中
|
||||||
|
"""
|
|
@ -253,14 +253,18 @@ class Session(OrgModelMixin):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def save_to_storage(self, f):
|
def save_replay_to_storage(self, f):
|
||||||
local_path = self.get_local_path()
|
local_path = self.get_local_path()
|
||||||
try:
|
try:
|
||||||
name = default_storage.save(local_path, f)
|
name = default_storage.save(local_path, f)
|
||||||
return name, None
|
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
return None, e
|
return None, e
|
||||||
|
|
||||||
|
if settings.SERVER_REPLAY_STORAGE:
|
||||||
|
from .tasks import upload_session_replay_to_external_storage
|
||||||
|
upload_session_replay_to_external_storage.delay(str(self.id))
|
||||||
|
return name, None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_sessions_active(cls, sessions_id):
|
def set_sessions_active(cls, sessions_id):
|
||||||
data = {cls.ACTIVE_CACHE_KEY_PREFIX.format(i): i for i in sessions_id}
|
data = {cls.ACTIVE_CACHE_KEY_PREFIX.format(i): i for i in sessions_id}
|
||||||
|
@ -456,4 +460,3 @@ class ReplayStorage(CommonModelMixin):
|
||||||
|
|
||||||
def can_delete(self):
|
def can_delete(self):
|
||||||
return not self.in_defaults()
|
return not self.in_defaults()
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,12 @@ from django.utils import timezone
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
from ops.celery.decorator import (
|
from ops.celery.decorator import (
|
||||||
register_as_period_task, after_app_ready_start, after_app_shutdown_clean_periodic
|
register_as_period_task, after_app_ready_start, after_app_shutdown_clean_periodic
|
||||||
)
|
)
|
||||||
from .models import Status, Session, Command
|
from .models import Status, Session, Command
|
||||||
|
from .backends import server_replay_storage
|
||||||
|
from .utils import find_session_replay_local
|
||||||
|
|
||||||
|
|
||||||
CACHE_REFRESH_INTERVAL = 10
|
CACHE_REFRESH_INTERVAL = 10
|
||||||
|
@ -68,3 +69,26 @@ def clean_expired_session_period():
|
||||||
# 删除session记录
|
# 删除session记录
|
||||||
session.delete()
|
session.delete()
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task
|
||||||
|
def upload_session_replay_to_external_storage(session_id):
|
||||||
|
logger.info(f'Start upload session to external storage: {session_id}')
|
||||||
|
session = Session.objects.filter(id=session_id).first()
|
||||||
|
if not session:
|
||||||
|
logger.error(f'Session db item not found: {session_id}')
|
||||||
|
return
|
||||||
|
local_path, foobar = find_session_replay_local(session)
|
||||||
|
if not local_path:
|
||||||
|
logger.error(f'Session replay not found, may be upload error: {local_path}')
|
||||||
|
return
|
||||||
|
abs_path = default_storage.path(local_path)
|
||||||
|
remote_path = session.get_rel_replay_path()
|
||||||
|
ok, err = server_replay_storage.upload(abs_path, remote_path)
|
||||||
|
if not ok:
|
||||||
|
logger.error(f'Session replay upload to external error: {err}')
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
default_storage.delete(local_path)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
|
@ -2,43 +2,18 @@
|
||||||
#
|
#
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from django.core.cache import cache
|
from django.conf import settings
|
||||||
from django.core.files.storage import default_storage
|
from django.core.files.storage import default_storage
|
||||||
import jms_storage
|
import jms_storage
|
||||||
|
|
||||||
from assets.models import Asset, SystemUser
|
|
||||||
from users.models import User
|
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from .const import USERS_CACHE_KEY, ASSETS_CACHE_KEY, SYSTEM_USER_CACHE_KEY
|
|
||||||
|
from .backends import server_replay_storage
|
||||||
from .models import ReplayStorage
|
from .models import ReplayStorage
|
||||||
|
|
||||||
logger = get_logger(__name__)
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def get_session_asset_list():
|
|
||||||
return Asset.objects.values_list('hostname', flat=True)
|
|
||||||
|
|
||||||
|
|
||||||
def get_session_user_list():
|
|
||||||
return User.objects.exclude(role=User.ROLE.APP).values_list('username', flat=True)
|
|
||||||
|
|
||||||
|
|
||||||
def get_session_system_user_list():
|
|
||||||
return SystemUser.objects.values_list('username', flat=True)
|
|
||||||
|
|
||||||
|
|
||||||
def get_user_list_from_cache():
|
|
||||||
return cache.get(USERS_CACHE_KEY)
|
|
||||||
|
|
||||||
|
|
||||||
def get_asset_list_from_cache():
|
|
||||||
return cache.get(ASSETS_CACHE_KEY)
|
|
||||||
|
|
||||||
|
|
||||||
def get_system_user_list_from_cache():
|
|
||||||
return cache.get(SYSTEM_USER_CACHE_KEY)
|
|
||||||
|
|
||||||
|
|
||||||
def find_session_replay_local(session):
|
def find_session_replay_local(session):
|
||||||
# 新版本和老版本的文件后缀不同
|
# 新版本和老版本的文件后缀不同
|
||||||
session_path = session.get_rel_replay_path() # 存在外部存储上的路径
|
session_path = session.get_rel_replay_path() # 存在外部存储上的路径
|
||||||
|
@ -62,6 +37,8 @@ def download_session_replay(session):
|
||||||
for storage in replay_storages
|
for storage in replay_storages
|
||||||
if not storage.in_defaults()
|
if not storage.in_defaults()
|
||||||
}
|
}
|
||||||
|
if settings.SERVER_REPLAY_STORAGE:
|
||||||
|
configs['SERVER_REPLAY_STORAGE'] = settings.SERVER_REPLAY_STORAGE
|
||||||
if not configs:
|
if not configs:
|
||||||
msg = "Not found replay file, and not remote storage set"
|
msg = "Not found replay file, and not remote storage set"
|
||||||
return None, msg
|
return None, msg
|
||||||
|
|
Loading…
Reference in New Issue