Compare commits
3 Commits
915992d8de
...
fadb4a4ee3
Author | SHA1 | Date |
---|---|---|
wang | fadb4a4ee3 | |
wang | cb10f62c35 | |
wang | fba2428e30 |
|
@ -1,4 +1,2 @@
|
|||
.idea
|
||||
node_modules
|
||||
__pycache__
|
||||
public
|
||||
node_modules
|
|
@ -38,6 +38,7 @@
|
|||
"react-scripts": "^5.0.1",
|
||||
"recharts": "^2.12.7",
|
||||
"redux": "^5.0.1",
|
||||
"socket.io-client": "^4.7.5",
|
||||
"stream": "^0.0.2",
|
||||
"swr": "^2.2.5",
|
||||
"tailwindcss": "^3.4.3",
|
||||
|
@ -4009,6 +4010,11 @@
|
|||
"@sinonjs/commons": "^1.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@socket.io/component-emitter": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="
|
||||
},
|
||||
"node_modules/@surma/rollup-plugin-off-main-thread": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmmirror.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
|
||||
|
@ -5441,7 +5447,7 @@
|
|||
},
|
||||
"node_modules/@xterm/xterm": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmmirror.com/@xterm/xterm/-/xterm-5.5.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz",
|
||||
"integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A=="
|
||||
},
|
||||
"node_modules/@xtuc/ieee754": {
|
||||
|
@ -7865,6 +7871,46 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-client": {
|
||||
"version": "6.5.4",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz",
|
||||
"integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1",
|
||||
"xmlhttprequest-ssl": "~2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-client/node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-parser": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz",
|
||||
"integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.16.0",
|
||||
"resolved": "https://registry.npmmirror.com/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz",
|
||||
|
@ -16477,6 +16523,32 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-client": {
|
||||
"version": "4.7.5",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz",
|
||||
"integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io-client": "~6.5.2",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-parser": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sockjs": {
|
||||
"version": "0.3.24",
|
||||
"resolved": "https://registry.npmmirror.com/sockjs/-/sockjs-0.3.24.tgz",
|
||||
|
@ -18912,6 +18984,14 @@
|
|||
"resolved": "https://registry.npmmirror.com/xmlchars/-/xmlchars-2.2.0.tgz",
|
||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
|
||||
},
|
||||
"node_modules/xmlhttprequest-ssl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
||||
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz",
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
"react-scripts": "^5.0.1",
|
||||
"recharts": "^2.12.7",
|
||||
"redux": "^5.0.1",
|
||||
"socket.io-client": "^4.7.5",
|
||||
"stream": "^0.0.2",
|
||||
"swr": "^2.2.5",
|
||||
"tailwindcss": "^3.4.3",
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
import { Terminal } from "@xterm/xterm";
|
||||
import "@xterm/xterm/css/xterm.css";
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import io, { Socket } from "socket.io-client";
|
||||
|
||||
function base64Decode(encoded: string): string {
|
||||
return atob(encoded);
|
||||
}
|
||||
|
||||
export default function WebSSH() {
|
||||
const location = useLocation();
|
||||
const terminalObj = useRef<HTMLDivElement | null>(null);
|
||||
const [terminal, setTerminal] = useState<Terminal | null>(null);
|
||||
const [socket, setSocket] = useState<Socket | null>(null);
|
||||
const [ip, setIp] = useState("");
|
||||
const [port, setPort] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
const params = new URLSearchParams(location.search);
|
||||
const encodedIp = params.get("ip");
|
||||
const encodedPort = params.get("port");
|
||||
const encodedPassword = params.get("password");
|
||||
|
||||
if (encodedIp && encodedPort && encodedPassword) {
|
||||
setIp(base64Decode(encodedIp));
|
||||
setPort(base64Decode(encodedPort));
|
||||
setPassword(base64Decode(encodedPassword));
|
||||
}
|
||||
}, [location]);
|
||||
|
||||
useEffect(() => {
|
||||
if (terminal === null) {
|
||||
setTerminal(new Terminal());
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (terminal !== null) {
|
||||
terminal.open(terminalObj.current as HTMLDivElement);
|
||||
|
||||
const newSocket = io("ws://36.138.114.105:32087");
|
||||
setSocket(newSocket);
|
||||
|
||||
terminal.onData((data) => {
|
||||
newSocket.emit("input", data);
|
||||
});
|
||||
|
||||
terminal.onSelectionChange(() => {
|
||||
if (terminal.hasSelection()) {
|
||||
navigator.clipboard.writeText(terminal.getSelection());
|
||||
}
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
newSocket.emit("heartbeat");
|
||||
}, 1000);
|
||||
|
||||
newSocket.on("output", (data: string) => {
|
||||
terminal.write(data);
|
||||
});
|
||||
|
||||
return () => {
|
||||
newSocket.disconnect();
|
||||
};
|
||||
}
|
||||
}, [terminal]);
|
||||
|
||||
useEffect(() => {
|
||||
if (socket && ip && port && password) {
|
||||
socket.emit("connect_ssh", { ip, port, password });
|
||||
}
|
||||
}, [socket, ip, port, password]);
|
||||
|
||||
function pasteContent(event: React.MouseEvent) {
|
||||
navigator.clipboard.readText().then((content) => {
|
||||
socket?.emit("input", content);
|
||||
});
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div ref={terminalObj} onContextMenu={pasteContent} style={{ height: "100vh", width: "100%" }}>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -23,11 +23,12 @@ import ClassID from '../TeacherPages/classlistpages/classId';
|
|||
import ManageTest from '../TeacherPages/TestManage/ManageTest';
|
||||
import SendTest from '../TeacherPages/TestManage/SendTest';
|
||||
import Marking from '../TeacherPages/MarkingPages/Marking';
|
||||
import SendTrain from '../TeacherPages/Trainmanage/SendTrain'
|
||||
import TrainManage from '../TeacherPages/Trainmanage/Trainmanage'
|
||||
import StudentLink from '../TeacherPages/MarkingPages/StudentLink';
|
||||
|
||||
|
||||
import SendTrain from '../TeacherPages/SendTrain/SendTrain';
|
||||
import TrainManage from '../TeacherPages/SendTest/trainmanage';
|
||||
import Test from "../TeacherPages/teachermanagetest/Test.tsx"
|
||||
// 定义一个组件来包裹除了特定页面(exam)外的所有页面使其有导航
|
||||
const MainLayout = ({ headerNav:HeaderNav }) => {
|
||||
return (
|
||||
|
@ -69,6 +70,7 @@ function App() {
|
|||
<Route path="/classID/:key" element={<MainLayout headerNav={HeaderNavTeacher} />}>
|
||||
<Route index element={<ClassID/>} />
|
||||
</Route>
|
||||
<Route path="test" element={<Test />}/>
|
||||
|
||||
{/* 页面使用单独的布局,不包含HeaderNav和HeaderNavTeacher */}
|
||||
<Route path="exam/:examId" element={<Exam />} />{/* 练习-考试页面 */}
|
||||
|
|
|
@ -4,7 +4,7 @@ module.exports = function(app) {
|
|||
app.use(
|
||||
'/api', // 如果请求路径匹配'/api',则进行代理
|
||||
createProxyMiddleware({
|
||||
target: 'http://127.0.0.1:5000', // 目标后端服务地址
|
||||
target: 'http://36.138.114.105:32087', // 目标后端服务地址
|
||||
changeOrigin: true,
|
||||
})
|
||||
);
|
||||
|
|
14
build.sh
14
build.sh
|
@ -20,13 +20,14 @@ build_image() {
|
|||
|
||||
# 推送镜像
|
||||
push_image() {
|
||||
local service_name=$1
|
||||
read -p "是否要推送到《达梦启元云原生大数据平台》? [Y/N] " confirm
|
||||
if [[ $confirm =~ ^[yY]([eE][sS])?$ ]]; then
|
||||
echo "tag"
|
||||
docker tag "${current_dir}-flask-app" 36.138.114.105:31000/cnsof50011836/flask-app
|
||||
echo "pushing"
|
||||
docker push 36.138.114.105:31000/cnsof50011836/flask-app
|
||||
echo "pushed"
|
||||
echo "${service_name} tag"
|
||||
docker tag "${service_name}" 36.138.114.105:31000/cnsof50011836/$service_name
|
||||
echo "${service_name} pushing"
|
||||
docker push 36.138.114.105:31000/cnsof50011836/$service_name
|
||||
echo "${service_name} pushed"
|
||||
else
|
||||
echo "用户选择不推送镜像"
|
||||
fi
|
||||
|
@ -43,7 +44,8 @@ main() {
|
|||
build_image build-frontend
|
||||
build_image flask-app
|
||||
|
||||
push_image
|
||||
push_image flask-app
|
||||
push_image base-dm
|
||||
|
||||
echo "脚本结束"
|
||||
}
|
||||
|
|
|
@ -23,14 +23,11 @@ services:
|
|||
flask-app:
|
||||
build: ./python
|
||||
restart: always
|
||||
image: flask-app
|
||||
depends_on:
|
||||
- base-dm
|
||||
ports:
|
||||
- '8000:8000'
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl --silent --fail localhost:8000/flask-health-check || exit 1"]
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
- '8765:8765'
|
||||
command: gunicorn -w 3 -t 60 -b 0.0.0.0:8000 app:app
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ RUN useradd -m -s /bin/bash dmdba \
|
|||
WORKDIR /home/dmdba
|
||||
|
||||
# 传入安装包并解压
|
||||
RUN wget https://download.dameng.com/eco/adapter/DM8/202405/dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip
|
||||
RUN unzip dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \
|
||||
RUN wget https://download.dameng.com/eco/adapter/DM8/202405/dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \
|
||||
&& unzip dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \
|
||||
&& chown -R dmdba:dmdba /home/dmdba \
|
||||
&& rm -f dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \
|
||||
&& 7z x dm8_20240408_x86_rh7_64.iso \
|
||||
|
|
|
@ -9,6 +9,8 @@ RUN sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.l
|
|||
&& apt-get install -y python3.10-venv libssl-dev sudo vim python3-pip ssh wget unzip p7zip* language-pack-zh-hans language-selector-common locales locales-all \
|
||||
# 设置中文环境
|
||||
&& apt install -y $(check-language-support) \
|
||||
&& sed -i 's/^#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config \
|
||||
&& sudo sed -i 's/^UsePAM yes/UsePAM no/' /etc/ssh/sshd_config \
|
||||
&& echo "zh_CN.UTF-8 UTF-8" >> /etc/locale.gen \
|
||||
&& sudo /usr/sbin/update-locale LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8 \
|
||||
&& locale-gen \
|
||||
|
|
|
@ -1,26 +1 @@
|
|||
FROM ubuntu
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV LANG=zh_CN.UTF-8
|
||||
ENV LC_ALL=zh_CN.UTF-8
|
||||
# 基础软件安装
|
||||
RUN sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list \
|
||||
&& apt-get -y update && apt-get -y upgrade \
|
||||
&& apt-get install -y sudo vim python3-pip ssh wget unzip p7zip* language-pack-zh-hans language-selector-common locales locales-all \
|
||||
# 设置中文环境
|
||||
&& apt install -y $(check-language-support) \
|
||||
&& echo "zh_CN.UTF-8 UTF-8" >> /etc/locale.gen \
|
||||
&& sudo /usr/sbin/update-locale LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8 \
|
||||
&& locale-gen \
|
||||
# 添加用户
|
||||
&& useradd -m -s /bin/bash dmdba \
|
||||
# 修改用户密码
|
||||
&& echo "dmdba:123456" | chpasswd
|
||||
# 传入安装包并解压
|
||||
WORKDIR /home/dmdba
|
||||
RUN wget https://download.dameng.com/eco/adapter/DM8/202405/dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip
|
||||
RUN unzip dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \
|
||||
&& chown -R dmdba:dmdba /home/dmdba \
|
||||
&& rm -f dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip \
|
||||
&& 7z x dm8_20240408_x86_rh7_64.iso \
|
||||
&& rm -f dm8_20240408_x86_rh7_64.iso \
|
||||
&& chmod +x DMInstall.bin
|
||||
FROM base-dm
|
|
@ -0,0 +1,27 @@
|
|||
SHELL=/bin/bash
|
||||
KUBERNETES_SERVICE_PORT_HTTPS=443
|
||||
KUBERNETES_SERVICE_PORT=443
|
||||
HOSTNAME=flask-app-deployment-76d66d98b8-s6hxs
|
||||
DMCCA_CANVAS_NAME=flask-app
|
||||
PWD=/home/flask
|
||||
LOGNAME=flask
|
||||
TZ=Asia/Shanghai
|
||||
HOME=/home/flask
|
||||
LANG=zh_CN.UTF-8
|
||||
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
|
||||
VIRTUAL_ENV=/home/flask/venv
|
||||
TERM=xterm
|
||||
USER=flask
|
||||
DMCCA_CANVAS_NAMESPACE=cnsof50011836-system
|
||||
SHLVL=2
|
||||
KUBERNETES_PORT_443_TCP_PROTO=tcp
|
||||
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
|
||||
KUBERNETES_SERVICE_HOST=10.96.0.1
|
||||
LC_ALL=zh_CN.UTF-8
|
||||
KUBERNETES_PORT=tcp://10.96.0.1:443
|
||||
KUBERNETES_PORT_443_TCP_PORT=443
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
|
||||
MAIL=/var/mail/flask
|
||||
DEBIAN_FRONTEND=noninteractive
|
||||
OLDPWD=/root
|
||||
_=/usr/bin/printenv
|
|
@ -0,0 +1,3 @@
|
|||
.idea
|
||||
__pycache__
|
||||
public
|
|
@ -4,10 +4,12 @@ FROM base
|
|||
RUN pip install --upgrade pip
|
||||
|
||||
# 创建一个用户运行flask
|
||||
RUN adduser flask && \
|
||||
RUN useradd -m -s /bin/bash flask && \
|
||||
chown -R flask:flask /home/flask && \
|
||||
mkdir -p /var/log/flask-app && touch /var/log/flask-app/flask-app.err.log && touch /var/log/flask-app/flask-app.out.log && \
|
||||
chown -R flask:flask /var/log/flask-app
|
||||
chown -R flask:flask /var/log/flask-app && \
|
||||
service ssh start && \
|
||||
service ssh restart
|
||||
WORKDIR /home/flask
|
||||
USER flask
|
||||
|
||||
|
@ -24,10 +26,12 @@ RUN python3 -m venv "$VIRTUAL_ENV" && \
|
|||
export FLASK_APP=app.py && \
|
||||
pip3 install dmPython-2.5.5-cp310-cp310-linux_x86_64.whl && rm dmPython-2.5.5-cp310-cp310-linux_x86_64.whl && \
|
||||
MAKEFLAGS="-j$(nproc)" pip install -r requirements.txt
|
||||
|
||||
COPY --from=build-dmpython /home/dmdba/build_artifacts/libdmdpi.so /usr/lib/
|
||||
COPY --from=build-frontend /usr/src/app/build/ /home/flask/public/
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 5000
|
||||
EXPOSE 8000 22 8765
|
||||
USER root
|
||||
|
||||
CMD ["gunicorn", "-w", "3", "-t", "60", "-b", "0.0.0.0:8000", "app:app"]
|
|
@ -1,12 +1,29 @@
|
|||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
|
||||
import paramiko
|
||||
|
||||
from teacher_func import *
|
||||
from student_func import *
|
||||
from k8s_func import *
|
||||
|
||||
from flask import Flask, render_template, request, jsonify, send_from_directory, session
|
||||
from flask_cors import CORS
|
||||
|
||||
from flask_socketio import SocketIO, emit, disconnect
|
||||
import logging
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
app = Flask(__name__, static_folder="public")
|
||||
CORS(app, resources={r"/*": {"origins": "*"}})
|
||||
CORS(app)
|
||||
cors = CORS(app, resource={
|
||||
r"/*":{
|
||||
"origins":"*"
|
||||
}
|
||||
})
|
||||
app.config['SECRET_KEY'] = '350625'
|
||||
socketio = SocketIO(app, cors_allowed_origins="*")
|
||||
|
||||
clients = {}
|
||||
|
||||
@app.route('/api/student', methods=['POST']) # 检测历史是否登录过,登录则直接进入index,反之则进去login界面
|
||||
def student(): # 判断是否已经登录
|
||||
|
@ -249,6 +266,17 @@ def Find_details():
|
|||
result=Find_details_Func(ID)
|
||||
print(result)
|
||||
return jsonify({'TestScore':result})
|
||||
@app.route("/api/teacher/list_pods")
|
||||
def teacher_list_pods():
|
||||
return list_pods()
|
||||
@app.route("/api/teacher/list_services")
|
||||
def teacher_list_services():
|
||||
return list_services()
|
||||
|
||||
@app.route("/api/teacher/create_pod")
|
||||
def teacher_create_pod():
|
||||
create_pod(0, "test")
|
||||
|
||||
|
||||
|
||||
@app.route('/')
|
||||
|
@ -257,7 +285,56 @@ def catch_all(path = "index.html"):
|
|||
return send_from_directory("public", path)
|
||||
|
||||
|
||||
@socketio.on('connect_ssh')
|
||||
def handle_connect_ssh(data):
|
||||
ip = data['ip']
|
||||
port = int(data['port'])
|
||||
password = data['password']
|
||||
client_id = request.sid
|
||||
|
||||
ssh_client = paramiko.SSHClient()
|
||||
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
|
||||
try:
|
||||
ssh_client.connect(ip, port=port, username='your-username', password=password)
|
||||
transport = ssh_client.get_transport()
|
||||
channel = transport.open_session()
|
||||
channel.get_pty()
|
||||
channel.invoke_shell()
|
||||
|
||||
clients[client_id] = {
|
||||
'ssh_client': ssh_client,
|
||||
'channel': channel
|
||||
}
|
||||
|
||||
socketio.start_background_task(target=read_from_channel, channel=channel, client_id=client_id)
|
||||
except Exception as e:
|
||||
emit('output', f'Connection failed: {str(e)}')
|
||||
|
||||
|
||||
def read_from_channel(channel, client_id):
|
||||
while True:
|
||||
if channel.recv_ready():
|
||||
data = channel.recv(1024).decode('utf-8')
|
||||
socketio.emit('output', data, room=client_id)
|
||||
|
||||
|
||||
@socketio.on('input')
|
||||
def handle_input(data):
|
||||
client_id = request.sid
|
||||
if client_id in clients:
|
||||
clients[client_id]['channel'].send(data)
|
||||
|
||||
|
||||
@socketio.on('disconnect')
|
||||
def handle_disconnect():
|
||||
client_id = request.sid
|
||||
if client_id in clients:
|
||||
clients[client_id]['channel'].close()
|
||||
clients[client_id]['ssh_client'].close()
|
||||
del clients[client_id]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=5000, debug=True)
|
||||
socketio.run(app, host='0.0.0.0', port=5000)
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: NAME
|
||||
namespace: ""
|
||||
labels:
|
||||
app: NAME
|
||||
spec:
|
||||
containers:
|
||||
- name: base-dm
|
||||
image: harbor.dameng.io/cnsof50011836/base-dm
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
limits:
|
||||
cpu: '1'
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: '0.25'
|
||||
memory: 0.5G
|
|
@ -0,0 +1,85 @@
|
|||
import json
|
||||
|
||||
import yaml
|
||||
from kubernetes import client, config
|
||||
from flask import jsonify
|
||||
# Load in-cluster config
|
||||
config.load_incluster_config()
|
||||
v1 = client.CoreV1Api()
|
||||
namespace = open("/var/run/secrets/kubernetes.io/serviceaccount/namespace").read()
|
||||
IP = "36.138.114.105"
|
||||
def list_pods():
|
||||
ret = v1.list_namespaced_pod(namespace, watch=False)
|
||||
return {
|
||||
"list": [{
|
||||
"name": item.metadata.name.replace("database-dmserver-0", "student-2210502337-0-12"),
|
||||
"ip": item.status.pod_ip
|
||||
} for item in ret.items]
|
||||
}
|
||||
|
||||
def list_services():
|
||||
ret = v1.list_namespaced_service(namespace)
|
||||
return {
|
||||
"list": [
|
||||
# "name": item.metadata.name.replace("database-dmserver-0", "student-2210502337-0-12"),
|
||||
# "ip": item.spec.cluster_ip,
|
||||
# "ports": [[port.to_dict() for port in item.spec.ports]],
|
||||
#
|
||||
item.to_dict()
|
||||
# "node_port": item.spec.ports[0].node_port,
|
||||
for item in ret.items]
|
||||
}
|
||||
|
||||
def create_pod(type, name):
|
||||
# 读取 pod yaml 文件
|
||||
with open(f"assets/type{type}-pod.yaml") as f:
|
||||
pod_manifest = yaml.safe_load(f)
|
||||
pod_manifest["metadata"]["name"] = name
|
||||
pod_manifest["metadata"]["labels"]["app"] = name
|
||||
# 创建 Pod
|
||||
resp = v1.create_namespaced_pod(
|
||||
body=pod_manifest,
|
||||
namespace=namespace
|
||||
)
|
||||
print(f"pod '{resp.metadata.name}' 创建成功")
|
||||
# 创建 Service
|
||||
service_manifest = {
|
||||
"apiVersion": "v1",
|
||||
"kind": "Service",
|
||||
"metadata": {
|
||||
"name": name+ "-service"
|
||||
},
|
||||
"spec": {
|
||||
"selector": {
|
||||
"app": pod_manifest['metadata']['labels']['app']
|
||||
},
|
||||
"ports": [
|
||||
{
|
||||
"protocol": "TCP",
|
||||
"port": 22,
|
||||
"targetPort": 22
|
||||
},
|
||||
{
|
||||
"protocol": "TCP",
|
||||
"port": 5236,
|
||||
"targetPort": 5236
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
resp = v1.create_namespaced_service(
|
||||
body=service_manifest,
|
||||
namespace=namespace
|
||||
)
|
||||
print(f"服务 '{resp.metadata.name}' 创建成功")
|
||||
# 创建成功,再次查询,拿到端口
|
||||
service = v1.read_namespaced_service(name=name+ "-service", namespace=namespace)
|
||||
print(service)
|
||||
print("访问地址:" + IP + ":" + service.spec.ports[0].node_port)
|
||||
|
||||
|
||||
def delete_pod(name):
|
||||
pass
|
||||
|
||||
|
|
@ -1,4 +1,8 @@
|
|||
Flask==2.3.0
|
||||
Flask_Cors==4.0.0
|
||||
pycryptodome==3.19.0
|
||||
gunicorn
|
||||
gunicorn
|
||||
kubernetes
|
||||
websockets
|
||||
paramiko
|
||||
flask-socketio
|
|
@ -117,7 +117,7 @@ def get_lesson_func(id):
|
|||
|
||||
def student_succeed_func(ID):
|
||||
cursor = db.cursor()
|
||||
cursor.execute(f'SELECT * FROM STUDENT WHERE ID={ID}')
|
||||
cursor.execute(f'SELECT * FROM STUDENT WHERE ID={ID}')# 报错
|
||||
student_succeed = cursor.fetchall()[0]
|
||||
student_succeeds = student_succeed[0], student_succeed[1], student_succeed[3], student_succeed[4]
|
||||
cursor.close()
|
||||
|
|
Loading…
Reference in New Issue