UNPKG

@cocalc/server

Version:

CoCalc server functionality: functions used by either the hub and the next.js server

128 lines (124 loc) 5.08 kB
"use strict"; /* multi-user: a multi-user Linux system where the hub runs as root, so can create and delete user accounts, etc. There is some security and isolation between projects, coming from different operating system users. This is mainly used for cocalc-docker, which is a deployment of CoCalc running in a single docker container, with one hub running as root. This **executes some basic shell commands** (e.g., useradd, rsync) to start and stop the project, copy files between projects, etc. This code is very similar to single-user.ts, except with some small modifications due to having to create and delete Linux users. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const util_1 = require("./util"); const base_1 = require("./base"); const logger_1 = __importDefault(require("@cocalc/backend/logger")); const misc_1 = require("@cocalc/backend/misc"); const winston = (0, logger_1.default)("project-control:multi-user"); const MAX_START_TIME_MS = 30000; const MAX_STOP_TIME_MS = 20000; class Project extends base_1.BaseProject { constructor(project_id) { super(project_id); this.HOME = (0, util_1.homePath)(this.project_id); this.uid = (0, misc_1.getUid)(this.project_id); } async state() { if (this.stateChanging != null) { return this.stateChanging; } const state = await (0, util_1.getState)(this.HOME); winston.debug(`got state of ${this.project_id} = ${JSON.stringify(state)}`); this.saveStateToDatabase(state); return state; } async status() { const status = await (0, util_1.getStatus)(this.HOME); // TODO: don't include secret token in log message. winston.debug(`got status of ${this.project_id} = ${JSON.stringify(status)}`); this.saveStatusToDatabase(status); return status; } async start() { if (this.stateChanging != null) return; winston.info(`start ${this.project_id}`); // Home directory const HOME = this.HOME; if (await (0, util_1.isProjectRunning)(HOME)) { winston.debug("start -- already running"); await this.saveStateToDatabase({ state: "running" }); return; } try { this.stateChanging = { state: "starting" }; await this.saveStateToDatabase(this.stateChanging); await this.siteLicenseHook(); await (0, util_1.mkdir)(HOME, { recursive: true }); await (0, util_1.createUser)(this.project_id); await (0, util_1.chown)(HOME, this.uid); await (0, util_1.ensureConfFilesExists)(HOME, this.uid); // this.get('env') = extra env vars for project (from synctable): const env = await (0, util_1.getEnvironment)(this.project_id); winston.debug(`start ${this.project_id}: env = ${JSON.stringify(env)}`); // Setup files await (0, util_1.setupDataPath)(HOME, this.uid); // Fork and launch project server daemon await (0, util_1.launchProjectDaemon)(env, this.uid); await this.wait({ until: async () => { if (!(await (0, util_1.isProjectRunning)(this.HOME))) { return false; } const status = await this.status(); return !!status.secret_token && !!status["hub-server.port"]; }, maxTime: MAX_START_TIME_MS, }); } finally { this.stateChanging = undefined; // ensure state valid await this.state(); } } async stop() { if (this.stateChanging != null) return; winston.info("stop ", this.project_id); if (!(await (0, util_1.isProjectRunning)(this.HOME))) { await this.saveStateToDatabase({ state: "opened" }); return; } try { this.stateChanging = { state: "stopping" }; await this.saveStateToDatabase(this.stateChanging); await (0, util_1.deleteUser)(this.project_id); await this.wait({ until: async () => !(await (0, util_1.isProjectRunning)(this.HOME)), maxTime: MAX_STOP_TIME_MS, }); } finally { this.stateChanging = undefined; // ensure state valid in database await this.state(); } } async copyPath(opts) { winston.debug("copyPath ", this.project_id, opts); await (0, util_1.copyPath)(opts, this.project_id, opts.target_project_id ? (0, misc_1.getUid)(opts.target_project_id) : undefined); return ""; } } function get(project_id) { return (0, base_1.getProject)(project_id) ?? new Project(project_id); } exports.default = get; //# sourceMappingURL=multi-user.js.map