piston/api/src/config.js

200 lines
5.2 KiB
JavaScript
Raw Normal View History

2021-02-20 23:39:03 +01:00
const fss = require('fs');
const yargs = require('yargs');
const hide_bin = require('yargs/helpers').hideBin; //eslint-disable-line snakecasejs/snakecasejs
const Logger = require('logplease');
const logger = Logger.create('config');
const yaml = require('js-yaml');
2021-02-20 15:13:56 +01:00
const header = `#
# ____ _ _
# | _ \\(_)___| |_ ___ _ __
# | |_) | / __| __/ _ \\| '_ \\
# | __/| \\__ \\ || (_) | | | |
# |_| |_|___/\\__\\___/|_| |_|
#
# A High performance code execution engine
# github.com/engineer-man/piston
#
2021-02-20 23:39:03 +01:00
`;
2021-02-20 15:13:56 +01:00
const argv = yargs(hide_bin(process.argv))
2021-02-20 23:39:03 +01:00
.usage('Usage: $0 -c [config]')
.demandOption('c') //eslint-disable-line snakecasejs/snakecasejs
.option('config', {
alias: 'c',
describe: 'config file to load from',
default: '/piston/config.yaml'
2021-02-20 15:13:56 +01:00
})
2021-02-20 23:39:03 +01:00
.option('make-config', {
alias: 'm',
type: 'boolean',
describe: 'create config file and populate defaults if it does not already exist'
}).argv;
2021-02-20 15:13:56 +01:00
const options = [
{
2021-02-20 23:39:03 +01:00
key: 'log_level',
desc: 'Level of data to log',
default: 'INFO',
2021-02-20 15:13:56 +01:00
/* eslint-disable snakecasejs/snakecasejs */
options: Object.values(Logger.LogLevels),
validators: [x=>Object.values(Logger.LogLevels).includes(x) || `Log level ${x} does not exist`]
/* eslint-enable snakecasejs/snakecasejs */
},
{
2021-02-20 23:39:03 +01:00
key: 'bind_address',
desc: 'Address to bind REST API on\nThank @Bones for the number',
default: '0.0.0.0:6969',
2021-02-20 15:13:56 +01:00
validators: []
},
{
2021-02-20 23:39:03 +01:00
key: 'data_directory',
desc: 'Absolute path to store all piston related data at',
default: '/piston',
validators: [x=> fss.exists_sync(x) || `Directory ${x} does not exist`]
2021-02-20 15:13:56 +01:00
},
{
2021-02-20 23:39:03 +01:00
key: 'cache_ttl',
desc: 'Time in milliseconds to keep data in cache for at a maximum',
2021-02-20 15:13:56 +01:00
default: 60 * 60 * 1000,
validators: []
},
{
2021-02-20 23:39:03 +01:00
key: 'cache_flush_time',
desc: 'Interval in milliseconds to flush cache to disk at',
2021-02-20 15:13:56 +01:00
default: 90 * 60 * 1000, //90 minutes
validators: []
},
{
2021-02-20 23:39:03 +01:00
key: 'state_flush_time',
desc: 'Interval in milliseconds to flush state to disk at',
2021-02-20 15:13:56 +01:00
default: 5000, // 5 seconds (file is tiny)
validators: []
},
{
2021-02-20 23:39:03 +01:00
key: 'runner_uid_min',
desc: 'Minimum uid to use for runner',
2021-02-20 15:13:56 +01:00
default: 1000,
validators: []
},
{
2021-02-20 23:39:03 +01:00
key: 'runner_uid_max',
desc: 'Maximum uid to use for runner',
2021-02-20 15:13:56 +01:00
default: 1500,
validators: []
},
{
2021-02-20 23:39:03 +01:00
key: 'runner_gid_min',
desc: 'Minimum gid to use for runner',
2021-02-20 15:13:56 +01:00
default: 1000,
validators: []
},
{
2021-02-20 23:39:03 +01:00
key: 'runner_gid_max',
desc: 'Maximum gid to use for runner',
2021-02-20 15:13:56 +01:00
default: 1500,
validators: []
2021-02-21 09:37:13 +01:00
},
{
key: 'enable_unshare',
desc: 'Enable using unshare to disable networking',
default: true,
validators: []
},
{
key: 'output_max_size',
desc: 'Max size of each stdio buffer',
default: 1024,
validators: []
2021-02-22 10:56:54 +01:00
},
{
key: 'max_process_count',
desc: 'Max number of processes per job',
default: 64,
validators: []
},
{
key: 'max_open_files',
desc: 'Max number of open files per job',
default: 2048,
validators: []
2021-02-20 15:13:56 +01:00
}
2021-02-20 23:39:03 +01:00
];
2021-02-20 15:13:56 +01:00
2021-03-05 07:29:09 +01:00
function make_default_config(){
let content = header.split('\n');
options.forEach(option => {
content.concat(option.desc.split('\n').map(x=>`# ${x}`));
if(option.options)
content.append('# Options: ' + option.options.join(', '));
content.append(`${option.key}: ${option.default}`);
content.append(''); // New line between
});
return content.join('\n');
}
2021-02-20 15:13:56 +01:00
2021-02-20 23:39:03 +01:00
logger.info(`Loading Configuration from ${argv.config}`);
2021-03-05 07:29:09 +01:00
if(argv['make-config'])
logger.debug('Make configuration flag is set');
2021-02-20 15:13:56 +01:00
2021-02-20 23:39:03 +01:00
if(!!argv['make-config'] && !fss.exists_sync(argv.config)){
logger.info('Writing default configuration...');
2021-02-20 15:13:56 +01:00
try {
2021-03-05 07:29:09 +01:00
fss.write_file_sync(argv.config, make_default_config());
2021-02-20 15:13:56 +01:00
} catch (err) {
2021-02-20 23:39:03 +01:00
logger.error('Error writing default configuration:', err.message);
process.exit(1);
2021-02-20 15:13:56 +01:00
}
}
2021-03-05 07:29:09 +01:00
2021-02-20 23:39:03 +01:00
var config = {};
2021-03-05 07:29:09 +01:00
2021-02-20 23:39:03 +01:00
logger.debug('Reading config file');
2021-03-05 07:29:09 +01:00
2021-02-20 15:13:56 +01:00
try{
2021-02-20 23:39:03 +01:00
const cfg_content = fss.read_file_sync(argv.config);
2021-03-05 07:29:09 +01:00
config = yaml.load(cfg_content);
2021-02-20 15:13:56 +01:00
}catch(err){
2021-03-05 07:29:09 +01:00
logger.error('Error reading configuration file:', err.message);
2021-02-20 23:39:03 +01:00
process.exit(1);
2021-02-20 15:13:56 +01:00
}
2021-02-20 23:39:03 +01:00
logger.debug('Validating config entries');
2021-03-05 07:29:09 +01:00
2021-02-20 23:39:03 +01:00
var errored=false;
2021-03-05 07:29:09 +01:00
options.forEach(option => {
logger.debug('Checking option', option.key);
var cfg_val = config[option.key];
2021-02-20 15:13:56 +01:00
if(cfg_val == undefined){
2021-02-20 23:39:03 +01:00
errored = true;
2021-03-05 07:29:09 +01:00
logger.error(`Config key ${option.key} does not exist on currently loaded configuration`);
2021-02-20 23:39:03 +01:00
return;
2021-02-20 15:13:56 +01:00
}
2021-03-05 07:29:09 +01:00
option.validators.forEach(validator => {
2021-02-20 23:39:03 +01:00
var response = validator(cfg_val);
2021-02-20 15:13:56 +01:00
if(response !== true){
2021-02-20 23:39:03 +01:00
errored = true;
2021-03-05 07:29:09 +01:00
logger.error(`Config option ${option.key} failed validation:`, response);
2021-02-20 23:39:03 +01:00
return;
2021-02-20 15:13:56 +01:00
}
2021-02-20 23:39:03 +01:00
});
});
2021-02-20 15:13:56 +01:00
2021-02-20 23:39:03 +01:00
if(errored) process.exit(1);
2021-02-20 15:13:56 +01:00
2021-02-20 23:39:03 +01:00
logger.info('Configuration successfully loaded');
2021-02-20 15:13:56 +01:00
2021-02-20 23:39:03 +01:00
module.exports = config;
2021-02-20 15:13:56 +01:00