@vaharoni/devops 1.0.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -0
- package/dist/app-support/crypto/index.d.ts +15 -0
- package/dist/app-support/crypto/index.d.ts.map +1 -0
- package/dist/app-support/crypto/index.js +30 -0
- package/dist/app-support/crypto/internal-token.d.ts +20 -0
- package/dist/app-support/crypto/internal-token.d.ts.map +1 -0
- package/dist/app-support/crypto/internal-token.js +42 -0
- package/dist/app-support/crypto/internal-token.spec.d.ts +2 -0
- package/dist/app-support/crypto/internal-token.spec.d.ts.map +1 -0
- package/dist/app-support/crypto/internal-token.spec.js +45 -0
- package/dist/app-support/crypto/secret.d.ts +3 -0
- package/dist/app-support/crypto/secret.d.ts.map +1 -0
- package/dist/app-support/crypto/secret.js +12 -0
- package/dist/app-support/crypto/secret.spec.d.ts +2 -0
- package/dist/app-support/crypto/secret.spec.d.ts.map +1 -0
- package/dist/app-support/crypto/secret.spec.js +15 -0
- package/dist/app-support/discovery/dev-discovery-loader.d.ts +2 -0
- package/dist/app-support/discovery/dev-discovery-loader.d.ts.map +1 -0
- package/dist/app-support/discovery/dev-discovery-loader.js +30 -0
- package/dist/app-support/discovery/service-endpoint.d.ts +2 -0
- package/dist/app-support/discovery/service-endpoint.d.ts.map +1 -0
- package/dist/app-support/discovery/service-endpoint.js +10 -0
- package/dist/cli/affected.d.ts +11 -0
- package/dist/cli/affected.d.ts.map +1 -0
- package/dist/cli/affected.js +103 -0
- package/dist/cli/common.d.ts +89 -0
- package/dist/cli/common.d.ts.map +1 -0
- package/dist/cli/common.js +236 -0
- package/dist/cli/common.spec.d.ts +2 -0
- package/dist/cli/common.spec.d.ts.map +1 -0
- package/dist/cli/common.spec.js +64 -0
- package/dist/cli/console.d.ts +11 -0
- package/dist/cli/console.d.ts.map +1 -0
- package/dist/cli/console.js +35 -0
- package/dist/cli/constant.d.ts +11 -0
- package/dist/cli/constant.d.ts.map +1 -0
- package/dist/cli/constant.js +22 -0
- package/dist/cli/db.d.ts +11 -0
- package/dist/cli/db.d.ts.map +1 -0
- package/dist/cli/db.js +119 -0
- package/dist/cli/dml.d.ts +11 -0
- package/dist/cli/dml.d.ts.map +1 -0
- package/dist/cli/dml.js +116 -0
- package/dist/cli/env.d.ts +11 -0
- package/dist/cli/env.d.ts.map +1 -0
- package/dist/cli/env.js +67 -0
- package/dist/cli/exec.d.ts +11 -0
- package/dist/cli/exec.d.ts.map +1 -0
- package/dist/cli/exec.js +50 -0
- package/dist/cli/image.d.ts +11 -0
- package/dist/cli/image.d.ts.map +1 -0
- package/dist/cli/image.js +140 -0
- package/dist/cli/init.d.ts +11 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +66 -0
- package/dist/cli/internal-curl.d.ts +11 -0
- package/dist/cli/internal-curl.d.ts.map +1 -0
- package/dist/cli/internal-curl.js +43 -0
- package/dist/cli/job.d.ts +11 -0
- package/dist/cli/job.d.ts.map +1 -0
- package/dist/cli/job.js +67 -0
- package/dist/cli/jwt.d.ts +11 -0
- package/dist/cli/jwt.d.ts.map +1 -0
- package/dist/cli/jwt.js +27 -0
- package/dist/cli/namespace.d.ts +11 -0
- package/dist/cli/namespace.d.ts.map +1 -0
- package/dist/cli/namespace.js +70 -0
- package/dist/cli/prep-build.d.ts +11 -0
- package/dist/cli/prep-build.d.ts.map +1 -0
- package/dist/cli/prep-build.js +82 -0
- package/dist/cli/prisma.d.ts +11 -0
- package/dist/cli/prisma.d.ts.map +1 -0
- package/dist/cli/prisma.js +25 -0
- package/dist/cli/redis.d.ts +11 -0
- package/dist/cli/redis.d.ts.map +1 -0
- package/dist/cli/redis.js +76 -0
- package/dist/cli/registry.d.ts +11 -0
- package/dist/cli/registry.d.ts.map +1 -0
- package/dist/cli/registry.js +58 -0
- package/dist/cli/run-many.d.ts +11 -0
- package/dist/cli/run-many.d.ts.map +1 -0
- package/dist/cli/run-many.js +50 -0
- package/dist/cli/run.d.ts +11 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +37 -0
- package/dist/cli/template.d.ts +11 -0
- package/dist/cli/template.d.ts.map +1 -0
- package/dist/cli/template.js +123 -0
- package/dist/cli/test.d.ts +11 -0
- package/dist/cli/test.d.ts.map +1 -0
- package/dist/cli/test.js +28 -0
- package/dist/devops.d.ts +3 -0
- package/dist/devops.d.ts.map +1 -0
- package/dist/devops.js +103 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/libs/affected-entities.d.ts +15 -0
- package/dist/libs/affected-entities.d.ts.map +1 -0
- package/dist/libs/affected-entities.js +52 -0
- package/dist/libs/config.d.ts +6 -0
- package/dist/libs/config.d.ts.map +1 -0
- package/dist/libs/config.js +98 -0
- package/dist/libs/dependencies.d.ts +19 -0
- package/dist/libs/dependencies.d.ts.map +1 -0
- package/dist/libs/dependencies.js +62 -0
- package/dist/libs/dependencies.spec.d.ts +2 -0
- package/dist/libs/dependencies.spec.d.ts.map +1 -0
- package/dist/libs/dependencies.spec.js +21 -0
- package/dist/libs/digital-ocean/container-reg.d.ts +6 -0
- package/dist/libs/digital-ocean/container-reg.d.ts.map +1 -0
- package/dist/libs/digital-ocean/container-reg.js +69 -0
- package/dist/libs/discovery/dependencies.d.ts +19 -0
- package/dist/libs/discovery/dependencies.d.ts.map +1 -0
- package/dist/libs/discovery/dependencies.js +62 -0
- package/dist/libs/discovery/dependencies.spec.d.ts +2 -0
- package/dist/libs/discovery/dependencies.spec.d.ts.map +1 -0
- package/dist/libs/discovery/dependencies.spec.js +21 -0
- package/dist/libs/discovery/images.d.ts +5 -0
- package/dist/libs/discovery/images.d.ts.map +1 -0
- package/dist/libs/discovery/images.js +45 -0
- package/dist/libs/discovery/index.d.ts +5 -0
- package/dist/libs/discovery/index.d.ts.map +1 -0
- package/dist/libs/discovery/index.js +55 -0
- package/dist/libs/discovery/package-json-processor.d.ts +3 -0
- package/dist/libs/discovery/package-json-processor.d.ts.map +1 -0
- package/dist/libs/discovery/package-json-processor.js +34 -0
- package/dist/libs/discovery/process-common.d.ts +25 -0
- package/dist/libs/discovery/process-common.d.ts.map +1 -0
- package/dist/libs/discovery/process-common.js +40 -0
- package/dist/libs/discovery/process-package-json.d.ts +3 -0
- package/dist/libs/discovery/process-package-json.d.ts.map +1 -0
- package/dist/libs/discovery/process-package-json.js +34 -0
- package/dist/libs/discovery/process-pyproject-toml.d.ts +3 -0
- package/dist/libs/discovery/process-pyproject-toml.d.ts.map +1 -0
- package/dist/libs/discovery/process-pyproject-toml.js +36 -0
- package/dist/libs/discovery/pyproject-toml-processor.d.ts +3 -0
- package/dist/libs/discovery/pyproject-toml-processor.d.ts.map +1 -0
- package/dist/libs/discovery/pyproject-toml-processor.js +39 -0
- package/dist/libs/git-helpers.d.ts +8 -0
- package/dist/libs/git-helpers.d.ts.map +1 -0
- package/dist/libs/git-helpers.js +20 -0
- package/dist/libs/hetzner/reg-secret.d.ts +3 -0
- package/dist/libs/hetzner/reg-secret.d.ts.map +1 -0
- package/dist/libs/hetzner/reg-secret.js +39 -0
- package/dist/libs/k8s-constants.d.ts +12 -0
- package/dist/libs/k8s-constants.d.ts.map +1 -0
- package/dist/libs/k8s-constants.js +66 -0
- package/dist/libs/k8s-db.d.ts +18 -0
- package/dist/libs/k8s-db.d.ts.map +1 -0
- package/dist/libs/k8s-db.js +73 -0
- package/dist/libs/k8s-generate.d.ts +17 -0
- package/dist/libs/k8s-generate.d.ts.map +1 -0
- package/dist/libs/k8s-generate.js +179 -0
- package/dist/libs/k8s-helpers.d.ts +11 -0
- package/dist/libs/k8s-helpers.d.ts.map +1 -0
- package/dist/libs/k8s-helpers.js +42 -0
- package/dist/libs/k8s-image-config.d.ts +8 -0
- package/dist/libs/k8s-image-config.d.ts.map +1 -0
- package/dist/libs/k8s-image-config.js +113 -0
- package/dist/libs/k8s-job-waiter.d.ts +8 -0
- package/dist/libs/k8s-job-waiter.d.ts.map +1 -0
- package/dist/libs/k8s-job-waiter.js +84 -0
- package/dist/libs/k8s-namespace.d.ts +7 -0
- package/dist/libs/k8s-namespace.d.ts.map +1 -0
- package/dist/libs/k8s-namespace.js +27 -0
- package/dist/libs/k8s-redis.d.ts +6 -0
- package/dist/libs/k8s-redis.d.ts.map +1 -0
- package/dist/libs/k8s-redis.js +31 -0
- package/dist/libs/k8s-secrets-manager.d.ts +5 -0
- package/dist/libs/k8s-secrets-manager.d.ts.map +1 -0
- package/dist/libs/k8s-secrets-manager.js +61 -0
- package/dist/libs/validate-env.d.ts +56 -0
- package/dist/libs/validate-env.d.ts.map +1 -0
- package/dist/libs/validate-env.js +214 -0
- package/dist/libs/validate-env.spec.d.ts +2 -0
- package/dist/libs/validate-env.spec.d.ts.map +1 -0
- package/dist/libs/validate-env.spec.js +168 -0
- package/dist/libs/workspace-discovery.d.ts +2 -0
- package/dist/libs/workspace-discovery.d.ts.map +1 -0
- package/dist/libs/workspace-discovery.js +75 -0
- package/dist/test.d.ts +2 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +1 -0
- package/dist/types/index.d.ts +925 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +79 -0
- package/package.json +55 -0
- package/src/app-support/crypto/index.ts +31 -0
- package/src/app-support/crypto/internal-token.spec.ts +53 -0
- package/src/app-support/crypto/internal-token.ts +82 -0
- package/src/app-support/crypto/secret.spec.ts +18 -0
- package/src/app-support/crypto/secret.ts +13 -0
- package/src/app-support/discovery/dev-discovery-loader.ts +35 -0
- package/src/app-support/discovery/service-endpoint.ts +12 -0
- package/src/cli/affected.ts +116 -0
- package/src/cli/common.spec.ts +78 -0
- package/src/cli/common.ts +323 -0
- package/src/cli/console.ts +46 -0
- package/src/cli/constant.ts +25 -0
- package/src/cli/db.ts +133 -0
- package/src/cli/dml.ts +126 -0
- package/src/cli/env.ts +87 -0
- package/src/cli/exec.sh +21 -0
- package/src/cli/exec.ts +57 -0
- package/src/cli/image.ts +197 -0
- package/src/cli/init.ts +75 -0
- package/src/cli/internal-curl.ts +48 -0
- package/src/cli/job.ts +80 -0
- package/src/cli/jwt.ts +32 -0
- package/src/cli/namespace.ts +78 -0
- package/src/cli/prep-build.ts +96 -0
- package/src/cli/prisma.ts +33 -0
- package/src/cli/redis.ts +83 -0
- package/src/cli/registry.ts +76 -0
- package/src/cli/run-many.ts +61 -0
- package/src/cli/run.ts +46 -0
- package/src/cli/template.ts +169 -0
- package/src/cli/test.ts +30 -0
- package/src/devops.ts +119 -0
- package/src/index.ts +3 -0
- package/src/libs/affected-entities.ts +71 -0
- package/src/libs/config.ts +117 -0
- package/src/libs/digital-ocean/container-reg.ts +81 -0
- package/src/libs/discovery/dependencies.spec.ts +25 -0
- package/src/libs/discovery/dependencies.ts +73 -0
- package/src/libs/discovery/images.ts +57 -0
- package/src/libs/discovery/index.ts +60 -0
- package/src/libs/discovery/process-common.ts +55 -0
- package/src/libs/discovery/process-package-json.ts +47 -0
- package/src/libs/discovery/process-pyproject-toml.ts +43 -0
- package/src/libs/git-helpers.ts +32 -0
- package/src/libs/hetzner/reg-secret.ts +54 -0
- package/src/libs/k8s-constants.ts +83 -0
- package/src/libs/k8s-db.ts +83 -0
- package/src/libs/k8s-generate.ts +211 -0
- package/src/libs/k8s-helpers.ts +59 -0
- package/src/libs/k8s-image-config.ts +165 -0
- package/src/libs/k8s-job-waiter.ts +124 -0
- package/src/libs/k8s-namespace.ts +41 -0
- package/src/libs/k8s-redis.ts +31 -0
- package/src/libs/k8s-secrets-manager.ts +79 -0
- package/src/libs/validate-env.spec.ts +223 -0
- package/src/libs/validate-env.ts +266 -0
- package/src/target-templates/.devops/config/constants.yaml +17 -0
- package/src/target-templates/.devops/config/images.yaml +88 -0
- package/src/target-templates/.devops/docker-images/common/docker-common.sh +23 -0
- package/src/target-templates/.devops/docker-images/node-services/node-exec.sh +8 -0
- package/src/target-templates/.devops/docker-images/node-services/node-run.sh +8 -0
- package/src/target-templates/.devops/docker-images/node-services.Dockerfile +34 -0
- package/src/target-templates/.devops/docker-images/python-services/python-exec.sh +8 -0
- package/src/target-templates/.devops/docker-images/python-services/python-run.sh +8 -0
- package/src/target-templates/.devops/docker-images/python-services.Dockerfile +29 -0
- package/src/target-templates/.devops/env.example.yaml +23 -0
- package/src/target-templates/.devops/infra/hetzner/abandoned/harbor-values.yaml +30 -0
- package/src/target-templates/.devops/infra/hetzner/abandoned/hcloud-config.yaml +134 -0
- package/src/target-templates/.devops/infra/hetzner/cert-manager.yaml +25 -0
- package/src/target-templates/.devops/infra/hetzner/harbor-cert.yaml +13 -0
- package/src/target-templates/.devops/infra/hetzner/harbor-values.yaml +76 -0
- package/src/target-templates/.devops/infra/hetzner/hcloud-config.yaml +113 -0
- package/src/target-templates/.devops/infra/hetzner/ingress-nginx-annotations.yaml +49 -0
- package/src/target-templates/.devops/infra/hetzner/ingress-nginx-configmap.yaml +8 -0
- package/src/target-templates/.devops/infra/hetzner/retain-storage-class.yaml +8 -0
- package/src/target-templates/.devops/infra/monitoring-ingress.yaml +62 -0
- package/src/target-templates/.devops/infra/stackgres-ui-ingress.yaml +35 -0
- package/src/target-templates/.devops/infra/test.yaml +60 -0
- package/src/target-templates/.devops/manifests/_index.yaml +21 -0
- package/src/target-templates/.devops/manifests/cron-jobs.yaml.hb +55 -0
- package/src/target-templates/.devops/manifests/db-migrate-job.yaml.hb +42 -0
- package/src/target-templates/.devops/manifests/deployment-debug.yaml.hb +44 -0
- package/src/target-templates/.devops/manifests/deployment-process.yaml.hb +47 -0
- package/src/target-templates/.devops/manifests/deployment-web.yaml.hb +53 -0
- package/src/target-templates/.devops/manifests/ingress.yaml.hb +21 -0
- package/src/target-templates/.devops/manifests/prefect.yaml.hb +62 -0
- package/src/target-templates/.devops/manifests/service.yaml.hb +15 -0
- package/src/target-templates/.devops/milvus/production/milvus-values.yaml +2 -0
- package/src/target-templates/.devops/milvus/staging/milvus-values.yaml +2 -0
- package/src/target-templates/.devops/postgres/DailyOperatorRestart.yaml +54 -0
- package/src/target-templates/.devops/postgres/production/cluster/PodDisruptionBudget.yaml +27 -0
- package/src/target-templates/.devops/postgres/production/cluster/SGCluster.yaml +47 -0
- package/src/target-templates/.devops/postgres/production/cluster/StackGres-alerts.yaml +191 -0
- package/src/target-templates/.devops/postgres/production/configurations/06-SGDistributedLogs.yaml +11 -0
- package/src/target-templates/.devops/postgres/production/configurations/07-SGObjectStorage.yaml +18 -0
- package/src/target-templates/.devops/postgres/production/configurations/08-SGScript.yaml +12 -0
- package/src/target-templates/.devops/postgres/staging/cluster/SGCluster.yaml +42 -0
- package/src/target-templates/.devops/postgres/staging/configurations/07-SGObjectStorage.yaml +18 -0
- package/src/target-templates/.devops/postgres/staging/configurations/08-SGScript.yaml +12 -0
- package/src/target-templates/.devops/prefect/production/prefect-values.yaml +14 -0
- package/src/target-templates/.devops/prefect/staging/prefect-values.yaml +14 -0
- package/src/target-templates/.devops/redis/production/redis-values.yaml +20 -0
- package/src/target-templates/.devops/redis/staging/redis-values.yaml +8 -0
- package/src/target-templates/.envrc +5 -0
- package/src/target-templates/.github/actions/build-image@v1/action.yaml +86 -0
- package/src/target-templates/.github/actions/connect-to-digital-ocean@v1/action.yaml +29 -0
- package/src/target-templates/.github/actions/connect-to-hetzner@v1/action.yaml +31 -0
- package/src/target-templates/.github/actions/connect-to-infra@v1/action.yaml +46 -0
- package/src/target-templates/.github/actions/db-migrate@v1/action.yaml +23 -0
- package/src/target-templates/.github/actions/deploy-image@v1/action.yaml +33 -0
- package/src/target-templates/.github/actions/setup-prereq@v1/action.yaml +29 -0
- package/src/target-templates/.github/workflows/k8s-build.yaml +84 -0
- package/src/target-templates/applications/example-data-pipeline/pyproject.toml +14 -0
- package/src/target-templates/applications/example-data-pipeline/src/example_data_pipeline/main.py +38 -0
- package/src/target-templates/applications/example-node/index.ts +30 -0
- package/src/target-templates/applications/example-node/package.json +26 -0
- package/src/target-templates/applications/example-node/tsconfig.json +3 -0
- package/src/target-templates/applications/example-python/pyproject.toml +20 -0
- package/src/target-templates/applications/example-python/src/example_python/__init__.py +0 -0
- package/src/target-templates/applications/example-python/src/example_python/main.py +13 -0
- package/src/target-templates/applications/example-python/src/example_python/scripts.py +17 -0
- package/src/target-templates/applications/example-python/tests/__init__.py +0 -0
- package/src/target-templates/applications/jobs/README.md +68 -0
- package/src/target-templates/applications/jobs/index.ts +1 -0
- package/src/target-templates/applications/jobs/package.json +30 -0
- package/src/target-templates/applications/jobs/tsconfig.json +3 -0
- package/src/target-templates/config/.env.development +1 -0
- package/src/target-templates/config/.env.global +4 -0
- package/src/target-templates/config/.env.test +1 -0
- package/src/target-templates/db/db/__init__.py +0 -0
- package/src/target-templates/db/db/db_client_test.py +46 -0
- package/src/target-templates/db/db-client-test.ts +140 -0
- package/src/target-templates/db/db-client.ts +19 -0
- package/src/target-templates/db/env.yaml +4 -0
- package/src/target-templates/db/package.json +17 -0
- package/src/target-templates/db/prisma/schema.prisma +24 -0
- package/src/target-templates/db/prisma-setup-vitest.ts +27 -0
- package/src/target-templates/db/pyproject.toml +14 -0
- package/src/target-templates/db/tsconfig.json +3 -0
- package/src/target-templates/devops +3 -0
- package/src/target-templates/devopspy +3 -0
- package/src/target-templates/dml/package.json +7 -0
- package/src/target-templates/dml/tsconfig.json +3 -0
- package/src/target-templates/libs/example-node-lib/bun.lock +27 -0
- package/src/target-templates/libs/example-node-lib/index.ts +3 -0
- package/src/target-templates/libs/example-node-lib/package.json +12 -0
- package/src/target-templates/libs/example-node-lib/tsconfig.json +3 -0
- package/src/target-templates/libs/example-python-lib/pyproject.toml +11 -0
- package/src/target-templates/libs/example-python-lib/src/example_python_lib/__init__.py +2 -0
- package/src/target-templates/pyproject.toml +19 -0
- package/src/target-templates/tmp/.gitkeep +0 -0
- package/src/target-templates/tsconfig.json +27 -0
- package/src/test.ts +0 -0
- package/src/types/index.ts +173 -0
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"k8s-generate.d.ts","sourceRoot":"","sources":["../../src/libs/k8s-generate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAqB3I,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,UAaf;AAED,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAMvH;AAED,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,UAOf;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,UAMf;AA6FD,qBAAa,qBAAqB;IAIb,WAAW,EAAE,MAAM;IAAS,KAAK,EAAE,MAAM;IAAS,MAAM,EAAE,MAAM;IAHnF,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,YAAY,EAAE,IAAI,CAAC,qBAAqB,EAAE,cAAc,CAAC,CAAC;gBAEvC,WAAW,EAAE,MAAM,EAAS,KAAK,EAAE,MAAM,EAAS,MAAM,EAAE,MAAM;IAYnF,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,wBAAwB;IAmB7D,YAAY,IAAI,uBAAuB;IAOvC,QAAQ,IAAI,mBAAmB;CAMhC"}
|
@@ -0,0 +1,179 @@
|
|
1
|
+
import { BASE_SECRET_KEY } from "./k8s-namespace";
|
2
|
+
import { containerRegistryRepoPath, dbMigrateJobName, domainNameForEnv, envToNamespace, imageDebugName, MISSING_DOMAIN_KEY_ERROR, secretName } from "./k8s-constants";
|
3
|
+
import { getWorkspaceScale } from "./k8s-image-config";
|
4
|
+
import path from "path";
|
5
|
+
import yaml from "yaml";
|
6
|
+
import fs from 'fs';
|
7
|
+
import { globSync } from "glob";
|
8
|
+
import _, { template } from 'lodash';
|
9
|
+
import Handlebars from "handlebars";
|
10
|
+
import { getImageData } from "./config";
|
11
|
+
import { getImageDescendentData } from "./discovery/images";
|
12
|
+
const MANIFEST_FOLDER_PATH = path.join(process.cwd(), '.devops/manifests');
|
13
|
+
const MANIFEST_INDEX_FILE_PATH = path.join(MANIFEST_FOLDER_PATH, '_index.yaml');
|
14
|
+
const DB_MIGRATE_TEMPLATE_NAME = 'db-migrate';
|
15
|
+
// = Interface
|
16
|
+
export function generateImageDeployments(monorepoEnv, image, gitSha) {
|
17
|
+
const generator = new ImageContextGenerator(monorepoEnv, image, gitSha);
|
18
|
+
const apps = getImageDescendentData(image)
|
19
|
+
.filter((packageData) => packageData.deployment)
|
20
|
+
.flatMap((projectData) => {
|
21
|
+
const context = generator.getDeployment(projectData);
|
22
|
+
const renderFn = (template) => Handlebars.compile(template)(context);
|
23
|
+
return generateManifestForDeployment(projectData.rootPath, projectData.deployment.template, renderFn);
|
24
|
+
});
|
25
|
+
const debug = generateDebugDeployment(monorepoEnv, image, gitSha);
|
26
|
+
const manifest = [debug, ...apps].join("\n---\n");
|
27
|
+
return ensureProperDomainsPresent(manifest, monorepoEnv, image);
|
28
|
+
}
|
29
|
+
export function generateWorkspaceDeployment(packageData, monorepoEnv, image, gitSha) {
|
30
|
+
const generator = new ImageContextGenerator(monorepoEnv, image, gitSha);
|
31
|
+
const context = generator.getDeployment(packageData);
|
32
|
+
const renderFn = (template) => Handlebars.compile(template)(context);
|
33
|
+
const manifest = generateManifestForDeployment(packageData.rootPath, packageData.deployment.template, renderFn).join("\n---\n");
|
34
|
+
return ensureProperDomainsPresent(manifest, monorepoEnv, image);
|
35
|
+
}
|
36
|
+
export function generateDebugDeployment(monorepoEnv, image, gitSha) {
|
37
|
+
const generator = new ImageContextGenerator(monorepoEnv, image, gitSha);
|
38
|
+
const context = generator.getDebug();
|
39
|
+
const renderFn = (template) => Handlebars.compile(template)(context);
|
40
|
+
const debugTemplate = getImageData(image)["debug-template"];
|
41
|
+
return generateManifestsFromTemplateName(debugTemplate, renderFn).map(x => yaml.stringify(x)).join("\n---\n");
|
42
|
+
}
|
43
|
+
export function generateDbMigrateJob(monorepoEnv, image, gitSha) {
|
44
|
+
const generator = new ImageContextGenerator(monorepoEnv, image, gitSha);
|
45
|
+
const context = generator.getDbMigrate();
|
46
|
+
const renderFn = (template) => Handlebars.compile(template)(context);
|
47
|
+
return generateManifestsFromTemplateName(DB_MIGRATE_TEMPLATE_NAME, renderFn).map(x => yaml.stringify(x)).join("\n---\n");
|
48
|
+
}
|
49
|
+
// = Verification
|
50
|
+
function ensureProperDomainsPresent(manifest, monorepoEnv, image) {
|
51
|
+
if (manifest.includes(MISSING_DOMAIN_KEY_ERROR)) {
|
52
|
+
console.error(`The image ${image} does not have a domain defined for the environment ${monorepoEnv}. Please add it to the .devops/config/images.yaml.`);
|
53
|
+
process.exit(1);
|
54
|
+
}
|
55
|
+
return manifest;
|
56
|
+
}
|
57
|
+
// = Generation logic
|
58
|
+
// L1 generation: composite
|
59
|
+
function generateManifestForDeployment(rootPath, templateName, renderFn) {
|
60
|
+
const defaults = generateManifestsFromTemplateName(templateName, renderFn);
|
61
|
+
const overrides = generateManifestFromFilesInFolder(rootPath, renderFn);
|
62
|
+
const keyExtractor = (manifest) => `${manifest.kind}-${manifest.metadata.name}`;
|
63
|
+
const defaultTemplateLookup = _.keyBy(defaults, keyExtractor);
|
64
|
+
const overrideTemplateLookup = _.keyBy(overrides, keyExtractor);
|
65
|
+
const mergedTemplates = _.merge(defaultTemplateLookup, overrideTemplateLookup);
|
66
|
+
return Object.values(mergedTemplates).map(x => yaml.stringify(x));
|
67
|
+
}
|
68
|
+
// L2 generation
|
69
|
+
function generateManifestsFromTemplateName(templateName, renderFn) {
|
70
|
+
const entries = manifestFilesForTemplate(templateName);
|
71
|
+
if (!entries) {
|
72
|
+
console.error(`No entries found for ${templateName} in ${MANIFEST_INDEX_FILE_PATH}`);
|
73
|
+
process.exit(1);
|
74
|
+
}
|
75
|
+
return generateManifestsFromFileList(entries.map(entry => path.join(MANIFEST_FOLDER_PATH, entry)), renderFn);
|
76
|
+
}
|
77
|
+
// L2 generation
|
78
|
+
function generateManifestFromFilesInFolder(folderPath, renderFn) {
|
79
|
+
const manifestOverridePath = path.join(folderPath, 'manifests');
|
80
|
+
if (!fs.existsSync(manifestOverridePath)) {
|
81
|
+
return [];
|
82
|
+
}
|
83
|
+
const files = globSync(path.join(manifestOverridePath, '**/*')).filter(x => fs.lstatSync(x).isFile());
|
84
|
+
return generateManifestsFromFileList(files, renderFn);
|
85
|
+
}
|
86
|
+
// L3 generation
|
87
|
+
function generateManifestsFromFileList(filesList, renderFn) {
|
88
|
+
return filesList.flatMap((filePath) => {
|
89
|
+
try {
|
90
|
+
const manifestFileStr = fs.readFileSync(filePath, 'utf8');
|
91
|
+
const renderedStr = renderFn(manifestFileStr);
|
92
|
+
const res = yaml.parseAllDocuments(renderedStr);
|
93
|
+
res.forEach((doc) => {
|
94
|
+
if (!doc.get("kind") || !doc.getIn(["metadata", "name"])) {
|
95
|
+
console.error(`Invalid manifest file ${filePath}: kind and metadata.name must be present`);
|
96
|
+
console.error(doc.toString());
|
97
|
+
process.exit(1);
|
98
|
+
}
|
99
|
+
});
|
100
|
+
return res.map(x => x.toJSON());
|
101
|
+
}
|
102
|
+
catch (e) {
|
103
|
+
if (e instanceof Error) {
|
104
|
+
console.error(`Could not parse ${filePath}: ${e.message}`);
|
105
|
+
}
|
106
|
+
else {
|
107
|
+
console.error(`Could not parse ${filePath}`);
|
108
|
+
}
|
109
|
+
process.exit(1);
|
110
|
+
}
|
111
|
+
});
|
112
|
+
}
|
113
|
+
// Infra: the template index file
|
114
|
+
let _manifestIndex;
|
115
|
+
function manifestFilesForTemplate(template) {
|
116
|
+
if (!_manifestIndex) {
|
117
|
+
try {
|
118
|
+
const indexFileStr = fs.readFileSync(MANIFEST_INDEX_FILE_PATH, 'utf8');
|
119
|
+
_manifestIndex = yaml.parse(indexFileStr);
|
120
|
+
}
|
121
|
+
catch {
|
122
|
+
console.error(`Unable to process ${MANIFEST_INDEX_FILE_PATH}`);
|
123
|
+
process.exit(1);
|
124
|
+
}
|
125
|
+
}
|
126
|
+
return _manifestIndex[template];
|
127
|
+
}
|
128
|
+
// Infra: the image context generator
|
129
|
+
export class ImageContextGenerator {
|
130
|
+
monorepoEnv;
|
131
|
+
image;
|
132
|
+
gitSha;
|
133
|
+
replicaMap;
|
134
|
+
imageContext;
|
135
|
+
constructor(monorepoEnv, image, gitSha) {
|
136
|
+
this.monorepoEnv = monorepoEnv;
|
137
|
+
this.image = image;
|
138
|
+
this.gitSha = gitSha;
|
139
|
+
this.replicaMap = getWorkspaceScale(monorepoEnv, image);
|
140
|
+
this.imageContext = {
|
141
|
+
monorepo_env: monorepoEnv,
|
142
|
+
namespace: envToNamespace(monorepoEnv),
|
143
|
+
env_secret_name: secretName(),
|
144
|
+
env_base_secret_key: BASE_SECRET_KEY,
|
145
|
+
domain_name: domainNameForEnv(image, monorepoEnv),
|
146
|
+
image_path: containerRegistryRepoPath(image, monorepoEnv, gitSha),
|
147
|
+
};
|
148
|
+
}
|
149
|
+
getDeployment(pkgData) {
|
150
|
+
if (!pkgData.deployment) {
|
151
|
+
console.error(`The deployment key is missing for workspace ${pkgData.name}`);
|
152
|
+
process.exit(1);
|
153
|
+
}
|
154
|
+
return {
|
155
|
+
// Basic context
|
156
|
+
project_name: pkgData.name,
|
157
|
+
...this.imageContext,
|
158
|
+
// Defaults that can be overriden by pkgData.deployment
|
159
|
+
app_name: pkgData.name,
|
160
|
+
subdomain: pkgData.deployment.service_name,
|
161
|
+
// This may override the defaults above
|
162
|
+
...pkgData.deployment,
|
163
|
+
// Override from config map
|
164
|
+
replicas: this.replicaMap[pkgData.name] ?? 1,
|
165
|
+
};
|
166
|
+
}
|
167
|
+
getDbMigrate() {
|
168
|
+
return {
|
169
|
+
...this.imageContext,
|
170
|
+
db_migrate_job_name: dbMigrateJobName(this.gitSha),
|
171
|
+
};
|
172
|
+
}
|
173
|
+
getDebug() {
|
174
|
+
return {
|
175
|
+
...this.imageContext,
|
176
|
+
debug_pod_name: imageDebugName(this.image)
|
177
|
+
};
|
178
|
+
}
|
179
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
export declare function kubectlCommand(cmd: string, opts?: {
|
2
|
+
monorepoEnv?: string;
|
3
|
+
namespace?: string;
|
4
|
+
}): string;
|
5
|
+
export declare function upsertConfigMapCommand(monorepoEnv: string, configMapName: string, data: Record<string, string>): string;
|
6
|
+
export declare function patchSecretKeyCommand(monorepoEnv: string, secretName: string, secretKey: string, secretValue: string): {
|
7
|
+
fullCommand: string;
|
8
|
+
redactedCommand: string;
|
9
|
+
};
|
10
|
+
export declare function applyHandler(filePrefix: string, command: "apply" | "delete", manifest: string): void;
|
11
|
+
//# sourceMappingURL=k8s-helpers.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"k8s-helpers.d.ts","sourceRoot":"","sources":["../../src/libs/k8s-helpers.ts"],"names":[],"mappings":"AAMA,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,IAAI,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,UAQxD;AAED,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,UAe9G;AAED,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;;;EAUpH;AAED,wBAAgB,YAAY,CAC1B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,GAAG,QAAQ,EAC3B,QAAQ,EAAE,MAAM,QAQjB"}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { CommandExecutor } from "../cli/common";
|
2
|
+
import { envToNamespace } from "./k8s-constants";
|
3
|
+
import fs from "fs";
|
4
|
+
const TMP_MANIFEST_FOLDER = "tmp/k8s-manifests";
|
5
|
+
export function kubectlCommand(cmd, opts = {}) {
|
6
|
+
if (opts.monorepoEnv || opts.namespace) {
|
7
|
+
const namespace = opts.namespace ?? envToNamespace(opts.monorepoEnv);
|
8
|
+
return `kubectl -n ${namespace} ${cmd}`;
|
9
|
+
}
|
10
|
+
else {
|
11
|
+
return `kubectl ${cmd}`;
|
12
|
+
}
|
13
|
+
}
|
14
|
+
export function upsertConfigMapCommand(monorepoEnv, configMapName, data) {
|
15
|
+
const manifest = {
|
16
|
+
apiVersion: 'v1',
|
17
|
+
kind: 'ConfigMap',
|
18
|
+
metadata: {
|
19
|
+
name: configMapName,
|
20
|
+
namespace: envToNamespace(monorepoEnv),
|
21
|
+
labels: {
|
22
|
+
env: monorepoEnv
|
23
|
+
}
|
24
|
+
},
|
25
|
+
data
|
26
|
+
};
|
27
|
+
const applyCmd = kubectlCommand(`apply -f -`, { monorepoEnv });
|
28
|
+
return `echo '${JSON.stringify(manifest)}' | ${applyCmd}`;
|
29
|
+
}
|
30
|
+
export function patchSecretKeyCommand(monorepoEnv, secretName, secretKey, secretValue) {
|
31
|
+
const redactedCommand = kubectlCommand(`patch secret ${secretName} -p='{"stringData": {"${secretKey}": **REDACTED**}}'`, { monorepoEnv });
|
32
|
+
const fullCommand = redactedCommand.replace("**REDACTED**", JSON.stringify(secretValue));
|
33
|
+
return { fullCommand, redactedCommand };
|
34
|
+
}
|
35
|
+
export function applyHandler(filePrefix, command, manifest) {
|
36
|
+
if (!fs.existsSync(TMP_MANIFEST_FOLDER)) {
|
37
|
+
fs.mkdirSync(TMP_MANIFEST_FOLDER, { recursive: true });
|
38
|
+
}
|
39
|
+
const path = `${TMP_MANIFEST_FOLDER}/${filePrefix}-${Date.now()}.yaml`;
|
40
|
+
fs.writeFileSync(path, manifest);
|
41
|
+
new CommandExecutor(kubectlCommand(`${command} -f ${path}`)).exec();
|
42
|
+
}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
export declare function getImageVersion(monorepoEnv: string, image: string): string | undefined;
|
2
|
+
export declare function setImageVersion(monorepoEnv: string, image: string, version: string): string;
|
3
|
+
export declare function deleteImageVersion(monorepoEnv: string, image: string): string;
|
4
|
+
export declare function setWorkspaceScale(monorepoEnv: string, image: string, workspaceName: string, replicaCount: number): number | undefined;
|
5
|
+
export declare function getWorkspaceScale(monorepoEnv: string, image: string): Record<string, number>;
|
6
|
+
export declare function getWorkspaceScale(monorepoEnv: string, image: string, workspaceName: string): number;
|
7
|
+
export declare function resetWorkspaceScale(monorepoEnv: string, image: string, workspaceName?: string): number | Record<string, number>;
|
8
|
+
//# sourceMappingURL=k8s-image-config.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"k8s-image-config.d.ts","sourceRoot":"","sources":["../../src/libs/k8s-image-config.ts"],"names":[],"mappings":"AAqDA,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,sBAGjE;AAED,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,UAIhB;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,UAGpE;AA2BD,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,sBAuBrB;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAC9F,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAAC;AAcrG,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,aAAa,CAAC,EAAE,MAAM,mCAoBvB"}
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import { CommandExecutor } from "../cli/common";
|
2
|
+
import { getWorkspace } from "./discovery";
|
3
|
+
import { imageConfigMap } from "./k8s-constants";
|
4
|
+
import { kubectlCommand, upsertConfigMapCommand } from "./k8s-helpers";
|
5
|
+
function updateImageConfigMap(monorepoEnv, image, data = {}) {
|
6
|
+
const imageConfigMapName = imageConfigMap(image);
|
7
|
+
return new CommandExecutor(upsertConfigMapCommand(monorepoEnv, imageConfigMapName, data)).exec();
|
8
|
+
}
|
9
|
+
function getImageConfigMap(monorepoEnv, image) {
|
10
|
+
const imageConfigMapName = imageConfigMap(image);
|
11
|
+
const { statusCode, stdout } = new CommandExecutor(kubectlCommand(`get configmap ${imageConfigMapName} -o jsonpath='{.data}'`, { monorepoEnv }), { quiet: true }).exec({ asObject: true });
|
12
|
+
if (statusCode !== 0 || !stdout)
|
13
|
+
return {};
|
14
|
+
try {
|
15
|
+
return JSON.parse(stdout);
|
16
|
+
}
|
17
|
+
catch {
|
18
|
+
console.error(`Error parsing config map data for ${image}. Received: ${stdout}`);
|
19
|
+
process.exit(1);
|
20
|
+
}
|
21
|
+
}
|
22
|
+
function deserializeImageConfigMapKey(monorepoEnv, image, key) {
|
23
|
+
const value = getImageConfigMap(monorepoEnv, image)[key];
|
24
|
+
if (!value)
|
25
|
+
return {};
|
26
|
+
try {
|
27
|
+
return JSON.parse(value);
|
28
|
+
}
|
29
|
+
catch {
|
30
|
+
console.error(`Error parsing config map data for ${image} for key ${key}. Received: ${value}`);
|
31
|
+
process.exit(1);
|
32
|
+
}
|
33
|
+
}
|
34
|
+
// = Version
|
35
|
+
export function getImageVersion(monorepoEnv, image) {
|
36
|
+
const data = getImageConfigMap(monorepoEnv, image);
|
37
|
+
return data.version;
|
38
|
+
}
|
39
|
+
export function setImageVersion(monorepoEnv, image, version) {
|
40
|
+
const data = getImageConfigMap(monorepoEnv, image);
|
41
|
+
return updateImageConfigMap(monorepoEnv, image, { ...data, version });
|
42
|
+
}
|
43
|
+
export function deleteImageVersion(monorepoEnv, image) {
|
44
|
+
const { version, ...rest } = getImageConfigMap(monorepoEnv, image);
|
45
|
+
return updateImageConfigMap(monorepoEnv, image, rest);
|
46
|
+
}
|
47
|
+
// = Scale
|
48
|
+
function setK8sScale(monorepoEnv, workspaceName, replicaCount) {
|
49
|
+
const workspaceData = getWorkspace(workspaceName);
|
50
|
+
const serviceName = workspaceData.packageDataEntries.find(x => x.deployment?.service_name)?.deployment?.service_name;
|
51
|
+
if (!serviceName) {
|
52
|
+
console.error(`Workspace ${workspaceName} must have a service_name defined in its deployment key in package.json. Skipping.`);
|
53
|
+
return false;
|
54
|
+
}
|
55
|
+
new CommandExecutor(kubectlCommand(`scale deployment ${workspaceName} --replicas=${replicaCount}`, { monorepoEnv })).exec();
|
56
|
+
return true;
|
57
|
+
}
|
58
|
+
// Returns the old version prior to setting
|
59
|
+
export function setWorkspaceScale(monorepoEnv, image, workspaceName, replicaCount) {
|
60
|
+
const workspaceData = getWorkspace(workspaceName);
|
61
|
+
if (!workspaceData.packageDataEntries.find(x => x.deployment)) {
|
62
|
+
console.error(`Workspace ${workspaceName} does not have deployment data.`);
|
63
|
+
process.exit(1);
|
64
|
+
}
|
65
|
+
if (replicaCount < 1) {
|
66
|
+
console.error("Replica count must be at least 1.");
|
67
|
+
process.exit(1);
|
68
|
+
}
|
69
|
+
const { scale: _scale, ...rest } = getImageConfigMap(monorepoEnv, image);
|
70
|
+
const parsedScale = deserializeImageConfigMapKey(monorepoEnv, image, "scale");
|
71
|
+
const isApplicable = setK8sScale(monorepoEnv, workspaceName, replicaCount);
|
72
|
+
if (!isApplicable)
|
73
|
+
return;
|
74
|
+
updateImageConfigMap(monorepoEnv, image, {
|
75
|
+
...rest,
|
76
|
+
scale: JSON.stringify({
|
77
|
+
...parsedScale,
|
78
|
+
[workspaceName]: replicaCount,
|
79
|
+
}),
|
80
|
+
});
|
81
|
+
return parsedScale?.[workspaceName] ?? 1;
|
82
|
+
}
|
83
|
+
export function getWorkspaceScale(monorepoEnv, image,
|
84
|
+
/** If not provided, returns all workspaces */
|
85
|
+
workspaceName) {
|
86
|
+
const parsedScale = deserializeImageConfigMapKey(monorepoEnv, image, "scale");
|
87
|
+
if (!workspaceName)
|
88
|
+
return parsedScale ?? {};
|
89
|
+
const _ensureWorkspace = getWorkspace(workspaceName);
|
90
|
+
return parsedScale?.[workspaceName] ?? 1;
|
91
|
+
}
|
92
|
+
// /** Returns the old scale prior to deletion */
|
93
|
+
export function resetWorkspaceScale(monorepoEnv, image, workspaceName) {
|
94
|
+
const { scale: _scale, ...rest } = getImageConfigMap(monorepoEnv, image);
|
95
|
+
const parsedScale = deserializeImageConfigMapKey(monorepoEnv, image, "scale");
|
96
|
+
if (!workspaceName) {
|
97
|
+
updateImageConfigMap(monorepoEnv, image, rest);
|
98
|
+
Object.entries(parsedScale ?? {})
|
99
|
+
.filter(([_name, scale]) => Number(scale) > 1)
|
100
|
+
.forEach(([name, _scale]) => {
|
101
|
+
setK8sScale(monorepoEnv, name, 1);
|
102
|
+
});
|
103
|
+
return parsedScale;
|
104
|
+
}
|
105
|
+
else {
|
106
|
+
const oldScale = parsedScale?.[workspaceName] ?? 1;
|
107
|
+
const newScale = { ...parsedScale };
|
108
|
+
delete newScale[workspaceName];
|
109
|
+
updateImageConfigMap(monorepoEnv, image, { ...rest, scale: JSON.stringify(newScale) });
|
110
|
+
setK8sScale(monorepoEnv, workspaceName, 1);
|
111
|
+
return oldScale;
|
112
|
+
}
|
113
|
+
}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
export type JobStatuses = Record<string, {
|
2
|
+
status: "success" | "failure" | "timeout";
|
3
|
+
elapsed: number;
|
4
|
+
error?: string;
|
5
|
+
}>;
|
6
|
+
export declare function k8sJobWaiter(monorepoEnv: string, timeoutInS: number, jobs: string[]): Promise<JobStatuses>;
|
7
|
+
export declare function printJobStatuses(statuses: JobStatuses): void;
|
8
|
+
//# sourceMappingURL=k8s-job-waiter.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"k8s-job-waiter.d.ts","sourceRoot":"","sources":["../../src/libs/k8s-job-waiter.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,WAAW,GAAG,MAAM,CAC9B,MAAM,EACN;IAAE,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAC/E,CAAC;AAqEF,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EAAE,wBAKf;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,WAAW,QAmCrD"}
|
@@ -0,0 +1,84 @@
|
|
1
|
+
import { CommandExecutor } from "../cli/common";
|
2
|
+
import { envToNamespace } from "./k8s-constants";
|
3
|
+
import { kubectlCommand } from "./k8s-helpers";
|
4
|
+
const POLL_INTERVAL_SEC = 1;
|
5
|
+
class K8sJobWaiter {
|
6
|
+
monorepoEnv;
|
7
|
+
timeoutInMs;
|
8
|
+
namespace;
|
9
|
+
jobStatuses;
|
10
|
+
constructor(monorepoEnv, timeoutInS) {
|
11
|
+
this.monorepoEnv = monorepoEnv;
|
12
|
+
this.namespace = envToNamespace(monorepoEnv);
|
13
|
+
this.jobStatuses = {};
|
14
|
+
this.timeoutInMs = timeoutInS * 1000;
|
15
|
+
}
|
16
|
+
async pollJob(job) {
|
17
|
+
const startTime = Date.now();
|
18
|
+
while (true) {
|
19
|
+
const res = await this.fetchStatus(job);
|
20
|
+
const elapsed = Date.now() - startTime;
|
21
|
+
if (res.failure > 0) {
|
22
|
+
const error = await this.fetchError(job);
|
23
|
+
this.jobStatuses[job] = { status: "failure", elapsed, error };
|
24
|
+
return;
|
25
|
+
}
|
26
|
+
if (res.success > 0) {
|
27
|
+
this.jobStatuses[job] = { status: "success", elapsed };
|
28
|
+
return;
|
29
|
+
}
|
30
|
+
if (elapsed >= this.timeoutInMs) {
|
31
|
+
this.jobStatuses[job] = { status: "timeout", elapsed };
|
32
|
+
return;
|
33
|
+
}
|
34
|
+
await new Promise((res) => setTimeout(res, POLL_INTERVAL_SEC * 1000));
|
35
|
+
}
|
36
|
+
}
|
37
|
+
async fetchStatus(job) {
|
38
|
+
const result = new CommandExecutor(kubectlCommand(`get job ${job} -o jsonpath='{.status.failed},{.status.succeeded}'`, { namespace: this.namespace })).exec();
|
39
|
+
const [failure, success] = result.split(",").map((x) => Number(x));
|
40
|
+
return { failure, success };
|
41
|
+
}
|
42
|
+
async fetchError(job) {
|
43
|
+
try {
|
44
|
+
const podName = new CommandExecutor(kubectlCommand(`get pod -l job-name=${job} -o name`, {
|
45
|
+
namespace: this.namespace,
|
46
|
+
})).exec();
|
47
|
+
const logs = new CommandExecutor(kubectlCommand(`logs ${podName}`, { namespace: this.namespace })).exec();
|
48
|
+
return logs;
|
49
|
+
}
|
50
|
+
catch (e) {
|
51
|
+
console.log("Error fetching logs for job", { job, e });
|
52
|
+
return `<COULD NOT FETCH ERROR FOR ${job}>`;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
export async function k8sJobWaiter(monorepoEnv, timeoutInS, jobs) {
|
57
|
+
const waiter = new K8sJobWaiter(monorepoEnv, timeoutInS);
|
58
|
+
await Promise.all(jobs.map((job) => waiter.pollJob(job)));
|
59
|
+
return waiter.jobStatuses;
|
60
|
+
}
|
61
|
+
export function printJobStatuses(statuses) {
|
62
|
+
console.log("Statuses:");
|
63
|
+
Object.entries(statuses).forEach(([job, statusRecord]) => {
|
64
|
+
console.log(`${job}: ${statusRecord.status} ${Math.round((statusRecord.elapsed / 1000) * 100) / 100}s`);
|
65
|
+
});
|
66
|
+
console.log();
|
67
|
+
Object.entries(statuses)
|
68
|
+
.filter(([_, statusRecord]) => statusRecord.status === "failure")
|
69
|
+
.forEach(([job, statusRecord]) => {
|
70
|
+
console.error(`Error for ${job}:`);
|
71
|
+
console.error(statusRecord.error);
|
72
|
+
console.error();
|
73
|
+
});
|
74
|
+
const failures = Object.entries(statuses).filter(([_, statusRecord]) => ["failure", "timeout"].includes(statusRecord.status));
|
75
|
+
if (failures.length > 0) {
|
76
|
+
console.error();
|
77
|
+
console.error(`Some jobs did not succeed: ${failures.map(([job, _]) => job).join(", ")}`);
|
78
|
+
console.error();
|
79
|
+
process.exit(1);
|
80
|
+
}
|
81
|
+
Object.entries(statuses).forEach(([job, statusRecord]) => {
|
82
|
+
console.log(`${job}: ${statusRecord.status}`);
|
83
|
+
});
|
84
|
+
}
|
@@ -0,0 +1,7 @@
|
|
1
|
+
export declare const BASE_SECRET_KEY = "baseSecret";
|
2
|
+
export declare function checkEnvSetup(monorepoEnv: string): boolean;
|
3
|
+
export declare function createNamespace(monorepoEnv: string): void;
|
4
|
+
export declare function createEmptyEnvSecret(monorepoEnv: string): void;
|
5
|
+
export declare function patchBaseSecret(monorepoEnv: string): void;
|
6
|
+
export declare function deleteNamespace(monorepoEnv: string): void;
|
7
|
+
//# sourceMappingURL=k8s-namespace.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"k8s-namespace.d.ts","sourceRoot":"","sources":["../../src/libs/k8s-namespace.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,eAAe,eAAe,CAAC;AAE5C,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,WAQhD;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,QAElD;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,QAGvD;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,QAQlD;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,QAGlD"}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { CommandExecutor } from "../cli/common";
|
2
|
+
import { envToNamespace, secretName } from "./k8s-constants";
|
3
|
+
import { kubectlCommand, patchSecretKeyCommand } from "./k8s-helpers";
|
4
|
+
import { randomBytes } from "crypto";
|
5
|
+
export const BASE_SECRET_KEY = 'baseSecret';
|
6
|
+
export function checkEnvSetup(monorepoEnv) {
|
7
|
+
const namespace = envToNamespace(monorepoEnv);
|
8
|
+
const exitCode = new CommandExecutor(kubectlCommand(`get ns ${namespace}`)).exec({
|
9
|
+
onlyStatusCode: true,
|
10
|
+
});
|
11
|
+
return exitCode === 0;
|
12
|
+
}
|
13
|
+
export function createNamespace(monorepoEnv) {
|
14
|
+
new CommandExecutor(kubectlCommand(`create ns ${envToNamespace(monorepoEnv)}`)).exec();
|
15
|
+
}
|
16
|
+
export function createEmptyEnvSecret(monorepoEnv) {
|
17
|
+
const cmd = kubectlCommand(`create secret generic ${secretName()}`, { namespace: envToNamespace(monorepoEnv) });
|
18
|
+
new CommandExecutor(cmd).exec();
|
19
|
+
}
|
20
|
+
export function patchBaseSecret(monorepoEnv) {
|
21
|
+
const { fullCommand, redactedCommand } = patchSecretKeyCommand(monorepoEnv, secretName(), BASE_SECRET_KEY, randomBytes(32).toString('hex'));
|
22
|
+
new CommandExecutor(fullCommand, { quiet: true, redactedCommand }).exec();
|
23
|
+
}
|
24
|
+
export function deleteNamespace(monorepoEnv) {
|
25
|
+
const cmd = kubectlCommand(`delete ns ${envToNamespace(monorepoEnv)}`);
|
26
|
+
new CommandExecutor(cmd).exec();
|
27
|
+
}
|
@@ -0,0 +1,6 @@
|
|
1
|
+
export declare function getRedisList(): string | null;
|
2
|
+
export declare function getRedisPassword(namespace: string): {
|
3
|
+
password: string;
|
4
|
+
} | null;
|
5
|
+
export declare function establishRedisTunnel(namespace: string, port: string): void;
|
6
|
+
//# sourceMappingURL=k8s-redis.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"k8s-redis.d.ts","sourceRoot":"","sources":["../../src/libs/k8s-redis.ts"],"names":[],"mappings":"AAGA,wBAAgB,YAAY,kBAK3B;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM;;SAajD;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAKnE"}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import { CommandExecutor } from "../cli/common";
|
2
|
+
import { kubectlCommand } from "./k8s-helpers";
|
3
|
+
export function getRedisList() {
|
4
|
+
const cmd = kubectlCommand(`get pods -l app.kubernetes.io/name=redis -A`);
|
5
|
+
const res = new CommandExecutor(cmd, { quiet: true }).exec();
|
6
|
+
if (!res)
|
7
|
+
return null;
|
8
|
+
return res;
|
9
|
+
}
|
10
|
+
export function getRedisPassword(namespace) {
|
11
|
+
const cmd = kubectlCommand(`get secrets/${namespace} -o jsonpath="{.data}"`, {
|
12
|
+
namespace,
|
13
|
+
});
|
14
|
+
const res = new CommandExecutor(cmd, { quiet: true }).exec();
|
15
|
+
if (!res)
|
16
|
+
return null;
|
17
|
+
try {
|
18
|
+
const resJson = JSON.parse(res);
|
19
|
+
const password = atob(resJson["redis-password"]);
|
20
|
+
return { password };
|
21
|
+
}
|
22
|
+
catch {
|
23
|
+
return null;
|
24
|
+
}
|
25
|
+
}
|
26
|
+
export function establishRedisTunnel(namespace, port) {
|
27
|
+
const cmd = kubectlCommand(`port-forward svc/${namespace}-master ${port}:6379`, {
|
28
|
+
namespace,
|
29
|
+
});
|
30
|
+
new CommandExecutor(cmd).spawn();
|
31
|
+
}
|
@@ -0,0 +1,5 @@
|
|
1
|
+
export declare function getMonorepoSecret(monorepoEnv: string, keys?: string[]): string;
|
2
|
+
/** E.g.: setMonorepoSecret('staging', ['KEY1=val1', 'KEY2=val2']) */
|
3
|
+
export declare function setMonorepoSecret(monorepoEnv: string, pairs?: string[]): void;
|
4
|
+
export declare function deleteMonorepoSecret(monorepoEnv: string, keys?: string[]): void;
|
5
|
+
//# sourceMappingURL=k8s-secrets-manager.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"k8s-secrets-manager.d.ts","sourceRoot":"","sources":["../../src/libs/k8s-secrets-manager.ts"],"names":[],"mappings":"AA0DA,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,UAKzE;AAED,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,GAAE,MAAM,EAAO,QAQ1E;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,QAE5E"}
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import { CommandExecutor } from "../cli/common";
|
2
|
+
import { secretName } from "./k8s-constants";
|
3
|
+
import { kubectlCommand, patchSecretKeyCommand } from "./k8s-helpers";
|
4
|
+
// This env file should not be used in local development
|
5
|
+
const SECRET_FILE_NAME = "env_json";
|
6
|
+
// Basic commands (L1)
|
7
|
+
// Override the secret value with the new value
|
8
|
+
function execUpdateSecret(monorepoEnv, secretValue) {
|
9
|
+
const { fullCommand, redactedCommand } = patchSecretKeyCommand(monorepoEnv, secretName(), SECRET_FILE_NAME, JSON.stringify(secretValue));
|
10
|
+
new CommandExecutor(fullCommand, { quiet: true, redactedCommand }).exec();
|
11
|
+
}
|
12
|
+
function getSecret(monorepoEnv, keys = []) {
|
13
|
+
// Dots in jsonpath can only be accessed with a \ prefix
|
14
|
+
const escapedSecretFileName = SECRET_FILE_NAME.replaceAll(".", "\\.");
|
15
|
+
// prettier-ignore
|
16
|
+
const cmd = kubectlCommand(`get secrets/${secretName()} -o jsonpath="{.data['${escapedSecretFileName}']}"`, { monorepoEnv });
|
17
|
+
const res = new CommandExecutor(cmd, { quiet: true }).exec();
|
18
|
+
if (!res)
|
19
|
+
return {};
|
20
|
+
const resJson = JSON.parse(atob(res));
|
21
|
+
if (!keys || keys.length === 0)
|
22
|
+
return resJson;
|
23
|
+
return Object.fromEntries(keys.filter((x) => resJson[x]).map((x) => [x, resJson[x]]));
|
24
|
+
}
|
25
|
+
// Combined commands (L2)
|
26
|
+
function updateSecret(monorepoEnv, vars) {
|
27
|
+
if (!vars || Object.keys(vars).length === 0) {
|
28
|
+
console.error("Keys-value pairs to set must be provided, e.g. KEY1=val1 KEY2=val2");
|
29
|
+
process.exit(1);
|
30
|
+
}
|
31
|
+
const current = getSecret(monorepoEnv);
|
32
|
+
const newVars = { ...current, ...vars };
|
33
|
+
execUpdateSecret(monorepoEnv, newVars);
|
34
|
+
}
|
35
|
+
function deleteSecretKeys(monorepoEnv, keys = []) {
|
36
|
+
if (!keys || keys.length === 0) {
|
37
|
+
console.error("Keys to delete must be provided");
|
38
|
+
process.exit(1);
|
39
|
+
}
|
40
|
+
const secretValue = getSecret(monorepoEnv);
|
41
|
+
keys.forEach((key) => delete secretValue[key]);
|
42
|
+
execUpdateSecret(monorepoEnv, secretValue);
|
43
|
+
}
|
44
|
+
//= Interface (L3)
|
45
|
+
export function getMonorepoSecret(monorepoEnv, keys = []) {
|
46
|
+
const value = getSecret(monorepoEnv, keys);
|
47
|
+
return Object.entries(value)
|
48
|
+
.map((pair) => pair.join("="))
|
49
|
+
.join("\n");
|
50
|
+
}
|
51
|
+
/** E.g.: setMonorepoSecret('staging', ['KEY1=val1', 'KEY2=val2']) */
|
52
|
+
export function setMonorepoSecret(monorepoEnv, pairs = []) {
|
53
|
+
const pairsObj = Object.fromEntries(pairs.map((x) => {
|
54
|
+
const [key, ...values] = x.split("=");
|
55
|
+
return [key, values.join("=")];
|
56
|
+
}));
|
57
|
+
updateSecret(monorepoEnv, pairsObj);
|
58
|
+
}
|
59
|
+
export function deleteMonorepoSecret(monorepoEnv, keys = []) {
|
60
|
+
deleteSecretKeys(monorepoEnv, keys);
|
61
|
+
}
|