Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the --rebuild option to the k8s-env command #3480

Merged
merged 12 commits into from
Dec 4, 2023
6 changes: 5 additions & 1 deletion e2e/test/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ const {

const TEST_HOST = TEST_OPENSEARCH ? OPENSEARCH_HOST : ELASTICSEARCH_HOST;

// TERASLICE_PORT must match e2e/docker-compose.yml
const TERASLICE_PORT = 45678;

function newId(prefix, lowerCase = false, length = 15) {
let characters = '0123456789abcdefghijklmnopqrstuvwxyz';

Expand Down Expand Up @@ -80,5 +83,6 @@ module.exports = {
newId,
TEST_HOST,
TEST_PLATFORM,
KEEP_OPEN
KEEP_OPEN,
TERASLICE_PORT
};
6 changes: 3 additions & 3 deletions e2e/test/global.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const signale = require('./signale');
const setupTerasliceConfig = require('./setup-config');
const downloadAssets = require('./download-assets');
const {
CONFIG_PATH, ASSETS_PATH, TEST_PLATFORM
CONFIG_PATH, ASSETS_PATH, TEST_PLATFORM, TERASLICE_PORT
} = require('./config');

module.exports = async () => {
Expand All @@ -39,9 +39,9 @@ module.exports = async () => {
]);

if (TEST_PLATFORM === 'kubernetes') {
await deployK8sTeraslice();
await deployK8sTeraslice(TERASLICE_PORT);
await teraslice.waitForTeraslice();
await setAliasAndBaseAssets();
await setAliasAndBaseAssets(TERASLICE_PORT);
} else {
await Promise.all([setupTerasliceConfig(), downloadAssets()]);
await dockerUp();
Expand Down
3 changes: 2 additions & 1 deletion e2e/test/setup-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const {
KAFKA_BROKER,
ELASTICSEARCH_HOST,
TEST_HOST,
TERASLICE_PORT,
ELASTICSEARCH_API_VERSION,
CLUSTER_NAME,
HOST_IP,
Expand Down Expand Up @@ -66,7 +67,7 @@ module.exports = async function setupTerasliceConfig() {
assets_directory: '/app/assets',
autoload_directory: '/app/autoload',
workers: WORKERS_PER_NODE,
port: 45678,
port: TERASLICE_PORT,
name: CLUSTER_NAME,
master_hostname: HOST_IP,
index_settings: {
Expand Down
6 changes: 3 additions & 3 deletions e2e/test/teraslice-harness.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const fse = require('fs-extra');
const {
TEST_HOST, HOST_IP, SPEC_INDEX_PREFIX,
DEFAULT_NODES, newId, DEFAULT_WORKERS, GENERATE_ONLY,
EXAMPLE_INDEX_SIZES, EXAMPLE_INDEX_PREFIX, TEST_PLATFORM
EXAMPLE_INDEX_SIZES, EXAMPLE_INDEX_PREFIX, TEST_PLATFORM, TERASLICE_PORT
} = require('./config');
const { scaleWorkers, getElapsed } = require('./docker-helpers');
const signale = require('./signale');
Expand All @@ -27,7 +27,7 @@ module.exports = class TerasliceHarness {
const { client } = await createClient({ node: TEST_HOST });
this.client = client;
this.teraslice = new TerasliceClient({
host: `http://${HOST_IP}:45678`,
host: `http://${HOST_IP}:${TERASLICE_PORT}`,
timeout: 2 * 60 * 1000
});
}
Expand Down Expand Up @@ -90,7 +90,7 @@ module.exports = class TerasliceHarness {
if (TEST_PLATFORM === 'kubernetes') {
try {
cleanupIndex(this.client, `${SPEC_INDEX_PREFIX}*`);
await showState();
await showState(TERASLICE_PORT);
} catch (err) {
signale.error('Failure to clean indices and assets', err);
throw err;
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"k8s": "TEST_ELASTICSEARCH='true' ELASTICSEARCH_PORT='9200' ts-scripts k8s-env",
"k8s:kafka": "TEST_ELASTICSEARCH='true' ELASTICSEARCH_PORT='9200' TEST_KAFKA='true' KAFKA_PORT='9092' ts-scripts k8s-env",
"k8s:noBuild": "TEST_ELASTICSEARCH='true' ELASTICSEARCH_PORT='9200' SKIP_DOCKER_BUILD_IN_K8S='true' ts-scripts k8s-env",
"k8s:rebuild": "ts-scripts k8s-env --rebuild='true'",
"lint": "eslint --cache --ext .js,.jsx,.ts,.tsx .",
"lint:fix": "yarn lint --fix && yarn sync",
"setup": "yarn $YARN_SETUP_ARGS && yarn run build --force",
Expand Down
2 changes: 1 addition & 1 deletion packages/scripts/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@terascope/scripts",
"displayName": "Scripts",
"version": "0.61.0",
"version": "0.62.0",
"description": "A collection of terascope monorepo scripts",
"homepage": "https://github.com/terascope/teraslice/tree/master/packages/scripts#readme",
"bugs": {
Expand Down
31 changes: 29 additions & 2 deletions packages/scripts/src/cmds/k8s-env.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CommandModule } from 'yargs';
import * as config from '../helpers/config';
import { launchK8sEnv } from '../helpers/k8s-env';
import { launchK8sEnv, rebuildTeraslice } from '../helpers/k8s-env';
import { kafkaVersionMapper } from '../helpers/mapper';

const cmd: CommandModule = {
Expand All @@ -11,6 +11,7 @@ const cmd: CommandModule = {
.example('TEST_ELASTICSEARCH=\'true\' ELASTICSEARCH_PORT=\'9200\' $0 k8s-env', 'Start a kind kubernetes cluster running teraslice and elasticsearch.')
.example('TEST_ELASTICSEARCH=\'true\' ELASTICSEARCH_PORT=\'9200\' TEST_KAFKA=\'true\' KAFKA_PORT=\'9092\' $0 k8s-env', 'Start a kind kubernetes cluster running teraslice, elasticsearch, kafka, and zookeeper.')
.example('TEST_ELASTICSEARCH=\'true\' ELASTICSEARCH_PORT=\'9200\' SKIP_DOCKER_BUILD_IN_K8S=\'true\' $0 k8s-env', 'Start a kind kubernetes cluster, but skip building a new teraslice docker image.')
.example('$0 k8s-env --rebuild=\'true\'', 'Rebuild teraslice and redeploy to k8s cluster. ES store data is retained.')
.option('elasticsearch-version', {
description: 'The elasticsearch version to use',
type: 'string',
Expand Down Expand Up @@ -45,11 +46,36 @@ const cmd: CommandModule = {
description: 'Skip building the teraslice docker iamge',
type: 'boolean',
default: config.SKIP_DOCKER_BUILD_IN_K8S
})
.option('rebuild', {
description: 'Stop, rebuild, then restart the teraslice docker iamge',
type: 'boolean',
default: false
})
.option('ts-port', {
description: 'Port where teraslice api will be exposed.',
type: 'number',
default: 5678
});
},
handler(argv) {
const kafkaCPVersion = kafkaVersionMapper(argv.kafkaVersion as string);

if (Boolean(argv.rebuild) === true) {
return rebuildTeraslice({
elasticsearchVersion: argv.elasticsearchVersion as string,
kafkaVersion: argv.kafkaVersion as string,
kafkaImageVersion: kafkaCPVersion,
zookeeperVersion: kafkaCPVersion,
minioVersion: argv.minioVersion as string,
rabbitmqVersion: argv.rabbitmqVersion as string,
opensearchVersion: argv.opensearchVersion as string,
nodeVersion: argv['node-version'] as string,
skipBuild: Boolean(argv['skip-build']),
tsPort: argv['ts-port'] as number
});
}

return launchK8sEnv({
elasticsearchVersion: argv.elasticsearchVersion as string,
kafkaVersion: argv.kafkaVersion as string,
Expand All @@ -59,7 +85,8 @@ const cmd: CommandModule = {
rabbitmqVersion: argv.rabbitmqVersion as string,
opensearchVersion: argv.opensearchVersion as string,
nodeVersion: argv['node-version'] as string,
skipBuild: Boolean(argv['skip-build'])
skipBuild: Boolean(argv['skip-build']),
tsPort: argv['ts-port'] as number
});
},
};
Expand Down
25 changes: 25 additions & 0 deletions packages/scripts/src/helpers/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,28 @@ export const AvailablePackageConfigKeys: readonly (keyof PackageConfig)[] = [
export type TSCommands = 'docs';

export type GlobalCMDOptions = EmptyObject;

export interface kindCluster {
kind: string;
apiVersion: string;
name: string;
nodes: [
{
role: string;
extraPortMappings: [
{
containerPort: number;
hostPort: number;
},
{
containerPort: number;
hostPort: number;
},
{
containerPort: number;
hostPort: number;
}
]
}
]
}
105 changes: 78 additions & 27 deletions packages/scripts/src/helpers/k8s-env/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
createKindCluster,
destroyKindCluster,
dockerTag,
isKindInstalled,
isKubectlInstalled,
Expand All @@ -14,6 +15,9 @@ import * as config from '../config';
import { ensureServices } from '../test-runner/services';
import { K8s } from './k8s';

const rootInfo = getRootInfo();
const e2eImage = `${rootInfo.name}:e2e`;

export async function launchK8sEnv(options: k8sEnvOptions) {
signale.pending('Starting k8s environment with the following options: ', options);

Expand All @@ -32,41 +36,27 @@ export async function launchK8sEnv(options: k8sEnvOptions) {
}

signale.pending('Creating kind cluster');
await createKindCluster('k8s-env');
await createKindCluster('k8s-env', options.tsPort);
signale.success('Kind cluster created');
const k8s = new K8s();

await k8s.createNamespace('services-ns.yaml', 'services');

const rootInfo = getRootInfo();
const e2eImage = `${rootInfo.name}:e2e`;

let devImage;
if (options.skipBuild) {
devImage = `${getDevDockerImage()}-nodev${options.nodeVersion}`;
} else {
try {
const publishOptions: PublishOptions = {
dryRun: true,
nodeVersion: options.nodeVersion,
type: PublishType.Dev
};
devImage = await buildDevDockerImage(publishOptions);
} catch (err) {
signale.error('Docker image build failed: ', err);
process.exit(1);
}
const k8s = new K8s(options.tsPort);
try {
await k8s.createNamespace('services-ns.yaml', 'services');
} catch (err) {
signale.fatal(err);
await destroyKindCluster();
process.exit(1);
}

try {
await dockerTag(devImage, e2eImage);
await buildAndTagTerasliceImage(options);
} catch (err) {
signale.error(`Failed to tag docker image ${devImage} as ${e2eImage}.`, err);
signale.error(err);
await destroyKindCluster();
process.exit(1);
}

signale.pending('Loading teraslice docker image');
await kindLoadTerasliceImage(e2eImage);
signale.success('Teraslice docker image loaded');

await ensureServices('k8s_env', {
...options,
Expand All @@ -83,6 +73,67 @@ export async function launchK8sEnv(options: k8sEnvOptions) {
testPlatform: 'kubernetes'
});

await k8s.deployK8sTeraslice(true);
try {
await k8s.deployK8sTeraslice(true);
} catch (err) {
signale.fatal('Error deploying Teraslice. Shutting down k8s cluster: ', err);
await destroyKindCluster();
process.exit(1);
}
signale.success('k8s environment ready.\nNext steps:\n\tAdd alias: teraslice-cli aliases add <cluster-alias> http://localhost:5678\n\t\tExample: teraslice-cli aliases add cluster1 http://localhost:5678\n\tLoad assets: teraslice-cli assets deploy <cluster-alias> <user/repo-name>\n\t\tExample: teraslice-cli assets deploy cluster1 terascope/elasticsearch-assets\n\tRegister a job: teraslice-cli tjm register <cluster-alias> <path/to/job/file.json>\n\t\tExample: teraslice-cli tjm reg cluster1 JOB.JSON\n\tStart a job: teraslice-cli tjm start <path/to/job/file.json>\n\t\tExample: teraslice-cli tjm start JOB.JSON\nDelete the kind k8s cluster: kind delete cluster --name k8se2e\n\tSee the docs for more options: https://terascope.github.io/teraslice/docs/packages/teraslice-cli/overview');
}

export async function rebuildTeraslice(options: k8sEnvOptions) {
let k8s: K8s;
try {
k8s = new K8s(options.tsPort);
} catch (err) {
signale.error('k8se-env --rebuild command failed. Do you have a running k8s cluster?');
process.exit(1);
}

signale.time('Rebuild teraslice');

try {
await buildAndTagTerasliceImage(options);
} catch (err) {
signale.error(err);
process.exit(1);
}

signale.pending('Loading Teraslice Docker image');
await kindLoadTerasliceImage(e2eImage);
signale.success('Teraslice Docker image loaded');

try {
await k8s.deployK8sTeraslice(true);
} catch (err) {
signale.error('Error re-deploying Teraslice: ', err);
process.exit(1);
}
signale.timeEnd('Rebuild teraslice');
}

async function buildAndTagTerasliceImage(options:k8sEnvOptions) {
let devImage;
if (options.skipBuild) {
devImage = `${getDevDockerImage()}-nodev${options.nodeVersion}`;
} else {
try {
const publishOptions: PublishOptions = {
dryRun: true,
nodeVersion: options.nodeVersion,
type: PublishType.Dev
};
devImage = await buildDevDockerImage(publishOptions);
} catch (err) {
throw new Error(`Docker image build failed: ${err}`);
}
}

try {
await dockerTag(devImage, e2eImage);
} catch (err) {
throw new Error(`Failed to tag docker image ${devImage} as ${e2eImage}: ${err}`);
}
}
1 change: 1 addition & 0 deletions packages/scripts/src/helpers/k8s-env/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface k8sEnvOptions {
opensearchVersion: string;
nodeVersion: string;
skipBuild: boolean;
tsPort: number
}

// TODO: create a common parent for each resource type,
Expand Down
Loading
Loading