diff --git a/docs/configuration/clustering-k8s.md b/docs/configuration/clustering-k8s.md index 5b7a737e7a2..cba38abb998 100644 --- a/docs/configuration/clustering-k8s.md +++ b/docs/configuration/clustering-k8s.md @@ -6,6 +6,8 @@ sidebar_label: Kubernetes Clustering Teraslice supports the use of Kubernetes as a cluster manager. The following versions of Kubernetes have been used: +* `1.22.*` +* `1.20.*` * `1.19.*` * `1.18.*` * `1.17.*` @@ -175,8 +177,37 @@ labels that Teraslice uses. It is possible to set CPU and memory resource constraints for your Teraslice Workers that translate to Kubernetes resource constraints. Resources for -Execution Controllers are handled separately and described below. Currently you -can specify optional integer values on your job or in the Teraslice master +Execution Controllers are handled separately and described below. + +#### New Method for Setting Resources + +The new method for setting CPU and memory resources on Teraslice workers allows +you to explicitly set the CPU and memory requests and limits separately on the +Teraslice Job, which will result in the Kubernetes deployment for the Teraslice +workers having the corresponding resource set. You may set any combination of +the following resources on your job or omit them entirely. + +```json +"resources_requests_cpu": 0.25, +"resources_limits_cpu": 1, +"resources_requests_memory": 128000000, +"resources_limits_memory": 536870912, +``` + +The cpu settings are in [Kubernetes CPU Units](https://kubernetes.io/docs/tasks/configure-pod-container/assign-cpu-resource/#cpu-units) +and the memory settings are in bytes. + +Note: The old method of setting just `cpu` or `memory` on the job or in the +Teraslice master config file will be ignored if any of the new `resource_*` job +properties are configured. + +#### Old Method for Setting Resources + +**DEPRECATED** This older method of specifying CPU and memory resources should +be avoided and will be removed in future versions. They are only present +briefly to aid in the migration of jobs. + +You can specify optional integer values on your job or in the Teraslice master configuration as shown below. The `cpu` setting is in vcores and the `memory` setting is in bytes. Teraslice `cpu` and `memory` settings on your Teraslice Job override any settings in the master configuration. Both are optional, @@ -417,9 +448,7 @@ cd examples/k8s export NAMESPACE=ts-dev1 export TERASLICE_K8S_IMAGE=teraslice-k8sdev:1 export TERASLICE_MODE=minikube -# Set the version of Kubernetes you want to run -export KUBERNETES_VERSION=v1.19.7 -minikube start --memory 4096 --cpus 4 --kubernetes-version=${KUBERNETES_VERSION} +minikube start --memory 4096 --cpus 4 eval $(minikube docker-env) make build make setup-all diff --git a/examples/k8s/Makefile b/examples/k8s/Makefile index e1ec343c79b..39c5b044a6c 100644 --- a/examples/k8s/Makefile +++ b/examples/k8s/Makefile @@ -192,6 +192,7 @@ register: ## creates asset and registers job earl tjm register ${TERASLICE_ALIAS} example-job.json earl tjm register ${TERASLICE_ALIAS} example-job-labels.json earl tjm register ${TERASLICE_ALIAS} example-job-resource.json + earl tjm register ${TERASLICE_ALIAS} example-job-separate-resources.json earl tjm register ${TERASLICE_ALIAS} example-job-targets.json earl tjm register ${TERASLICE_ALIAS} example-job-volume.json @@ -199,6 +200,7 @@ deregister: ## resets jobs earl tjm reset example-job.json || echo '* it is okay' earl tjm reset example-job-labels.json || echo '* it is okay' earl tjm reset example-job-resource.json || echo '* it is okay' + earl tjm reset example-job-separate-resources.json || echo '* it is okay' earl tjm reset example-job-targets.json || echo '* it is okay' earl tjm reset example-job-volume.json || echo '* it is okay' diff --git a/examples/k8s/example-job-separate-resources.json b/examples/k8s/example-job-separate-resources.json new file mode 100644 index 00000000000..089c4728b4e --- /dev/null +++ b/examples/k8s/example-job-separate-resources.json @@ -0,0 +1,29 @@ +{ + "name": "example-data-generator-job-separate-resources", + "lifecycle": "once", + "workers": 2, + "assets": [ + "example", + "elasticsearch", + "standard" + ], + "resources_requests_cpu": 0.25, + "resources_limits_cpu": 1, + "resources_requests_memory": 128000000, + "resources_limits_memory": 536870912, + "operations": [ + { + "_op": "data_generator", + "size": 5000000 + }, + { + "_op": "example-op" + }, + { + "_op": "elasticsearch_bulk", + "index": "terak8s-example-data", + "type": "events", + "size": 5000 + } + ] +} diff --git a/package.json b/package.json index edd0ab26e12..062c7384766 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "teraslice-workspace", "displayName": "Teraslice", - "version": "0.78.0", + "version": "0.79.0", "private": true, "homepage": "https://github.com/terascope/teraslice", "bugs": { diff --git a/packages/data-mate/src/function-configs/date/setTimezone.ts b/packages/data-mate/src/function-configs/date/setTimezone.ts index 551e5d8f814..229ba38e8df 100644 --- a/packages/data-mate/src/function-configs/date/setTimezone.ts +++ b/packages/data-mate/src/function-configs/date/setTimezone.ts @@ -3,6 +3,7 @@ import { isNumber, isString, setTimezoneFP, + timezoneToOffset, toISO8601 } from '@terascope/utils'; import { @@ -62,8 +63,7 @@ export const setTimezoneConfig: FieldTransformConfig = { }, field: 'testField', input: '2020-02-14T20:45:30.091Z', - // FIXME this test breaks during daylight savings - output: [new Date('2020-02-14T20:45:30.091Z').getTime(), 1 * 60], + output: [new Date('2020-02-14T20:45:30.091Z').getTime(), timezoneToOffset('Europe/Paris')], serialize_output: toISO8601 } ], diff --git a/packages/job-components/package.json b/packages/job-components/package.json index 1a13745970f..c5546c5cea3 100644 --- a/packages/job-components/package.json +++ b/packages/job-components/package.json @@ -1,7 +1,7 @@ { "name": "@terascope/job-components", "displayName": "Job Components", - "version": "0.56.1", + "version": "0.56.2", "description": "A teraslice library for validating jobs schemas, registering apis, and defining and running new Job APIs", "homepage": "https://github.com/terascope/teraslice/tree/master/packages/job-components#readme", "bugs": { diff --git a/packages/job-components/src/config-validators.ts b/packages/job-components/src/config-validators.ts index 2a7a18ca06c..0dfa471ed6c 100644 --- a/packages/job-components/src/config-validators.ts +++ b/packages/job-components/src/config-validators.ts @@ -64,5 +64,15 @@ export function validateJobConfig( throw new Error(`Validation failed for job config: ${inputConfig.name} - ${err.message}`); } - return config.getProperties(); + const jobProperties = config.getProperties(); + + if ((jobProperties.cpu && jobProperties.resources_limits_cpu) + || (jobProperties.cpu && jobProperties.resources_requests_cpu) + || (jobProperties.memory && jobProperties.resources_limits_memory) + || (jobProperties.memory && jobProperties.resources_requests_memory) + ) { + throw new Error(`Validation failed for job config: ${inputConfig.name} - cpu/memory can't be mixed with resource settings of the same type.`); + } + + return jobProperties; } diff --git a/packages/job-components/src/interfaces/jobs.ts b/packages/job-components/src/interfaces/jobs.ts index a3cfd323875..18c39207bbd 100644 --- a/packages/job-components/src/interfaces/jobs.ts +++ b/packages/job-components/src/interfaces/jobs.ts @@ -112,6 +112,14 @@ export interface ValidatedJobConfig { /** This will only be available in the context of k8s */ memory_execution_controller?: number; /** This will only be available in the context of k8s */ + resources_requests_cpu?: number; + /** This will only be available in the context of k8s */ + resources_requests_memory?: number; + /** This will only be available in the context of k8s */ + resources_limits_cpu?: number; + /** This will only be available in the context of k8s */ + resources_limits_memory?: number; + /** This will only be available in the context of k8s */ volumes?: Volume[]; /** This will only be available in the context of k8s */ kubernetes_image?: string; diff --git a/packages/job-components/src/job-schemas.ts b/packages/job-components/src/job-schemas.ts index 57f9e5b3c0a..c2f443acd72 100644 --- a/packages/job-components/src/job-schemas.ts +++ b/packages/job-components/src/job-schemas.ts @@ -303,6 +303,30 @@ export function jobSchema(context: Context): convict.Schema { format: 'Number', }; + schemas.resources_requests_cpu = { + doc: 'kubernetes CPU request, in cores, to set on Teraslice workers', + default: undefined, + format: 'Number' + }; + + schemas.resources_requests_memory = { + doc: 'kubernetes memory request, in bytes, to set on Teraslice workers', + default: undefined, + format: 'Number' + }; + + schemas.resources_limits_cpu = { + doc: 'kubernetes CPU limit, in cores, to set on Teraslice workers', + default: undefined, + format: 'Number' + }; + + schemas.resources_limits_memory = { + doc: 'kubernetes memory limit, in bytes, to set on Teraslice workers', + default: undefined, + format: 'Number' + }; + schemas.volumes = { default: [], doc: 'array of volumes to be mounted by job workers', diff --git a/packages/job-components/test/config-validators-spec.ts b/packages/job-components/test/config-validators-spec.ts index 4ee10e27dd1..b0983157a88 100644 --- a/packages/job-components/test/config-validators-spec.ts +++ b/packages/job-components/test/config-validators-spec.ts @@ -598,7 +598,7 @@ describe('when validating k8s clustering', () => { const context = new TestContext('teraslice-operations'); context.sysconfig.teraslice.cluster_manager_type = 'kubernetes'; - describe('when passed a jobConfig with resources', () => { + describe('when passed a jobConfig with cpu and memory', () => { it('should return a completed and valid jobConfig', () => { const schema = jobSchema(context); const job = { @@ -620,6 +620,58 @@ describe('when validating k8s clustering', () => { }); }); + describe('when passed a jobConfig with cpu and memory resources', () => { + it('should return a completed and valid jobConfig', () => { + const schema = jobSchema(context); + const job = { + resources_requests_cpu: 1, + resources_requests_memory: 805306368, + resources_limits_cpu: 1.5, + resources_limits_memory: 905306368, + operations: [ + { + _op: 'noop', + }, + { + _op: 'noop', + }, + ], + }; + + const jobConfig = validateJobConfig(schema, job); + expect(jobConfig.resources_requests_cpu).toEqual(job.resources_requests_cpu); + expect(jobConfig.resources_requests_memory).toEqual(job.resources_requests_memory); + expect(jobConfig.resources_limits_cpu).toEqual(job.resources_limits_cpu); + expect(jobConfig.resources_limits_memory).toEqual(job.resources_limits_memory); + }); + }); + + describe('when passed a jobConfig with old and new cpu and memory resources', () => { + it('should throw an exception', () => { + const schema = jobSchema(context); + const job = { + cpu: 1, + memory: 805306368, + resources_requests_cpu: 1, + resources_limits_cpu: 1.5, + resources_requests_memory: 805306368, + resources_limits_memory: 905306368, + operations: [ + { + _op: 'noop', + }, + { + _op: 'noop', + }, + ], + }; + + expect(() => { + validateJobConfig(schema, job); + }).toThrowError('Validation failed for job config: undefined - cpu/memory can\'t be mixed with resource settings of the same type.'); + }); + }); + describe('when passed a jobConfig with targets', () => { it('should return a completed and valid jobConfig', () => { const schema = jobSchema(context); diff --git a/packages/teraslice-cli/package.json b/packages/teraslice-cli/package.json index 7e7a2d77c39..a3691bc0302 100644 --- a/packages/teraslice-cli/package.json +++ b/packages/teraslice-cli/package.json @@ -1,7 +1,7 @@ { "name": "teraslice-cli", "displayName": "Teraslice CLI", - "version": "0.48.1", + "version": "0.48.2", "description": "Command line manager for teraslice jobs, assets, and cluster references.", "keywords": [ "teraslice" @@ -51,7 +51,7 @@ "pretty-bytes": "^5.6.0", "prompts": "^2.4.2", "signale": "^1.4.0", - "teraslice-client-js": "^0.44.1", + "teraslice-client-js": "^0.44.2", "tmp": "^0.2.0", "tty-table": "^4.1.5", "yargs": "^17.3.1", diff --git a/packages/teraslice-client-js/package.json b/packages/teraslice-client-js/package.json index 2581a8daac5..06e108f93f5 100644 --- a/packages/teraslice-client-js/package.json +++ b/packages/teraslice-client-js/package.json @@ -1,7 +1,7 @@ { "name": "teraslice-client-js", "displayName": "Teraslice Client (JavaScript)", - "version": "0.44.1", + "version": "0.44.2", "description": "A Node.js client for teraslice jobs, assets, and cluster references.", "keywords": [ "elasticsearch", @@ -31,7 +31,7 @@ "test:watch": "ts-scripts test --watch . --" }, "dependencies": { - "@terascope/job-components": "^0.56.1", + "@terascope/job-components": "^0.56.2", "auto-bind": "^4.0.0", "got": "^11.8.3" }, diff --git a/packages/teraslice-op-test-harness/package.json b/packages/teraslice-op-test-harness/package.json index f537bcc1096..c38f5b34650 100644 --- a/packages/teraslice-op-test-harness/package.json +++ b/packages/teraslice-op-test-harness/package.json @@ -21,10 +21,10 @@ "bluebird": "^3.7.2" }, "devDependencies": { - "@terascope/job-components": "^0.56.1" + "@terascope/job-components": "^0.56.2" }, "peerDependencies": { - "@terascope/job-components": ">=0.56.1" + "@terascope/job-components": ">=0.56.2" }, "engines": { "node": "^12.22.0 || >=14.17.0", diff --git a/packages/teraslice-test-harness/package.json b/packages/teraslice-test-harness/package.json index 1c76bc0cc54..2d35441d082 100644 --- a/packages/teraslice-test-harness/package.json +++ b/packages/teraslice-test-harness/package.json @@ -36,10 +36,10 @@ "fs-extra": "^10.0.0" }, "devDependencies": { - "@terascope/job-components": "^0.56.1" + "@terascope/job-components": "^0.56.2" }, "peerDependencies": { - "@terascope/job-components": ">=0.56.1" + "@terascope/job-components": ">=0.56.2" }, "engines": { "node": "^12.22.0 || >=14.17.0", diff --git a/packages/teraslice/lib/cluster/services/cluster/backends/kubernetes/k8sResource.js b/packages/teraslice/lib/cluster/services/cluster/backends/kubernetes/k8sResource.js index 56b0ebc4dc4..b58a2f6dcb5 100644 --- a/packages/teraslice/lib/cluster/services/cluster/backends/kubernetes/k8sResource.js +++ b/packages/teraslice/lib/cluster/services/cluster/backends/kubernetes/k8sResource.js @@ -266,14 +266,40 @@ class K8sResource { _setResources() { let cpu; let memory; + let maxMemory; + + const container = this.resource.spec.template.spec.containers[0]; // use teraslice config as defaults and execution config will override it const envVars = Object.assign({}, this.terasliceConfig.env_vars, this.execution.env_vars); if (this.nodeType === 'worker') { - // The settings on the executions override the cluster configs - cpu = this.execution.cpu || this.terasliceConfig.cpu || -1; - memory = this.execution.memory || this.terasliceConfig.memory || -1; + if (this.execution.resources_requests_cpu + || this.execution.resources_limits_cpu) { + if (this.execution.resources_requests_cpu) { + _.set(container, 'resources.requests.cpu', this.execution.resources_requests_cpu); + } + if (this.execution.resources_limits_cpu) { + _.set(container, 'resources.limits.cpu', this.execution.resources_limits_cpu); + } + } else if (this.execution.cpu || this.terasliceConfig.cpu) { + // The settings on the executions override the cluster configs + cpu = this.execution.cpu || this.terasliceConfig.cpu || -1; + _.set(container, 'resources.requests.cpu', cpu); + _.set(container, 'resources.limits.cpu', cpu); + } + if (this.execution.resources_requests_memory + || this.execution.resources_limits_memory) { + _.set(container, 'resources.requests.memory', this.execution.resources_requests_memory); + _.set(container, 'resources.limits.memory', this.execution.resources_limits_memory); + maxMemory = this.execution.resources_limits_memory; + } else if (this.execution.memory || this.terasliceConfig.memory) { + // The settings on the executions override the cluster configs + memory = this.execution.memory || this.terasliceConfig.memory || -1; + _.set(container, 'resources.requests.memory', memory); + _.set(container, 'resources.limits.memory', memory); + maxMemory = memory; + } } if (this.nodeType === 'execution_controller') { @@ -282,21 +308,17 @@ class K8sResource { || this.terasliceConfig.cpu_execution_controller || -1; memory = this.execution.memory_execution_controller || this.terasliceConfig.memory_execution_controller || -1; - } - - const container = this.resource.spec.template.spec.containers[0]; - - if (cpu !== -1) { _.set(container, 'resources.requests.cpu', cpu); _.set(container, 'resources.limits.cpu', cpu); - } - - if (memory !== -1) { _.set(container, 'resources.requests.memory', memory); _.set(container, 'resources.limits.memory', memory); + maxMemory = memory; } - setMaxOldSpaceViaEnv(container.env, envVars, memory); + // NOTE: This sucks, this manages the memory env var but it ALSO is + // responsible for doing the config and execution env var merge, which + // should NOT be in this function + setMaxOldSpaceViaEnv(container.env, envVars, maxMemory); } _setTargets() { diff --git a/packages/teraslice/package.json b/packages/teraslice/package.json index b5c8d3ae9f0..1ffe9cb1e39 100644 --- a/packages/teraslice/package.json +++ b/packages/teraslice/package.json @@ -1,7 +1,7 @@ { "name": "teraslice", "displayName": "Teraslice", - "version": "0.78.0", + "version": "0.79.0", "description": "Distributed computing platform for processing JSON data", "homepage": "https://github.com/terascope/teraslice#readme", "bugs": { @@ -38,7 +38,7 @@ }, "dependencies": { "@terascope/elasticsearch-api": "^3.0.2", - "@terascope/job-components": "^0.56.1", + "@terascope/job-components": "^0.56.2", "@terascope/teraslice-messaging": "^0.27.1", "@terascope/utils": "^0.44.1", "async-mutex": "^0.3.2", diff --git a/packages/teraslice/test/lib/cluster/services/cluster/backends/kubernetes/k8sResource-spec.js b/packages/teraslice/test/lib/cluster/services/cluster/backends/kubernetes/k8sResource-spec.js index 42313b5efe5..3d5914a6616 100644 --- a/packages/teraslice/test/lib/cluster/services/cluster/backends/kubernetes/k8sResource-spec.js +++ b/packages/teraslice/test/lib/cluster/services/cluster/backends/kubernetes/k8sResource-spec.js @@ -38,9 +38,7 @@ describe('k8sResource', () => { describe('worker deployment', () => { it('has valid resource object.', () => { - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.kind).toBe('Deployment'); expect(kr.resource.spec.replicas).toBe(2); @@ -67,9 +65,7 @@ describe('k8sResource', () => { it('has valid resource object when terasliceConfig has kubernetes_image_pull_secret.', () => { terasliceConfig.kubernetes_image_pull_secret = 'teraslice-image-pull-secret'; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.spec.template.spec.imagePullSecrets[0]).toEqual( yaml.load(` @@ -79,9 +75,7 @@ describe('k8sResource', () => { it('has podAntiAffinity when terasliceConfig has kubernetes_worker_antiaffinity true.', () => { terasliceConfig.kubernetes_worker_antiaffinity = true; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); // console.log(yaml.dump(kr.resource.spec.template.spec.affinity)); expect(kr.resource.spec.template.spec.affinity).toEqual( @@ -108,9 +102,7 @@ describe('k8sResource', () => { terasliceConfig.assets_directory = '/assets'; terasliceConfig.assets_volume = 'asset-volume'; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.spec.replicas).toBe(2); expect(kr.resource.metadata.name).toBe('ts-wkr-example-data-generator-job-7ba9afb0-417a'); @@ -146,9 +138,7 @@ describe('k8sResource', () => { { name: 'teraslice-data1', path: '/data' } ]; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); // First check the configMap volumes, which should be present on all // deployments @@ -181,9 +171,7 @@ describe('k8sResource', () => { { name: 'tmp', path: '/tmp' } ]; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); // Now check for the volumes added via job expect(kr.resource.spec.template.spec.volumes[1]).toEqual(yaml.load(` @@ -206,9 +194,7 @@ describe('k8sResource', () => { }); it('does not have memory/cpu limits/requests when not set in config or execution', () => { - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.metadata.labels['teraslice.terascope.io/exId']) .toEqual('e76a0278-d9bc-4d78-bf14-431bcd97528c'); @@ -222,9 +208,7 @@ describe('k8sResource', () => { terasliceConfig.cpu = 1; terasliceConfig.memory = 2147483648; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.metadata.labels['teraslice.terascope.io/exId']) .toEqual('e76a0278-d9bc-4d78-bf14-431bcd97528c'); @@ -242,10 +226,10 @@ describe('k8sResource', () => { }); it('has the ability to set custom env', () => { - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); + // NOTE: the env var merge happens in _setResources(), which is + // somewhat out of place. const envArray = kr.resource.spec.template.spec.containers[0].env; expect(_.find(envArray, { name: 'FOO' }).value) .toEqual('baz'); @@ -260,9 +244,7 @@ describe('k8sResource', () => { terasliceConfig.cpu = 1; terasliceConfig.memory = 2147483648; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.metadata.labels['teraslice.terascope.io/exId']) .toEqual('e76a0278-d9bc-4d78-bf14-431bcd97528c'); @@ -284,9 +266,7 @@ describe('k8sResource', () => { terasliceConfig.cpu = 1; terasliceConfig.memory = 2147483648; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.metadata.labels['teraslice.terascope.io/exId']) .toEqual('e76a0278-d9bc-4d78-bf14-431bcd97528c'); @@ -307,9 +287,7 @@ describe('k8sResource', () => { execution.cpu = 1; execution.memory = 2147483648; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.metadata.labels['teraslice.terascope.io/exId']) .toEqual('e76a0278-d9bc-4d78-bf14-431bcd97528c'); @@ -326,13 +304,34 @@ describe('k8sResource', () => { .toEqual('--max-old-space-size=1843'); }); + // eslint-disable-next-line jest/no-disabled-tests + it('has separate memory and cpu limits and requests when set on execution', () => { + execution.resources_requests_cpu = 1; + execution.resources_limits_cpu = 2; + execution.resources_requests_memory = 2147483648; + execution.resources_limits_memory = 3147483648; + + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); + + expect(kr.resource.metadata.labels['teraslice.terascope.io/exId']) + .toEqual('e76a0278-d9bc-4d78-bf14-431bcd97528c'); + expect(kr.resource.spec.template.spec.containers[0].resources).toEqual(yaml.load(` + requests: + memory: 2147483648 + cpu: 1 + limits: + memory: 3147483648 + cpu: 2`)); + + const envArray = kr.resource.spec.template.spec.containers[0].env; + expect(_.find(envArray, { name: 'NODE_OPTIONS' }).value) + .toEqual('--max-old-space-size=2702'); + }); + it('has memory limits and requests when set on execution', () => { - execution.cpu = -1; execution.memory = 2147483648; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.spec.template.spec.containers[0].resources).toEqual(yaml.load(` requests: @@ -347,11 +346,8 @@ describe('k8sResource', () => { it('has cpu limits and requests when set on execution', () => { execution.cpu = 1; - execution.memory = -1; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.spec.template.spec.containers[0].resources).toEqual(yaml.load(` requests: @@ -363,9 +359,7 @@ describe('k8sResource', () => { it('has scratch volume when ephemeral_storage is set true on execution', () => { execution.ephemeral_storage = true; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.spec.template.spec.containers[0].volumeMounts) .toEqual( @@ -379,9 +373,7 @@ describe('k8sResource', () => { it('does not have scratch volume when ephemeral_storage is set false on execution', () => { execution.ephemeral_storage = false; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.spec.template.spec.containers[0].volumeMounts) .toEqual([{ mountPath: '/app/config', name: 'config' }]); @@ -391,9 +383,7 @@ describe('k8sResource', () => { describe('worker deployments with targets', () => { it('does not have affinity or toleration properties when targets equals [].', () => { execution.targets = []; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.spec.template.spec).not.toHaveProperty('affinity'); expect(kr.resource.spec.template.spec).not.toHaveProperty('toleration'); @@ -403,9 +393,7 @@ describe('k8sResource', () => { execution.targets = [ { key: 'zone', value: 'west' } ]; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.spec.template.spec.affinity).toEqual(yaml.load(` nodeAffinity: @@ -423,9 +411,7 @@ describe('k8sResource', () => { { key: 'zone', value: 'west' } ]; terasliceConfig.kubernetes_worker_antiaffinity = true; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.spec.template.spec.affinity).toEqual(yaml.load(` nodeAffinity: @@ -457,9 +443,7 @@ describe('k8sResource', () => { execution.targets = [ { key: 'zone', value: 'west', constraint: 'required' } ]; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.spec.template.spec.affinity).toEqual(yaml.load(` nodeAffinity: @@ -477,9 +461,7 @@ describe('k8sResource', () => { { key: 'zone', value: 'west', constraint: 'required' }, { key: 'region', value: '42', constraint: 'required' } ]; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.spec.template.spec.affinity).toEqual(yaml.load(` nodeAffinity: @@ -500,9 +482,7 @@ describe('k8sResource', () => { execution.targets = [ { key: 'zone', value: 'west', constraint: 'preferred' } ]; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.spec.template.spec.affinity).toEqual(yaml.load(` nodeAffinity: @@ -521,9 +501,7 @@ describe('k8sResource', () => { { key: 'zone', value: 'west', constraint: 'preferred' }, { key: 'region', value: 'texas', constraint: 'preferred' } ]; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.spec.template.spec.affinity).toEqual(yaml.load(` nodeAffinity: @@ -548,9 +526,7 @@ describe('k8sResource', () => { execution.targets = [ { key: 'zone', value: 'west', constraint: 'accepted' } ]; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); // console.log(yaml.dump(kr.resource.spec.template.spec.tolerations)); expect(kr.resource.spec.template.spec.tolerations).toEqual(yaml.load(` @@ -565,9 +541,7 @@ describe('k8sResource', () => { { key: 'zone', value: 'west', constraint: 'accepted' }, { key: 'region', value: 'texas', constraint: 'accepted' } ]; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); // console.log(yaml.dump(kr.resource.spec.template.spec.tolerations)); expect(kr.resource.spec.template.spec.tolerations).toEqual(yaml.load(` @@ -586,9 +560,7 @@ describe('k8sResource', () => { { key: 'zone', value: 'west', constraint: 'required' }, { key: 'region', value: 'texas', constraint: 'preferred' } ]; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); // console.log(yaml.dump(kr.resource.spec.template.spec.tolerations)); expect(kr.resource.spec.template.spec.affinity).toEqual(yaml.load(` @@ -619,9 +591,7 @@ describe('k8sResource', () => { { key: 'zone', value: 'west', constraint: 'accepted' }, { key: 'region', value: 'texas', constraint: 'accepted' } ]; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.spec.template.spec.affinity).toEqual(yaml.load(` nodeAffinity: @@ -670,9 +640,7 @@ describe('k8sResource', () => { key2: 'value2' }; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); // console.log(yaml.dump(kr.resource)); expect(kr.resource.metadata.labels['job.teraslice.terascope.io/key1']).toEqual('value1'); @@ -686,9 +654,7 @@ describe('k8sResource', () => { abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij1234: 'value3', }; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); // console.log(yaml.dump(kr.resource)); expect(kr.resource.metadata.labels['job.teraslice.terascope.io/key-1']).toEqual('value1'); expect(kr.resource.metadata.labels['job.teraslice.terascope.io/key2-']).toEqual('value2'); @@ -699,9 +665,7 @@ describe('k8sResource', () => { describe('teraslice job with one valid external_ports set', () => { it('generates k8s worker deployment with containerPort on container', () => { execution.external_ports = [9090]; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); // eslint-disable-next-line no-console // console.log(yaml.dump(kr.resource.spec.template.spec.containers[0].ports)); @@ -714,9 +678,7 @@ describe('k8sResource', () => { it('generates k8s execution controller job with containerPort on container', () => { execution.external_ports = [9090]; - const kr = new K8sResource( - 'jobs', 'execution_controller', terasliceConfig, execution - ); + const kr = new K8sResource('jobs', 'execution_controller', terasliceConfig, execution); // eslint-disable-next-line no-console // console.log(yaml.dump(kr.resource.spec.template.spec.containers[0].ports)); @@ -734,9 +696,7 @@ describe('k8sResource', () => { 9090, { name: 'metrics', port: 9091 } ]; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); // eslint-disable-next-line no-console // console.log(yaml.dump(kr.resource.spec.template.spec.containers[0].ports)); @@ -750,9 +710,7 @@ describe('k8sResource', () => { it('generates k8s execution controller job with containerPort on container', () => { execution.external_ports = [9090, 9091]; - const kr = new K8sResource( - 'jobs', 'execution_controller', terasliceConfig, execution - ); + const kr = new K8sResource('jobs', 'execution_controller', terasliceConfig, execution); // eslint-disable-next-line no-console // console.log(yaml.dump(kr.resource.spec.template.spec.containers[0].ports)); @@ -767,9 +725,7 @@ describe('k8sResource', () => { describe('execution_controller job', () => { it('has valid resource object.', () => { - const kr = new K8sResource( - 'jobs', 'execution_controller', terasliceConfig, execution - ); + const kr = new K8sResource('jobs', 'execution_controller', terasliceConfig, execution); expect(kr.resource.kind).toBe('Job'); expect(kr.resource.metadata.name).toBe('ts-exc-example-data-generator-job-7ba9afb0-417a'); @@ -796,9 +752,7 @@ describe('k8sResource', () => { terasliceConfig.cpu_execution_controller = 1; terasliceConfig.memory_execution_controller = 2147483648; - const kr = new K8sResource( - 'jobs', 'execution_controller', terasliceConfig, execution - ); + const kr = new K8sResource('jobs', 'execution_controller', terasliceConfig, execution); expect(kr.resource.spec.template.spec.containers[0].resources).toEqual(yaml.load(` requests: @@ -819,9 +773,7 @@ describe('k8sResource', () => { terasliceConfig.cpu_execution_controller = 1; terasliceConfig.memory_execution_controller = 2147483648; - const kr = new K8sResource( - 'jobs', 'execution_controller', terasliceConfig, execution - ); + const kr = new K8sResource('jobs', 'execution_controller', terasliceConfig, execution); expect(kr.resource.spec.template.spec.containers[0].resources).toEqual(yaml.load(` requests: @@ -848,9 +800,7 @@ describe('k8sResource', () => { ['teraslice-JOB-name', 'ts-wkr-teraslice-job-name-7ba9afb0-417a'] ])('when Job Name is %s the k8s worker name is: %s', (jobName, k8sName) => { execution.name = jobName; - const kr = new K8sResource( - 'deployments', 'worker', terasliceConfig, execution - ); + const kr = new K8sResource('deployments', 'worker', terasliceConfig, execution); expect(kr.resource.metadata.name).toBe(k8sName); }); @@ -863,9 +813,7 @@ describe('k8sResource', () => { { key: 'key2', value: 'value2' } ]; - const kr = new K8sResource( - 'jobs', 'execution_controller', terasliceConfig, execution - ); + const kr = new K8sResource('jobs', 'execution_controller', terasliceConfig, execution); expect(kr.resource.kind).toBe('Job'); expect(kr.resource.metadata.name).toBe('ts-exc-example-data-generator-job-7ba9afb0-417a'); @@ -908,9 +856,7 @@ describe('k8sResource', () => { { key: 'region', value: 'texas', constraint: 'accepted' } ]; - const kr = new K8sResource( - 'jobs', 'execution_controller', terasliceConfig, execution - ); + const kr = new K8sResource('jobs', 'execution_controller', terasliceConfig, execution); expect(kr.resource.kind).toBe('Job'); expect(kr.resource.metadata.name).toBe('ts-exc-example-data-generator-job-7ba9afb0-417a');