Rework cpuShares into cpuQuota
cpuShares is the relative weight wrt other apps. This is used when there is contention for CPU. If we want this, maybe we implement a UI where we show all the apps and let the user re-order them. As it stands, it is confusing. cpuQuota is a more straightforward "hard limit" of the CPU% that you want the app to consume. Can be tested with : stress -c 8 -t 20s
This commit is contained in:
34
src/apps.js
34
src/apps.js
@@ -32,7 +32,7 @@ exports = module.exports = {
|
||||
setIcon,
|
||||
setTags,
|
||||
setMemoryLimit,
|
||||
setCpuShares,
|
||||
setCpuQuota,
|
||||
setMounts,
|
||||
setAutomaticBackup,
|
||||
setAutomaticUpdate,
|
||||
@@ -163,7 +163,6 @@ const appstore = require('./appstore.js'),
|
||||
manifestFormat = require('cloudron-manifestformat'),
|
||||
notifications = require('./notifications.js'),
|
||||
once = require('./once.js'),
|
||||
os = require('os'),
|
||||
path = require('path'),
|
||||
paths = require('./paths.js'),
|
||||
PassThrough = require('stream').PassThrough,
|
||||
@@ -173,7 +172,6 @@ const appstore = require('./appstore.js'),
|
||||
services = require('./services.js'),
|
||||
shell = require('./shell.js'),
|
||||
storage = require('./storage.js'),
|
||||
system = require('./system.js'),
|
||||
tasks = require('./tasks.js'),
|
||||
tgz = require('./backupformat/tgz.js'),
|
||||
TransformStream = require('stream').Transform,
|
||||
@@ -185,7 +183,7 @@ const appstore = require('./appstore.js'),
|
||||
_ = require('underscore');
|
||||
|
||||
const APPS_FIELDS_PREFIXED = [ 'apps.id', 'apps.appStoreId', 'apps.installationState', 'apps.errorJson', 'apps.runState',
|
||||
'apps.health', 'apps.containerId', 'apps.manifestJson', 'apps.accessRestrictionJson', 'apps.memoryLimit', 'apps.cpuShares',
|
||||
'apps.health', 'apps.containerId', 'apps.manifestJson', 'apps.accessRestrictionJson', 'apps.memoryLimit', 'apps.cpuQuota',
|
||||
'apps.label', 'apps.tagsJson', 'apps.taskId', 'apps.reverseProxyConfigJson', 'apps.servicesConfigJson', 'apps.operatorsJson',
|
||||
'apps.sso', 'apps.debugModeJson', 'apps.enableBackup', 'apps.proxyAuth', 'apps.containerIp', 'apps.crontab',
|
||||
'apps.creationTime', 'apps.updateTime', 'apps.enableAutomaticUpdate', 'apps.upstreamUri',
|
||||
@@ -408,10 +406,10 @@ function validateMemoryLimit(manifest, memoryLimit) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function validateCpuShares(cpuShares) {
|
||||
assert.strictEqual(typeof cpuShares, 'number');
|
||||
function validateCpuQuota(cpuQuota) {
|
||||
assert.strictEqual(typeof cpuQuota, 'number');
|
||||
|
||||
if (cpuShares < 2 || cpuShares > 1024) return new BoxError(BoxError.BAD_FIELD, 'cpuShares has to be between 2 and 1024');
|
||||
if (cpuQuota < 1 || cpuQuota > 100) return new BoxError(BoxError.BAD_FIELD, 'cpuQuota has to be between 1 and 100');
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -574,7 +572,7 @@ function removeInternalFields(app) {
|
||||
const result = _.pick(app,
|
||||
'id', 'appStoreId', 'installationState', 'error', 'runState', 'health', 'taskId',
|
||||
'subdomain', 'domain', 'fqdn', 'certificate', 'crontab', 'upstreamUri',
|
||||
'accessRestriction', 'manifest', 'portBindings', 'iconUrl', 'memoryLimit', 'cpuShares', 'operators',
|
||||
'accessRestriction', 'manifest', 'portBindings', 'iconUrl', 'memoryLimit', 'cpuQuota', 'operators',
|
||||
'sso', 'debugMode', 'reverseProxyConfig', 'enableBackup', 'creationTime', 'updateTime', 'ts', 'tags',
|
||||
'label', 'secondaryDomains', 'redirectDomains', 'aliasDomains', 'env', 'enableAutomaticUpdate',
|
||||
'storageVolumeId', 'storageVolumePrefix', 'mounts', 'enableTurn', 'enableRedis',
|
||||
@@ -834,7 +832,7 @@ async function add(id, appStoreId, manifest, subdomain, domain, portBindings, da
|
||||
accessRestriction = data.accessRestriction || null,
|
||||
accessRestrictionJson = JSON.stringify(accessRestriction),
|
||||
memoryLimit = data.memoryLimit || 0,
|
||||
cpuShares = data.cpuShares || 512,
|
||||
cpuQuota = data.cpuQuota || 100,
|
||||
installationState = data.installationState,
|
||||
runState = data.runState,
|
||||
sso = 'sso' in data ? data.sso : null,
|
||||
@@ -858,11 +856,11 @@ async function add(id, appStoreId, manifest, subdomain, domain, portBindings, da
|
||||
const queries = [];
|
||||
|
||||
queries.push({
|
||||
query: 'INSERT INTO apps (id, appStoreId, manifestJson, installationState, runState, accessRestrictionJson, memoryLimit, cpuShares, '
|
||||
query: 'INSERT INTO apps (id, appStoreId, manifestJson, installationState, runState, accessRestrictionJson, memoryLimit, cpuQuota, '
|
||||
+ 'sso, debugModeJson, mailboxName, mailboxDomain, label, tagsJson, reverseProxyConfigJson, servicesConfigJson, icon, '
|
||||
+ 'enableMailbox, mailboxDisplayName, upstreamUri, enableTurn, enableRedis) '
|
||||
+ ' VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
args: [ id, appStoreId, manifestJson, installationState, runState, accessRestrictionJson, memoryLimit, cpuShares,
|
||||
args: [ id, appStoreId, manifestJson, installationState, runState, accessRestrictionJson, memoryLimit, cpuQuota,
|
||||
sso, debugModeJson, mailboxName, mailboxDomain, label, tagsJson, reverseProxyConfigJson, servicesConfigJson, icon,
|
||||
enableMailbox, mailboxDisplayName, upstreamUri, enableTurn, enableRedis ]
|
||||
});
|
||||
@@ -1568,25 +1566,25 @@ async function setMemoryLimit(app, memoryLimit, auditSource) {
|
||||
return { taskId };
|
||||
}
|
||||
|
||||
async function setCpuShares(app, cpuShares, auditSource) {
|
||||
async function setCpuQuota(app, cpuQuota, auditSource) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof cpuShares, 'number');
|
||||
assert.strictEqual(typeof cpuQuota, 'number');
|
||||
assert.strictEqual(typeof auditSource, 'object');
|
||||
|
||||
const appId = app.id;
|
||||
let error = checkAppState(app, exports.ISTATE_PENDING_RESIZE);
|
||||
if (error) throw error;
|
||||
|
||||
error = validateCpuShares(cpuShares);
|
||||
error = validateCpuQuota(cpuQuota);
|
||||
if (error) throw error;
|
||||
|
||||
const task = {
|
||||
args: {},
|
||||
values: { cpuShares }
|
||||
values: { cpuQuota }
|
||||
};
|
||||
const taskId = await safe(addTask(appId, exports.ISTATE_PENDING_RESIZE, task, auditSource));
|
||||
|
||||
await eventlog.add(eventlog.ACTION_APP_CONFIGURE, auditSource, { appId, app, cpuShares, taskId });
|
||||
await eventlog.add(eventlog.ACTION_APP_CONFIGURE, auditSource, { appId, app, cpuQuota, taskId });
|
||||
|
||||
return { taskId };
|
||||
}
|
||||
@@ -2338,7 +2336,7 @@ async function clone(app, data, user, auditSource) {
|
||||
|
||||
const icons = await getIcons(app.id);
|
||||
|
||||
const dolly = _.pick(app, 'memoryLimit', 'cpuShares', 'crontab', 'reverseProxyConfig', 'env', 'servicesConfig', 'tags',
|
||||
const dolly = _.pick(app, 'memoryLimit', 'cpuQuota', 'crontab', 'reverseProxyConfig', 'env', 'servicesConfig', 'tags',
|
||||
'enableMailbox', 'mailboxDisplayName', 'mailboxName', 'mailboxDomain', 'enableInbox', 'inboxName', 'inboxDomain',
|
||||
'enableTurn', 'enableRedis', 'mounts', 'enableBackup', 'enableAutomaticUpdate', 'accessRestriction', 'operators', 'sso');
|
||||
|
||||
@@ -2902,7 +2900,7 @@ async function loadConfig(app) {
|
||||
const appConfig = safe.JSON.parse(safe.fs.readFileSync(path.join(paths.APPS_DATA_DIR, app.id + '/config.json')));
|
||||
let data = {};
|
||||
if (appConfig) {
|
||||
data = _.pick(appConfig, 'memoryLimit', 'cpuShares', 'enableBackup', 'reverseProxyConfig', 'env', 'servicesConfig', 'label', 'tags', 'enableAutomaticUpdate');
|
||||
data = _.pick(appConfig, 'memoryLimit', 'cpuQuota', 'enableBackup', 'reverseProxyConfig', 'env', 'servicesConfig', 'label', 'tags', 'enableAutomaticUpdate');
|
||||
}
|
||||
|
||||
const icon = safe.fs.readFileSync(path.join(paths.APPS_DATA_DIR, app.id + '/icon.png'));
|
||||
|
||||
Reference in New Issue
Block a user