Compare commits

...
Author SHA1 Message Date
Justin Lin 0e37b13d99 wip: not working yet... 2025-03-11 19:56:56 +08:00
Justin Lin b2a251576c fix: save stdout and stderr without tee 2025-02-22 14:07:15 +08:00
Justin Lin 8cc006e3a4 fix: check files using abs path (#175)
the docker user is changed from commander to root due to #168 pr.
Use absolute path instead of relative path to prevent false detection.
2025-02-15 20:55:03 +08:00
Justin Lin d6ae6d818d Fix network (#174) 2025-02-15 20:52:25 +08:00
wancat 6692ae2b9b fix: check files using abs path
(the docker user is changed due to feat-ssh pr)
2025-02-15 20:42:50 +08:00
Justin Lin fab02d03a9 fix: update env samples, use dash only for naming networks 2024-12-27 21:01:31 +08:00
Justin Lin 9e44ebe415 fix: remove unwanted error logging 2024-12-27 20:56:23 +08:00
Justin Lin 019caf58e4 fix: use a different docker network for dev to prevent "interna" settings conflicts 2024-12-27 20:56:05 +08:00
11 changed files with 70 additions and 45 deletions

No files matched your search

+1 -1
View File
@@ -3,6 +3,7 @@ PORT=3000
BASE_URL=https://example.com
SECRET_KEY=YOU_SHOULD_CHANGE_THIS
BACKEND_URL=http://backend:3000
DOCKER_NETWORK=linux-odyssey-players
MONGO_ROOT_PASSWORD=adminpassword
MONGO_USER=commander
@@ -29,7 +30,6 @@ ADMIN_PORT=3001
# GITHUB_CLIENT_SECRET=
# SURVEY_URL=
# BUG_REPORT_URL=
# DOCKER_NETWORK=
# SURVEY_URL=
# BUG_REPORT_URL=
+1 -1
View File
@@ -3,6 +3,7 @@ PORT=3000
BASE_URL=http://localhost:5173
MONGO_URL=mongodb://localhost:27017/odyssey-test
SECRET_KEY=sample-secret
DOCKER_NETWORK=linux-odyssey-players-dev
# Optional
# BACKEND_URL=http://host.docker.internal:3000
@@ -17,7 +18,6 @@ SECRET_KEY=sample-secret
# GITHUB_CLIENT_SECRET=
# SURVEY_URL=
# BUG_REPORT_URL=
# DOCKER_NETWORK=
# SURVEY_URL=
# BUG_REPORT_URL=
+3 -4
View File
@@ -13,7 +13,7 @@ services:
base:
image: linuxodyssey/quest-base
networks:
- players
- players-dev
build:
context: .
dockerfile: ./quests/Dockerfile
@@ -22,7 +22,6 @@ services:
networks:
internal:
players:
name: linux-odyssey-players
players-dev:
name: linux-odyssey-players-dev
internal: false
external: true
+29 -8
View File
@@ -1,24 +1,39 @@
PROMPT='%F{2}%n%f:%F{6}%~%f $ '
unsetopt CASE_GLOB
setopt CHASE_LINKS
emulate bash
# emulate bash
set +o prompt_cr
preexec() {
export CMD_START_TIME=$(date +%s%N) # capture start time
export CMD_NAME=$1 # capture command
export CMD_NAME="$1" # capture command
export CMD_PID=$$
# A list of interactive commands
interactive_commands=("vim" "nano" "top" "ssh" "less" "zsh" "bash")
# # A list of interactive commands
# readlink /proc/$PPID/exe
interactive_commands=("vim" "nano" "top" "ssh" "less" "zsh" "bash" "script" "exec")
# # if [[ $CMD_EXECUTED = 1 ]]; then
# # export CMD_EXECUTED=0
# # return
# # fi
# Check if the command is in the list of interactive commands
# # Check if the command is in the list of interactive commands
if [[ " ${interactive_commands[@]} " =~ " $1 " ]]; then
# If it is, just execute it normally
exec
# exec
# echo IF
return
else
# If it's not, execute it and redirect its output to a file
exec > >(tee /tmp/cmd.out) 2> >(tee /tmp/cmd.error >&2)
# exec > >(tee /tmp/cmd.out) 2> >(tee /tmp/cmd.error >&2)
# echo ELSE
# export CMD_EXECUTED=1
# eval >&1 >/tmp/cmd.out
# exec >&1
# exec
script --quiet -O /tmp/cmd.out -c "$CMD_NAME"
return 1
fi
}
@@ -29,7 +44,12 @@ precmd() {
export CMD_ERROR_FILE=/tmp/cmd.error
# Now run your Node.js script with the result as an argument
node /usr/local/lib/container/cli.js; rm /tmp/cmd.out /tmp/cmd.error 2>/dev/null
node /usr/local/lib/container/cli.js
if [[ -n $CMD_PID ]]; then
# echo $CMD_PID
# kill $CMD_PID
fi
# rm /tmp/cmd.out /tmp/cmd.error 2>/dev/null
# Reset variables
unset CMD_START_TIME
@@ -38,5 +58,6 @@ precmd() {
unset CMD_OUTPUT_FILE
unset CMD_ERROR_FILE
unset CMD_NAME
export CMD_EXECUTED=0
}
+4 -4
View File
@@ -164,7 +164,7 @@ stages:
command:
- ^cp hello.txt hello2.txt$
files:
- path: hello2.txt
- path: /home/commander/hello2.txt
type: file
exceptions:
- condition:
@@ -224,7 +224,7 @@ stages:
command:
- ^cp world.txt world2.txt$
files:
- path: world2.txt
- path: /home/commander/world2.txt
type: file
exceptions:
- condition:
@@ -292,9 +292,9 @@ stages:
command:
- ^cp
files:
- path: notes2
- path: /home/commander/notes2
type: directory
- path: notes2/note.txt
- path: /home/commander/notes2/note.txt
type: file
exceptions:
- condition:
+6 -6
View File
@@ -44,12 +44,12 @@ stages:
- ls
condition:
files:
- path: hello.txt
- path: /home/commander/hello.txt
type: file
exceptions:
- condition:
files:
- path: hello$
- path: /home/commander/hello
type: file
responses:
- type: narrative
@@ -107,12 +107,12 @@ stages:
- ls-touch
condition:
files:
- path: world.txt
- path: /home/commander/world.txt
type: file
exceptions:
- condition:
files:
- path: world$
- path: /home/commander/world
type: file
responses:
- type: narrative
@@ -154,7 +154,7 @@ stages:
- ls-2
condition:
files:
- path: notes
- path: /home/commander/notes
type: folder
responses:
- type: narrative
@@ -203,7 +203,7 @@ stages:
- cd-notes
condition:
files:
- path: notes/note.txt
- path: /home/commander/notes/note.txt
type: file
responses:
- type: narrative
+8 -8
View File
@@ -49,9 +49,9 @@ stages:
command:
- ^mv hello.txt notes$
files:
- path: notes/hello.txt
- path: /home/commander/notes/hello.txt
type: file
- path: hello.txt
- path: /home/commander/hello.txt
exists: false
responses:
- type: narrative
@@ -106,9 +106,9 @@ stages:
command:
- ^mv
files:
- path: wow.txt
- path: /home/commander/wow.txt
type: file
- path: world.txt
- path: /home/commander/world.txt
exists: false
responses:
- type: narrative
@@ -148,9 +148,9 @@ stages:
command:
- ^mv
files:
- path: docs
- path: /home/commander/docs
type: directory
- path: notes
- path: /home/commander/notes
exists: false
responses:
- type: narrative
@@ -187,9 +187,9 @@ stages:
command:
- ^mv
files:
- path: hi.txt
- path: /home/commander/hi.txt
type: file
- path: docs/hello.txt
- path: /home/commander/docs/hello.txt
exists: false
exceptions:
- condition:
+10 -10
View File
@@ -44,7 +44,7 @@ stages:
command:
- ^rm\s
files:
- path: hello.txt
- path: /home/commander/hello.txt
exists: false
responses:
- content: |
@@ -58,7 +58,7 @@ stages:
command:
- ^ls$
files:
- path: hello.txt
- path: /home/commander/hello.txt
exists: false
responses:
- content: |
@@ -78,9 +78,9 @@ stages:
command:
- ^rm
files:
- path: world.txt
- path: /home/commander/world.txt
exists: false
- path: wow.txt
- path: /home/commander/wow.txt
exists: false
responses:
- content: |
@@ -111,7 +111,7 @@ stages:
command:
- ^rmdir empty$
files:
- path: empty
- path: /home/commander/empty
exists: false
responses:
- content: |
@@ -139,7 +139,7 @@ stages:
command:
- ^rmdir notes$
files:
- path: notes
- path: /home/commander/notes
type: folder
exists: true
responses:
@@ -161,10 +161,10 @@ stages:
command:
- ^rm
files:
- path: notes
- path: /home/commander/notes
type: folder
exists: true
- path: notes/note.txt
- path: /home/commander/notes/note.txt
exists: false
exceptions:
- condition:
@@ -203,7 +203,7 @@ stages:
task: 使用 `rmdir` 刪除 `notes` 資料夾
condition:
files:
- path: notes
- path: /home/commander/notes
exists: false
responses:
- content: |
@@ -238,7 +238,7 @@ stages:
command:
- ^rm -r trash$
files:
- path: trash
- path: /home/commander/trash
exists: false
responses:
- content: |
@@ -8,6 +8,7 @@ import { asyncHandler } from '../../middleware/error.js'
export const newCommand = asyncHandler(async (req: Request, res: Response) => {
const { command, pwd, output, error, params } = matchedData(req)
console.log(command, output, error)
const { sessionId } = req.user as any
const session = await Session.findById(sessionId)
+1 -1
View File
@@ -72,7 +72,7 @@ function createConfig() {
projectRoot,
docker: {
network: get('DOCKER_NETWORK', 'linux-odyssey-players'),
network: get('DOCKER_NETWORK', 'linux-odyssey-players-dev'),
defaultImage: get('QUEST_IMAGE', 'linuxodyssey/quest-base'),
imagePrefix: get('DOCKER_PREFIX', 'linuxodyssey/quest-'),
mountQuest: process.env.MOUNT_QUEST === 'true',
+6 -2
View File
@@ -33,6 +33,9 @@ export async function createContainer(
imageId: string
): Promise<Docker.Container> {
let binds: string[] = []
binds.push(
`${config.docker.hostProjectRoot}/quests/.includes/zshrc:/etc/zsh/zshrc`
)
if (await questHomeExists(questId)) {
logger.info('Mounting quest home', questId)
binds.push(
@@ -94,20 +97,21 @@ export async function attachContainer(
config.docker.network
].IPAddress
let error: Error | null = null
for (let i = 0; i < 10; i++) {
try {
// eslint-disable-next-line no-await-in-loop
const stream = await connectToSSH(containerIp, { token })
return stream
} catch (err) {
logger.error('Failed to connect to SSH', err)
error = err as Error
// eslint-disable-next-line no-await-in-loop
await new Promise((resolve) => {
setTimeout(resolve, 1000)
})
}
}
throw new Error('Failed to connect to SSH')
throw new Error('Failed to connect to SSH', { cause: error })
}
export async function deleteContainer(id: string) {