!17 webconsole终端基本功能调通

* webconsole终端基本功能调通
This commit is contained in:
剑子仙机 2022-01-14 03:39:38 +00:00
parent 8d5732df9d
commit 8ed2e800f6
13 changed files with 104 additions and 42 deletions

View File

@ -30,9 +30,9 @@ class HostModel(BaseModel):
def __str__(self):
return f'主机:{self.hostname}'
def get_host_client(self, pkey=None, default_env=None):
def get_host_client(self, pkey=None):
pkey = pkey or self.private_key
return SSH(hostname=self.ip, port=self.port, username=self.username, pkey=pkey, default_env=default_env)
return SSH(hostname=self.ip, port=self.port, username=self.username, pkey=pkey)
class HostType(BaseModel):

View File

@ -20,7 +20,6 @@ class BaseConstant:
SERVER_IP = get_ip_address()
BASE_DIR = Path(__file__).resolve().parent.parent
DEBUG = True
DEFAULT_CACHE_REDIS = "redis://127.0.0.1:6379/1"
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.

View File

@ -4,7 +4,6 @@ from threading import Thread
from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer
from django.contrib.auth.models import AnonymousUser
from django_redis import get_redis_connection
from apps.host.models import HostModel
@ -30,7 +29,7 @@ class SshConsumer(WebsocketConsumer):
self.user = self.scope['user']
self.host_id = self.scope['url_route']['kwargs']['id']
if isinstance(self.user, AnonymousUser):
if not self.user:
self.close()
else:
self.accept()
@ -65,12 +64,7 @@ class SshConsumer(WebsocketConsumer):
def receive(self, text_data=None, bytes_data=None):
data = text_data or bytes_data
if data:
data = json.loads(data)
resize = data.get('resize')
if resize and len(resize) == 2:
self.xterm.resize_pty(*resize)
else:
self.xterm.send(data['data'])
self.xterm.send(data)
def websocket_disconnect(self, message):
raise StopConsumer()

View File

@ -43,8 +43,7 @@ class SshJob:
service_post_name = service_name + '_post'
service_post_path = os.path.join(SCRIPTS_DIR, service_post_name)
if os.path.exists(service_post_path):
print(type(result))
command = "%s '%s'" % (service_post_path, json.dumps(result))
command = "%s '%s'" % (service_post_path, result)
output = os.popen(command)
result = ast.literal_eval(output.read())
update_job(instance=self.job, status="Success", result=result, host_by=host_ips)

View File

@ -1,7 +1,6 @@
import logging
from channels.db import database_sync_to_async
from django.contrib.auth.models import AnonymousUser
from apps.accounts.models import User
from rest_framework_jwt.settings import api_settings
@ -17,7 +16,7 @@ def get_user(user_id: int):
try:
user = User.objects.get(id=user_id)
except User.DoesNotExist:
return AnonymousUser()
return None
return user
@ -34,11 +33,11 @@ class AuthMiddleware:
user_id = None
token = scope.get('query_string', None)
if not token:
scope['user'] = AnonymousUser()
scope['user'] = None
if token.decode().startswith('user_id='):
user_id = token.decode().replace('user_id=', '')
if not user_id:
scope['user'] = AnonymousUser()
scope['user'] = None
else:
scope['user'] = await get_user(user_id=user_id)
return await self.application(scope, receive, send, *args, **kwargs)

View File

@ -5,7 +5,6 @@ from .middleware import AuthMiddleware
ws_router = AuthMiddleware(
URLRouter([
path('ws/exec/<str:token>/', ExecConsumer.as_asgi()),
path('ws/ssh/<int:id>/', SshConsumer.as_asgi()),
])
)

View File

@ -8,9 +8,19 @@ https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
"""
import os
from django.urls import path
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
from consumer.consumers import SshConsumer
from consumer.middleware import AuthMiddleware
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sysom.settings')
application = get_asgi_application()
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": AuthMiddleware(
URLRouter([
path('ws/ssh/<int:id>/', SshConsumer.as_asgi()),
])
)
})

View File

@ -48,17 +48,6 @@ DEBUG = constant.DEBUG
if DEBUG:
CORS_ORIGIN_ALLOW_ALL = True
# Redis缓存
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": constant.DEFAULT_CACHE_REDIS,
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
# Mysql数据库
DATABASES = constant.DATABASES
@ -75,16 +64,6 @@ TEMPLATES = [
WSGI_APPLICATION = 'sysom.wsgi.application'
ASGI_APPLICATION = 'sysom.asgi.application'
# channels 配置
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("127.0.0.1", 6379)]
}
}
}
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LANGUAGE_CODE = constant.LANGUAGE_CODE

View File

@ -74,6 +74,11 @@ export default [
name: 'match',
component: './vmcore/match',
},
{
path: '/vmcore/analyse',
name: 'analyse',
component: './vmcore/analyse',
},
],
},
{

View File

@ -67,7 +67,11 @@
"react-dom": "^17.0.0",
"react-helmet-async": "^1.0.4",
"umi": "^3.5.0",
"umi-serve": "^1.9.10"
"umi-serve": "^1.9.10",
"xterm": "^4.16.0",
"xterm-addon-attach": "^0.6.0",
"xterm-addon-fit": "^0.5.0",
"xterm-addon-web-links": "^0.5.0"
},
"devDependencies": {
"@ant-design/pro-cli": "^2.0.2",

View File

@ -63,4 +63,5 @@ export default {
'menu.diagnose': '诊断中心',
'menu.diagnose.io': 'IO延时诊断',
'menu.diagnose.net': '网络诊断',
'menu.vmcore.analyse': '在线分析',
};

View File

@ -0,0 +1,53 @@
import React, { useEffect, useRef } from 'react';
import 'xterm/css/xterm.css';
import { message } from 'antd';
import { PageContainer } from '@ant-design/pro-layout';
import { Terminal } from 'xterm';
import { WebLinksAddon } from 'xterm-addon-web-links';
import { FitAddon } from 'xterm-addon-fit';
import { AttachAddon } from 'xterm-addon-attach';
const WebConsole = (props) => {
const divRef = useRef(null);
let socket = null;
const initTerminal = () => {
const terminal = new Terminal({
cursorBlink: true,
});
socket = new WebSocket(`ws://127.0.0.1:8001/ws/ssh/2/?user_id=1`);
socket.onopen = () => {
terminal.focus();
};
socket.onerror = () => {
message.error('连接出错')
};
const webLinksAddon = new WebLinksAddon();
const fitAddon = new FitAddon();
const attachAddon = new AttachAddon(socket);
terminal.loadAddon(webLinksAddon);
terminal.loadAddon(fitAddon);
terminal.loadAddon(attachAddon);
terminal.open(divRef.current);
fitAddon.fit();
terminal.prompt = () => {
terminal.write('\r\n ');
};
terminal.prompt();
};
useEffect(() => {
if (socket) {
socket.close();
}
initTerminal();
}, []);
return (
<PageContainer>
<div style={{ marginTop: 10, width: 760, height: 500 }} ref={divRef} />;
</PageContainer>
)
};
export default WebConsole

View File

@ -17546,6 +17546,26 @@ xtend@^4.0.0:
resolved "https://registry.npm.taobao.org/xtend/download/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q=
xterm-addon-attach@^0.6.0:
version "0.6.0"
resolved "https://registry.npmmirror.com/xterm-addon-attach/download/xterm-addon-attach-0.6.0.tgz#220c23addd62ab88c9914e2d4c06f7407e44680e"
integrity sha1-Igwjrd1iq4jJkU4tTAb3QH5EaA4=
xterm-addon-fit@^0.5.0:
version "0.5.0"
resolved "https://registry.npmmirror.com/xterm-addon-fit/download/xterm-addon-fit-0.5.0.tgz#2d51b983b786a97dcd6cde805e700c7f913bc596"
integrity sha1-LVG5g7eGqX3NbN6AXnAMf5E7xZY=
xterm-addon-web-links@^0.5.0:
version "0.5.0"
resolved "https://registry.npmmirror.com/xterm-addon-web-links/download/xterm-addon-web-links-0.5.0.tgz#c6869c0032e6709e2437315199d794a3b94a183e"
integrity sha512-egDNFDvuArQ0QKE/ZdP1HMo70Lm8nSOjuIJY0kYjqCCE6yntjyuGzjeoYD+CIQ12gJ6B6thVh8nTApi27qYiag==
xterm@^4.16.0:
version "4.16.0"
resolved "https://registry.npmmirror.com/xterm/download/xterm-4.16.0.tgz#af25223c72917438842121e1bcd1b60ffd7e8476"
integrity sha512-nAbuigL9CYkI075mdfqpnB8cHZNKxENCj1CQ9Tm5gSvWkMtkanmRN2mkHGjSaET1/3+X9BqISFFo7Pd2mXVjiQ==
y18n@^4.0.0:
version "4.0.3"
resolved "https://registry.npm.taobao.org/y18n/download/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"