Skip to content

Commit

Permalink
Remote rendering: Support reading config from file (grafana#73)
Browse files Browse the repository at this point in the history
  • Loading branch information
marefr authored Dec 17, 2019
1 parent e1641c2 commit 89fce4f
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 92 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ node_modules
scripts
.prettierignore
.prettierrc.json
dev.json
Dockerfile
Makefile
plugin_start*
Expand Down
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ FROM base
COPY --from=build /usr/src/app/node_modules node_modules
COPY --from=build /usr/src/app/build build
COPY --from=build /usr/src/app/proto proto
COPY --from=build /usr/src/app/default.json config.json

EXPOSE 8081

ENTRYPOINT ["dumb-init", "--"]

CMD ["node", "build/app.js", "server", "--port=8081"]
CMD ["node", "build/app.js", "server", "--config=config.json"]
14 changes: 14 additions & 0 deletions default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"service": {
"port": 8081,
"metrics": {
"enabled": false,
"collectDefaultMetrics": true,
"buckets": [0.5, 1, 3, 5, 7, 10, 20, 30, 60]
},
"rendering": {
"chromeBin": null,
"ignoresHttpsErrors": false
}
}
}
14 changes: 14 additions & 0 deletions dev.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"service": {
"port": 8081,
"metrics": {
"enabled": true,
"collectDefaultMetrics": true,
"buckets": [0.5, 1, 3, 5, 7, 10, 20, 30, 60]
},
"rendering": {
"chromeBin": null,
"ignoresHttpsErrors": false
}
}
}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
"prettier:check": "prettier --list-different \"**/*.ts\"",
"prettier:write": "prettier --list-different \"**/*.ts\" --write",
"precommit": "npm run tslint & npm run typecheck",
"watch": "ENABLE_METRICS=true tsc-watch --onSuccess \"node build/app.js server --port=8080\"",
"watch": "tsc-watch --onSuccess \"node build/app.js server --config=dev.json\"",
"build": "tsc",
"start": "ENABLE_METRICS=true node build/app.js --port=8080"
"start": "node build/app.js --config=dev.json"
},
"dependencies": {
"@grpc/proto-loader": "^0.5.3",
Expand All @@ -24,6 +24,7 @@
"express-prom-bundle": "^5.1.5",
"google-protobuf": "3.5.0",
"grpc": "^1.24.2",
"lodash": "^4.17.15",
"minimist": "^1.2.0",
"morgan": "^1.9.0",
"mz": "^2.7.0",
Expand Down
60 changes: 50 additions & 10 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,68 @@
import { GrpcPlugin } from './grpc-plugin';
import { HttpServer } from './http-server';
import * as path from 'path';
import * as puppeteer from 'puppeteer';
import * as _ from 'lodash';
import { GrpcPlugin } from './plugin/grpc-plugin';
import { HttpServer } from './service/http-server';
import { ConsoleLogger, PluginLogger } from './logger';
import { newPluginBrowser, newServerBrowser } from './browser';
import { Browser } from './browser';
import * as minimist from 'minimist';
import { defaultPluginConfig, defaultServiceConfig, readJSONFileSync } from './config';

async function main() {
const argv = minimist(process.argv.slice(2));
const env = Object.assign({}, process.env);
const command = argv._[0];

if (command === undefined) {
const config = defaultPluginConfig;

if (env['GF_RENDERER_PLUGIN_IGNORE_HTTPS_ERRORS']) {
config.rendering.ignoresHttpsErrors = env['GF_RENDERER_PLUGIN_IGNORE_HTTPS_ERRORS'] === 'true';
}

if (env['GF_RENDERER_PLUGIN_CHROME_BIN']) {
config.rendering.chromeBin = env['GF_RENDERER_PLUGIN_CHROME_BIN'];
} else if ((process as any).pkg) {
const parts = puppeteer.executablePath().split(path.sep);
while (!parts[0].startsWith('chrome-')) {
parts.shift();
}

config.rendering.chromeBin = [path.dirname(process.execPath), ...parts].join(path.sep);
}

const logger = new PluginLogger();
const browser = newPluginBrowser(logger);
const plugin = new GrpcPlugin(logger, browser);
const browser = new Browser(config.rendering, logger);
const plugin = new GrpcPlugin(config, logger, browser);
plugin.start();
} else if (command === 'server') {
let config = defaultServiceConfig;
const logger = new ConsoleLogger();

if (!argv.port) {
logger.error('Specify http port using argument --port=5000');
return;
if (argv.config) {
try {
const fileConfig = readJSONFileSync(argv.config);
config = _.merge(config, fileConfig);
} catch (e) {
logger.error('failed to read config from path', argv.config, 'error', e);
return;
}
}

if (env['IGNORE_HTTPS_ERRORS']) {
config.rendering.ignoresHttpsErrors = env['IGNORE_HTTPS_ERRORS'] === 'true';
}

if (env['CHROME_BIN']) {
config.rendering.chromeBin = env['CHROME_BIN'];
}

if (env['ENABLE_METRICS']) {
config.service.metrics.enabled = env['ENABLE_METRICS'] === 'true';
}

const browser = newServerBrowser(logger);
const server = new HttpServer({ port: argv.port }, logger, browser);
const browser = new Browser(config.rendering, logger);
const server = new HttpServer(config, logger, browser);

server.start();
} else {
Expand Down
52 changes: 5 additions & 47 deletions src/browser.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,14 @@
import * as path from 'path';
import * as os from 'os';
import * as puppeteer from 'puppeteer';
import { Logger } from './logger';
import uniqueFilename = require('unique-filename');

export function newPluginBrowser(log: Logger): Browser {
const env = Object.assign({}, process.env);
let ignoreHTTPSErrors = false;

if (env['GF_RENDERER_PLUGIN_IGNORE_HTTPS_ERRORS']) {
ignoreHTTPSErrors = env['GF_RENDERER_PLUGIN_IGNORE_HTTPS_ERRORS'] === 'true';
}

let chromeBin: any;
if (env['GF_RENDERER_PLUGIN_CHROME_BIN']) {
chromeBin = env['GF_RENDERER_PLUGIN_CHROME_BIN'];
} else if ((process as any).pkg) {
const parts = puppeteer.executablePath().split(path.sep);
while (!parts[0].startsWith('chrome-')) {
parts.shift();
}

chromeBin = [path.dirname(process.execPath), ...parts].join(path.sep);
}

return new Browser(log, ignoreHTTPSErrors, chromeBin);
}

export function newServerBrowser(log: Logger): Browser {
const env = Object.assign({}, process.env);
let ignoreHTTPSErrors = false;

if (env['IGNORE_HTTPS_ERRORS']) {
ignoreHTTPSErrors = env['IGNORE_HTTPS_ERRORS'] === 'true';
}

let chromeBin: any;
if (env['CHROME_BIN']) {
chromeBin = env['CHROME_BIN'];
}

return new Browser(log, ignoreHTTPSErrors, chromeBin);
}
import { RenderingConfig } from './config';

export class Browser {
chromeBin?: string;
ignoreHTTPSErrors: boolean;

constructor(private log: Logger, ignoreHTTPSErrors: boolean, chromeBin?: string) {
this.ignoreHTTPSErrors = ignoreHTTPSErrors;
this.chromeBin = chromeBin;
}
constructor(private config: RenderingConfig, private log: Logger) {}

validateOptions(options) {
options.width = parseInt(options.width, 10) || 1000;
Expand Down Expand Up @@ -79,12 +37,12 @@ export class Browser {

const launcherOptions: any = {
env: env,
ignoreHTTPSErrors: this.ignoreHTTPSErrors,
ignoreHTTPSErrors: this.config.ignoresHttpsErrors,
args: ['--no-sandbox'],
};

if (this.chromeBin) {
launcherOptions.executablePath = this.chromeBin;
if (this.config.chromeBin) {
launcherOptions.executablePath = this.config.chromeBin;
}

browser = await puppeteer.launch(launcherOptions);
Expand Down
61 changes: 61 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import * as fs from 'fs';

export interface RenderingConfig {
chromeBin?: string;
ignoresHttpsErrors: boolean;
}

export interface ServiceConfig {
service: {
port: number;

metrics: {
enabled: boolean;
collectDefaultMetrics: boolean;
buckets: number[];
};
};
rendering: RenderingConfig;
}

export interface PluginConfig {
plugin: {
grpc: {
host: string;
port: number;
};
};
rendering: RenderingConfig;
}

const defaultRenderingConfig: RenderingConfig = {
chromeBin: undefined,
ignoresHttpsErrors: false,
};

export const defaultServiceConfig: ServiceConfig = {
service: {
port: 8081,
metrics: {
enabled: false,
collectDefaultMetrics: true,
buckets: [0.5, 1, 3, 5, 7, 10, 20, 30, 60],
},
},
rendering: defaultRenderingConfig,
};

export const defaultPluginConfig: PluginConfig = {
plugin: {
grpc: {
host: '127.0.0.1',
port: 50059,
},
},
rendering: defaultRenderingConfig,
};

export const readJSONFileSync = (filePath: string): any => {
const rawdata = fs.readFileSync(filePath, 'utf8');
return JSON.parse(rawdata);
};
31 changes: 20 additions & 11 deletions src/grpc-plugin.ts → src/plugin/grpc-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import * as grpc from 'grpc';
import * as protoLoader from '@grpc/proto-loader';
import { Logger } from './logger';
import { Browser } from './browser';
import { Logger } from '../logger';
import { Browser } from '../browser';
import { PluginConfig } from '../config';

const SERVER_ADDRESS = '127.0.0.1:50059';
const RENDERER_PROTO_PATH = __dirname + '/../proto/renderer.proto';
const HEALTH_PROTO_PATH = __dirname + '/../proto/health.proto';
const RENDERER_PROTO_PATH = __dirname + '/../../proto/renderer.proto';
const HEALTH_PROTO_PATH = __dirname + '/../../proto/health.proto';

export const renderPackageDef = protoLoader.loadSync(RENDERER_PROTO_PATH, {
keepCase: true,
Expand All @@ -27,11 +27,10 @@ export const rendererProtoDescriptor = grpc.loadPackageDefinition(renderPackageD
export const healthProtoDescriptor = grpc.loadPackageDefinition(healthPackageDef);

export class GrpcPlugin {
constructor(private log: Logger, private browser: Browser) {}
constructor(private config: PluginConfig, private log: Logger, private browser: Browser) {}

start() {
const server = new grpc.Server();

const grpcHealthV1: any = healthProtoDescriptor['grpc']['health']['v1'];
server.addService(grpcHealthV1.Health.service, {
check: this.check.bind(this),
Expand All @@ -41,15 +40,25 @@ export class GrpcPlugin {
render: this.render.bind(this),
});

server.bind(SERVER_ADDRESS, grpc.ServerCredentials.createInsecure());
const address = `${this.config.plugin.grpc.host}:${this.config.plugin.grpc.port}`;
const boundPortNumber = server.bind(address, grpc.ServerCredentials.createInsecure());
if (boundPortNumber === 0) {
throw new Error(`failed to bind address=${address}, boundPortNumber=${boundPortNumber}`);
}
server.start();

console.log(`1|1|tcp|${SERVER_ADDRESS}|grpc`);
console.log(`1|1|tcp|${this.config.plugin.grpc.host}:${boundPortNumber}|grpc`);

if (this.browser.chromeBin) {
this.log.info('Renderer plugin started', 'chromeBin', this.browser.chromeBin, 'ignoreHTTPSErrors', this.browser.ignoreHTTPSErrors);
this.log.info(
'Renderer plugin started',
'chromeBin',
this.config.rendering.chromeBin,
'ignoreHTTPSErrors',
this.config.rendering.ignoresHttpsErrors
);
} else {
this.log.info('Renderer plugin started', 'ignoreHttpsErrors', this.browser.ignoreHTTPSErrors);
this.log.info('Renderer plugin started', 'ignoreHttpsErrors', this.config.rendering.ignoresHttpsErrors);
}
}

Expand Down
Loading

0 comments on commit 89fce4f

Please sign in to comment.