Skip to content
This repository was archived by the owner on Nov 23, 2022. It is now read-only.

Commit 63b751d

Browse files
committed
Merge branch 'develop', prepare 3.1.0
2 parents 719df37 + 69a02d1 commit 63b751d

File tree

16 files changed

+1400
-1456
lines changed

16 files changed

+1400
-1456
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ docker run -d \
3939
# for SSH that holds allowed public keys
4040
-v /home/user/.ssh/authorized_keys:/root/.ssh/authorized_keys:ro
4141

42-
# this is your private key used for JWT
43-
-e EXO_PRIVATE_KEY=your_private_key
42+
# this is your private key used for JWT encryption
43+
-e EXO_PRIVATE_KEY=your_jwt_encryption_key
4444

4545
# this is used to tell traefik to which deployment current docker service belongs
4646
--label traefik.backend=exoframe-server

package.json

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"start": "node index.js",
99
"test": "NODE_ENV=testing jest --coverage --silent --maxWorkers=2 --ci",
1010
"coveralls": "cat ./coverage/lcov.info | coveralls",
11-
"build": "pkg -t node8.9.0-alpine -o exoframe-server ."
11+
"build": "pkg -t node8.11.3-alpine -o exoframe-server ."
1212
},
1313
"pkg": {
1414
"assets": "src/templates/*.html"
@@ -17,30 +17,30 @@
1717
"author": "Tim Ermilov <yamalight@gmail.com>",
1818
"license": "MIT",
1919
"dependencies": {
20-
"chokidar": "^2.0.3",
20+
"chokidar": "^2.0.4",
2121
"cors": "^2.8.4",
22-
"dockerode": "^2.5.5",
23-
"fastify": "^1.5.0",
24-
"fastify-auth": "^0.2.0",
22+
"dockerode": "^2.5.6",
23+
"fastify": "^1.11.2",
24+
"fastify-auth": "^0.3.0",
2525
"highland": "^2.13.0",
26-
"js-yaml": "^3.11.0",
27-
"jsonwebtoken": "^8.2.1",
28-
"lodash": "^4.17.10",
29-
"lokijs": "^1.5.4",
26+
"js-yaml": "^3.12.0",
27+
"jsonwebtoken": "^8.3.0",
28+
"lodash": "^4.17.11",
29+
"lokijs": "^1.5.5",
3030
"mkdirp": "^0.5.1",
31-
"node-fetch": "^2.1.2",
32-
"rimraf": "^2.6.1",
31+
"node-fetch": "^2.2.0",
32+
"rimraf": "^2.6.2",
3333
"semver-compare": "^1.0.0",
34-
"sshpk": "^1.14.1",
35-
"tar-fs": "^1.16.2",
36-
"uuid": "^3.2.1",
37-
"winston": "^2.4.2"
34+
"signale": "^1.3.0",
35+
"sshpk": "^1.14.2",
36+
"tar-fs": "^1.16.3",
37+
"uuid": "^3.3.2"
3838
},
3939
"devDependencies": {
40-
"coveralls": "^3.0.1",
41-
"get-port": "^3.2.0",
42-
"jest": "^22.4.4",
43-
"pkg": "^4.3.1"
40+
"coveralls": "^3.0.2",
41+
"get-port": "^4.0.0",
42+
"jest": "^23.6.0",
43+
"pkg": "^4.3.4"
4444
},
4545
"jest": {
4646
"testEnvironment": "node"

src/auth/index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ const loginRoutes = (fastify, opts, next) => {
5959
method: 'POST',
6060
path: '/login',
6161
async handler(request, reply) {
62-
const {body: {user, token, requestId}} = request;
62+
const {
63+
body: {user, token, requestId},
64+
} = request;
6365
const loginReq = reqCollection.findOne({uid: requestId});
6466

6567
if (!token || !user) {
@@ -84,7 +86,7 @@ const loginRoutes = (fastify, opts, next) => {
8486
return;
8587
}
8688
} catch (e) {
87-
reply.code(503).send({error: `Could not read public keys file! ${e.toString()}`});
89+
reply.code(405).send({error: `Could not read public keys file! ${e.toString()}`});
8890
return;
8991
}
9092

src/docker/start.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,16 @@ exports.start = async ({image, username, resultStream, existing = []}) => {
240240
Labels['traefik.frontend.rule'] = `Host:${host}`;
241241
}
242242

243+
// if rate-limit is set - add it to config
244+
if (config.rateLimit) {
245+
// we're using IP-based rate-limit
246+
Labels['traefik.frontend.rateLimit.extractorFunc'] = 'client.ip';
247+
// set values from project config
248+
Labels['traefik.frontend.rateLimit.rateSet.exo.period'] = config.rateLimit.period;
249+
Labels['traefik.frontend.rateLimit.rateSet.exo.average'] = String(config.rateLimit.average);
250+
Labels['traefik.frontend.rateLimit.rateSet.exo.burst'] = String(config.rateLimit.burst);
251+
}
252+
243253
// if running in swarm mode - run traefik as swarm service
244254
if (serverConfig.swarm) {
245255
// create service config

src/docker/templates/compose.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const updateCompose = ({username, baseName, serverConfig, composePath, util, res
2323
// read compose file
2424
const compose = yaml.safeLoad(fs.readFileSync(composePath, 'utf8'));
2525

26-
if (serverConfig.swarm && compose.version !== '3') {
26+
if (serverConfig.swarm && typeof compose.version === 'string' && !compose.version.startsWith('3')) {
2727
util.logger.debug('Compose file should be of version 3!');
2828
util.writeStatus(resultStream, {
2929
message: 'Running in swarm mode, can only deploy docker-compose file of version 3!',

src/docker/templates/dockerfile.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,6 @@ exports.executeTemplate = async ({username, resultStream, util, docker, existing
2525
const buildRes = await docker.build({username, resultStream});
2626
util.logger.debug('Build result:', buildRes);
2727

28-
// check for errors in build log
29-
if (
30-
buildRes.log
31-
.map(it => it.toLowerCase())
32-
.some(it => it.includes('error') || (it.includes('failed') && !it.includes('optional')))
33-
) {
34-
util.logger.debug('Build log conains error!');
35-
util.writeStatus(resultStream, {message: 'Build log contains errors!', level: 'error'});
36-
resultStream.end('');
37-
return;
38-
}
39-
4028
// start image
4129
const container = await docker.start(Object.assign({}, buildRes, {username, existing, resultStream}));
4230
util.logger.debug(container);

src/docker/templates/nginx.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,6 @@ exports.executeTemplate = async ({username, tempDockerDir, resultStream, util, d
3737
const buildRes = await docker.build({username, resultStream});
3838
util.logger.debug('Build result:', buildRes);
3939

40-
// check for errors in build log
41-
if (
42-
buildRes.log
43-
.map(it => it.toLowerCase())
44-
.some(it => it.includes('error') || (it.includes('failed') && !it.includes('optional')))
45-
) {
46-
util.logger.debug('Build log conains error!');
47-
util.writeStatus(resultStream, {message: 'Build log contains errors!', level: 'error'});
48-
resultStream.end('');
49-
return;
50-
}
51-
5240
// start image
5341
const container = await docker.start(Object.assign({}, buildRes, {username, existing, resultStream}));
5442
util.logger.debug(container);

src/docker/templates/node.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,18 +58,6 @@ exports.executeTemplate = async ({username, tempDockerDir, resultStream, util, d
5858
const buildRes = await docker.build({username, resultStream});
5959
util.logger.debug('Build result:', buildRes);
6060

61-
// check for errors in build log
62-
if (
63-
buildRes.log
64-
.map(it => it.toLowerCase())
65-
.some(it => it.includes('error') || (it.includes('failed') && !it.includes('optional')))
66-
) {
67-
util.logger.debug('Build log conains error!');
68-
util.writeStatus(resultStream, {message: 'Build log contains errors!', level: 'error'});
69-
resultStream.end('');
70-
return;
71-
}
72-
7361
// start image
7462
const container = await docker.start(Object.assign({}, buildRes, {username, existing, resultStream}));
7563
util.logger.debug(container.Name);

src/logger/index.js

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
1-
const winston = require('winston');
1+
const {Signale} = require('signale');
22

3+
// prepare level
34
const levelTesting = process.env.NODE_ENV === 'testing' ? 'error' : false;
45
const level = levelTesting || process.env.NODE_ENV === 'production' ? 'info' : 'debug';
56

6-
const logger = new winston.Logger({
7-
transports: [
8-
new winston.transports.Console({
9-
level,
10-
colorize: true,
11-
timestamp: true,
12-
prettyPrint: true,
13-
label: 'exoframe-server',
14-
}),
15-
],
7+
const logger = new Signale({
8+
scope: 'exoframe-server',
9+
types: {
10+
debug: {
11+
stream: level === 'debug' ? [process.stdout] : [],
12+
},
13+
info: {
14+
stream: level === 'info' ? [process.stdout] : [],
15+
},
16+
warn: {
17+
stream: level === 'info' ? [process.stdout] : [],
18+
},
19+
},
1620
});
1721

1822
module.exports = logger;

src/routes/deploy.js

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,38 @@ const deploy = async ({username, existing, resultStream}) => {
6868
await template.executeTemplate(templateProps);
6969
};
7070

71+
const scheduleCleanup = ({username, project, existing}) => {
72+
process.nextTick(async () => {
73+
// wait a bit for it to start
74+
await sleep(WAIT_TIME);
75+
76+
// get all current containers
77+
const containers = await docker.listContainers();
78+
// find containers for current user and project
79+
const running = containers.filter(
80+
c => c.Labels['exoframe.user'] === username && c.Labels['exoframe.project'] === project
81+
);
82+
83+
// filter out old container that don't have new containers
84+
// that are already up and running
85+
const toRemove = existing.filter(container => {
86+
const newInstance = running.find(runningContainer =>
87+
util.compareNames(container.Labels['exoframe.name'], runningContainer.Labels['exoframe.name'])
88+
);
89+
return newInstance && newInstance.State === 'running' && newInstance.Status.toLowerCase().includes('up');
90+
});
91+
92+
// remove old containers
93+
await Promise.all(toRemove.map(removeContainer));
94+
95+
// if not done - schedule with remaining containers
96+
if (toRemove.length !== existing.length) {
97+
const notRemoved = existing.filter(c => !toRemove.find(rc => rc.Id === c.Id));
98+
scheduleCleanup({username, project, existing: notRemoved});
99+
}
100+
});
101+
};
102+
71103
module.exports = fastify => {
72104
fastify.route({
73105
method: 'POST',
@@ -138,13 +170,7 @@ module.exports = fastify => {
138170
// deploy new versions
139171
deploy({username, payload: request.payload, resultStream});
140172
// schedule cleanup
141-
process.nextTick(async () => {
142-
// wait a bit for it to start
143-
await sleep(WAIT_TIME);
144-
145-
// remove old containers
146-
await Promise.all(existing.map(removeContainer));
147-
});
173+
scheduleCleanup({username, project, existing});
148174
// reply with deploy stream
149175
reply.code(200).send(new Readable().wrap(resultStream));
150176
},

0 commit comments

Comments
 (0)