From 10882d9bd111a7d033af04c8c01b975e17e27217 Mon Sep 17 00:00:00 2001 From: Peter Luitjens <43619525+busma13@users.noreply.github.com> Date: Fri, 31 Jan 2025 14:59:24 -0700 Subject: [PATCH] [e2e, scripts] Start K8s e2e from helmfile (#3929) This PR makes the following changes: - creates a `helm` directory in `e2e` with the following: - helmfile.yaml - values.yaml - modified elastic/elasticsearch-6.8.9 chart - modified elastic/elasticsearch-7.9.3 chart - modified confluentinc/cp-helm-charts-0.6.1 chart (kafka and zookeeper) - go templates for teraslice and services - update the teraslice helm chart to include the `autoload_directory` - update `ts-scripts test` to start k8s e2e tests via helmfile using the -use-helmfile` flag - update e2e to use helmfile commands instead of the k8s api when started via helm - update default service versions for tests - kafka version from `3.5` to `3.7`, which is `cp-kafka:v7.7.2` - opensearch1 from `1.3.10` to `1.3.11` - opensearch2 from `2.8.0` to `2.15.0` - k8s e2e tests now run on opensearch2, not elasticsearch7 - update mappings between kafka and cp-kafka versions - bump e2e version from `0.7.1` to `0.8.0` - bump scripts version from `1.9.3` to `1.10.0` ref: #3931 --------- Co-authored-by: Joseph Soto --- .github/workflows/test.yml | 209 ++++++++++-------- e2e/helm/elasticsearch/README.md | 7 + .../elasticsearch/elasticsearch-6.8.9.tgz | Bin 0 -> 24085 bytes .../elasticsearch/elasticsearch-7.9.3.tgz | Bin 0 -> 26116 bytes e2e/helm/helmfile.yaml | 70 ++++++ e2e/helm/kafka/README.md | 3 + e2e/helm/kafka/cp-helm-charts-0.6.1.tgz | Bin 0 -> 50595 bytes e2e/helm/templates/es6.yaml.gotmpl | 31 +++ e2e/helm/templates/es7.yaml.gotmpl | 29 +++ e2e/helm/templates/kafka.yaml.gotmpl | 30 +++ e2e/helm/templates/minio.yaml.gotmpl | 41 ++++ e2e/helm/templates/os1.yaml.gotmpl | 36 +++ e2e/helm/templates/os2.yaml.gotmpl | 39 ++++ e2e/helm/templates/teraslice.yaml.gotmpl | 79 +++++++ e2e/helm/values.yaml | 81 +++++++ e2e/k8s/kindConfigTestPorts.yaml | 7 +- e2e/package.json | 9 +- e2e/test/config.ts | 5 +- e2e/test/global.setup.ts | 12 +- e2e/test/teardown.ts | 14 +- helm/teraslice/templates/deployment.yaml | 7 + helm/teraslice/values.yaml | 2 + package.json | 2 +- packages/elasticsearch-api/package.json | 2 +- packages/elasticsearch-store/package.json | 2 +- packages/scripts/package.json | 2 +- packages/scripts/src/cmds/test.ts | 10 +- packages/scripts/src/helpers/config.ts | 7 +- packages/scripts/src/helpers/k8s-env/index.ts | 3 +- packages/scripts/src/helpers/kind.ts | 2 +- packages/scripts/src/helpers/mapper.ts | 19 +- packages/scripts/src/helpers/scripts.ts | 110 ++++++++- .../scripts/src/helpers/test-runner/index.ts | 48 ++-- .../src/helpers/test-runner/interfaces.ts | 1 + .../scripts/src/helpers/test-runner/utils.ts | 4 +- packages/scripts/test/helpers-spec.ts | 8 +- packages/scripts/test/service-spec.ts | 3 +- packages/scripts/test/test-runner-spec.ts | 3 +- packages/teraslice/package.json | 2 +- yarn.lock | 7 +- 40 files changed, 791 insertions(+), 155 deletions(-) create mode 100644 e2e/helm/elasticsearch/README.md create mode 100644 e2e/helm/elasticsearch/elasticsearch-6.8.9.tgz create mode 100644 e2e/helm/elasticsearch/elasticsearch-7.9.3.tgz create mode 100644 e2e/helm/helmfile.yaml create mode 100644 e2e/helm/kafka/README.md create mode 100644 e2e/helm/kafka/cp-helm-charts-0.6.1.tgz create mode 100644 e2e/helm/templates/es6.yaml.gotmpl create mode 100644 e2e/helm/templates/es7.yaml.gotmpl create mode 100644 e2e/helm/templates/kafka.yaml.gotmpl create mode 100644 e2e/helm/templates/minio.yaml.gotmpl create mode 100644 e2e/helm/templates/os1.yaml.gotmpl create mode 100644 e2e/helm/templates/os2.yaml.gotmpl create mode 100644 e2e/helm/templates/teraslice.yaml.gotmpl create mode 100644 e2e/helm/values.yaml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 71a3bb6735f..eeda236200e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -74,15 +74,14 @@ jobs: - name: Test run: yarn test --suite unit -- - teraslice-elasticsearch-tests: + e2e-k8s-tests: runs-on: ubuntu-latest needs: [compute-node-version-vars, verify-build, cache-docker-images] strategy: # opensearch is finiky, keep testing others if it fails fail-fast: false matrix: - node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS) }} - search-version: [elasticsearch6, elasticsearch7, opensearch1, opensearch2] + node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS_EXT_K8S) }} steps: - name: Check out code uses: actions/checkout@v4 @@ -115,19 +114,27 @@ jobs: path: /tmp/docker_cache key: docker-images-${{ hashFiles('./images/image-list.txt') }} - - name: Test ${{ matrix.search-version }} - run: yarn test:${{ matrix.search-version }} - working-directory: ./packages/teraslice + - name: Compile e2e code + run: yarn build + working-directory: ./e2e - elasticsearch-store-tests: + - name: Install Kind and Kubectl + uses: helm/kind-action@v1.10.0 + with: + install_only: "true" + + - name: Test k8s elasticsearch7 + run: NODE_VERSION=${{ matrix.node-version }} yarn test:k8s + working-directory: ./e2e + + e2e-k8s-v2-tests: runs-on: ubuntu-latest needs: [compute-node-version-vars, verify-build, cache-docker-images] strategy: # opensearch is finiky, keep testing others if it fails fail-fast: false matrix: - node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS) }} - search-version: [elasticsearch6, elasticsearch7, opensearch1, opensearch2] + node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS_EXT_K8S) }} steps: - name: Check out code uses: actions/checkout@v4 @@ -160,43 +167,46 @@ jobs: path: /tmp/docker_cache key: docker-images-${{ hashFiles('./images/image-list.txt') }} - - name: Test ${{ matrix.search-version }} - run: yarn test:${{ matrix.search-version }} - working-directory: ./packages/elasticsearch-store - - lint-and-sync: - runs-on: ubuntu-latest - needs: [compute-node-version-vars, verify-build, cache-docker-images] - # will remove the checkout, build and setup when the artifact is made to just - # test the linting and syncing of the codebase - steps: - - name: Check out code - uses: actions/checkout@v4 - - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSION_MAIN) }} - cache: 'yarn' + - name: Compile e2e code + run: yarn build + working-directory: ./e2e - - name: Install and build packages - run: yarn && yarn setup + - name: Install Kind and Kubectl + uses: helm/kind-action@v1.10.0 + with: + install_only: "true" - - name: Lint codebase - run: yarn lint + - name: Install Helmfile + run: | + VERSION=$(curl -s https://api.github.com/repos/helmfile/helmfile/releases/latest | jq -r '.tag_name') + VERSION_NO_V=${VERSION#v} + curl -L "https://github.com/helmfile/helmfile/releases/download/${VERSION}/helmfile_${VERSION_NO_V}_linux_amd64.tar.gz" -o helmfile.tgz + tar -xzf helmfile.tgz + chmod +x helmfile + mv helmfile /usr/local/bin/helmfile + helm plugin install https://github.com/databus23/helm-diff + helmfile version + helm version + + - name: Test CLI Commands + run: | + command -v kind + command -v kubectl + command -v helm + command -v helmfile - - name: Sync codebase - run: yarn sync --verify + - name: Test k8s V2 opensearch2 + run: NODE_VERSION=${{ matrix.node-version }} yarn test:k8sV2Helmfile + working-directory: ./e2e - elasticsearch-api-tests: + e2e-external-storage-tests: runs-on: ubuntu-latest needs: [compute-node-version-vars, verify-build, cache-docker-images] strategy: # opensearch is finiky, keep testing others if it fails fail-fast: false matrix: - node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS) }} - search-version: [elasticsearch6, elasticsearch7, opensearch1, opensearch2] + node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS_EXT_STORAGE) }} steps: - name: Check out code uses: actions/checkout@v4 @@ -229,19 +239,22 @@ jobs: path: /tmp/docker_cache key: docker-images-${{ hashFiles('./images/image-list.txt') }} - - name: Test ${{ matrix.search-version }} - run: yarn test:${{ matrix.search-version }} - working-directory: ./packages/elasticsearch-api + - name: Compile e2e code + run: yarn build + working-directory: ./e2e - e2e-tests: + - name: Test external Asset Storage opensearch1 + run: NODE_VERSION=${{ matrix.node-version }} yarn test:s3AssetStorage + working-directory: ./e2e + + e2e-external-storage-tests-encrypted: runs-on: ubuntu-latest needs: [compute-node-version-vars, verify-build, cache-docker-images] strategy: # opensearch is finiky, keep testing others if it fails fail-fast: false matrix: - node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS) }} - search-version: [elasticsearch6, elasticsearch7, opensearch1, opensearch2] + node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS_EXT_STORAGE) }} steps: - name: Check out code uses: actions/checkout@v4 @@ -274,22 +287,35 @@ jobs: path: /tmp/docker_cache key: docker-images-${{ hashFiles('./images/image-list.txt') }} + - name: Install mkcert + run: curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64" && sudo chmod 777 mkcert-v*-linux-amd64 && sudo cp mkcert-v*-linux-amd64 /usr/local/bin/mkcert + + - name: Install grep + run: sudo apt update && sudo apt install grep + + - name: Check mkcert + run: command -v mkcert + + - name: Check grep + run: command -v grep + - name: Compile e2e code run: yarn build working-directory: ./e2e - - name: Test ${{ matrix.search-version }} - run: NODE_VERSION=${{ matrix.node-version }} yarn test:${{ matrix.search-version }} + - name: Test external Asset Storage opensearch1 + run: ENCRYPT_MINIO=true NODE_VERSION=${{ matrix.node-version }} yarn test:s3AssetStorage working-directory: ./e2e - e2e-k8s-tests: + teraslice-elasticsearch-tests: runs-on: ubuntu-latest needs: [compute-node-version-vars, verify-build, cache-docker-images] strategy: # opensearch is finiky, keep testing others if it fails fail-fast: false matrix: - node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS_EXT_K8S) }} + node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS) }} + search-version: [elasticsearch6, elasticsearch7, opensearch1, opensearch2] steps: - name: Check out code uses: actions/checkout@v4 @@ -322,27 +348,19 @@ jobs: path: /tmp/docker_cache key: docker-images-${{ hashFiles('./images/image-list.txt') }} - - name: Compile e2e code - run: yarn build - working-directory: ./e2e - - - name: Install Kind and Kubectl - uses: helm/kind-action@v1.10.0 - with: - install_only: "true" - - - name: Test k8s elasticsearch7 - run: NODE_VERSION=${{ matrix.node-version }} yarn test:k8s - working-directory: ./e2e + - name: Test ${{ matrix.search-version }} + run: yarn test:${{ matrix.search-version }} + working-directory: ./packages/teraslice - e2e-k8s-v2-tests: + elasticsearch-store-tests: runs-on: ubuntu-latest needs: [compute-node-version-vars, verify-build, cache-docker-images] strategy: # opensearch is finiky, keep testing others if it fails fail-fast: false matrix: - node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS_EXT_K8S) }} + node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS) }} + search-version: [elasticsearch6, elasticsearch7, opensearch1, opensearch2] steps: - name: Check out code uses: actions/checkout@v4 @@ -375,27 +393,43 @@ jobs: path: /tmp/docker_cache key: docker-images-${{ hashFiles('./images/image-list.txt') }} - - name: Compile e2e code - run: yarn build - working-directory: ./e2e + - name: Test ${{ matrix.search-version }} + run: yarn test:${{ matrix.search-version }} + working-directory: ./packages/elasticsearch-store - - name: Install Kind and Kubectl - uses: helm/kind-action@v1.10.0 - with: - install_only: "true" + lint-and-sync: + runs-on: ubuntu-latest + needs: [compute-node-version-vars, verify-build, cache-docker-images] + # will remove the checkout, build and setup when the artifact is made to just + # test the linting and syncing of the codebase + steps: + - name: Check out code + uses: actions/checkout@v4 - - name: Test k8s V2 elasticsearch7 - run: NODE_VERSION=${{ matrix.node-version }} yarn test:k8sV2 - working-directory: ./e2e + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSION_MAIN) }} + cache: 'yarn' - e2e-external-storage-tests: + - name: Install and build packages + run: yarn && yarn setup + + - name: Lint codebase + run: yarn lint + + - name: Sync codebase + run: yarn sync --verify + + elasticsearch-api-tests: runs-on: ubuntu-latest needs: [compute-node-version-vars, verify-build, cache-docker-images] strategy: # opensearch is finiky, keep testing others if it fails fail-fast: false matrix: - node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS_EXT_STORAGE) }} + node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS) }} + search-version: [elasticsearch6, elasticsearch7, opensearch1, opensearch2] steps: - name: Check out code uses: actions/checkout@v4 @@ -428,22 +462,19 @@ jobs: path: /tmp/docker_cache key: docker-images-${{ hashFiles('./images/image-list.txt') }} - - name: Compile e2e code - run: yarn build - working-directory: ./e2e - - - name: Test external Asset Storage opensearch1 - run: NODE_VERSION=${{ matrix.node-version }} yarn test:s3AssetStorage - working-directory: ./e2e + - name: Test ${{ matrix.search-version }} + run: yarn test:${{ matrix.search-version }} + working-directory: ./packages/elasticsearch-api - e2e-external-storage-tests-encrypted: + e2e-tests: runs-on: ubuntu-latest needs: [compute-node-version-vars, verify-build, cache-docker-images] strategy: # opensearch is finiky, keep testing others if it fails fail-fast: false matrix: - node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS_EXT_STORAGE) }} + node-version: ${{ fromJSON(needs.compute-node-version-vars.outputs.NODE_VERSIONS) }} + search-version: [elasticsearch6, elasticsearch7, opensearch1, opensearch2] steps: - name: Check out code uses: actions/checkout@v4 @@ -476,24 +507,12 @@ jobs: path: /tmp/docker_cache key: docker-images-${{ hashFiles('./images/image-list.txt') }} - - name: Install mkcert - run: curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64" && sudo chmod 777 mkcert-v*-linux-amd64 && sudo cp mkcert-v*-linux-amd64 /usr/local/bin/mkcert - - - name: Install grep - run: sudo apt update && sudo apt install grep - - - name: Check mkcert - run: command -v mkcert - - - name: Check grep - run: command -v grep - - name: Compile e2e code run: yarn build working-directory: ./e2e - - name: Test external Asset Storage opensearch1 - run: ENCRYPT_MINIO=true NODE_VERSION=${{ matrix.node-version }} yarn test:s3AssetStorage + - name: Test ${{ matrix.search-version }} + run: NODE_VERSION=${{ matrix.node-version }} yarn test:${{ matrix.search-version }} working-directory: ./e2e check-docker-limit-after: diff --git a/e2e/helm/elasticsearch/README.md b/e2e/helm/elasticsearch/README.md new file mode 100644 index 00000000000..fb382a2e430 --- /dev/null +++ b/e2e/helm/elasticsearch/README.md @@ -0,0 +1,7 @@ +The es binaries in this directory are patched charts from https://artifacthub.io/packages/helm/elastic/elasticsearch (specifically charts versions 7.9.3 and 6.8.9) + +Since these charts are no longer maintained, they have incompatible kubernetes api resources that needed to be updated. + +The es charts for 6.8.9 and 7.9.3 have a lot files in them and I didn't want to push up 140+ files to the teraslice repo. + +In the future we can potentially place these charts in the es assets repo and submit them to artifact hub to get rid of these binaries. diff --git a/e2e/helm/elasticsearch/elasticsearch-6.8.9.tgz b/e2e/helm/elasticsearch/elasticsearch-6.8.9.tgz new file mode 100644 index 0000000000000000000000000000000000000000..cb28ba5f17bf38dc1c2973eaf1ebf5dd2fbf6195 GIT binary patch literal 24085 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 b_X6($D4~QBem?js00960ewE#_0C)lb38TK` literal 0 HcmV?d00001 diff --git a/e2e/helm/helmfile.yaml b/e2e/helm/helmfile.yaml new file mode 100644 index 00000000000..e991a11322c --- /dev/null +++ b/e2e/helm/helmfile.yaml @@ -0,0 +1,70 @@ +environments: + default: + values: + - values.yaml +--- + +repositories: + - name: opensearch + url: https://opensearch-project.github.io/helm-charts/ + - name: minio + url: https://charts.min.io/ + +helmDefaults: + wait: true + +releases: + - name: opensearch1 + namespace: services-dev1 + chart: opensearch/opensearch + version: 2.17.1 + installed: {{ .Values | get "opensearch1.enabled" false }} + values: + - ./templates/os1.yaml.gotmpl + + - name: opensearch2 + namespace: services-dev1 + chart: opensearch/opensearch + version: 2.17.1 + installed: {{ .Values | get "opensearch2.enabled" true }} + values: + - ./templates/os2.yaml.gotmpl + + - name: elasticsearch6 + namespace: services-dev1 + chart: ./elasticsearch/elasticsearch-6.8.9.tgz + installed: {{ .Values | get "elasticsearch6.enabled" false }} + values: + - ./templates/es6.yaml.gotmpl + + - name: elasticsearch7 + namespace: services-dev1 + chart: ./elasticsearch/elasticsearch-7.9.3.tgz + installed: {{ .Values | get "elasticsearch7.enabled" false }} + values: + - ./templates/es7.yaml.gotmpl + + - name: minio + namespace: services-dev1 + chart: minio/minio + version: 5.3.0 + installed: {{ .Values | get "minio.enabled" false }} + values: + - ./templates/minio.yaml.gotmpl + + - name: kafka + namespace: services-dev1 + chart: ./kafka/cp-helm-charts-0.6.1.tgz + installed: {{ .Values | get "kafka.enabled" true }} + values: + - ./templates/kafka.yaml.gotmpl + + - name: teraslice + namespace: ts-dev1 + chart: ../../helm/teraslice + needs: + - services-dev1/{{ .Values | get "teraslice.stateCluster" "opensearch2" }} + values: + - ./templates/teraslice.yaml.gotmpl + labels: + app: teraslice diff --git a/e2e/helm/kafka/README.md b/e2e/helm/kafka/README.md new file mode 100644 index 00000000000..92710e5b2bc --- /dev/null +++ b/e2e/helm/kafka/README.md @@ -0,0 +1,3 @@ +The compressed archive in this directory is a modified copy of the confluentinc/cp-helm-charts from + +Since these charts are no longer maintained, they have incompatible kubernetes api resources that needed to be updated. diff --git a/e2e/helm/kafka/cp-helm-charts-0.6.1.tgz b/e2e/helm/kafka/cp-helm-charts-0.6.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..28cb64cea1e65344020b121ea41b372aedfb0582 GIT binary patch literal 50595 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 pg { if (TEST_PLATFORM === 'kubernetes' || TEST_PLATFORM === 'kubernetesV2') { await downloadAssets(); - const k8s = new K8s(TERASLICE_PORT, KIND_CLUSTER); - await k8s.deployK8sTeraslice(TEST_PLATFORM, true, false); + if (USE_HELMFILE) { + await helmfileSync(); + } else { + const k8s = new K8s(TERASLICE_PORT, KIND_CLUSTER); + await k8s.deployK8sTeraslice(TEST_PLATFORM, true, false); + } await teraslice.waitForTeraslice(); await setAlias(TERASLICE_PORT); } else { diff --git a/e2e/test/teardown.ts b/e2e/test/teardown.ts index 05566a836a6..f336211e3ef 100644 --- a/e2e/test/teardown.ts +++ b/e2e/test/teardown.ts @@ -1,9 +1,9 @@ import { ElasticsearchTestHelpers, Client } from 'elasticsearch-store'; -import { K8s } from '@terascope/scripts'; +import { helmfileDelete, K8s } from '@terascope/scripts'; import fse from 'fs-extra'; import { - KEEP_OPEN, CONFIG_PATH, ASSETS_PATH, - TEST_INDEX_PREFIX, TEST_PLATFORM, TERASLICE_PORT, KIND_CLUSTER + KEEP_OPEN, CONFIG_PATH, ASSETS_PATH, TEST_INDEX_PREFIX, + TEST_PLATFORM, TERASLICE_PORT, KIND_CLUSTER, USE_HELMFILE } from './config.js'; import { tearDown } from './docker-helpers.js'; import signale from './signale.js'; @@ -26,8 +26,12 @@ export async function teardown(testClient?: Client) { try { if (TEST_PLATFORM === 'kubernetes' || TEST_PLATFORM === 'kubernetesV2') { - const k8s = new K8s(TERASLICE_PORT, KIND_CLUSTER); - await k8s.deleteTerasliceNamespace('ts-ns.yaml'); + if (USE_HELMFILE) { + await helmfileDelete('teraslice'); + } else { + const k8s = new K8s(TERASLICE_PORT, KIND_CLUSTER); + await k8s.deleteTerasliceNamespace('ts-ns.yaml'); + } await cleanupIndex(client, 'ts-dev1_*'); } else { await tearDown(); diff --git a/helm/teraslice/templates/deployment.yaml b/helm/teraslice/templates/deployment.yaml index 2f665304b88..173bdcb1352 100644 --- a/helm/teraslice/templates/deployment.yaml +++ b/helm/teraslice/templates/deployment.yaml @@ -70,6 +70,9 @@ spec: mountPath: /app/config - name: teraslice-assets mountPath: /app/assets + - name: autoload + mountPath: /app/autoload + readOnly: true {{- range .Values.dataVolumes }} - name: {{ .name }} mountPath: {{ .path }} @@ -122,6 +125,10 @@ spec: {{- else }} emptyDir: {} {{- end }} + - name: autoload + hostPath: + path: /autoload + type: Directory {{- range .Values.dataVolumes }} - name: {{ .name }} persistentVolumeClaim: diff --git a/helm/teraslice/values.yaml b/helm/teraslice/values.yaml index ad624a2bc67..3af4f3ac1fc 100644 --- a/helm/teraslice/values.yaml +++ b/helm/teraslice/values.yaml @@ -38,12 +38,14 @@ priorityClass: master: teraslice: assets_directory: /app/assets + autoload_directory: /app/autoload workers: 0 # Teraslice Worker Config Options worker: teraslice: assets_directory: /app/assets + autoload_directory: /app/autoload # Terafoundation # Everything under terafoundation key will used as the master and worker config diff --git a/package.json b/package.json index ca759460388..4304cc15172 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@eslint/js": "~9.19.0", "@swc/core": "1.10.9", "@swc/jest": "~0.2.37", - "@terascope/scripts": "~1.9.3", + "@terascope/scripts": "~1.10.0", "@types/bluebird": "~3.5.42", "@types/convict": "~6.1.6", "@types/elasticsearch": "~5.0.43", diff --git a/packages/elasticsearch-api/package.json b/packages/elasticsearch-api/package.json index 9b6153eee41..82ce93e916f 100644 --- a/packages/elasticsearch-api/package.json +++ b/packages/elasticsearch-api/package.json @@ -20,7 +20,7 @@ "test:elasticsearch7": "TEST_RESTRAINED_ELASTICSEARCH='true' ELASTICSEARCH_VERSION='7.9.3' yarn workspace @terascope/scripts ts-scripts test ../elasticsearch-api --", "test:elasticsearch8": "TEST_RESTRAINED_ELASTICSEARCH='true' ELASTICSEARCH_VERSION='8.1.2' yarn workspace @terascope/scripts ts-scripts test ../elasticsearch-api --", "test:opensearch1": "TEST_RESTRAINED_OPENSEARCH='true' yarn workspace @terascope/scripts ts-scripts test --debug ../elasticsearch-api --", - "test:opensearch2": "TEST_RESTRAINED_OPENSEARCH='true' OPENSEARCH_VERSION='2.8.0' yarn workspace @terascope/scripts ts-scripts test --debug ../elasticsearch-api --", + "test:opensearch2": "TEST_RESTRAINED_OPENSEARCH='true' OPENSEARCH_VERSION='2.15.0' yarn workspace @terascope/scripts ts-scripts test --debug ../elasticsearch-api --", "test:watch": "TEST_RESTRAINED_ELASTICSEARCH='true' yarn workspace @terascope/scripts ts-scripts test --watch ../elasticsearch-api --" }, "dependencies": { diff --git a/packages/elasticsearch-store/package.json b/packages/elasticsearch-store/package.json index ba96ad8bc0b..223f28caea9 100644 --- a/packages/elasticsearch-store/package.json +++ b/packages/elasticsearch-store/package.json @@ -26,7 +26,7 @@ "test:elasticsearch7": "TEST_ELASTICSEARCH='true' ELASTICSEARCH_VERSION='7.9.3' yarn workspace @terascope/scripts ts-scripts test ../elasticsearch-store --", "test:elasticsearch8": "TEST_ELASTICSEARCH='true' ELASTICSEARCH_VERSION='8.1.2' yarn workspace @terascope/scripts ts-scripts test ../elasticsearch-store --", "test:opensearch1": "TEST_OPENSEARCH='true' yarn workspace @terascope/scripts ts-scripts test ../elasticsearch-store --", - "test:opensearch2": "TEST_OPENSEARCH='true' OPENSEARCH_VERSION='2.8.0' yarn workspace @terascope/scripts ts-scripts test ../elasticsearch-store --", + "test:opensearch2": "TEST_OPENSEARCH='true' OPENSEARCH_VERSION='2.15.0' yarn workspace @terascope/scripts ts-scripts test ../elasticsearch-store --", "test:watch": "ts-scripts yarn workspace @terascope/scripts test --watch ../elasticsearch-store --" }, "dependencies": { diff --git a/packages/scripts/package.json b/packages/scripts/package.json index c8968a99751..4afaaae564c 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -1,7 +1,7 @@ { "name": "@terascope/scripts", "displayName": "Scripts", - "version": "1.9.3", + "version": "1.10.0", "description": "A collection of terascope monorepo scripts", "homepage": "https://github.com/terascope/teraslice/tree/master/packages/scripts#readme", "bugs": { diff --git a/packages/scripts/src/cmds/test.ts b/packages/scripts/src/cmds/test.ts index bb22d88d965..c6768f62535 100644 --- a/packages/scripts/src/cmds/test.ts +++ b/packages/scripts/src/cmds/test.ts @@ -23,6 +23,7 @@ type Options = { 'ignore-mount': boolean; 'test-platform': string; 'skip-image-deletion': boolean; + 'use-helmfile': boolean; }; const jestArgs = getExtraArgs(); @@ -107,6 +108,11 @@ const cmd: CommandModule = { type: 'boolean', default: config.SKIP_IMAGE_DELETION, }) + .option('use-helmfile', { + description: 'If true k8s tests will launch using helmfile, if false tests use kubectl and @kubernetes/client-node', + type: 'boolean', + default: config.USE_HELMFILE, + }) .positional('packages', { description: 'Runs the tests for one or more package and/or an asset, if none specified it will run all of the tests', coerce(arg) { @@ -133,6 +139,7 @@ const cmd: CommandModule = { const testPlatform = hoistJestArg(argv, 'test-platform', 'string') as 'native' | 'kubernetes' | 'kubernetesV2'; const kindClusterName = testPlatform === 'native' ? 'default' : 'k8s-e2e'; const skipImageDeletion = hoistJestArg(argv, 'skip-image-deletion', 'boolean'); + const useHelmfile = hoistJestArg(argv, 'use-helmfile', 'boolean'); if (debug && watch) { throw new Error('--debug and --watch conflict, please set one or the other'); @@ -154,7 +161,8 @@ const cmd: CommandModule = { ignoreMount, testPlatform, kindClusterName, - skipImageDeletion + skipImageDeletion, + useHelmfile }); }, }; diff --git a/packages/scripts/src/helpers/config.ts b/packages/scripts/src/helpers/config.ts index df35f1a86cb..a36a00c724a 100644 --- a/packages/scripts/src/helpers/config.ts +++ b/packages/scripts/src/helpers/config.ts @@ -19,9 +19,9 @@ export const __DEFAULT_ELASTICSEARCH6_VERSION = '6.8.6'; /** Default elasticsearch7 version used to populate the CI cache */ export const __DEFAULT_ELASTICSEARCH7_VERSION = '7.9.3'; /** Default opensearch1 version used to populate the CI cache */ -export const __DEFAULT_OPENSEARCH1_VERSION = '1.3.10'; +export const __DEFAULT_OPENSEARCH1_VERSION = '1.3.11'; /** Default opensearch2 version used to populate the CI cache */ -export const __DEFAULT_OPENSEARCH2_VERSION = '2.8.0'; +export const __DEFAULT_OPENSEARCH2_VERSION = '2.15.0'; export const TERASLICE_PORT = '45678'; export const HOST_IP = process.env.HOST_IP || address(); @@ -46,7 +46,7 @@ export const KAFKA_NAME = process.env.KAFKA_NAME || 'kafka'; 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.5'; +export const KAFKA_VERSION = process.env.KAFKA_VERSION || '3.7'; // 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'; @@ -207,3 +207,4 @@ export const DOCKER_IMAGES_PATH = './images'; export const DOCKER_IMAGE_LIST_PATH = `${DOCKER_IMAGES_PATH}/image-list.txt`; export const DOCKER_CACHE_PATH = '/tmp/docker_cache'; export const SKIP_IMAGE_DELETION = toBoolean(process.env.SKIP_IMAGE_DELETION) || false; +export const USE_HELMFILE = toBoolean(process.env.USE_HELMFILE) || false; diff --git a/packages/scripts/src/helpers/k8s-env/index.ts b/packages/scripts/src/helpers/k8s-env/index.ts index d36b34e8e8e..be29e795db4 100644 --- a/packages/scripts/src/helpers/k8s-env/index.ts +++ b/packages/scripts/src/helpers/k8s-env/index.ts @@ -107,7 +107,8 @@ export async function launchK8sEnv(options: K8sEnvOptions) { useExistingServices: false, ignoreMount: false, testPlatform: options.clusteringType, - skipImageDeletion: false + skipImageDeletion: false, + useHelmfile: false }); try { diff --git a/packages/scripts/src/helpers/kind.ts b/packages/scripts/src/helpers/kind.ts index ee790a0fa7e..84d9f600d91 100644 --- a/packages/scripts/src/helpers/kind.ts +++ b/packages/scripts/src/helpers/kind.ts @@ -54,7 +54,7 @@ export class Kind { configFile.nodes[0].extraMounts.push(...dockerFileMounts); } } - configFile.nodes[0].extraPortMappings[1].hostPort = Number.parseInt(teraslicePort, 10); + configFile.nodes[0].extraPortMappings[0].hostPort = Number.parseInt(teraslicePort, 10); const updatedYaml = yaml.dump(configFile); const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'tempYaml')); diff --git a/packages/scripts/src/helpers/mapper.ts b/packages/scripts/src/helpers/mapper.ts index 497b6d74b0f..faabebecedd 100644 --- a/packages/scripts/src/helpers/mapper.ts +++ b/packages/scripts/src/helpers/mapper.ts @@ -11,19 +11,22 @@ export function kafkaVersionMapper(kafkaVersion: string): string { } const kafkaMapper: Record> = { 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' + 0: '7.0.16', + 1: '7.1.15', + 2: '7.2.13', + 3: '7.3.11', + 4: '7.4.8', + 5: '7.5.7', + 6: '7.6.4', + 7: '7.7.2', + 8: '7.8.0' }, 2: { 4: '5.4.10', 5: '5.5.12', 6: '6.0.15', - 7: '6.1.13', - 8: '6.2.12' + 7: '6.1.15', + 8: '6.2.15' } }; diff --git a/packages/scripts/src/helpers/scripts.ts b/packages/scripts/src/helpers/scripts.ts index 8000eeb28de..44c6e2acd12 100644 --- a/packages/scripts/src/helpers/scripts.ts +++ b/packages/scripts/src/helpers/scripts.ts @@ -13,9 +13,10 @@ import { TSCommands, PackageInfo } from './interfaces.js'; import { getRootDir } from './misc.js'; import signale from './signale.js'; import * as config from './config.js'; -import { getE2eK8sDir } from '../helpers/packages.js'; +import { getE2EDir, getE2eK8sDir } from '../helpers/packages.js'; import { YamlDeploymentResource, YamlServiceResource } from './k8s-env/interfaces.js'; import { Kind } from './kind.js'; +import { ENV_SERVICES } from './config.js'; const logger = debugLogger('ts-scripts:cmd'); @@ -625,6 +626,24 @@ export async function isKubectlInstalled(): Promise { } } +export async function isHelmInstalled(): Promise { + try { + const subprocess = await execaCommand('command -v helm'); + return !!subprocess.stdout; + } catch (err) { + return false; + } +} + +export async function isHelmfileInstalled(): Promise { + try { + const subprocess = await execaCommand('command -v helmfile'); + return !!subprocess.stdout; + } catch (err) { + return false; + } +} + export async function k8sStopService(serviceName: string): Promise { const e2eK8sDir = getE2eK8sDir(); if (!e2eK8sDir) { @@ -730,7 +749,7 @@ export async function showState(tsPort: string) { } async function showESIndices() { - const subprocess = await execaCommand(`curl ${config.HOST_IP}:${config.ELASTICSEARCH_PORT}/_cat/indices?v`); + const subprocess = await execaCommand(`curl ${config.SEARCH_TEST_HOST}/_cat/indices?v`); return subprocess.stdout; } @@ -762,3 +781,90 @@ export async function logTCPPorts() { signale.error('Execa command failed trying to log ports: ', err); } } + +export async function helmfileDelete(selector: string) { + const e2eDir = getE2EDir(); + if (!e2eDir) { + throw new Error('Missing e2e test directory'); + } + const helmfilePath = path.join(e2eDir, 'helm/helmfile.yaml'); + + try { + const subprocess = await execaCommand(`helmfile delete -f ${helmfilePath} --selector app=${selector}`); + logger.debug('helmfile delete: ', subprocess.stdout); + } catch (err) { + logger.info(err); + } +} + +export async function helmfileDiff() { + const e2eDir = getE2EDir(); + if (!e2eDir) { + throw new Error('Missing e2e test directory'); + } + const helmfilePath = path.join(e2eDir, 'helm/helmfile.yaml'); + const values = createValuesStringFromServicesArray(); + + const subprocess = await execaCommand(`helmfile ${values} diff -f ${helmfilePath} --suppress-secrets`); + logger.debug('helmfile diff: ', subprocess.stdout); +} + +export async function helmfileSync() { + const e2eDir = getE2EDir(); + if (!e2eDir) { + throw new Error('Missing e2e test directory'); + } + const helmfilePath = path.join(e2eDir, 'helm/helmfile.yaml'); + const values = createValuesStringFromServicesArray(); + + const subprocess = await execaCommand(`helmfile ${values} sync -f ${helmfilePath}`); + logger.debug('helmfile sync: ', subprocess.stdout); +} + +export async function launchE2EWithHelmfile() { + await helmfileDiff(); + await helmfileSync(); +} + +function createValuesStringFromServicesArray() { + let values = ENV_SERVICES.reduce((valuesString, service) => { + let serviceString = service.toString(); + let version; + let stateCluster; + let newValuesString; + + // Setting the stateCluster will only work properly if there is a single ES/OS service + // If we need multiple in the future we need to modify this. + if (service === 'opensearch') { + serviceString += config.OPENSEARCH_VERSION.charAt(0); + version = config.OPENSEARCH_VERSION; + stateCluster = serviceString; + } + if (service === 'elasticsearch') { + serviceString += config.ELASTICSEARCH_VERSION.charAt(0); + version = config.ELASTICSEARCH_VERSION; + stateCluster = serviceString; + } + if (service === 'kafka') { + version = config.KAFKA_IMAGE_VERSION; + } + if (service === 'zookeeper') { + version = config.ZOOKEEPER_VERSION; + } + if (service === 'minio') { + version = config.MINIO_VERSION; + } + + newValuesString = `${valuesString} --state-values-set ${serviceString}.enabled=true --state-values-set ${serviceString}.version=${version}`; + + if (stateCluster) { + newValuesString += ` --state-values-set teraslice.stateCluster=${stateCluster}`; + } + + return newValuesString; + }, ''); + + values += ` --state-values-set teraslice.image.tag=e2e-nodev${config.NODE_VERSION}`; + logger.debug('helmfile command values: ', values); + return values; +} diff --git a/packages/scripts/src/helpers/test-runner/index.ts b/packages/scripts/src/helpers/test-runner/index.ts index 9f871934a07..8f5a89675b1 100644 --- a/packages/scripts/src/helpers/test-runner/index.ts +++ b/packages/scripts/src/helpers/test-runner/index.ts @@ -10,9 +10,9 @@ import { ensureServices, loadOrPullServiceImages } from './services.js'; import { PackageInfo } from '../interfaces.js'; import { TestOptions } from './interfaces.js'; import { - runJest, dockerTag, isKindInstalled, - isKubectlInstalled, loadThenDeleteImageFromCache, - deleteDockerImageCache + runJest, dockerTag, isKindInstalled, isKubectlInstalled, + loadThenDeleteImageFromCache, deleteDockerImageCache, + isHelmInstalled, isHelmfileInstalled, launchE2EWithHelmfile } from '../scripts.js'; import { Kind } from '../kind.js'; import { @@ -212,7 +212,19 @@ async function runE2ETest( const kubectlInstalled = await isKubectlInstalled(); if (!kubectlInstalled && !isCI) { - signale.error('Please install kubectl before running k8s tests. https://kubernetes.io/docs/tasks/tools/'); + signale.error('Please install kubectl before running k8s tests. https://kubernetes.io/docs/tasks/tools'); + process.exit(1); + } + + const helmInstalled = await isHelmInstalled(); + if (!helmInstalled && !isCI) { + signale.error('Please install Helm before running k8s tests.https://helm.sh/docs/intro/install'); + process.exit(1); + } + + const helmfileInstalled = await isHelmfileInstalled(); + if (!helmfileInstalled && !isCI) { + signale.error('Please install helmfile before running k8s tests. https://helmfile.readthedocs.io/en/latest/#installation'); process.exit(1); } @@ -227,8 +239,10 @@ async function runE2ETest( await kind.destroyCluster(); process.exit(1); } - const k8s = new K8s(TERASLICE_PORT, options.kindClusterName); - await k8s.createNamespace('services-ns.yaml', 'services'); + if (!options.useHelmfile) { + const k8s = new K8s(TERASLICE_PORT, options.kindClusterName); + await k8s.createNamespace('services-ns.yaml', 'services'); + } } catch (err) { tracker.addError(err); } @@ -268,18 +282,26 @@ async function runE2ETest( if (kind && (options.testPlatform === 'kubernetes' || options.testPlatform === 'kubernetesV2')) { try { await kind.loadTerasliceImage(e2eImage); + if (options.useHelmfile) { + const timeLabel = 'helmfile deployment'; + signale.time(timeLabel); + await launchE2EWithHelmfile(); + signale.timeEnd(timeLabel); + } } catch (err) { tracker.addError(err); } } - try { - tracker.addCleanup( - 'e2e:services', - await ensureServices(suite, options) - ); - } catch (err) { - tracker.addError(err); + if (!options.useHelmfile) { + try { + tracker.addCleanup( + 'e2e:services', + await ensureServices(suite, options) + ); + } catch (err) { + tracker.addError(err); + } } if (!options.skipImageDeletion) { diff --git a/packages/scripts/src/helpers/test-runner/interfaces.ts b/packages/scripts/src/helpers/test-runner/interfaces.ts index e886964baf6..8bfdeb44a95 100644 --- a/packages/scripts/src/helpers/test-runner/interfaces.ts +++ b/packages/scripts/src/helpers/test-runner/interfaces.ts @@ -17,6 +17,7 @@ export type TestOptions = { testPlatform: 'native' | 'kubernetes' | 'kubernetesV2'; kindClusterName: string; skipImageDeletion: boolean; + useHelmfile: boolean; }; export type GroupedPackages = { diff --git a/packages/scripts/src/helpers/test-runner/utils.ts b/packages/scripts/src/helpers/test-runner/utils.ts index f1780913789..f2a7430a8e1 100644 --- a/packages/scripts/src/helpers/test-runner/utils.ts +++ b/packages/scripts/src/helpers/test-runner/utils.ts @@ -71,7 +71,8 @@ export function getEnv(options: TestOptions, suite: string): ExecEnv { KIND_CLUSTER: options.kindClusterName, TERASLICE_PORT: config.TERASLICE_PORT, TJM_TEST_MODE: suite !== 'e2e' ? 'true' : 'false', - NODE_OPTIONS: '--experimental-vm-modules' + NODE_OPTIONS: '--experimental-vm-modules', + USE_HELMFILE: options.useHelmfile ? 'true' : 'false' }; if (config.DOCKER_NETWORK_NAME) { @@ -138,7 +139,6 @@ export function getEnv(options: TestOptions, suite: string): ExecEnv { DISABLE_SECURITY_PLUGIN: true, DISABLE_INSTALL_DEMO_CONFIG: true, SEARCH_TEST_HOST: `${config.SEARCH_TEST_HOST}` - }); } diff --git a/packages/scripts/test/helpers-spec.ts b/packages/scripts/test/helpers-spec.ts index 403a4431c61..5fe37f5f648 100644 --- a/packages/scripts/test/helpers-spec.ts +++ b/packages/scripts/test/helpers-spec.ts @@ -49,15 +49,15 @@ describe('Helpers', () => { expect(() => kafkaVersionMapper('2.3')).toThrow(); expect(() => kafkaVersionMapper('2.9')).toThrow(); expect(() => kafkaVersionMapper('3')).toThrow(); - expect(() => kafkaVersionMapper('3.6')).toThrow(); + expect(() => kafkaVersionMapper('3.9')).toThrow(); expect(() => kafkaVersionMapper('4.0')).toThrow(); }); it('should be able to convert kafka versions to the proper confluent/cp-kafka versions', () => { - expect(kafkaVersionMapper('3.1')).toBe('7.1.9'); - expect(kafkaVersionMapper('3.5')).toBe('7.5.1'); + expect(kafkaVersionMapper('3.1')).toBe('7.1.15'); + expect(kafkaVersionMapper('3.5')).toBe('7.5.7'); expect(kafkaVersionMapper('2.4')).toBe('5.4.10'); - expect(kafkaVersionMapper('2.8')).toBe('6.2.12'); + expect(kafkaVersionMapper('2.8')).toBe('6.2.15'); }); }); }); diff --git a/packages/scripts/test/service-spec.ts b/packages/scripts/test/service-spec.ts index e6469d1b7a0..c2fdc2cb4c3 100644 --- a/packages/scripts/test/service-spec.ts +++ b/packages/scripts/test/service-spec.ts @@ -111,7 +111,8 @@ describe('services', () => { ignoreMount: false, testPlatform: 'native', kindClusterName: 'default', - skipImageDeletion: false + skipImageDeletion: false, + useHelmfile: false }; let services: any; diff --git a/packages/scripts/test/test-runner-spec.ts b/packages/scripts/test/test-runner-spec.ts index d428592aaef..82f90e0735f 100644 --- a/packages/scripts/test/test-runner-spec.ts +++ b/packages/scripts/test/test-runner-spec.ts @@ -22,7 +22,8 @@ describe('Test Runner Helpers', () => { ignoreMount: true, testPlatform: 'native', kindClusterName: 'default', - skipImageDeletion: false + skipImageDeletion: false, + useHelmfile: false }; function makeTestOptions(input: Partial): TestOptions { diff --git a/packages/teraslice/package.json b/packages/teraslice/package.json index 02e7cec371d..88205c7c864 100644 --- a/packages/teraslice/package.json +++ b/packages/teraslice/package.json @@ -30,7 +30,7 @@ "test:elasticsearch6": "TEST_ELASTICSEARCH='true' ELASTICSEARCH_VERSION='6.8.6' yarn workspace @terascope/scripts ts-scripts test ../teraslice --", "test:elasticsearch7": "TEST_ELASTICSEARCH='true' ELASTICSEARCH_VERSION='7.9.3' yarn workspace @terascope/scripts ts-scripts test ../teraslice --", "test:opensearch1": "TEST_OPENSEARCH='true' yarn workspace @terascope/scripts ts-scripts test ../teraslice --", - "test:opensearch2": "TEST_OPENSEARCH='true' OPENSEARCH_VERSION='2.8.0' yarn workspace @terascope/scripts ts-scripts test ../teraslice --", + "test:opensearch2": "TEST_OPENSEARCH='true' OPENSEARCH_VERSION='2.15.0' yarn workspace @terascope/scripts ts-scripts test ../teraslice --", "test:watch": "TEST_ELASTICSEARCH='true' yarn workspace @terascope/scripts ts-scripts test --watch ../teraslice --" }, "resolutions": { diff --git a/yarn.lock b/yarn.lock index dc6020fafb8..dbaae941935 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2964,7 +2964,7 @@ __metadata: languageName: unknown linkType: soft -"@terascope/scripts@npm:~1.9.3, @terascope/scripts@workspace:packages/scripts": +"@terascope/scripts@npm:~1.10.0, @terascope/scripts@workspace:packages/scripts": version: 0.0.0-use.local resolution: "@terascope/scripts@workspace:packages/scripts" dependencies: @@ -6415,8 +6415,9 @@ __metadata: version: 0.0.0-use.local resolution: "e2e@workspace:e2e" dependencies: - "@terascope/scripts": "npm:~1.9.3" + "@terascope/scripts": "npm:~1.10.0" "@terascope/types": "npm:~1.4.1" + "@terascope/utils": "npm:~1.7.3" bunyan: "npm:~1.8.15" elasticsearch-store: "npm:~1.8.1" fs-extra: "npm:~11.3.0" @@ -13387,7 +13388,7 @@ __metadata: "@eslint/js": "npm:~9.19.0" "@swc/core": "npm:1.10.9" "@swc/jest": "npm:~0.2.37" - "@terascope/scripts": "npm:~1.9.3" + "@terascope/scripts": "npm:~1.10.0" "@types/bluebird": "npm:~3.5.42" "@types/convict": "npm:~6.1.6" "@types/elasticsearch": "npm:~5.0.43"