!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): def __str__(self):
return f'主机:{self.hostname}' 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 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): class HostType(BaseModel):

View File

@ -20,7 +20,6 @@ class BaseConstant:
SERVER_IP = get_ip_address() SERVER_IP = get_ip_address()
BASE_DIR = Path(__file__).resolve().parent.parent BASE_DIR = Path(__file__).resolve().parent.parent
DEBUG = True DEBUG = True
DEFAULT_CACHE_REDIS = "redis://127.0.0.1:6379/1"
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. '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.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer from channels.exceptions import StopConsumer
from django.contrib.auth.models import AnonymousUser
from django_redis import get_redis_connection from django_redis import get_redis_connection
from apps.host.models import HostModel from apps.host.models import HostModel
@ -30,7 +29,7 @@ class SshConsumer(WebsocketConsumer):
self.user = self.scope['user'] self.user = self.scope['user']
self.host_id = self.scope['url_route']['kwargs']['id'] self.host_id = self.scope['url_route']['kwargs']['id']
if isinstance(self.user, AnonymousUser): if not self.user:
self.close() self.close()
else: else:
self.accept() self.accept()
@ -65,12 +64,7 @@ class SshConsumer(WebsocketConsumer):
def receive(self, text_data=None, bytes_data=None): def receive(self, text_data=None, bytes_data=None):
data = text_data or bytes_data data = text_data or bytes_data
if data: if data:
data = json.loads(data) self.xterm.send(data)
resize = data.get('resize')
if resize and len(resize) == 2:
self.xterm.resize_pty(*resize)
else:
self.xterm.send(data['data'])
def websocket_disconnect(self, message): def websocket_disconnect(self, message):
raise StopConsumer() raise StopConsumer()

View File

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

View File

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

View File

@ -5,7 +5,6 @@ from .middleware import AuthMiddleware
ws_router = AuthMiddleware( ws_router = AuthMiddleware(
URLRouter([ URLRouter([
path('ws/exec/<str:token>/', ExecConsumer.as_asgi()),
path('ws/ssh/<int:id>/', SshConsumer.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 import os
from django.urls import path
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application 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') 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: if DEBUG:
CORS_ORIGIN_ALLOW_ALL = True 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数据库 # Mysql数据库
DATABASES = constant.DATABASES DATABASES = constant.DATABASES
@ -75,16 +64,6 @@ TEMPLATES = [
WSGI_APPLICATION = 'sysom.wsgi.application' WSGI_APPLICATION = 'sysom.wsgi.application'
ASGI_APPLICATION = 'sysom.asgi.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' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LANGUAGE_CODE = constant.LANGUAGE_CODE LANGUAGE_CODE = constant.LANGUAGE_CODE

View File

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

View File

@ -67,7 +67,11 @@
"react-dom": "^17.0.0", "react-dom": "^17.0.0",
"react-helmet-async": "^1.0.4", "react-helmet-async": "^1.0.4",
"umi": "^3.5.0", "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": { "devDependencies": {
"@ant-design/pro-cli": "^2.0.2", "@ant-design/pro-cli": "^2.0.2",

View File

@ -63,4 +63,5 @@ export default {
'menu.diagnose': '诊断中心', 'menu.diagnose': '诊断中心',
'menu.diagnose.io': 'IO延时诊断', 'menu.diagnose.io': 'IO延时诊断',
'menu.diagnose.net': '网络诊断', '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" resolved "https://registry.npm.taobao.org/xtend/download/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha1-u3J3n1+kZRhrH0OPZ0+jR/2121Q= 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: y18n@^4.0.0:
version "4.0.3" version "4.0.3"
resolved "https://registry.npm.taobao.org/y18n/download/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" resolved "https://registry.npm.taobao.org/y18n/download/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"