@cocalc/project
Version:
CoCalc: project daemon
137 lines (123 loc) • 4.09 kB
text/typescript
/*
* This file is part of CoCalc: Copyright © 2021 Sagemath, Inc.
* License: AGPLv3 s.t. "Commons Clause" – see LICENSE.md for details
*/
/*
This configures the project hub based on an environment variable or other data.
*/
import debug from "debug";
import { existsSync } from "fs";
import { setPriority } from "os";
const L = debug("project:project-setup");
// const { callback2: cb2 } = require("@cocalc/util/async-utils");
// const { execute_code } = require("@cocalc/backend/misc_node");
// 19 is the minimum, we keep it 1 above that.
export const DEFAULT_FREE_PROCS_NICENESS = 18;
// this only lists some of the fields in use, there might be more
interface ProjectConfig {
quota?: {
member_host?: boolean;
dedicated_disks?: { name: string }[];
};
}
export function getProjectConfig(): ProjectConfig | null {
const conf_enc = process.env.COCALC_PROJECT_CONFIG;
if (conf_enc == null) {
return null;
}
try {
L(`configure(${conf_enc.slice(0, 30)}...)`);
const conf_raw = Buffer.from(conf_enc, "base64").toString("utf8");
return JSON.parse(conf_raw);
} catch (err) {
// we report and ignore errors
L(`ERROR parsing COCALC_PROJECT_CONFIG -- '${conf_enc}' -- ${err}`);
return null;
}
}
// this is for kucalc projects only
export function is_free_project(): boolean {
const conf = getProjectConfig();
const ifp = conf?.quota?.member_host === false;
L(`is_free_project: ${ifp}`);
return ifp;
}
export function configure() {
if (is_free_project()) {
L(`member_host is false -- renicing everything`);
setPriority(process.pid, DEFAULT_FREE_PROCS_NICENESS);
}
}
// Contains additional environment variables. Base 64 encoded JSON of {[key:string]:string}.
export function set_extra_env(): { [key: string]: string } | undefined {
sage_aarch64_hack();
if (!process.env.COCALC_EXTRA_ENV) {
L("set_extra_env: nothing provided");
return;
}
const ret: { [key: string]: string } = {};
try {
const env64 = process.env.COCALC_EXTRA_ENV;
const raw = Buffer.from(env64, "base64").toString("utf8");
L(`set_extra_env: ${raw}`);
const data = JSON.parse(raw);
if (typeof data === "object") {
for (let k in data) {
const v = data[k];
if (typeof v !== "string" || v.length === 0) {
L(
`set_extra_env: ignoring key ${k}, value is not a string or has length 0`
);
continue;
}
// this is the meat of all this – this should happen after cleanup()!
process.env[k] = v;
ret[k] = v;
}
}
} catch (err) {
// we report and ignore errors
L(
`ERROR set_extra_env -- cannot process '${process.env.COCALC_EXTRA_ENV}' -- ${err}`
);
}
return ret;
}
// this should happen before set_extra_env
export function cleanup(): void {
// clean environment to get rid of nvm and other variables
if (process.env.PATH == null) return;
process.env.PATH = process.env.PATH.split(":")
.filter((x) => !x.startsWith("/cocalc/nvm"))
.join(":");
const envrm = [
"DATA",
"BASE_PATH",
"NODE_PATH",
"NODE_ENV",
"NODE_VERSION",
"NVM_CD_FLAGS",
"NVM_DIR",
"NVM_BIN",
"DEBUG",
"PATH_COCALC",
"COCALC_ROOT",
];
envrm.forEach((name) => delete process.env[name]);
// Also get rid of any npm_ vars that get set due to how the project server
// is started. This is mainly an issue with cocalc-docker.
for (const key in process.env) {
if (key.startsWith("npm_")) delete process.env[key];
}
}
// See https://github.com/opencv/opencv/issues/14884
// Importing Sage in various situations, e.g., as is done for sage server,
// is fundamentally broken on aarch64 linux due to this issue. Yes, I explained
// this on sage-devel, but nobody understood.
// It's also important to NOT do this hack if you're not on aarch64!
function sage_aarch64_hack(): void {
const LD_PRELOAD = "/usr/lib/aarch64-linux-gnu/libgomp.so.1";
if (process.arch == "arm64" && existsSync(LD_PRELOAD)) {
process.env.LD_PRELOAD = LD_PRELOAD;
}
}