UNPKG

gce-elastic-docker

Version:

A package to help setup Elasticsearch / Kibana clusters on Google Compute Engine.

198 lines (164 loc) 6.18 kB
import { writeFileSync } from 'fs'; import { removeSync } from 'fs-extra'; import * as tempy from 'tempy'; import { ChildNode } from '../child-node'; import { elastic_uploader } from '../elastic-uploader'; import { kibana_password_dir, kibana_users_env_var } from '../image'; import { INode, Node } from '../node'; import { NodeCreateOpts } from '../node-create-opts'; import { EndTask, FullTask, INodeCreateTasks } from '../tasks'; import { Utils } from '../utils'; export class NodeCreator { private child_node: ChildNode; private o: NodeCreateOpts; constructor(node: ChildNode, opts: NodeCreateOpts) { if (node.kibana && !opts.kibana_network_tag) { throw Error(`missing required kibana network tag for kibana node ${node.name}`); } this.child_node = node; this.o = opts; } create(): INodeCreateTasks { const tasks: INodeCreateTasks = { elastic_ready: new FullTask(), kibana_ready: new FullTask(), kso_upload: new FullTask(), main: new EndTask(), node_create: new FullTask(), scripts_upload: new FullTask(), sm_upload: new FullTask() }; process.nextTick(async() => { try { const node = await this._make_node(tasks.node_create); await this._wait_for_elastic(tasks.elastic_ready, node); await this._wait_for_kibana(tasks.kibana_ready, node); await this._upload_kso(tasks.kso_upload, node); await this._upload_scripts(tasks.scripts_upload, node); await this._upload_sm(tasks.sm_upload, node); tasks.main.end_resolve_cb(node); } catch (e) { tasks.main.end_reject_cb(e); } }); return tasks; } async partial_create() { return await this._make_node_no_task(); } private _get_create_cmd(env_file: string) { const merged_labels = this.child_node.get_merged_labels(); const lkeys = Object.keys(merged_labels); const k_tag_line = this.child_node.kibana ? ` --tags=${this.o.kibana_network_tag}` : ''; return `gcloud beta compute instances create-with-container ${this.child_node.name} ` + '--format=json ' + `--boot-disk-size=${this.child_node.dsize}GB ` + `--boot-disk-type=${this.child_node.dtype} ` + `--machine-type=${this.child_node.mtype} ` + `--zone=${this.child_node.zone} ` + `--service-account=${this.child_node.service_account} ` + // necessary to pull image `--container-image=${this.child_node.image} ` + '--container-restart-policy=always ' + '--container-privileged ' + // necessary to set memlock ulimit '--container-mount-host-path=mount-path=' + '/usr/share/elasticsearch/data,host-path=/home/es-data,mode=rw ' + `--container-mount-host-path=mount-path=${kibana_password_dir},` + 'host-path=/home/kibana-users,mode=rw ' + `--labels=${lkeys.map(k => `${k}=${merged_labels[k]}`).join(',')} ` + '--metadata=startup-script="' + `echo 'vm.max_map_count=${this.child_node.max_map_count}' > /etc/sysctl.conf; ` + 'sysctl -p; ' + 'mkdir -m 777 /home/es-data; ' + 'mkdir -m 777 /home/kibana-users;" ' + `--container-env-file=${env_file} ` + k_tag_line; } private async _make_node(task: FullTask): Promise<Node> { await task.start_resolve_cb(); let node; try { node = await this._make_node_no_task(); } catch (e) { this._stop_at_task(task, e); } task.end_resolve_cb(node); return node; } private async _make_node_no_task(): Promise<Node> { let tmp_env_file; try { tmp_env_file = this._make_temp_env_file(); const cmd = this._get_create_cmd(tmp_env_file); if (this.o.verbose) { console.log(`creating node ${this.child_node.name} w/ the following command:\n\n${cmd}`); } const res = await Utils.exec(cmd, this.o.verbose); removeSync(tmp_env_file); const dat = JSON.parse(<string> res); const copy: INode = JSON.parse(JSON.stringify(this.child_node)); copy.ip = dat[0].networkInterfaces[0].networkIP; copy.created = (new Date(dat[0].creationTimestamp)).valueOf(); return new Node(copy); } catch (e) { removeSync(tmp_env_file); throw e; } } private _make_temp_env_file() { const env = this.child_node.get_merged_env(); const kusers_env_value = this.o.get_kibana_users_env_value(); if (this.child_node.kibana && kusers_env_value) { env[kibana_users_env_var] = kusers_env_value; } const file = tempy.file(); const file_content = Object.keys(env).map(k => `${k}=${env[k]}`).join('\n'); writeFileSync(file, file_content); return file; } private _stop_at_task(task: FullTask, err) { task.end_reject_cb(err); throw err; } private async _upload_kso(task: FullTask, node: Node) { await task.start_resolve_cb(); let res; if (this.child_node.kibana) { try { res = await elastic_uploader.kso(node, this.o.kso, this.o.verbose); } catch (e) { this._stop_at_task(task, e); } } task.end_resolve_cb(res); } private async _upload_scripts(task: FullTask, node: Node) { await task.start_resolve_cb(); try { const res = await elastic_uploader.scripts(node, this.o.scripts, this.o.verbose); task.end_resolve_cb(res); } catch (e) { this._stop_at_task(task, e); } } private async _upload_sm(task: FullTask, node: Node) { await task.start_resolve_cb(); try { const res = await elastic_uploader.sm(node, this.o.sm, this.o.verbose); task.end_resolve_cb(res); } catch (e) { this._stop_at_task(task, e); } } private async _wait_for_elastic(task: FullTask, node: Node) { await task.start_resolve_cb(); await node.wait_for_elastic(this.o.interval, this.o.verbose); task.end_resolve_cb(); } private async _wait_for_kibana(task: FullTask, node: Node) { await task.start_resolve_cb(); if (this.child_node.kibana) { await node.wait_for_kibana(this.o.interval, this.o.verbose); } task.end_resolve_cb(); } }