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

Commit ca01102

Browse files
committed
Merge branch 'develop', prepare 0.20.0
2 parents 51b228a + 42eeba5 commit ca01102

File tree

8 files changed

+196
-104
lines changed

8 files changed

+196
-104
lines changed

src/docker/build.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ const tar = require('tar-fs');
44
// our modules
55
const logger = require('../logger');
66
const docker = require('./docker');
7-
const {tempDockerDir, getProjectConfig, tagFromConfig} = require('../util');
7+
const {tempDockerDir, getProjectConfig, tagFromConfig, writeStatus} = require('../util');
88

9-
module.exports = ({username}) =>
9+
module.exports = ({username, resultStream}) =>
1010
new Promise(async (resolve, reject) => {
1111
// get packed stream
1212
const tarStream = tar.pack(tempDockerDir);
@@ -17,6 +17,7 @@ module.exports = ({username}) =>
1717
// construct image tag
1818
const tag = tagFromConfig({username, config});
1919
logger.debug('building with tag:', tag);
20+
writeStatus(resultStream, {message: `Building image with tag: ${tag}`, level: 'verbose'});
2021

2122
// deploy as docker
2223
const log = [];
@@ -33,17 +34,21 @@ module.exports = ({username}) =>
3334
// process log data
3435
if (data.stream && data.stream.length) {
3536
log.push(data.stream);
37+
writeStatus(resultStream, {message: data.stream, level: 'verbose'});
3638
} else if (data.error && data.error.length) {
3739
// process error data
3840
log.push(data.error);
41+
writeStatus(resultStream, {message: data.error, level: 'error'});
3942
hasErrors = true;
4043
} else {
4144
// push everything else as-is
4245
log.push(s);
46+
writeStatus(resultStream, {message: s, level: 'verbose'});
4347
}
4448
} catch (e) {
4549
if (s && s.length) {
4650
log.push(s);
51+
writeStatus(resultStream, {message: s, level: 'verbose'});
4752
}
4853
}
4954
});

src/docker/dockercompose/index.js

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,18 @@ const fs = require('fs');
44
const path = require('path');
55
const yaml = require('js-yaml');
66
const uuid = require('uuid');
7-
const {exec} = require('child_process');
7+
const {spawn} = require('child_process');
88

99
// our packages
10-
const {tempDockerDir, getProjectConfig} = require('../../util');
10+
const {tempDockerDir, getProjectConfig, writeStatus} = require('../../util');
1111

1212
// compose file path
1313
const composePath = path.join(tempDockerDir, 'docker-compose.yml');
1414

1515
exports.hasCompose = () => {
1616
// if project already has docker-compose - just exit
1717
try {
18-
fs.readFileSync(path.join(tempDockerDir, 'docker-compose.yml'));
18+
fs.readFileSync(composePath);
1919
return true;
2020
} catch (e) {
2121
return false;
@@ -72,20 +72,22 @@ exports.updateCompose = ({username}) => {
7272
return compose;
7373
};
7474

75-
exports.executeCompose = () =>
76-
new Promise((resolve, reject) => {
77-
exec(
78-
'docker-compose up -d',
79-
{
80-
cwd: tempDockerDir,
81-
},
82-
(err, stdout, stderr) => {
83-
if (err) {
84-
reject(err);
85-
return;
86-
}
75+
exports.executeCompose = resultStream =>
76+
new Promise(resolve => {
77+
const dc = spawn('docker-compose', ['up', '-d'], {cwd: tempDockerDir});
8778

88-
resolve({log: `${stdout.toString()}\n${stderr.toString()}`});
89-
}
90-
);
79+
dc.stdout.on('data', data => {
80+
const message = data.toString().replace(/\n$/, '');
81+
const hasError = message.toLowerCase().includes('error');
82+
writeStatus(resultStream, {message, level: hasError ? 'error' : 'info'});
83+
});
84+
dc.stderr.on('data', data => {
85+
const message = data.toString().replace(/\n$/, '');
86+
const hasError = message.toLowerCase().includes('error');
87+
writeStatus(resultStream, {message, level: hasError ? 'error' : 'info'});
88+
});
89+
dc.on('exit', code => {
90+
writeStatus(resultStream, {message: `Docker-compose exited with code ${code.toString()}`, level: 'info'});
91+
resolve(code.toString());
92+
});
9193
});

src/docker/dockerfile/index.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@ const path = require('path');
44

55
// our packages
66
const logger = require('../../logger');
7-
const {tempDockerDir} = require('../../util');
7+
const {tempDockerDir, writeStatus} = require('../../util');
88
const nodeDockerfile = require('./node-docker');
99
const nginxDockerfile = require('./nginx-dockerfile');
1010

11-
module.exports = () => {
11+
module.exports = resultStream => {
1212
// if project already has dockerfile - just exit
1313
try {
1414
fs.readFileSync(path.join(tempDockerDir, 'Dockerfile'));
1515
logger.debug('Project already has dockerfile!');
16+
writeStatus(resultStream, {message: 'Deploying Dockerfile project..', level: 'info'});
1617
return;
1718
} catch (e) {
1819
logger.debug('No dockerfile found, going to generate a new one..');
@@ -25,14 +26,18 @@ module.exports = () => {
2526
// if it's a node.js project
2627
if (filesList.includes('package.json')) {
2728
dockerfile = nodeDockerfile({hasYarn: filesList.includes('yarn.lock')});
29+
writeStatus(resultStream, {message: 'Deploying Node.js project..', level: 'info'});
2830
} else if (filesList.includes('index.html')) {
2931
dockerfile = nginxDockerfile;
32+
writeStatus(resultStream, {message: 'Deploying Static HTML project..', level: 'info'});
3033
}
3134

3235
logger.debug('Using dockerfile:', dockerfile);
36+
writeStatus(resultStream, {message: 'Using dockerfile..', dockerfile, level: 'verbose'});
3337

3438
if (!dockerfile) {
3539
logger.error('No suitable dockerfile found');
40+
writeStatus(resultStream, {message: 'Error! No suitable dockerfile found!', level: 'error'});
3641
throw new Error('No suitable dockerfile found');
3742
}
3843

src/docker/start.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// our modules
22
const docker = require('./docker');
3-
const {getProjectConfig, baseNameFromImage, nameFromImage, projectFromConfig} = require('../util');
3+
const {getProjectConfig, baseNameFromImage, nameFromImage, projectFromConfig, writeStatus} = require('../util');
44
const {getConfig} = require('../config');
55

6-
module.exports = async ({image, username}) => {
6+
module.exports = async ({image, username, resultStream}) => {
77
const baseName = baseNameFromImage(image);
88
const name = nameFromImage(image);
99

@@ -70,6 +70,8 @@ module.exports = async ({image, username}) => {
7070
containerConfig.Labels['traefik.frontend.rule'] = `Host:${host}`;
7171
}
7272

73+
writeStatus(resultStream, {message: 'Starting container with following config:', containerConfig, level: 'verbose'});
74+
7375
// create container
7476
const container = await docker.createContainer(containerConfig);
7577

@@ -84,5 +86,7 @@ module.exports = async ({image, username}) => {
8486
// start container
8587
await container.start();
8688

89+
writeStatus(resultStream, {message: 'Container successfully started!', level: 'verbose'});
90+
8791
return container.inspect();
8892
};

src/routes/deploy.js

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,36 @@
11
// npm modules
2+
const _ = require('highland');
3+
const {Readable} = require('stream');
24

35
// our modules
46
const logger = require('../logger');
57
const {hasCompose, updateCompose, executeCompose} = require('../docker/dockercompose');
68
const generateDockerfile = require('../docker/dockerfile');
79
const build = require('../docker/build');
810
const start = require('../docker/start');
9-
const {sleep, cleanTemp, unpack, getProjectConfig, projectFromConfig} = require('../util');
11+
const {sleep, cleanTemp, unpack, getProjectConfig, projectFromConfig, writeStatus} = require('../util');
1012
const docker = require('../docker/docker');
1113
const {removeContainer} = require('../docker/util');
1214

1315
// time to wait before removing old projects on update
1416
const WAIT_TIME = 5000;
1517

1618
// deployment from unpacked files
17-
const deploy = async ({username}) => {
19+
const deploy = async ({username, resultStream}) => {
1820
// check if it's a docker-compose project
1921
if (hasCompose()) {
2022
// if it does - run compose workflow
2123
logger.debug('Docker-compose file found, executing compose workflow..');
24+
writeStatus(resultStream, {message: 'Deploying docker-compose project..', level: 'info'});
2225

2326
// update compose file with project params
2427
const composeConfig = updateCompose({username});
2528
logger.debug('Compose modified:', composeConfig);
29+
writeStatus(resultStream, {message: 'Compose file modified', data: composeConfig, level: 'verbose'});
2630

2731
// execute compose
28-
const {log} = await executeCompose();
29-
logger.debug('Compose executed:', log);
32+
const exitCode = await executeCompose(resultStream);
33+
logger.debug('Compose executed, exit code:', exitCode);
3034

3135
// get container infos
3236
const allContainers = await docker.listContainers({all: true});
@@ -38,36 +42,43 @@ const deploy = async ({username}) => {
3842
.map(container => container.inspect())
3943
);
4044
// return them
41-
return [{status: 'success', deployments}, 200];
45+
writeStatus(resultStream, {message: 'Deployment success!', deployments, level: 'info'});
46+
resultStream.end('');
47+
return;
4248
}
4349

4450
// generate dockerfile
45-
generateDockerfile();
51+
generateDockerfile(resultStream);
4652

4753
// build docker image
4854
try {
49-
const buildRes = await build({username});
50-
logger.debug('build result:', buildRes);
55+
const buildRes = await build({username, resultStream});
56+
logger.debug('Build result:', buildRes);
5157

5258
// check for errors in build log
5359
if (buildRes.log.map(it => it.toLowerCase()).some(it => it.includes('error') || it.includes('failed'))) {
54-
logger.debug('build log conains error!');
55-
return [{status: 'error', result: buildRes}, 400];
60+
logger.debug('Build log conains error!');
61+
writeStatus(resultStream, {message: 'Build log contains errors!', level: 'error'});
62+
resultStream.end('');
63+
return;
5664
}
5765

5866
// start image
59-
const containerInfo = await start(Object.assign(buildRes, {username}));
67+
const containerInfo = await start(Object.assign({}, buildRes, {username, resultStream}));
6068
logger.debug(containerInfo.Name);
6169

6270
// clean temp folder
6371
await cleanTemp();
6472

6573
const containerData = docker.getContainer(containerInfo.Id);
6674
const container = await containerData.inspect();
67-
return [{status: 'success', deployments: [container]}, 200];
75+
// return new deployments
76+
writeStatus(resultStream, {message: 'Deployment success!', deployments: [container], level: 'info'});
77+
resultStream.end('');
6878
} catch (e) {
6979
logger.debug('build failed!', e);
70-
return [{status: 'error', result: e}, 400];
80+
writeStatus(resultStream, {message: e.error, error: e.error, log: e.log, level: 'error'});
81+
resultStream.end('');
7182
}
7283
};
7384

@@ -89,10 +100,12 @@ module.exports = server => {
89100
await cleanTemp();
90101
// unpack to temp folder
91102
await unpack(request.payload.path);
103+
// create new highland stream for results
104+
const resultStream = _();
92105
// run deploy
93-
const [response, code] = await deploy({username});
94-
// respond
95-
reply(response).code(code);
106+
deploy({username, resultStream});
107+
// reply with deploy stream
108+
reply(new Readable().wrap(resultStream)).code(200);
96109
},
97110
});
98111

@@ -125,9 +138,12 @@ module.exports = server => {
125138
c => c.Labels['exoframe.user'] === username && c.Labels['exoframe.project'] === project
126139
);
127140

141+
// create new highland stream for results
142+
const resultStream = _();
128143
// deploy new versions
129-
// run deploy
130-
const [response, code] = await deploy({username, payload: request.payload});
144+
deploy({username, payload: request.payload, resultStream});
145+
// reply with deploy stream
146+
reply(new Readable().wrap(resultStream)).code(200);
131147
// wait a bit for it to start
132148
await sleep(WAIT_TIME);
133149

@@ -140,9 +156,6 @@ module.exports = server => {
140156
logger.error('Error removing old deployment:', e);
141157
}
142158
}
143-
144-
// respond
145-
reply(response).code(code);
146159
},
147160
});
148161
};

src/util/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,5 @@ exports.projectFromConfig = ({username, config}) => {
4949
};
5050

5151
exports.sleep = time => new Promise(r => setTimeout(r, time));
52+
53+
exports.writeStatus = (stream, data) => stream.write(`${JSON.stringify(data)}\n`);

0 commit comments

Comments
 (0)