Compare commits
3 Commits
e686473d9a
...
b7ac6612be
Author | SHA1 | Date |
---|---|---|
wang | b7ac6612be | |
wang | df8ece4dd8 | |
wang | ce75c0484d |
|
@ -4,31 +4,12 @@ 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() {
|
||||
export default function WebSSH({ ip = "10.233.183.99", port = "22", password = "123456", user = "dmdba" }) {
|
||||
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) {
|
||||
|
@ -69,9 +50,9 @@ export default function WebSSH() {
|
|||
|
||||
useEffect(() => {
|
||||
if (socket && ip && port && password) {
|
||||
socket.emit("connect_ssh", { ip, port, password });
|
||||
socket.emit("connect_ssh", { ip, port, password, user });
|
||||
}
|
||||
}, [socket, ip, port, password]);
|
||||
}, [socket, ip, port, password, user]);
|
||||
|
||||
function pasteContent(event: React.MouseEvent) {
|
||||
navigator.clipboard.readText().then((content) => {
|
||||
|
|
|
@ -83,7 +83,7 @@ function SendTrain(){
|
|||
endDate
|
||||
})
|
||||
alert('发布成功')
|
||||
window.location.href='http://localhost:3000/teacher/trainmanage'
|
||||
window.location.href='/teacher/trainmanage'
|
||||
}catch{
|
||||
alert('SendTrainTest出错')
|
||||
|
||||
|
|
|
@ -11,11 +11,23 @@ import { max, min } from 'lodash';
|
|||
|
||||
// 首页
|
||||
function Home(){
|
||||
const student_ID=localStorage.getItem('islogin')
|
||||
if(student_ID==null){
|
||||
window.location.href='http://localhost:3000/signin'
|
||||
alert('未登录,请先前往登录')
|
||||
}
|
||||
const [isChecked,setisChecked]=useState(false)
|
||||
//判断是否登录
|
||||
// useEffect(()=>{
|
||||
// if (!isChecked){
|
||||
// const is_login=localStorage.getItem('islogin')
|
||||
// if(!is_login){
|
||||
// alert('未登录')
|
||||
// window.location.href='/signin'
|
||||
// }else{
|
||||
// console.log(is_login);
|
||||
// console.log('已登录');
|
||||
// setisChecked(true)
|
||||
// }
|
||||
// //组件加载时自动调用login函数进行登录检测
|
||||
// }
|
||||
// },[]);//在组件加载时只调用一次
|
||||
|
||||
//课表数据
|
||||
const [lesson, setLesson] = useState([]);
|
||||
const [firstlesson, setfirstlesson] = useState([]);
|
||||
|
@ -36,7 +48,7 @@ function Home(){
|
|||
setLesson(lesson_data)
|
||||
}catch(error){
|
||||
if(student_ID.length===6){
|
||||
window.location.href='http://localhost:3000/teacher'
|
||||
window.location.href='/teacher'
|
||||
return
|
||||
}else{
|
||||
alert('提示出错')
|
||||
|
|
|
@ -81,7 +81,7 @@ function Exam() {
|
|||
clearInterval(interval);
|
||||
alert('考试时间到!');
|
||||
correct()
|
||||
window.location.href='http://localhost:3000/subject'
|
||||
window.location.href='/subject'
|
||||
}
|
||||
}, 1000);
|
||||
return () => clearInterval(interval);
|
||||
|
@ -183,7 +183,7 @@ function Exam() {
|
|||
setCountdown(0)
|
||||
localStorage.removeItem('time')
|
||||
alert('提交成功')
|
||||
window.location.href='http://localhost:3000/subject'
|
||||
window.location.href='/subject'
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@ function Operation2() {
|
|||
localStorage.removeItem('answeredJudge')
|
||||
localStorage.removeItem('RemainingTime')
|
||||
alert('提交成功')
|
||||
window.location.href='http://localhost:3000/train'
|
||||
window.location.href='/train'
|
||||
localStorage.removeItem('TrainData')
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,10 @@ 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 Test from '../TeacherPages/TestManage/Test.tsx'
|
||||
|
||||
|
||||
import SendTrain from '../TeacherPages/Trainmanage/SendTrain';
|
||||
|
@ -69,6 +72,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 />} />{/* 练习-考试页面 */}
|
||||
|
|
2
build.sh
2
build.sh
|
@ -43,9 +43,11 @@ main() {
|
|||
build_image build-dmpython
|
||||
build_image build-frontend
|
||||
build_image flask-app
|
||||
build_image code-server
|
||||
|
||||
push_image flask-app
|
||||
push_image base-dm
|
||||
push_image code-server
|
||||
|
||||
echo "脚本结束"
|
||||
}
|
||||
|
|
|
@ -31,3 +31,14 @@ services:
|
|||
- '8765:8765'
|
||||
command: gunicorn -w 3 -t 60 -b 0.0.0.0:8000 app:app
|
||||
|
||||
code-server:
|
||||
build: ./docker/code-server
|
||||
restart: always
|
||||
image: code-server
|
||||
depends_on:
|
||||
- build-dmpython
|
||||
ports:
|
||||
- '8443:8443'
|
||||
- '5000:5000'
|
||||
- '3000:3000'
|
||||
|
||||
|
|
|
@ -1,16 +1,24 @@
|
|||
# base-dm
|
||||
FROM base
|
||||
# 添加用户
|
||||
RUN useradd -m -s /bin/bash dmdba \
|
||||
# 修改用户密码
|
||||
&& echo "dmdba:123456" | chpasswd
|
||||
# 修改用户密码
|
||||
&& echo "dmdba:123456" | chpasswd \
|
||||
&& apt-get -y update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
p7zip-full unzip wget \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /config/* /tmp/* /var/lib/apt/lists/* /var/tmp/*
|
||||
WORKDIR /home/dmdba
|
||||
|
||||
# 传入安装包并解压
|
||||
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 \
|
||||
&& rm -f dm8_20240408_x86_rh7_64.iso \
|
||||
&& chmod +x DMInstall.bin
|
||||
# 下载安装包并解压
|
||||
RUN wget https://download.dameng.com/eco/adapter/DM8/202405/dm8_20240408_x86_rh7_64_ent_8.1.3.140.zip --no-check-certificate \
|
||||
&& 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 \
|
||||
&& apt-get remove -y p7zip-full unzip wget
|
||||
USER dmdba
|
||||
CMD ["/bin/bash", "-e"]
|
|
@ -1,24 +1,20 @@
|
|||
FROM ubuntu
|
||||
# base
|
||||
FROM ubuntu:22.04
|
||||
# apt安装时,防止卡死在交互界面
|
||||
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 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 \
|
||||
&& pip config set global.index-url https://mirrors.bfsu.edu.cn/pypi/web/simple \
|
||||
&& echo "**** clean up ****" && \
|
||||
apt-get clean && \
|
||||
rm -rf \
|
||||
/config/* \
|
||||
/tmp/* \
|
||||
/var/lib/apt/lists/* \
|
||||
/var/tmp/*
|
||||
&& apt-get -y update && apt-get -y upgrade \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
# && 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 \
|
||||
ssh locales language-pack-zh-hans-base \
|
||||
&& sed -i 's/^#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config \
|
||||
&& sed -i 's/^UsePAM yes/UsePAM no/' /etc/ssh/sshd_config \
|
||||
&& echo "zh_CN.UTF-8 UTF-8" >> /etc/locale.gen \
|
||||
&& /usr/sbin/update-locale LANG=zh_CN.UTF-8 LC_ALL=zh_CN.UTF-8 \
|
||||
&& locale-gen \
|
||||
# && pip config set global.index-url https://mirrors.bfsu.edu.cn/pypi/web/simple \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /config/* /tmp/* /var/lib/apt/lists/* /var/tmp/*
|
|
@ -1,7 +1,24 @@
|
|||
#build-dmpython
|
||||
FROM base-dm
|
||||
WORKDIR /home/dmdba
|
||||
COPY auto_install.xml .
|
||||
RUN ./DMInstall.bin -q /home/dmdba/auto_install.xml
|
||||
RUN ./DMInstall.bin -q /home/dmdba/auto_install.xml \
|
||||
&& rm -rf ./DMInstall.bin
|
||||
USER root
|
||||
RUN apt-get -y update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
python3-dev python3-pip gcc \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /config/* /tmp/* /var/lib/apt/lists/* /var/tmp/* \
|
||||
&& pip3 install wheel
|
||||
|
||||
USER dmdba
|
||||
# 编译
|
||||
WORKDIR /home/dmdba/dmdbms/drivers/python/dmPython
|
||||
RUN DM_HOME=/home/dmdba/dmdbms python3 setup.py bdist_wheel && mkdir /home/dmdba/build_artifacts && cp dist/dmPython-2.5.5-cp310-cp310-linux_x86_64.whl /home/dmdba/build_artifacts/ && cp /home/dmdba/dmdbms/bin/libdmdpi.so /home/dmdba/build_artifacts/
|
||||
RUN DM_HOME=/home/dmdba/dmdbms python3 setup.py bdist_wheel \
|
||||
&& mkdir /home/dmdba/build_artifacts \
|
||||
&& mv dist/dmPython-2.5.5-cp310-cp310-linux_x86_64.whl /home/dmdba/build_artifacts/ \
|
||||
&& cp /home/dmdba/dmdbms/bin/libdmdpi.so /home/dmdba/build_artifacts/
|
||||
USER root
|
||||
RUN apt-get remove -y python3-dev python3-pip gcc
|
||||
USER dmdba
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<KEY></KEY>
|
||||
|
||||
<!--安装程序组件类型,取值范围:0、1、2,0 表示安装全部,1 表示安装服务器,2 表示安装客户端。缺省为0。 -->
|
||||
<INSTALL_TYPE>0</INSTALL_TYPE>
|
||||
<INSTALL_TYPE>1</INSTALL_TYPE>
|
||||
|
||||
<!--安装路径,不允许为空。 -->
|
||||
<INSTALL_PATH>/home/dmdba/dmdbms</INSTALL_PATH>
|
||||
|
|
|
@ -1,57 +1,73 @@
|
|||
FROM ghcr.io/linuxserver/baseimage-ubuntu:jammy
|
||||
#code-server
|
||||
FROM build-dmpython
|
||||
|
||||
# set version label
|
||||
ARG BUILD_DATE
|
||||
ARG VERSION
|
||||
ARG CODE_RELEASE
|
||||
LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DATE}"
|
||||
LABEL maintainer="aptalca"
|
||||
ENV DEBIAN_FRONTEND="noninteractive"
|
||||
WORKDIR /home/dmdba
|
||||
USER root
|
||||
|
||||
# environment settings
|
||||
ARG DEBIAN_FRONTEND="noninteractive"
|
||||
ENV HOME="/config"
|
||||
|
||||
RUN \
|
||||
echo "**** install runtime dependencies ****" && \
|
||||
apt-get update && \
|
||||
apt-get install -y \
|
||||
git \
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
git jq libatomic1 nano net-tools netcat python3-pip nodejs npm curl sudo catatonit \
|
||||
cron \
|
||||
curl \
|
||||
gnupg \
|
||||
jq \
|
||||
libatomic1 \
|
||||
nano \
|
||||
net-tools \
|
||||
netcat \
|
||||
# 安装python nodejs
|
||||
python3 \
|
||||
python3-pip \
|
||||
nodejs \
|
||||
npm \
|
||||
sudo && \
|
||||
echo "**** install code-server ****" && \
|
||||
if [ -z ${CODE_RELEASE+x} ]; then \
|
||||
CODE_RELEASE=$(curl -sX GET https://api.github.com/repos/coder/code-server/releases/latest \
|
||||
| awk '/tag_name/{print $4;exit}' FS='[""]' | sed 's|^v||'); \
|
||||
fi && \
|
||||
mkdir -p /app/code-server && \
|
||||
curl -o \
|
||||
/tmp/code-server.tar.gz -L \
|
||||
"https://github.com/coder/code-server/releases/download/v${CODE_RELEASE}/code-server-${CODE_RELEASE}-linux-amd64.tar.gz" && \
|
||||
tar xf /tmp/code-server.tar.gz -C \
|
||||
/app/code-server --strip-components=1 && \
|
||||
echo "**** clean up ****" && \
|
||||
apt-get clean && \
|
||||
rm -rf \
|
||||
/config/* \
|
||||
/tmp/* \
|
||||
/var/lib/apt/lists/* \
|
||||
/var/tmp/*
|
||||
tzdata \
|
||||
xz-utils \
|
||||
&& CODE_RELEASE=$(curl -sX GET https://api.github.com/repos/coder/code-server/releases/latest | awk '/tag_name/{print $4;exit}' FS='[""]' | sed 's|^v||') \
|
||||
&& mkdir -p /app/code-server \
|
||||
&& curl -o /tmp/code-server.tar.gz -L "https://github.com/coder/code-server/releases/download/v${CODE_RELEASE}/code-server-${CODE_RELEASE}-linux-amd64.tar.gz" \
|
||||
&& tar xf /tmp/code-server.tar.gz -C /app/code-server --strip-components=1 \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/* \
|
||||
&& pip3 install /home/dmdba/build_artifacts/dmPython-2.5.5-cp310-cp310-linux_x86_64.whl \
|
||||
&& rm /home/dmdba/build_artifacts/dmPython-2.5.5-cp310-cp310-linux_x86_64.whl
|
||||
|
||||
# set environment variables
|
||||
ENV HOME="/root" \
|
||||
LANGUAGE="en_US.UTF-8" \
|
||||
LANG="en_US.UTF-8" \
|
||||
TERM="xterm" \
|
||||
S6_CMD_WAIT_FOR_SERVICES_MAXTIME="0" \
|
||||
S6_VERBOSITY=1 \
|
||||
S6_STAGE2_HOOK=/docker-mods \
|
||||
VIRTUAL_ENV=/lsiopy \
|
||||
PATH="/lsiopy/bin:$PATH" \
|
||||
HOME="/config"
|
||||
|
||||
# set version for s6 overlay
|
||||
ARG S6_OVERLAY_VERSION="3.1.6.2"
|
||||
ARG S6_OVERLAY_ARCH="x86_64"
|
||||
|
||||
# add s6 overlay
|
||||
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp
|
||||
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
|
||||
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_OVERLAY_ARCH}.tar.xz /tmp
|
||||
RUN tar -C / -Jxpf /tmp/s6-overlay-${S6_OVERLAY_ARCH}.tar.xz
|
||||
|
||||
# add s6 optional symlinks
|
||||
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-symlinks-noarch.tar.xz /tmp
|
||||
RUN tar -C / -Jxpf /tmp/s6-overlay-symlinks-noarch.tar.xz
|
||||
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-symlinks-arch.tar.xz /tmp
|
||||
RUN tar -C / -Jxpf /tmp/s6-overlay-symlinks-arch.tar.xz && \
|
||||
useradd -u 911 -U -d /config -s /bin/false abc && \
|
||||
usermod -G users abc && \
|
||||
mkdir -p \
|
||||
/app \
|
||||
/config \
|
||||
/defaults \
|
||||
/lsiopy
|
||||
|
||||
ARG MODS_VERSION="v3"
|
||||
ARG PKG_INST_VERSION="v1"
|
||||
ARG LSIOWN_VERSION="v1"
|
||||
ADD --chmod=744 "https://raw.githubusercontent.com/linuxserver/docker-mods/mod-scripts/docker-mods.${MODS_VERSION}" "/docker-mods"
|
||||
ADD --chmod=744 "https://raw.githubusercontent.com/linuxserver/docker-mods/mod-scripts/package-install.${PKG_INST_VERSION}" "/etc/s6-overlay/s6-rc.d/init-mods-package-install/run"
|
||||
ADD --chmod=744 "https://raw.githubusercontent.com/linuxserver/docker-mods/mod-scripts/lsiown.${LSIOWN_VERSION}" "/usr/bin/lsiown"
|
||||
|
||||
# 安装达梦数据库
|
||||
RUN mkdir -p /opt/dm8.zip && \
|
||||
wget -O root/opt/dm8.zip https://download.dameng.com/eco/adapter/DM8/202401END/dm8_20240408_x86_rh7_64.zip
|
||||
|
||||
# add local files
|
||||
COPY /root /
|
||||
|
||||
# ports and volumes
|
||||
EXPOSE 8443
|
||||
EXPOSE 5000 3000 8443
|
||||
ENTRYPOINT ["/init"]
|
|
@ -0,0 +1 @@
|
|||
oneshot
|
|
@ -0,0 +1 @@
|
|||
echo "[ls.io-init] done."
|
|
@ -0,0 +1,12 @@
|
|||
───────────────────────────────────────
|
||||
_____ __ __ _____ _____ _____ _____
|
||||
| | | | __|_ _| | |
|
||||
| --| | |__ | | | | | | | | |
|
||||
|_____|_____|_____| |_| |_____|_|_|_|
|
||||
_____ __ __ _ __ ____
|
||||
| __ | | | | | | \
|
||||
| __ -| | | | |__| | |
|
||||
|_____|_____|_|_____|____/
|
||||
|
||||
Based on images from linuxserver.io
|
||||
───────────────────────────────────────
|
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
|
||||
PUID=${PUID:-911}
|
||||
PGID=${PGID:-911}
|
||||
|
||||
groupmod -o -g "$PGID" abc
|
||||
usermod -o -u "$PUID" abc
|
||||
|
||||
cat /etc/s6-overlay/s6-rc.d/init-adduser/branding
|
||||
|
||||
if [[ -f /donate.txt ]]; then
|
||||
echo '
|
||||
To support the app dev(s) visit:'
|
||||
cat /donate.txt
|
||||
fi
|
||||
echo '
|
||||
To support LSIO projects visit:
|
||||
https://www.linuxserver.io/donate/
|
||||
|
||||
───────────────────────────────────────
|
||||
GID/UID
|
||||
───────────────────────────────────────'
|
||||
echo "
|
||||
User UID: $(id -u abc)
|
||||
User GID: $(id -g abc)
|
||||
───────────────────────────────────────
|
||||
"
|
||||
|
||||
lsiown abc:abc /app
|
||||
lsiown abc:abc /config
|
||||
lsiown abc:abc /defaults
|
|
@ -0,0 +1 @@
|
|||
oneshot
|
|
@ -0,0 +1 @@
|
|||
/etc/s6-overlay/s6-rc.d/init-adduser/run
|
|
@ -0,0 +1 @@
|
|||
oneshot
|
|
@ -0,0 +1 @@
|
|||
# This file doesn't do anything, it's just the end of the downstream image init process
|
|
@ -0,0 +1 @@
|
|||
oneshot
|
|
@ -0,0 +1 @@
|
|||
# This file doesn't do anything, it's just the start of the downstream image init process
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
|
||||
for cron_user in abc root; do
|
||||
if [[ -f "/etc/crontabs/${cron_user}" ]]; then
|
||||
lsiown "${cron_user}":"${cron_user}" "/etc/crontabs/${cron_user}"
|
||||
crontab -u "${cron_user}" "/etc/crontabs/${cron_user}"
|
||||
fi
|
||||
|
||||
if [[ -f "/defaults/crontabs/${cron_user}" ]]; then
|
||||
# make folders
|
||||
mkdir -p \
|
||||
/config/crontabs
|
||||
|
||||
# if crontabs do not exist in config
|
||||
if [[ ! -f "/config/crontabs/${cron_user}" ]]; then
|
||||
# copy crontab from system
|
||||
if crontab -l -u "${cron_user}" >/dev/null 2>&1; then
|
||||
crontab -l -u "${cron_user}" >"/config/crontabs/${cron_user}"
|
||||
fi
|
||||
|
||||
# if crontabs still do not exist in config (were not copied from system)
|
||||
# copy crontab from image defaults (using -n, do not overwrite an existing file)
|
||||
cp -n "/defaults/crontabs/${cron_user}" /config/crontabs/
|
||||
fi
|
||||
|
||||
# set permissions and import user crontabs
|
||||
lsiown "${cron_user}":"${cron_user}" "/config/crontabs/${cron_user}"
|
||||
crontab -u "${cron_user}" "/config/crontabs/${cron_user}"
|
||||
fi
|
||||
done
|
|
@ -0,0 +1 @@
|
|||
oneshot
|
|
@ -0,0 +1 @@
|
|||
/etc/s6-overlay/s6-rc.d/init-crontab-config/run
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
|
||||
# Directories
|
||||
SCRIPTS_DIR="/custom-cont-init.d"
|
||||
|
||||
# Make sure custom init directory exists and has files in it
|
||||
if [[ -e "${SCRIPTS_DIR}" ]] && [[ -n "$(/bin/ls -A ${SCRIPTS_DIR} 2>/dev/null)" ]]; then
|
||||
echo "[custom-init] Files found, executing"
|
||||
for SCRIPT in "${SCRIPTS_DIR}"/*; do
|
||||
NAME="$(basename "${SCRIPT}")"
|
||||
if [[ -f "${SCRIPT}" ]]; then
|
||||
echo "[custom-init] ${NAME}: executing..."
|
||||
/bin/bash "${SCRIPT}"
|
||||
echo "[custom-init] ${NAME}: exited $?"
|
||||
elif [[ ! -f "${SCRIPT}" ]]; then
|
||||
echo "[custom-init] ${NAME}: is not a file"
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "[custom-init] No custom files found, skipping..."
|
||||
fi
|
|
@ -0,0 +1 @@
|
|||
oneshot
|
|
@ -0,0 +1 @@
|
|||
/etc/s6-overlay/s6-rc.d/init-custom-files/run
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
|
||||
if find /run/s6/container_environment/FILE__* -maxdepth 1 > /dev/null 2>&1; then
|
||||
for FILENAME in /run/s6/container_environment/FILE__*; do
|
||||
SECRETFILE=$(cat "${FILENAME}")
|
||||
if [[ -f ${SECRETFILE} ]]; then
|
||||
FILESTRIP=${FILENAME//FILE__/}
|
||||
if [[ $(tail -n1 "${SECRETFILE}" | wc -l) != 0 ]]; then
|
||||
echo "[env-init] Your secret: ${FILENAME##*/}"
|
||||
echo " contains a trailing newline and may not work as expected"
|
||||
fi
|
||||
cat "${SECRETFILE}" >"${FILESTRIP}"
|
||||
echo "[env-init] ${FILESTRIP##*/} set from ${FILENAME##*/}"
|
||||
else
|
||||
echo "[env-init] cannot find secret in ${FILENAME##*/}"
|
||||
fi
|
||||
done
|
||||
fi
|
|
@ -0,0 +1 @@
|
|||
oneshot
|
|
@ -0,0 +1 @@
|
|||
/etc/s6-overlay/s6-rc.d/init-envfile/run
|
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
|
||||
MIGRATIONS_DIR="/migrations"
|
||||
MIGRATIONS_HISTORY="/config/.migrations"
|
||||
|
||||
echo "[migrations] started"
|
||||
|
||||
if [[ ! -d ${MIGRATIONS_DIR} ]]; then
|
||||
echo "[migrations] no migrations found"
|
||||
exit
|
||||
fi
|
||||
|
||||
for MIGRATION in $(find ${MIGRATIONS_DIR}/* | sort -n); do
|
||||
NAME="$(basename "${MIGRATION}")"
|
||||
if [[ -f ${MIGRATIONS_HISTORY} ]] && grep -Fxq "${NAME}" ${MIGRATIONS_HISTORY}; then
|
||||
echo "[migrations] ${NAME}: skipped"
|
||||
continue
|
||||
fi
|
||||
echo "[migrations] ${NAME}: executing..."
|
||||
chmod +x "${MIGRATION}"
|
||||
# Execute migration script in a subshell to prevent it from modifying the current environment
|
||||
("${MIGRATION}")
|
||||
EXIT_CODE=$?
|
||||
if [[ ${EXIT_CODE} -ne 0 ]]; then
|
||||
echo "[migrations] ${NAME}: failed with exit code ${EXIT_CODE}, contact support"
|
||||
exit "${EXIT_CODE}"
|
||||
fi
|
||||
echo "${NAME}" >>${MIGRATIONS_HISTORY}
|
||||
echo "[migrations] ${NAME}: succeeded"
|
||||
done
|
||||
|
||||
echo "[migrations] done"
|
|
@ -0,0 +1 @@
|
|||
oneshot
|
|
@ -0,0 +1 @@
|
|||
/etc/s6-overlay/s6-rc.d/init-migrations/run
|
|
@ -0,0 +1 @@
|
|||
oneshot
|
|
@ -0,0 +1 @@
|
|||
# This file doesn't do anything, it's just the end of the mod init process
|
|
@ -0,0 +1 @@
|
|||
oneshot
|
|
@ -0,0 +1 @@
|
|||
/etc/s6-overlay/s6-rc.d/init-mods-package-install/run
|
|
@ -0,0 +1 @@
|
|||
oneshot
|
|
@ -0,0 +1 @@
|
|||
# This file doesn't do anything, it's just the start of the mod init process
|
|
@ -0,0 +1 @@
|
|||
oneshot
|
|
@ -0,0 +1 @@
|
|||
# This file doesn't do anything, it's just the end of the mod init process
|
|
@ -0,0 +1 @@
|
|||
oneshot
|
|
@ -0,0 +1 @@
|
|||
# This file doesn't do anything, it just signals that services can start
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/with-contenv bash
|
||||
# shellcheck shell=bash
|
||||
|
||||
if builtin command -v crontab >/dev/null 2>&1 && [[ -n "$(crontab -l -u abc 2>/dev/null || true)" || -n "$(crontab -l -u root 2>/dev/null || true)" ]]; then
|
||||
if builtin command -v busybox >/dev/null 2>&1 && [[ $(busybox || true) =~ [[:space:]](crond)([,]|$) ]]; then
|
||||
exec busybox crond -f -S -l 5
|
||||
elif [[ -f /usr/bin/apt ]] && [[ -f /usr/sbin/cron ]]; then
|
||||
exec /usr/sbin/cron -f -L 5
|
||||
else
|
||||
echo "**** cron not found ****"
|
||||
sleep infinity
|
||||
fi
|
||||
else
|
||||
sleep infinity
|
||||
fi
|
|
@ -0,0 +1 @@
|
|||
longrun
|
|
@ -1,15 +1,18 @@
|
|||
#flask-app
|
||||
FROM base
|
||||
|
||||
# 升级pip
|
||||
RUN pip install --upgrade pip
|
||||
|
||||
# 创建一个用户运行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 && \
|
||||
service ssh start && \
|
||||
service ssh restart
|
||||
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 \
|
||||
&& apt-get -y update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
python3 python3-dev python3-pip python3-venv \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /config/* /tmp/* /var/lib/apt/lists/* /var/tmp/* \
|
||||
&& pip install --upgrade pip
|
||||
WORKDIR /home/flask
|
||||
USER flask
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ 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
|
||||
|
@ -256,13 +257,11 @@ def SendTrainTest():
|
|||
TrainJudge=data['TrainJudge']
|
||||
Hour=data['HourValue']
|
||||
Min=data['MinValue']
|
||||
StopTime=data['StopTime']
|
||||
Class=data['selectedItems']
|
||||
Train=data['Train']
|
||||
teacher_id=data['teacher_ID']
|
||||
startTime=data['startDate']
|
||||
endTime=data['endDate']
|
||||
SendTrainTestFunc(TrainChoice, TrainCompletion, TrainJudge, Hour, Min,Class,Train,teacher_id,startTime,endTime)
|
||||
TeacherMark(Class,teacher_id)
|
||||
SendTrainTestFunc(TrainChoice, TrainCompletion, TrainJudge, Hour, Min, StopTime,Class,Train,teacher_id)
|
||||
return '发布成功'
|
||||
|
||||
|
||||
|
@ -271,14 +270,26 @@ def Find_details():
|
|||
data=request.json
|
||||
ID=data['ID']
|
||||
result=Find_details_Func(ID)
|
||||
print(result)
|
||||
return jsonify({'TestScore':result})
|
||||
@app.route("/api/teacher/list_pods") # 列出pod
|
||||
def teacher_list_pods():
|
||||
return list_pods()
|
||||
@app.route("/api/teacher/list_services") # 列出服务
|
||||
def teacher_list_services():
|
||||
return list_services()
|
||||
|
||||
@app.route('/api/teacher/NotMarkTest',methods=["POST"])
|
||||
def NotMark():
|
||||
testID=request.json['testID']
|
||||
result=NotMarkTest(testID)
|
||||
return jsonify({'result':result})
|
||||
@app.route("/api/teacher/create_pod") # 创建服务 0为项目实训, 1为安装实训
|
||||
def teacher_create_pod():
|
||||
return create_pod(1, "test")
|
||||
|
||||
@app.route("/api/teacher/delete_pod") # 删除服务
|
||||
def teacher_delete_pod():
|
||||
return delete_pod("test")
|
||||
|
||||
@app.route("/api/teacher/check_pod") # 检测数据库是否安装成功 若成功,返回OK 否则返回NO
|
||||
def teacher_check_pod():
|
||||
return check_dm("test")
|
||||
|
||||
@app.route('/')
|
||||
@app.route('/<path:path>')
|
||||
|
@ -291,13 +302,14 @@ def handle_connect_ssh(data):
|
|||
ip = data['ip']
|
||||
port = int(data['port'])
|
||||
password = data['password']
|
||||
user = data['user']
|
||||
client_id = request.sid
|
||||
|
||||
print("connected to " + ip + " " + str(port) + " " + password)
|
||||
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)
|
||||
ssh_client.connect(ip, port=port, username=user, password=password)
|
||||
transport = ssh_client.get_transport()
|
||||
channel = transport.open_session()
|
||||
channel.get_pty()
|
||||
|
|
|
@ -4,16 +4,21 @@ metadata:
|
|||
name: NAME
|
||||
namespace: ""
|
||||
labels:
|
||||
app: NAME
|
||||
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
|
||||
containers:
|
||||
- name: base-dm
|
||||
image: harbor.dameng.io/cnsof50011836/base-dm:latest
|
||||
imagePullPolicy: Always
|
||||
command: [ "/bin/bash", "-c" ]
|
||||
args: [ "service ssh start && tail -f /dev/null" ]
|
||||
securityContext:
|
||||
runAsUser: 0
|
||||
runAsGroup: 0
|
||||
resources:
|
||||
limits:
|
||||
cpu: '1'
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: '0.25'
|
||||
memory: 0.5Gi
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: NAME
|
||||
spec:
|
||||
selector:
|
||||
app: NAME
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 22
|
||||
targetPort: 22
|
||||
name: "ssh"
|
||||
- protocol: TCP
|
||||
port: 5236
|
||||
targetPort: 5236
|
||||
name: "dm"
|
||||
type: ClusterIP
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: NAME
|
||||
namespace: ""
|
||||
labels:
|
||||
app: NAME
|
||||
spec:
|
||||
containers:
|
||||
- name: code-server
|
||||
image: harbor.dameng.io/cnsof50011836/code-server:latest
|
||||
imagePullPolicy: Always
|
||||
securityContext:
|
||||
runAsUser: 0
|
||||
runAsGroup: 0
|
||||
resources:
|
||||
limits:
|
||||
cpu: '1'
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: '0.25'
|
||||
memory: 0.5Gi
|
|
@ -0,0 +1,27 @@
|
|||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: NAME
|
||||
spec:
|
||||
selector:
|
||||
app: NAME
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8443
|
||||
targetPort: 8443
|
||||
name: "code"
|
||||
appProtocol: HTTP
|
||||
- protocol: TCP
|
||||
port: 5000
|
||||
targetPort: 5000
|
||||
name: "flask"
|
||||
appProtocol: HTTP
|
||||
- protocol: TCP
|
||||
port: 3000
|
||||
targetPort: 3000
|
||||
name: "frontend"
|
||||
appProtocol: HTTP
|
||||
type: NodePort
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
import json
|
||||
import traceback
|
||||
|
||||
import yaml
|
||||
from kubernetes import client, config
|
||||
from flask import jsonify
|
||||
import dmPython
|
||||
# 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,
|
||||
"ip": item.status.pod_ip
|
||||
} for item in ret.items]
|
||||
}
|
||||
|
||||
def list_services():
|
||||
ret = v1.list_namespaced_service(namespace)
|
||||
return {
|
||||
"list": [
|
||||
item.to_dict()
|
||||
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
|
||||
with open(f"assets/type{type}-service.yaml") as f:
|
||||
service_pod = yaml.safe_load(f)
|
||||
service_pod["metadata"]["name"] = name + "-service"
|
||||
service_pod["spec"]["selector"]["app"] = name
|
||||
|
||||
resp = v1.create_namespaced_service(
|
||||
body=service_pod,
|
||||
namespace=namespace
|
||||
)
|
||||
print(f"服务 '{resp.metadata.name}' 创建成功")
|
||||
if type == 1:
|
||||
# 创建成功,再次查询,拿到端口
|
||||
service = v1.read_namespaced_service(name=name + "-service", namespace=namespace)
|
||||
print(service)
|
||||
print("访问地址:" + IP + ":" + str(service.spec.ports[0].node_port))
|
||||
else:
|
||||
service = v1.read_namespaced_service(name=name + "-service", namespace=namespace)
|
||||
print(service)
|
||||
print("访问地址:" + IP + ":" + str(service.spec.ports[0].node_port))
|
||||
return f"{IP} {service.spec.ports[0].node_port}"
|
||||
|
||||
def delete_pod(name):
|
||||
v1.delete_namespaced_pod(name=name, namespace=namespace)
|
||||
v1.delete_namespaced_service(name=name + "-service", namespace=namespace)
|
||||
return "删除成功"
|
||||
|
||||
def check_dm(name):
|
||||
try:
|
||||
service = v1.read_namespaced_service(name=name + "-service", namespace=namespace)
|
||||
db = dmPython.connect(user='SYSDBA', password='SYSDBA', host=service.spec.cluster_ip, port="5236")
|
||||
cursor = db.cursor()
|
||||
records = cursor.execute("SELECT * FROM V$VERSION").fetchall()
|
||||
for record in records:
|
||||
print(record)
|
||||
return "OK"
|
||||
except:
|
||||
traceback.print_exc()
|
||||
return "NO"
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue