UNPKG

@ethersphere/bee-factory

Version:

Orchestration CLI for spinning up local development Bee cluster with Docker

302 lines (301 loc) 12.9 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Start = exports.ENV_ENV_PREFIX_KEY = void 0; const furious_commander_1 = require("furious-commander"); const root_command_1 = require("./root-command"); const docker_1 = require("../utils/docker"); const wait_1 = require("../utils/wait"); const ora_1 = __importDefault(require("ora")); const logging_1 = require("./root-command/logging"); const config_sources_1 = require("../utils/config-sources"); const package_json_1 = __importDefault(require("../../package.json")); const semver_1 = __importDefault(require("semver")); const DEFAULT_REPO = 'ethersphere'; exports.ENV_ENV_PREFIX_KEY = 'FACTORY_ENV_PREFIX'; const ENV_IMAGE_PREFIX_KEY = 'FACTORY_IMAGE_PREFIX'; const ENV_REPO_KEY = 'FACTORY_DOCKER_REPO'; const ENV_DETACH_KEY = 'FACTORY_DETACH'; const ENV_WORKERS_KEY = 'FACTORY_WORKERS'; const ENV_FRESH_KEY = 'FACTORY_FRESH'; class Start extends root_command_1.RootCommand { constructor() { super(...arguments); Object.defineProperty(this, "name", { enumerable: true, configurable: true, writable: true, value: 'start' }); Object.defineProperty(this, "description", { enumerable: true, configurable: true, writable: true, value: 'Spin up the Bee Factory cluster' }); Object.defineProperty(this, "fresh", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "detach", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "workers", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "repo", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "imagePrefix", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "envPrefix", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "beeVersion", { enumerable: true, configurable: true, writable: true, value: void 0 }); } run() { const _super = Object.create(null, { init: { get: () => super.init } }); return __awaiter(this, void 0, void 0, function* () { yield _super.init.call(this); if (this.workers < 0 || this.workers > docker_1.WORKER_COUNT) { throw new Error(`Worker count has to be between 0 and ${docker_1.WORKER_COUNT} including.`); } if (!this.beeVersion) { this.beeVersion = yield (0, config_sources_1.findBeeVersion)(); this.console.log('Bee version not specified. Found it configured externally.'); this.console.log(`Spinning up cluster with Bee version ${this.beeVersion}.`); } this.beeVersion = (0, config_sources_1.stripCommit)(this.beeVersion); const supportedBeeVersion = package_json_1.default.engines.supportedBee; if (!semver_1.default.satisfies(this.beeVersion, supportedBeeVersion, { includePrerelease: true })) { throw new Error(`Unsupported Bee version!\nThis version of Bee Factory supports versions: ${supportedBeeVersion}, but you have requested start of ${this.beeVersion}`); } const dockerOptions = yield this.buildDockerOptions(); const docker = new docker_1.Docker(this.console, this.envPrefix, this.imagePrefix, this.repo); const status = yield docker.getAllStatus(); if (Object.values(status).every(st => st === 'running')) { this.console.log('All containers are up and running'); if (this.detach) { return; } yield docker.logs(docker_1.ContainerType.QUEEN, process.stdout); } let queenAddress; process.on('SIGINT', () => __awaiter(this, void 0, void 0, function* () { try { yield docker.stopAll(false); } catch (e) { this.console.error(`Error: ${e}`); } process.exit(); })); const networkSpinner = (0, ora_1.default)({ text: 'Spawning network...', spinner: 'point', color: 'yellow', isSilent: this.verbosity === logging_1.VerbosityLevel.Quiet, }).start(); try { yield docker.createNetwork(); networkSpinner.succeed('Network is up'); } catch (e) { networkSpinner.fail(`It was not possible to spawn network!`); throw e; } const blockchainSpinner = (0, ora_1.default)({ text: 'Getting blockchain image version...', spinner: 'point', color: 'yellow', isSilent: this.verbosity === logging_1.VerbosityLevel.Quiet, }).start(); try { const blockchainVersion = yield docker.getBlockchainVersionFromQueenMetadata(this.beeVersion); blockchainSpinner.text = 'Starting blockchain node...'; yield docker.startBlockchainNode(blockchainVersion, dockerOptions); blockchainSpinner.text = 'Waiting until blockchain is ready...'; yield (0, wait_1.waitForBlockchain)(); blockchainSpinner.succeed('Blockchain node is up and listening'); } catch (e) { blockchainSpinner.fail(`It was not possible to start blockchain node!`); yield this.stopDocker(docker); throw e; } const queenSpinner = (0, ora_1.default)({ text: 'Starting queen Bee node...', spinner: 'point', color: 'yellow', isSilent: this.verbosity === logging_1.VerbosityLevel.Quiet, }).start(); try { yield docker.startQueenNode(this.beeVersion, dockerOptions); queenSpinner.text = 'Waiting until queen node is ready...'; queenAddress = yield (0, wait_1.waitForQueen)(() => __awaiter(this, void 0, void 0, function* () { return (yield docker.getStatusForContainer(docker_1.ContainerType.QUEEN)) === 'running'; })); queenSpinner.succeed('Queen node is up and listening'); } catch (e) { queenSpinner.fail(`It was not possible to start queen node!`); yield this.stopDocker(docker); throw e; } if (this.workers > 0) { const workerSpinner = (0, ora_1.default)({ text: 'Starting worker Bee nodes...', spinner: 'point', color: 'yellow', isSilent: this.verbosity === logging_1.VerbosityLevel.Quiet, }).start(); try { for (let i = 1; i <= this.workers; i++) { yield docker.startWorkerNode(this.beeVersion, i, queenAddress, dockerOptions); } workerSpinner.text = 'Waiting until all workers connect to queen...'; yield (0, wait_1.waitForWorkers)(this.workers, docker.getAllStatus.bind(docker)); workerSpinner.succeed('Worker nodes are up and listening'); } catch (e) { workerSpinner.fail(`It was not possible to start worker nodes!`); yield this.stopDocker(docker); throw e; } } if (!this.detach) { yield docker.logs(docker_1.ContainerType.QUEEN, process.stdout, true); } }); } stopDocker(docker) { return __awaiter(this, void 0, void 0, function* () { const dockerSpinner = (0, ora_1.default)({ text: 'Stopping all containers...', spinner: 'point', color: 'red', isSilent: this.verbosity === logging_1.VerbosityLevel.Quiet, }).start(); yield docker.stopAll(false); dockerSpinner.stop(); }); } buildDockerOptions() { return __awaiter(this, void 0, void 0, function* () { return { fresh: this.fresh, }; }); } } __decorate([ (0, furious_commander_1.Option)({ key: 'fresh', alias: 'f', type: 'boolean', description: 'The cluster data will be purged before start', envKey: ENV_FRESH_KEY, default: false, }), __metadata("design:type", Boolean) ], Start.prototype, "fresh", void 0); __decorate([ (0, furious_commander_1.Option)({ key: 'detach', alias: 'd', type: 'boolean', description: 'Spin up the cluster and exit. No logging is outputted.', envKey: ENV_DETACH_KEY, default: false, }), __metadata("design:type", Boolean) ], Start.prototype, "detach", void 0); __decorate([ (0, furious_commander_1.Option)({ key: 'workers', alias: 'w', type: 'number', description: `Number of workers to spin. Value between 0 and ${docker_1.WORKER_COUNT} including.`, envKey: ENV_WORKERS_KEY, default: docker_1.WORKER_COUNT, }), __metadata("design:type", Number) ], Start.prototype, "workers", void 0); __decorate([ (0, furious_commander_1.Option)({ key: 'repo', type: 'string', description: 'Docker repo', envKey: ENV_REPO_KEY, default: DEFAULT_REPO, }), __metadata("design:type", String) ], Start.prototype, "repo", void 0); __decorate([ (0, furious_commander_1.Option)({ key: 'image-prefix', type: 'string', description: 'Docker image name prefix', envKey: ENV_IMAGE_PREFIX_KEY, default: docker_1.DEFAULT_IMAGE_PREFIX, }), __metadata("design:type", String) ], Start.prototype, "imagePrefix", void 0); __decorate([ (0, furious_commander_1.Option)({ key: 'env-prefix', type: 'string', description: "Docker container's names prefix", envKey: exports.ENV_ENV_PREFIX_KEY, default: docker_1.DEFAULT_ENV_PREFIX, }), __metadata("design:type", String) ], Start.prototype, "envPrefix", void 0); __decorate([ (0, furious_commander_1.Argument)({ key: 'bee-version', description: 'Bee image version', required: false }), __metadata("design:type", String) ], Start.prototype, "beeVersion", void 0); exports.Start = Start;