mirror of
https://github.com/fccview/cronmaster.git
synced 2025-12-24 14:38:38 -05:00
Compare commits
3 Commits
bugfix/fix
...
pr-43-bugf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8329c0d030 | ||
|
|
6e34474993 | ||
|
|
65ac81d97c |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -11,5 +11,6 @@ node_modules
|
||||
.vscode
|
||||
.DS_Store
|
||||
.cursorignore
|
||||
.idea
|
||||
tsconfig.tsbuildinfo
|
||||
docker-compose.test.yml
|
||||
@@ -72,6 +72,12 @@ services:
|
||||
# replace root with your user - find it with: ls -asl /var/spool/cron/crontabs/
|
||||
# For multiple users, use comma-separated values: HOST_CRONTAB_USER=root,user1,user2
|
||||
- HOST_CRONTAB_USER=root
|
||||
|
||||
# --- !! IMPORTANT !!DOCKER EXEC USER
|
||||
# If you do not specify this user to be a valid user on your system,
|
||||
# any cronjob containing a docker command will fail. IDEALLY you should not be running
|
||||
# docker commands as root, so this is only a fallback. ONLY ONE USER IS ALLOWED.
|
||||
- DOCKER_EXEC_USER=fccview
|
||||
volumes:
|
||||
# --- MOUNT DOCKER SOCKET
|
||||
# Mount Docker socket to execute commands on host
|
||||
@@ -147,6 +153,7 @@ The following environment variables can be configured:
|
||||
| `DOCKER` | `false` | ONLY set this to true if you are runnign the app via docker, in the docker-compose.yml file |
|
||||
| `HOST_CRONTAB_USER` | `root` | Comma separated list of users that run cronjobs on your host machine |
|
||||
| `AUTH_PASSWORD` | `N/A` | If you set a password the application will be password protected with basic next-auth |
|
||||
| `DOCKER_EXEC_USER` | `N/A` | If you don't set this user you won't be able to run docker commands as root. |
|
||||
|
||||
**Example**: To change the clock update interval to 60 seconds:
|
||||
|
||||
|
||||
@@ -265,12 +265,19 @@ export const runCronJob = async (
|
||||
|
||||
if (isDocker) {
|
||||
const userInfo = await getUserInfo(job.user);
|
||||
const dockerExecUser = process.env.DOCKER_EXEC_USER;
|
||||
|
||||
if (userInfo && userInfo.username !== "root") {
|
||||
command = `nsenter -t 1 -m -u -i -n -p --setuid=${userInfo.uid} --setgid=${userInfo.gid} sh -c "${job.command}"`;
|
||||
} else {
|
||||
command = `nsenter -t 1 -m -u -i -n -p sh -c "${job.command}"`;
|
||||
let executionUser = userInfo ? userInfo.username : "root";
|
||||
|
||||
if (dockerExecUser && executionUser === "root") {
|
||||
console.log(
|
||||
`Overriding root execution. Running command as user: ${dockerExecUser}`
|
||||
);
|
||||
executionUser = dockerExecUser;
|
||||
}
|
||||
|
||||
const escapedCommand = job.command.replace(/'/g, "'\\''");
|
||||
command = `nsenter -t 1 -m -u -i -n -p su - ${executionUser} -c '${escapedCommand}'`;
|
||||
}
|
||||
|
||||
const { stdout, stderr } = await execAsync(command, {
|
||||
|
||||
@@ -21,7 +21,7 @@ const sanitizeScriptName = (name: string): string => {
|
||||
.replace(/-+/g, "-")
|
||||
.replace(/^-|-$/g, "")
|
||||
.substring(0, 50);
|
||||
}
|
||||
};
|
||||
|
||||
const generateUniqueFilename = async (baseName: string): Promise<string> => {
|
||||
const scripts = await loadAllScripts();
|
||||
@@ -34,14 +34,14 @@ const generateUniqueFilename = async (baseName: string): Promise<string> => {
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
};
|
||||
|
||||
const ensureScriptsDirectory = async () => {
|
||||
const scriptsDir = await SCRIPTS_DIR();
|
||||
if (!existsSync(scriptsDir)) {
|
||||
await mkdir(scriptsDir, { recursive: true });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const ensureHostScriptsDirectory = async () => {
|
||||
const hostProjectDir = process.env.HOST_PROJECT_DIR || process.cwd();
|
||||
@@ -50,7 +50,7 @@ const ensureHostScriptsDirectory = async () => {
|
||||
if (!existsSync(hostScriptsDir)) {
|
||||
await mkdir(hostScriptsDir, { recursive: true });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const saveScriptFile = async (filename: string, content: string) => {
|
||||
const isDocker = process.env.DOCKER === "true";
|
||||
@@ -59,7 +59,13 @@ const saveScriptFile = async (filename: string, content: string) => {
|
||||
|
||||
const scriptPath = join(scriptsDir, filename);
|
||||
await writeFile(scriptPath, content, "utf8");
|
||||
}
|
||||
|
||||
try {
|
||||
await execAsync(`chmod +x "${scriptPath}"`);
|
||||
} catch (error) {
|
||||
console.error(`Failed to set execute permissions on ${scriptPath}:`, error);
|
||||
}
|
||||
};
|
||||
|
||||
const deleteScriptFile = async (filename: string) => {
|
||||
const isDocker = process.env.DOCKER === "true";
|
||||
@@ -68,11 +74,11 @@ const deleteScriptFile = async (filename: string) => {
|
||||
if (existsSync(scriptPath)) {
|
||||
await unlink(scriptPath);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const fetchScripts = async (): Promise<Script[]> => {
|
||||
return await loadAllScripts();
|
||||
}
|
||||
};
|
||||
|
||||
export const createScript = async (
|
||||
formData: FormData
|
||||
@@ -120,7 +126,7 @@ export const createScript = async (
|
||||
console.error("Error creating script:", error);
|
||||
return { success: false, message: "Error creating script" };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const updateScript = async (
|
||||
formData: FormData
|
||||
@@ -159,7 +165,7 @@ export const updateScript = async (
|
||||
console.error("Error updating script:", error);
|
||||
return { success: false, message: "Error updating script" };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteScript = async (
|
||||
id: string
|
||||
@@ -180,7 +186,7 @@ export const deleteScript = async (
|
||||
console.error("Error deleting script:", error);
|
||||
return { success: false, message: "Error deleting script" };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const cloneScript = async (
|
||||
id: string,
|
||||
@@ -230,7 +236,7 @@ export const cloneScript = async (
|
||||
console.error("Error cloning script:", error);
|
||||
return { success: false, message: "Error cloning script" };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const getScriptContent = async (filename: string): Promise<string> => {
|
||||
try {
|
||||
@@ -263,9 +269,11 @@ export const getScriptContent = async (filename: string): Promise<string> => {
|
||||
console.error("Error reading script content:", error);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const executeScript = async (filename: string): Promise<{
|
||||
export const executeScript = async (
|
||||
filename: string
|
||||
): Promise<{
|
||||
success: boolean;
|
||||
output: string;
|
||||
error: string;
|
||||
@@ -301,4 +309,4 @@ export const executeScript = async (filename: string): Promise<{
|
||||
error: error.message || "Unknown error",
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -23,6 +23,12 @@ services:
|
||||
# replace root with your user - find it with: ls -asl /var/spool/cron/crontabs/
|
||||
# For multiple users, use comma-separated values: HOST_CRONTAB_USER=root,user1,user2
|
||||
- HOST_CRONTAB_USER=root
|
||||
|
||||
# --- !! IMPORTANT !!DOCKER EXEC USER
|
||||
# If you do not specify this user to be a valid user on your system,
|
||||
# any cronjob containing a docker command will fail. IDEALLY you should not be running
|
||||
# docker commands as root, so this is only a fallback. ONLY ONE USER IS ALLOWED.
|
||||
- DOCKER_EXEC_USER=fccview
|
||||
volumes:
|
||||
# --- MOUNT DOCKER SOCKET
|
||||
# Mount Docker socket to execute commands on host
|
||||
|
||||
Reference in New Issue
Block a user