Skip to content

Commit

Permalink
Merge pull request #3466 from terascope/k8s-env-script
Browse files Browse the repository at this point in the history
Create k8s-env command within ts-scripts to start a kubernetes dev environment
  • Loading branch information
godber authored Nov 21, 2023
2 parents 90d23d3 + d194a6d commit 7188767
Show file tree
Hide file tree
Showing 15 changed files with 448 additions and 63 deletions.
12 changes: 0 additions & 12 deletions e2e/k8s/kindConfig.yaml

This file was deleted.

12 changes: 12 additions & 0 deletions e2e/k8s/kindConfigDefaultPorts.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
kind: Cluster
name: k8se2e
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30200 # Map internal elasticsearch service to host port
hostPort: 9200
- containerPort: 30678 # Map internal teraslice service to host port
hostPort: 5678
- containerPort: 30092 # Map internal kafka service to host port
hostPort: 9092
12 changes: 12 additions & 0 deletions e2e/k8s/kindConfigTestPorts.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
kind: Cluster
name: k8se2e
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30200 # Map internal elasticsearch service to host port
hostPort: 49200
- containerPort: 30678 # Map internal teraslice service to host port
hostPort: 45678
- containerPort: 30092 # Map internal kafka service to host port
hostPort: 49092
4 changes: 2 additions & 2 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, HOST_IP
CONFIG_PATH, ASSETS_PATH, TEST_PLATFORM
} = require('./config');

module.exports = async () => {
Expand Down Expand Up @@ -41,7 +41,7 @@ module.exports = async () => {
if (TEST_PLATFORM === 'kubernetes') {
await deployK8sTeraslice();
await teraslice.waitForTeraslice();
await setAliasAndBaseAssets(HOST_IP);
await setAliasAndBaseAssets();
} else {
await Promise.all([setupTerasliceConfig(), downloadAssets()]);
await dockerUp();
Expand Down
2 changes: 1 addition & 1 deletion e2e/test/teraslice-harness.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ module.exports = class TerasliceHarness {
if (TEST_PLATFORM === 'kubernetes') {
try {
cleanupIndex(this.client, `${SPEC_INDEX_PREFIX}*`);
await showState(HOST_IP);
await showState();
} catch (err) {
signale.error('Failure to clean indices and assets', err);
throw err;
Expand Down
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
"build:watch": "yarn run build --watch",
"bump": "ts-scripts bump",
"docs": "ts-scripts docs",
"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",
"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 Expand Up @@ -77,7 +80,8 @@
"unit": [],
"_for_testing_": [
"elasticsearch"
]
],
"k8s_env": []
}
},
"docker": {
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.60.1",
"version": "0.60.2",
"description": "A collection of terascope monorepo scripts",
"homepage": "https://github.com/terascope/teraslice/tree/master/packages/scripts#readme",
"bugs": {
Expand Down
67 changes: 67 additions & 0 deletions packages/scripts/src/cmds/k8s-env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { CommandModule } from 'yargs';
import * as config from '../helpers/config';
import { launchK8sEnv } from '../helpers/k8s-env';
import { kafkaVersionMapper } from '../helpers/mapper';

const cmd: CommandModule = {
command: 'k8s-env',
describe: 'Run a local kubernetes dev environment using kind.',
builder(yargs) {
return yargs
.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.')
.option('elasticsearch-version', {
description: 'The elasticsearch version to use',
type: 'string',
default: config.ELASTICSEARCH_VERSION,
})
.option('kafka-version', {
description: 'The kafka version to use',
type: 'string',
default: config.KAFKA_VERSION,
})
.option('minio-version', {
description: 'The minio version to use',
type: 'string',
default: config.MINIO_VERSION,
})
.option('rabbitmq-version', {
description: 'The rabbitmq version to use',
type: 'string',
default: config.RABBITMQ_VERSION,
})
.option('opensearch-version', {
description: 'The opensearch version to use',
type: 'string',
default: config.OPENSEARCH_VERSION,
})
.option('node-version', {
description: 'Node version, there must be a Docker base image with this version (e.g. 18.16.0)',
type: 'string',
default: config.NODE_VERSION
})
.option('skip-build', {
description: 'Skip building the teraslice docker iamge',
type: 'boolean',
default: config.SKIP_DOCKER_BUILD_IN_K8S
});
},
handler(argv) {
const kafkaCPVersion = kafkaVersionMapper(argv.kafkaVersion as string);

return launchK8sEnv({
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'])
});
},
};

export = cmd;
32 changes: 9 additions & 23 deletions packages/scripts/src/helpers/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,12 @@ import {
toBoolean, toSafeString, isCI, toIntegerOrThrow
} from '@terascope/utils';
import { Service } from './interfaces';
import { kafkaVersionMapper } from './mapper';

const forceColor = process.env.FORCE_COLOR || '1';
export const FORCE_COLOR = toBoolean(forceColor)
? '1'
: '0';
const kafkaMapper = {
3: {
0: '7.0.11',
1: '7.1.9',
2: '7.2.7',
3: '7.3.5',
4: '7.4.2',
5: '7.5.1'
},
2: {
4: '5.4.10',
5: '5.5.12',
6: '6.0.15',
7: '6.1.13',
8: '6.2.12'
}
};
/** The timeout for how long a service has to stand up */
export const SERVICE_UP_TIMEOUT = process.env.SERVICE_UP_TIMEOUT ?? '2m';

Expand All @@ -51,11 +35,11 @@ export const KAFKA_HOSTNAME = process.env.KAFKA_HOSTNAME || HOST_IP;
export const KAFKA_PORT = process.env.KAFKA_PORT || '49092';
export const KAFKA_BROKER = `${KAFKA_HOSTNAME}:${KAFKA_PORT}`;
export const KAFKA_VERSION = process.env.KAFKA_VERSION || '3.1';
// Use kafkaMapper to determine confluentinc/cp-kafka image version from KAFKA_VERSION
export const KAFKA_IMAGE_VERSION = kafkaMapper[KAFKA_VERSION.charAt(0)][KAFKA_VERSION.charAt(2)];
// Use kafkaVersionMapper to determine confluentinc/cp-kafka image version from KAFKA_VERSION
export const KAFKA_IMAGE_VERSION = kafkaVersionMapper(KAFKA_VERSION);
export const KAFKA_DOCKER_IMAGE = process.env.KAFKA_DOCKER_IMAGE || 'confluentinc/cp-kafka';
// Zookeeper version needs to match KAFKA_IMAGE_VERSION which is determined by kafkaMapper
export const ZOOKEEPER_VERSION = kafkaMapper[KAFKA_VERSION.charAt(0)][KAFKA_VERSION.charAt(2)];
// Zookeeper version needs to match KAFKA_IMAGE_VERSION which is determined by kafkaVersionMapper
export const ZOOKEEPER_VERSION = KAFKA_IMAGE_VERSION;
export const ZOOKEEPER_CLIENT_PORT = process.env.ZOOKEEPER_CLIENT_PORT || '42181';
export const ZOOKEEPER_TICK_TIME = process.env.ZOOKEEPER_TICK_TIME || '2000';
export const ZOOKEEPER_DOCKER_IMAGE = process.env.ZOOKEEPER_DOCKER_IMAGE || 'confluentinc/cp-zookeeper';
Expand Down Expand Up @@ -112,7 +96,7 @@ export const DEV_TAG = toSafeString((
|| process.env.TRAVIS_BRANCH
|| process.env.CI_COMMIT_REF_SLUG
|| 'local'
// convert dependabot/npm_and_yarn/dep-x.x.x to dependabot
// convert dependabot/npm_and_yarn/dep-x.x.x to dependabot
).split('/', 1)[0]);

/**
Expand All @@ -128,6 +112,8 @@ export const DEV_DOCKER_IMAGE = process.env.DEV_DOCKER_IMAGE || undefined;
*/
export const SKIP_DOCKER_BUILD_IN_E2E = toBoolean(process.env.SKIP_DOCKER_BUILD_IN_E2E ?? false);

export const SKIP_DOCKER_BUILD_IN_K8S = toBoolean(process.env.SKIP_DOCKER_BUILD_IN_K8S ?? false);

export const SKIP_E2E_OUTPUT_LOGS = toBoolean(process.env.SKIP_E2E_OUTPUT_LOGS ?? !isCI);

/**
Expand Down Expand Up @@ -163,7 +149,7 @@ export const ENV_SERVICES = [
testOpensearch ? Service.Opensearch : undefined,
testElasticsearch ? Service.Elasticsearch : undefined,
toBoolean(TEST_KAFKA) ? Service.Kafka : undefined,
/// couple kafa with zookeeper
/// couple kafka with zookeeper
toBoolean(TEST_KAFKA) ? Service.Zookeeper : undefined,
toBoolean(TEST_MINIO) ? Service.Minio : undefined,
testRestrainedOpensearch ? Service.RestrainedOpensearch : undefined,
Expand Down
86 changes: 86 additions & 0 deletions packages/scripts/src/helpers/k8s-env/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// import { debugLogger } from '@terascope/utils';
import {
createKindCluster,
createNamespace,
deployK8sTeraslice,
dockerTag,
isKindInstalled,
isKubectlInstalled,
loadTerasliceImage
} from '../scripts';
import { k8sEnvOptions } from './interfaces';
import signale from '../signale';
import { getDevDockerImage, getRootInfo } from '../misc';
import { buildDevDockerImage } from '../publish/utils';
import { PublishOptions, PublishType } from '../publish/interfaces';
import * as config from '../config';
import { ensureServices } from '../test-runner/services';

// const logger = debugLogger('ts-scripts:cmd:k8s-env');

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

const kindInstalled = await isKindInstalled();
if (!kindInstalled) {
signale.error('Please install Kind before launching a k8s dev environment. https://kind.sigs.k8s.io/docs/user/quick-start');
process.exit(1);
}

const kubectlInstalled = await isKubectlInstalled();
if (!kubectlInstalled) {
signale.error('Please install kubectl before launching a k8s dev environment. https://kubernetes.io/docs/tasks/tools/');
process.exit(1);
}

signale.pending('Creating kind cluster');
await createKindCluster('k8s-env');
signale.success('Kind cluster created');
await createNamespace('services-ns.yaml');

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);
}
}

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

await loadTerasliceImage(e2eImage);

await ensureServices('k8s_env', {
...options,
debug: false,
trace: false,
bail: false,
watch: false,
all: false,
keepOpen: false,
reportCoverage: false,
useExistingServices: false,
elasticsearchAPIVersion: config.ELASTICSEARCH_API_VERSION,
ignoreMount: false,
testPlatform: 'kubernetes'
});

await deployK8sTeraslice(true);
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\n\tSee the docs for more options: https://terascope.github.io/teraslice/docs/packages/teraslice-cli/overview');
}
Loading

0 comments on commit 7188767

Please sign in to comment.