Skip to content

Commit

Permalink
Adds docker plugin (#460)
Browse files Browse the repository at this point in the history
  • Loading branch information
alanzanattadev authored and GauthierPLM committed Dec 6, 2018
1 parent a0a788b commit 363eef7
Show file tree
Hide file tree
Showing 11 changed files with 341 additions and 2 deletions.
1 change: 1 addition & 0 deletions images/plugins/docker.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions lib/ExecutionControlEpic/ConsoleFeature/Epics/ConsoleEpics.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import Rx from "rxjs";
import { addConsoleLogsForTask } from "../Actions/AddConsoleLog";
import { addConsoleSource } from "../Actions/AddConsoleSource";
import { addBufferedLogsForTask } from "../Actions/AddBufferedLogs";
import {
ConsoleLogError,
Expand Down Expand Up @@ -39,6 +40,11 @@ const consoleEpic = () => (action$: any) => {
}),
),

action$
.ofType("ADD_PLAN_CONFIGURATION")
.filter(action => action.payload.ownSource)
.map(action => addConsoleSource(action.payload.name, true)),

action$.ofType("FEATURE_LOAD").map(action =>
addConsoleLogsForTask({
...molecule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import { Map } from "immutable";

const initialState = Map().setIn(["Molecule"], ["Molecule", true]);
const initialState = Map().setIn(["Molecule"], ["Molecule", false]);

export default function(
state: ConsoleSourcesReducer = initialState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export function languageClientGetActions(
observer.next(
// TODO - Remove hard-coded values
bufferConsoleLogsForTask({
source: "Molecule",
source: planConfig.ownSource ? planConfig.name : "Molecule",
color: "#592b71",
version: "0.4.0",
severity: data.type,
Expand Down
203 changes: 203 additions & 0 deletions lib/ExecutionControlEpic/Plugins/Docker/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
"use babel";
// @flow

import type {
GeneratedPlanObject,
PlanConfig,
} from "../../PlanConfigurationFeature/Types/types";
import type { PackageTesterResult } from "../../../ProjectSystemEpic/PackageFeature/Types/types";
import type { Plugin } from "../../DevtoolLoadingFeature/Types/types";
import path from "path";
import yaml from "js-yaml";
import fs from "fs";
import moment from "moment";

const plugin: Plugin = {
info: {
name: "docker",
dominantColor: "#339fee",
iconUri: "atom://molecule/images/plugins/docker.svg",
},

configSchema: {
type: "object",
schemas: {
command: {
type: "enum",
label: "command",
default: "start",
enum: [
{ value: "build", description: "build" },
{ value: "up", description: "up" },
{ value: "push", description: "push" },
],
},
serviceName: {
type: "string",
label: "service name",
placeholder: "database,web... empty for all",
default: "",
},
bin: {
type: "string",
label: "binary path",
placeholder: "docker-compose",
default: "docker-compose",
},
},
},

getStrategyForPlan(plan: PlanConfig) {
if (plan.config.command === "up") {
return {
strategy: {
type: "node",
path: path.join(__dirname, "lsp"),
cwd: path.dirname(plan.packageInfo.path),
lsp: true,
env: {
COMPOSE_COMMAND: JSON.stringify({
bin: plan.config.bin,
command: plan.config.command,
service: plan.config.serviceName,
configFile: plan.packageInfo.path,
}),
},
},
};
} else {
const command = `${plan.config.bin} -f ${plan.packageInfo.path} ${
plan.config.command
} ${plan.config.serviceName}`;
return {
strategy: {
type: "terminal",
cwd: path.dirname(plan.packageInfo.path),
command: command,
env: process.env,
},
controller: {
onData(data: string, taskAPI: TaskAPI, helperAPI: HelperAPI) {},
onError(err: any, taskAPI: TaskAPI, helperAPI: HelperAPI) {
taskAPI.diagnostics.setForWorkspace({
uri: "docker-compose",
diagnostics: [
{
range: {
start: { line: -1, character: -1 },
end: { line: -1, character: -1 },
},
severity: helperAPI.severity.error,
message: `Error: ${err.code | 1}`.toString(),
date: moment().unix(),
},
],
});
},
},
};
}
},

async isPackage(packagePath: string): PackageTesterResult {
if (!packagePath.endsWith(".yaml")) {
return false;
}

const rawData = await new Promise((resolve, reject) => {
fs.readFile(packagePath, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
const fileConfig = yaml.safeLoad(rawData);
return "version" in fileConfig && "services" in fileConfig;
},

async generatePlansForPackage(
packagePath: string,
): Promise<Array<GeneratedPlanObject>> {
const rawData = await new Promise((resolve, reject) => {
fs.readFile(packagePath, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
const fileConfig = yaml.safeLoad(rawData);

return Promise.resolve([
{
name: `up`,
value: {
command: "up",
serviceName: "",
bin: "docker-compose",
},
autorun: false,
ownSource: true,
},
{
name: `build`,
value: {
command: "build",
serviceName: "",
bin: "docker-compose",
},
autorun: false,
},
{
name: `push`,
value: {
command: "push",
serviceName: "",
bin: "docker-compose",
},
autorun: false,
},
...Object.keys(fileConfig.services || {})
.map(serviceName => [
{
name: `up ${serviceName}`,
value: {
command: "up",
serviceName: serviceName,
bin: "docker-compose",
},
autorun: false,
ownSource: true,
},
{
name: `${
fileConfig.services[serviceName].image ? "pull" : "build"
} ${serviceName}`,
value: {
command: `${
fileConfig.services[serviceName].image ? "pull" : "build"
}`,
serviceName: serviceName,
bin: "docker-compose",
},
autorun: false,
},
{
name: `push ${serviceName}`,
value: {
command: "push",
serviceName: serviceName,
bin: "docker-compose",
},
autorun: false,
},
])
.reduce((red, arr) => [...red, ...arr], []),
]);
},
};

export default plugin;
59 changes: 59 additions & 0 deletions lib/ExecutionControlEpic/Plugins/Docker/lsp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* eslint-disable */
const {
createMessageConnection,
StreamMessageReader,
StreamMessageWriter,
} = require("vscode-jsonrpc");

const { spawn, exec } = require("child_process");
const process = require("process");
const StreamSplitter = require("stream-splitter");
const stripAnsi = require("strip-ansi");

const connection = createMessageConnection(
new StreamMessageReader(process.stdin),
new StreamMessageWriter(process.stdout),
);

connection.onRequest("initialize", () => {
return new Promise((resolve, reject) => {
const { bin, command, service, configFile } = JSON.parse(
process.env.COMPOSE_COMMAND,
);

const dockerProcess = spawn(bin, ["-f", configFile, command, service], {
stderr: "pipe",
stdout: "pipe",
});
dockerProcess.on("error", err =>
connection.sendNotification("window/logMessage", {
type: 3,
message: `Error running Docker: ${err}`,
}),
);

const lines = dockerProcess.stdout.pipe(StreamSplitter("\n"));
lines.on("token", line =>
connection.sendNotification("window/logMessage", {
type: 1,
message: stripAnsi(line.toString()),
}),
);

connection.onRequest("shutdown", () => {
return new Promise(resolve => {
dockerProcess.kill();
exec(
`${bin} -f ${configFile} stop ${service}`,
{},
(err, stdout, stderr) => {
resolve();
},
);
});
});
resolve();
});
});

connection.listen();
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const generatePlansEpic = (action$: Observable, store: Store) => {
autoGenerated: true,
autoRun: planObject.autoRun,
pinned: planObject.autoRun === true ? true : false,
ownSource: planObject.ownSource || false,
}),
)
.filter(
Expand Down
6 changes: 6 additions & 0 deletions lib/molecule-dev-environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ export default {
plugins: {
type: "object",
properties: {
Docker: {
type: "boolean",
description: "Activate or not Docker in Molecule",
default: true,
},
Eslint: {
type: "boolean",
description: "Activate or not Eslint in Molecule",
Expand Down Expand Up @@ -142,6 +147,7 @@ export default {

// Bind plugins. Path should be relative to /lib/ExecutionControlEpic/Plugins/
[
"Docker/index.js",
"Eslint/index.js",
"Nightwatch/index.js",
"Flowtype.js",
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"flow-language-server": "^0.5.0",
"immutable": "^3.8.1",
"jest-cli": "^23.1.0",
"js-yaml": "^3.12.0",
"less": "^3.0.4",
"mocha": "^5.1.1",
"moment": "^2.19.2",
Expand All @@ -76,6 +77,7 @@
"remote-redux-devtools": "^0.5.7",
"rxjs": "^5.4.3",
"stream-buffers": "^3.0.1",
"stream-splitter": "^0.3.2",
"styled-components": "^3.2.6",
"tree-kill": "^1.2.0",
"vscode-jsonrpc": "^3.6.1",
Expand Down
49 changes: 49 additions & 0 deletions testsData/test-docker/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
version: "3"
services:
redis:
image: redis:alpine
ports:
- "6379"
networks:
- frontend

db:
image: postgres:9.4
networks:
- backend

vote:
image: dockersamples/examplevotingapp_vote:before
ports:
- "5000:80"
networks:
- frontend
depends_on:
- redis

result:
image: dockersamples/examplevotingapp_result:before
ports:
- "5001:80"
networks:
- backend
depends_on:
- db

worker:
image: dockersamples/examplevotingapp_worker
networks:
- frontend
- backend

visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
stop_grace_period: 1m30s
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"

networks:
frontend:
backend:
Loading

0 comments on commit 363eef7

Please sign in to comment.