From 51f37f402f692c977530698ead8046d977ae4649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Uhl=C3=AD=C5=99?= Date: Thu, 5 May 2022 13:13:13 +0200 Subject: [PATCH] feat: adding docker meta label for required blockchain image (#88) --- README.md | 6 +-- generator/scripts/bee-docker-build.sh | 4 +- generator/scripts/bee.sh | 2 +- generator/scripts/blockchain-docker-build.sh | 7 +-- generator/scripts/build-environment.sh | 4 ++ src/command/start.ts | 25 +++++----- src/command/stop.ts | 2 +- src/utils/docker.ts | 49 +++++++++++++++++--- test/integration/start.spec.ts | 9 ++-- test/integration/stop.spec.ts | 5 +- 10 files changed, 74 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 711d760..d916dc3 100644 --- a/README.md +++ b/README.md @@ -32,10 +32,10 @@ $ npm install -g @ethersphere/bee-factory ```shell # This spin up the cluster and exits -$ bee-factory start --detach 1.2.0 1.5.1 +$ bee-factory start --detach 1.5.1 # This attaches to the Queen container and displays its logs -$ bee-factory logs queen +$ bee-factory logs queen --follow # This stops the cluster and keeping the containers so next time they are spinned up the data are kept # but data are not persisted across version's bump! @@ -43,7 +43,7 @@ $ bee-factory stop # You can also spin up the cluster without the --detach which then directly # attaches to the Queen logs and the cluster is terminated upon SIGINT (Ctrl+C) -$ bee-factory start 1.2.0 1.5.1 +$ bee-factory start 1.5.1 ``` For more details see the `--help` page of the CLI and its commands. diff --git a/generator/scripts/bee-docker-build.sh b/generator/scripts/bee-docker-build.sh index ee670bc..f22fcdf 100755 --- a/generator/scripts/bee-docker-build.sh +++ b/generator/scripts/bee-docker-build.sh @@ -10,9 +10,11 @@ DOCKERFILE } dockerbuild() { + BLOCKCHAIN_VERSION=$("$MY_PATH/utils/env-variable-value.sh" BLOCKCHAIN_VERSION) + IMAGE_NAME=$(basename "$1") IMAGE_NAME="$4/$IMAGE_NAME" - docker build "$1" --no-cache -f "$2" -t "$IMAGE_NAME:$3" + docker build "$1" --no-cache -f "$2" -t "$IMAGE_NAME:$3" --label "org.ethswarm.beefactory.blockchain-version=$BLOCKCHAIN_VERSION" } MY_PATH=$(dirname "$0") diff --git a/generator/scripts/bee.sh b/generator/scripts/bee.sh index 8323d20..57e1d0b 100755 --- a/generator/scripts/bee.sh +++ b/generator/scripts/bee.sh @@ -296,7 +296,7 @@ done echo "Check whether the queen node has been connected to every worker..." ELAPSED_TIME=0 WAITING_TIME=2 -TIMEOUT=$((2*30*WAITING_TIME)) +TIMEOUT=$((6*30*WAITING_TIME)) RESTRICTED_TOKEN="" while (( TIMEOUT > ELAPSED_TIME )) ; do check_queen_is_running diff --git a/generator/scripts/blockchain-docker-build.sh b/generator/scripts/blockchain-docker-build.sh index d48e008..d7c3823 100755 --- a/generator/scripts/blockchain-docker-build.sh +++ b/generator/scripts/blockchain-docker-build.sh @@ -5,13 +5,8 @@ MY_PATH=$( cd "$MY_PATH" && pwd ) BEE_ENV_PREFIX=$("$MY_PATH/utils/env-variable-value.sh" BEE_ENV_PREFIX) BEE_IMAGE_PREFIX=$("$MY_PATH/utils/env-variable-value.sh" BEE_IMAGE_PREFIX) BLOCKCHAIN_VERSION=$("$MY_PATH/utils/env-variable-value.sh" BLOCKCHAIN_VERSION) -STATE_COMMIT=$("$MY_PATH/utils/env-variable-value.sh" STATE_COMMIT) -if [ "$STATE_COMMIT" == 'true' ] ; then - BEE_VERSION=$("$MY_PATH/utils/build-image-tag.sh" get) - BLOCKCHAIN_VERSION+="-for-$BEE_VERSION" - echo "Blockchain will have image version: $BLOCKCHAIN_VERSION" -fi +echo "Blockchain will have image version: $BLOCKCHAIN_VERSION" NAME="$BEE_ENV_PREFIX-blockchain" diff --git a/generator/scripts/build-environment.sh b/generator/scripts/build-environment.sh index a3f1721..98104c4 100755 --- a/generator/scripts/build-environment.sh +++ b/generator/scripts/build-environment.sh @@ -51,6 +51,8 @@ GEN_TRAFFIC_UPLOAD_NODE_DEBUG="http://localhost:11635" CHEQUES_COUNT=1 # Bee version here means the base bee version on which the images will be built BEE_VERSION=$("$MY_PATH/utils/env-variable-value.sh" BEE_VERSION) +BLOCKCHAIN_VERSION=$("$MY_PATH/utils/env-variable-value.sh" BLOCKCHAIN_VERSION) + SUPPORTED_WORKER_N=4 # handle passed options @@ -123,6 +125,8 @@ if $GEN_TRAFFIC ; then "$MY_PATH/bee.sh" stop docker container prune -f + + export BLOCKCHAIN_VERSION+="-for-$BEE_VERSION" fi "$MY_PATH/bee-docker-build.sh" "$MY_PATH/blockchain-docker-build.sh" diff --git a/src/command/start.ts b/src/command/start.ts index d8d6b8f..cc07100 100644 --- a/src/command/start.ts +++ b/src/command/start.ts @@ -72,9 +72,6 @@ export class Start extends RootCommand implements LeafCommand { }) public envPrefix!: string - @Argument({ key: 'blockchain-version', description: 'Blockchain image version', required: true }) - public blockchainVersion!: string - @Argument({ key: 'bee-version', description: 'Bee image version', required: true }) public beeVersion!: string @@ -82,7 +79,7 @@ export class Start extends RootCommand implements LeafCommand { await super.init() const dockerOptions = await this.buildDockerOptions() - const docker = new Docker(this.console, this.envPrefix, this.imagePrefix) + const docker = new Docker(this.console, this.envPrefix, this.imagePrefix, this.repo) const status = await docker.getAllStatus() if (Object.values(status).every(st => st === 'running')) { @@ -111,7 +108,7 @@ export class Start extends RootCommand implements LeafCommand { text: 'Spawning network...', spinner: 'point', color: 'yellow', - isSilent: this.verbosity !== VerbosityLevel.Quiet, + isSilent: this.verbosity === VerbosityLevel.Quiet, }).start() try { @@ -123,14 +120,17 @@ export class Start extends RootCommand implements LeafCommand { } const blockchainSpinner = ora({ - text: 'Starting blockchain node...', + text: 'Getting blockchain image version...', spinner: 'point', color: 'yellow', - isSilent: this.verbosity !== VerbosityLevel.Quiet, + isSilent: this.verbosity === VerbosityLevel.Quiet, }).start() try { - await docker.startBlockchainNode(this.blockchainVersion, this.beeVersion, dockerOptions) + const blockchainVersion = await docker.getBlockchainVersionFromQueenMetadata(this.beeVersion) + + blockchainSpinner.text = 'Starting blockchain node...' + await docker.startBlockchainNode(blockchainVersion, dockerOptions) blockchainSpinner.text = 'Waiting until blockchain is ready...' await waitForBlockchain() blockchainSpinner.succeed('Blockchain node is up and listening') @@ -144,7 +144,7 @@ export class Start extends RootCommand implements LeafCommand { text: 'Starting queen Bee node...', spinner: 'point', color: 'yellow', - isSilent: this.verbosity !== VerbosityLevel.Quiet, + isSilent: this.verbosity === VerbosityLevel.Quiet, }).start() try { @@ -164,7 +164,7 @@ export class Start extends RootCommand implements LeafCommand { text: 'Starting worker Bee nodes...', spinner: 'point', color: 'yellow', - isSilent: this.verbosity !== VerbosityLevel.Quiet, + isSilent: this.verbosity === VerbosityLevel.Quiet, }).start() try { @@ -182,7 +182,7 @@ export class Start extends RootCommand implements LeafCommand { } if (!this.detach) { - await docker.logs(ContainerType.QUEEN, process.stdout) + await docker.logs(ContainerType.QUEEN, process.stdout, true) } } @@ -191,7 +191,7 @@ export class Start extends RootCommand implements LeafCommand { text: 'Stopping all containers...', spinner: 'point', color: 'red', - isSilent: this.verbosity !== VerbosityLevel.Quiet, + isSilent: this.verbosity === VerbosityLevel.Quiet, }).start() await docker.stopAll(false) @@ -201,7 +201,6 @@ export class Start extends RootCommand implements LeafCommand { private async buildDockerOptions(): Promise { return { - repo: this.repo, fresh: this.fresh, } } diff --git a/src/command/stop.ts b/src/command/stop.ts index c4a6603..bcd1494 100644 --- a/src/command/stop.ts +++ b/src/command/stop.ts @@ -43,7 +43,7 @@ export class Stop extends RootCommand implements LeafCommand { text: 'Stopping all containers...', spinner: 'point', color: 'yellow', - isSilent: this.verbosity !== VerbosityLevel.Quiet, + isSilent: this.verbosity === VerbosityLevel.Quiet, }).start() await docker.stopAll(true, this.deleteContainers) diff --git a/src/utils/docker.ts b/src/utils/docker.ts index d4fd72e..2064ba2 100644 --- a/src/utils/docker.ts +++ b/src/utils/docker.ts @@ -11,12 +11,14 @@ const WORKER_IMAGE_NAME_SUFFIX = '-worker' const NETWORK_NAME_SUFFIX = '-network' export const WORKER_COUNT = 4 +export const BLOCKCHAIN_VERSION_LABEL_KEY = 'org.ethswarm.beefactory.blockchain-version' + +// TODO: This should be possible to override with for example ENV variable in case somebody is rocking custom images const SWAP_FACTORY_ADDRESS = '0x5b1869D9A4C187F2EAa108f3062412ecf0526b24' const POSTAGE_STAMP_ADDRESS = '0xCfEB869F69431e42cdB54A4F4f105C19C080A601' const PRICE_ORACLE_ADDRESS = '0x254dffcd3277C0b1660F6d42EFbB754edaBAbC2B' export interface RunOptions { - repo: string fresh: boolean } @@ -52,6 +54,7 @@ export class Docker { private runningContainers: Container[] private envPrefix: string private imagePrefix: string + private repo?: string private get networkName() { return `${this.envPrefix}${NETWORK_NAME_SUFFIX}` @@ -60,21 +63,39 @@ export class Docker { private get blockchainName() { return `${this.envPrefix}${BLOCKCHAIN_IMAGE_NAME_SUFFIX}` } + private blockchainImage(blockchainVersion: string) { + if (!this.repo) throw new TypeError('Repo has to be defined!') + + return `${this.repo}/${this.imagePrefix}${BLOCKCHAIN_IMAGE_NAME_SUFFIX}:${blockchainVersion}` + } private get queenName() { return `${this.envPrefix}${QUEEN_IMAGE_NAME_SUFFIX}` } + private queenImage(beeVersion: string) { + if (!this.repo) throw new TypeError('Repo has to be defined!') + + return `${this.repo}/${this.imagePrefix}${QUEEN_IMAGE_NAME_SUFFIX}:${beeVersion}` + } + private workerName(index: number) { return `${this.envPrefix}${WORKER_IMAGE_NAME_SUFFIX}-${index}` } - constructor(console: Logging, envPrefix: string, imagePrefix: string) { + private workerImage(beeVersion: string, workerNumber: number) { + if (!this.repo) throw new TypeError('Repo has to be defined!') + + return `${this.repo}/${this.imagePrefix}${WORKER_IMAGE_NAME_SUFFIX}-${workerNumber}:${beeVersion}` + } + + constructor(console: Logging, envPrefix: string, imagePrefix: string, repo?: string) { this.docker = new Dockerode() this.console = console this.runningContainers = [] this.envPrefix = envPrefix this.imagePrefix = imagePrefix + this.repo = repo } public async createNetwork(): Promise { @@ -85,11 +106,11 @@ export class Docker { } } - public async startBlockchainNode(blockchainVersion: string, beeVersion: string, options: RunOptions): Promise { + public async startBlockchainNode(blockchainVersion: string, options: RunOptions): Promise { if (options.fresh) await this.removeContainer(this.blockchainName) const container = await this.findOrCreateContainer(this.blockchainName, { - Image: `${options.repo}/${this.imagePrefix}${BLOCKCHAIN_IMAGE_NAME_SUFFIX}:${blockchainVersion}-for-${beeVersion}`, + Image: this.blockchainImage(blockchainVersion), name: this.blockchainName, ExposedPorts: { '9545/tcp': {}, @@ -117,7 +138,7 @@ export class Docker { if (options.fresh) await this.removeContainer(this.queenName) const container = await this.findOrCreateContainer(this.queenName, { - Image: `${options.repo}/${this.imagePrefix}${QUEEN_IMAGE_NAME_SUFFIX}:${beeVersion}`, + Image: this.queenImage(beeVersion), name: this.queenName, ExposedPorts: { '1633/tcp': {}, @@ -160,7 +181,7 @@ export class Docker { if (options.fresh) await this.removeContainer(this.workerName(workerNumber)) const container = await this.findOrCreateContainer(this.workerName(workerNumber), { - Image: `${options.repo}/${this.imagePrefix}${WORKER_IMAGE_NAME_SUFFIX}-${workerNumber}:${beeVersion}`, + Image: this.workerImage(beeVersion, workerNumber), name: this.workerName(workerNumber), ExposedPorts: { '1633/tcp': {}, @@ -243,6 +264,22 @@ export class Docker { } } + public async getBlockchainVersionFromQueenMetadata(beeVersion: string): Promise { + // Lets pull the Queen's image if it is not present + const pullStream = await this.docker.pull(this.queenImage(beeVersion)) + await new Promise(res => this.docker.modem.followProgress(pullStream, res)) + + const queenMetadata = await this.docker.getImage(this.queenImage(beeVersion)).inspect() + + const version = queenMetadata.Config.Labels[BLOCKCHAIN_VERSION_LABEL_KEY] + + if (!version) { + throw new Error('Blockchain image version was not found in Queen image labels!') + } + + return version + } + public async getAllStatus(): Promise { return { queen: await this.getStatusForContainer(ContainerType.QUEEN), diff --git a/test/integration/start.spec.ts b/test/integration/start.spec.ts index 6f8531e..e1b618b 100644 --- a/test/integration/start.spec.ts +++ b/test/integration/start.spec.ts @@ -8,7 +8,6 @@ import { Bee, BeeDebug, Reference } from '@ethersphere/bee-js' import { DockerError } from '../../src/utils/docker' import { findContainer, waitForUsablePostageStamp } from '../utils/docker' -const BLOCKCHAIN_VERSION = '1.2.0' const BEE_VERSION = '1.5.1' let testFailed = false @@ -54,7 +53,7 @@ describe('start command', () => { 'should start cluster', wrapper(async () => { // As spinning the cluster with --detach the command will exit once the cluster is up and running - await run(['start', '--detach', BLOCKCHAIN_VERSION, BEE_VERSION]) + await run(['start', '--detach', BEE_VERSION]) await expect(findContainer(docker, 'queen')).resolves.toBeDefined() await expect(findContainer(docker, 'blockchain')).resolves.toBeDefined() @@ -84,7 +83,7 @@ describe('start command', () => { it( '', wrapper(async () => { - await run(['start', '--detach', BLOCKCHAIN_VERSION, BEE_VERSION]) + await run(['start', '--detach', BEE_VERSION]) expect(docker.getNetwork(`${envPrefix}-network`)).toBeDefined() }), @@ -96,7 +95,7 @@ describe('start command', () => { beforeAll(async () => { console.log('(before) Starting up Bee Factory') - await run(['start', '--detach', BLOCKCHAIN_VERSION, BEE_VERSION]) + await run(['start', '--detach', BEE_VERSION]) console.log('(before) Creating postage stamp ') const postage = await beeDebug.createPostageBatch('10', 18) @@ -117,7 +116,7 @@ describe('start command', () => { '', wrapper(async () => { console.log('(test) Starting the Bee Factory') - await run(['start', '--fresh', '--detach', BLOCKCHAIN_VERSION, BEE_VERSION]) + await run(['start', '--fresh', '--detach', BEE_VERSION]) console.log('(test) Trying to fetch the data') await expect(bee.downloadData(reference)).rejects.toHaveProperty('status', 404) diff --git a/test/integration/stop.spec.ts b/test/integration/stop.spec.ts index 552faed..7127e9f 100644 --- a/test/integration/stop.spec.ts +++ b/test/integration/stop.spec.ts @@ -6,7 +6,6 @@ import { run } from '../utils/run' import { ENV_ENV_PREFIX_KEY } from '../../src/command/start' import { findContainer } from '../utils/docker' -const BLOCKCHAIN_VERSION = '1.2.0' const BEE_VERSION = '1.5.1' describe('stop command', () => { @@ -27,7 +26,7 @@ describe('stop command', () => { describe('should stop cluster', () => { beforeAll(async () => { // As spinning the cluster with --detach the command will exit once the cluster is up and running - await run(['start', '--detach', BLOCKCHAIN_VERSION, BEE_VERSION]) + await run(['start', '--detach', BEE_VERSION]) }) it('', async () => { @@ -52,7 +51,7 @@ describe('stop command', () => { describe('should stop cluster and remove containers', () => { beforeAll(async () => { // As spinning the cluster with --detach the command will exit once the cluster is up and running - await run(['start', '--detach', BLOCKCHAIN_VERSION, BEE_VERSION]) + await run(['start', '--detach', BEE_VERSION]) }) it('', async () => {