Split out service related functions

This commit is contained in:
Girish Ramakrishnan
2018-12-02 18:05:19 -08:00
parent 823b3b8aa8
commit 7ed422a3c1
2 changed files with 79 additions and 94 deletions

View File

@@ -3,11 +3,11 @@
exports = module.exports = {
AddonsError: AddonsError,
getAddons: getAddons,
getAddon: getAddon,
configureAddon: configureAddon,
getServices: getServices,
getService: getService,
configureService: configureService,
getLogs: getLogs,
restartAddon: restartAddon,
restartService: restartService,
startAddons: startAddons,
updateAddonConfig: updateAddonConfig,
@@ -85,7 +85,6 @@ function AddonsError(reason, errorOrMessage) {
}
util.inherits(AddonsError, Error);
AddonsError.INTERNAL_ERROR = 'Internal Error';
AddonsError.NOT_SUPPORTED = 'Not Supported';
AddonsError.NOT_FOUND = 'Not Found';
AddonsError.NOT_ACTIVE = 'Not Active';
@@ -93,14 +92,6 @@ const NOOP = function (app, options, callback) { return callback(); };
const NOOP_CALLBACK = function (error) { if (error) debug(error); };
const RMADDONDIR_CMD = path.join(__dirname, 'scripts/rmaddondir.sh');
// TODO: maybe derive these defaults based on how many apps are using them
const DEFAULT_MEMORY_LIMITS = {
mysql: (1 + Math.round(os.totalmem()/(1024*1024*1024)/4)) * 256 * 1024 * 1024,
mongodb: (1 + Math.round(os.totalmem()/(1024*1024*1024)/4)) * 200 * 1024 * 1024,
postgresql: (1 + Math.round(os.totalmem()/(1024*1024*1024)/4)) * 256 * 1024 * 1024,
mail: Math.max((1 + Math.round(os.totalmem()/(1024*1024*1024)/4)) * 128, 256) * 1024 * 1024
};
// setup can be called multiple times for the same app (configure crash restart) and existing data must not be lost
// teardown is destructive. app data stored with the addon is lost
var KNOWN_ADDONS = {
@@ -110,8 +101,6 @@ var KNOWN_ADDONS = {
backup: NOOP,
restore: setupEmail,
clear: NOOP,
status: statusContainerAddon.bind(null, 'mail', 'CLOUDRON_MAIL_TOKEN'),
restart: restartContainerAddon.bind(null, 'email')
},
ldap: {
setup: setupLdap,
@@ -119,8 +108,6 @@ var KNOWN_ADDONS = {
backup: NOOP,
restore: setupLdap,
clear: NOOP,
status: null,
restart: null
},
localstorage: {
setup: setupLocalStorage, // docker creates the directory for us
@@ -128,8 +115,6 @@ var KNOWN_ADDONS = {
backup: NOOP, // no backup because it's already inside app data
restore: NOOP,
clear: clearLocalStorage,
status: null,
restart: null
},
mongodb: {
setup: setupMongoDb,
@@ -137,8 +122,6 @@ var KNOWN_ADDONS = {
backup: backupMongoDb,
restore: restoreMongoDb,
clear: clearMongodb,
status: statusContainerAddon.bind(null, 'mongodb', 'CLOUDRON_MONGODB_TOKEN'),
restart: restartContainerAddon.bind(null, 'mongodb')
},
mysql: {
setup: setupMySql,
@@ -146,8 +129,6 @@ var KNOWN_ADDONS = {
backup: backupMySql,
restore: restoreMySql,
clear: clearMySql,
status: statusContainerAddon.bind(null, 'mysql', 'CLOUDRON_MYSQL_TOKEN'),
restart: restartContainerAddon.bind(null, 'mysql')
},
oauth: {
setup: setupOauth,
@@ -155,8 +136,6 @@ var KNOWN_ADDONS = {
backup: NOOP,
restore: setupOauth,
clear: NOOP,
status: null,
restart: null
},
postgresql: {
setup: setupPostgreSql,
@@ -164,8 +143,6 @@ var KNOWN_ADDONS = {
backup: backupPostgreSql,
restore: restorePostgreSql,
clear: clearPostgreSql,
status: statusContainerAddon.bind(null, 'postgresql', 'CLOUDRON_POSTGRESQL_TOKEN'),
restart: restartContainerAddon.bind(null, 'postgresql')
},
recvmail: {
setup: setupRecvMail,
@@ -173,8 +150,6 @@ var KNOWN_ADDONS = {
backup: NOOP,
restore: setupRecvMail,
clear: NOOP,
status: null,
restart: null
},
redis: {
setup: setupRedis,
@@ -182,8 +157,6 @@ var KNOWN_ADDONS = {
backup: backupRedis,
restore: restoreRedis,
clear: clearRedis,
status: null,
restart: null
},
sendmail: {
setup: setupSendMail,
@@ -191,8 +164,6 @@ var KNOWN_ADDONS = {
backup: NOOP,
restore: setupSendMail,
clear: NOOP,
status: null,
restart: null
},
scheduler: {
setup: NOOP,
@@ -200,8 +171,6 @@ var KNOWN_ADDONS = {
backup: NOOP,
restore: NOOP,
clear: NOOP,
status: null,
restart: null
},
docker: {
setup: NOOP,
@@ -209,8 +178,34 @@ var KNOWN_ADDONS = {
backup: NOOP,
restore: NOOP,
clear: NOOP,
}
};
const KNOWN_SERVICES = {
mail: {
status: containerStatus.bind(null, 'mail', 'CLOUDRON_MAIL_TOKEN'),
restart: restartContainer.bind(null, 'mail'),
defaultMemoryLimit: Math.max((1 + Math.round(os.totalmem()/(1024*1024*1024)/4)) * 128, 256) * 1024 * 1024
},
mongodb: {
status: containerStatus.bind(null, 'mongodb', 'CLOUDRON_MONGODB_TOKEN'),
restart: restartContainer.bind(null, 'mongodb'),
defaultMemoryLimit: (1 + Math.round(os.totalmem()/(1024*1024*1024)/4)) * 200 * 1024 * 1024
},
mysql: {
status: containerStatus.bind(null, 'mysql', 'CLOUDRON_MYSQL_TOKEN'),
restart: restartContainer.bind(null, 'mysql'),
defaultMemoryLimit: (1 + Math.round(os.totalmem()/(1024*1024*1024)/4)) * 256 * 1024 * 1024
},
postgresql: {
status: containerStatus.bind(null, 'postgresql', 'CLOUDRON_POSTGRESQL_TOKEN'),
restart: restartContainer.bind(null, 'postgresql'),
defaultMemoryLimit: (1 + Math.round(os.totalmem()/(1024*1024*1024)/4)) * 256 * 1024 * 1024
},
docker: {
status: statusDocker,
restart: restartDocker
restart: restartDocker,
defaultMemoryLimit: 0
}
};
@@ -244,21 +239,16 @@ function dumpPath(addon, appId) {
}
}
function restartContainerAddon(addonName, callback) {
assert.strictEqual(typeof addonName, 'string');
function restartContainer(serviceName, callback) {
assert.strictEqual(typeof serviceName, 'string');
assert.strictEqual(typeof callback, 'function');
// only allow certain addon types to be started
const allowedAddons = ['email', 'mysql', 'mongodb', 'postgresql'];
if (allowedAddons.indexOf(addonName) === -1) return callback(new AddonsError(AddonsError.NOT_SUPPORTED));
assert(KNOWN_SERVICES[serviceName], `Unknown service ${serviceName}`);
// email container has a different name
const containerName = addonName === 'email' ? 'mail' : addonName;
docker.stopContainer(containerName, function (error) {
docker.stopContainer(serviceName, function (error) {
if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error));
docker.startContainer(containerName, function (error) {
docker.startContainer(serviceName, function (error) {
if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error));
callback(null);
@@ -266,7 +256,7 @@ function restartContainerAddon(addonName, callback) {
});
}
function statusContainerAddon(addonName, addonTokenName, callback) {
function containerStatus(addonName, addonTokenName, callback) {
assert.strictEqual(typeof addonName, 'string');
assert.strictEqual(typeof addonTokenName, 'string');
assert.strictEqual(typeof callback, 'function');
@@ -294,23 +284,22 @@ function statusContainerAddon(addonName, addonTokenName, callback) {
});
}
function getAddons(callback) {
function getServices(callback) {
assert.strictEqual(typeof callback, 'function');
// we currently list only addons which have a status function to report
var addons = Object.keys(KNOWN_ADDONS).filter(function (a) { return !!KNOWN_ADDONS[a].status; });
let services = Object.keys(KNOWN_SERVICES);
callback(null, addons);
callback(null, services);
}
function getAddon(addonName, callback) {
assert.strictEqual(typeof addonName, 'string');
function getService(serviceName, callback) {
assert.strictEqual(typeof serviceName, 'string');
assert.strictEqual(typeof callback, 'function');
if (!KNOWN_ADDONS[addonName]) return callback(new AddonsError(AddonsError.NOT_FOUND));
if (!KNOWN_SERVICES[serviceName]) return callback(new AddonsError(AddonsError.NOT_FOUND));
var tmp = {
name: addonName,
name: serviceName,
status: null,
config: {
// If a property is not set then we cannot change it through the api, see below
@@ -322,18 +311,15 @@ function getAddon(addonName, callback) {
settings.getPlatformConfig(function (error, platformConfig) {
if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error));
if (platformConfig[addonName] && platformConfig[addonName].memory && platformConfig[addonName].memorySwap) {
tmp.config.memory = platformConfig[addonName].memory;
tmp.config.memorySwap = platformConfig[addonName].memorySwap;
} else if (DEFAULT_MEMORY_LIMITS[addonName]) {
tmp.config.memory = DEFAULT_MEMORY_LIMITS[addonName];
if (platformConfig[serviceName] && platformConfig[serviceName].memory && platformConfig[serviceName].memorySwap) {
tmp.config.memory = platformConfig[serviceName].memory;
tmp.config.memorySwap = platformConfig[serviceName].memorySwap;
} else if (KNOWN_SERVICES[serviceName].defaultMemoryLimit) {
tmp.config.memory = KNOWN_SERVICES[serviceName].defaultMemoryLimit;
tmp.config.memorySwap = tmp.config.memory * 2;
}
// we are done if the addon has no specific status function
if (!KNOWN_ADDONS[addonName].status) return callback(null, tmp);
KNOWN_ADDONS[addonName].status(function (error, result) {
KNOWN_SERVICES[serviceName].status(function (error, result) {
if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error));
tmp.status = result.status;
@@ -346,24 +332,24 @@ function getAddon(addonName, callback) {
});
}
function configureAddon(addonName, data, callback) {
assert.strictEqual(typeof addonName, 'string');
function configureService(serviceName, data, callback) {
assert.strictEqual(typeof serviceName, 'string');
assert.strictEqual(typeof data, 'object');
assert.strictEqual(typeof callback, 'function');
if (!KNOWN_ADDONS[addonName]) return callback(new AddonsError(AddonsError.NOT_FOUND));
if (!KNOWN_SERVICES[serviceName]) return callback(new AddonsError(AddonsError.NOT_FOUND));
settings.getPlatformConfig(function (error, platformConfig) {
if (error) return callback(new AddonsError(AddonsError.INTERNAL_ERROR, error));
if (!platformConfig[addonName]) platformConfig[addonName] = {};
if (!platformConfig[serviceName]) platformConfig[serviceName] = {};
// if not specified we clear the entry and use defaults
if (!data.memory || !data.memorySwap) {
delete platformConfig[addonName];
delete platformConfig[serviceName];
} else {
platformConfig[addonName].memory = data.memory;
platformConfig[addonName].memorySwap = data.memorySwap;
platformConfig[serviceName].memory = data.memory;
platformConfig[serviceName].memorySwap = data.memorySwap;
}
settings.setPlatformConfig(platformConfig, function (error) {
@@ -424,14 +410,13 @@ function getLogs(addonName, options, callback) {
callback(null, transformStream);
}
function restartAddon(addon, callback) {
assert.strictEqual(typeof addon, 'string');
function restartService(serviceName, callback) {
assert.strictEqual(typeof serviceName, 'string');
assert.strictEqual(typeof callback, 'function');
if (!KNOWN_ADDONS[addon]) return callback(new AddonsError(AddonsError.NOT_FOUND));
if (!KNOWN_ADDONS[addon].restart) return callback(null);
if (!KNOWN_SERVICES[serviceName]) return callback(new AddonsError(AddonsError.NOT_FOUND));
KNOWN_ADDONS[addon].restart(callback);
KNOWN_ADDONS[serviceName].restart(callback);
}
function getAddonDetails(containerName, tokenEnvName, callback) {
@@ -613,19 +598,19 @@ function updateAddonConfig(platformConfig, callback) {
debug('updateAddonConfig: %j', platformConfig);
// TODO: this should possibly also rollback memory to default
async.eachSeries([ 'mysql', 'postgresql', 'mail', 'mongodb' ], function iterator(containerName, iteratorCallback) {
const containerConfig = platformConfig[containerName];
async.eachSeries([ 'mysql', 'postgresql', 'mail', 'mongodb' ], function iterator(serviceName, iteratorCallback) {
const containerConfig = platformConfig[serviceName];
let memory, memorySwap;
if (containerConfig && containerConfig.memory && containerConfig.memorySwap) {
memory = containerConfig.memory;
memorySwap = containerConfig.memorySwap;
} else {
memory = DEFAULT_MEMORY_LIMITS[containerName];
memory = KNOWN_SERVICES[serviceName].defaultMemoryLimit;
memorySwap = memory * 2;
}
const args = `update --memory ${memory} --memory-swap ${memorySwap} ${containerName}`.split(' ');
shell.spawn(`update${containerName}`, '/usr/bin/docker', args, { }, iteratorCallback);
const args = `update --memory ${memory} --memory-swap ${memorySwap} ${serviceName}`.split(' ');
shell.spawn(`update${serviceName}`, '/usr/bin/docker', args, { }, iteratorCallback);
}, callback);
}